mtk 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (147) hide show
  1. data/.yardopts +3 -2
  2. data/DEVELOPMENT_NOTES.md +114 -0
  3. data/INTRO.md +64 -8
  4. data/LICENSE.txt +1 -1
  5. data/README.md +31 -102
  6. data/Rakefile +56 -18
  7. data/bin/mtk +215 -0
  8. data/examples/crescendo.rb +5 -5
  9. data/examples/drum_pattern1.rb +23 -0
  10. data/examples/dynamic_pattern.rb +8 -11
  11. data/examples/gets_and_play.rb +26 -0
  12. data/examples/notation.rb +22 -0
  13. data/examples/play_midi.rb +8 -10
  14. data/examples/random_tone_row.rb +2 -2
  15. data/examples/syntax_to_midi.rb +28 -0
  16. data/examples/test_output.rb +8 -0
  17. data/examples/tone_row_melody.rb +6 -6
  18. data/lib/mtk.rb +52 -40
  19. data/lib/mtk/chord.rb +55 -0
  20. data/lib/mtk/constants/durations.rb +57 -0
  21. data/lib/mtk/constants/intensities.rb +61 -0
  22. data/lib/mtk/constants/intervals.rb +73 -0
  23. data/lib/mtk/constants/pitch_classes.rb +29 -0
  24. data/lib/mtk/constants/pitches.rb +52 -0
  25. data/lib/mtk/duration.rb +211 -0
  26. data/lib/mtk/events/event.rb +119 -0
  27. data/lib/mtk/events/note.rb +112 -0
  28. data/lib/mtk/events/parameter.rb +54 -0
  29. data/lib/mtk/helpers/collection.rb +164 -0
  30. data/lib/mtk/helpers/convert.rb +36 -0
  31. data/lib/mtk/helpers/lilypond.rb +162 -0
  32. data/lib/mtk/helpers/output_selector.rb +67 -0
  33. data/lib/mtk/helpers/pitch_collection.rb +23 -0
  34. data/lib/mtk/helpers/pseudo_constants.rb +26 -0
  35. data/lib/mtk/intensity.rb +156 -0
  36. data/lib/mtk/interval.rb +155 -0
  37. data/lib/mtk/lang/mtk_grammar.citrus +190 -13
  38. data/lib/mtk/lang/parser.rb +29 -0
  39. data/lib/mtk/melody.rb +94 -0
  40. data/lib/mtk/midi/dls_synth_device.rb +144 -0
  41. data/lib/mtk/midi/dls_synth_output.rb +62 -0
  42. data/lib/mtk/midi/file.rb +67 -32
  43. data/lib/mtk/midi/input.rb +97 -0
  44. data/lib/mtk/midi/jsound_input.rb +36 -17
  45. data/lib/mtk/midi/jsound_output.rb +48 -46
  46. data/lib/mtk/midi/output.rb +195 -0
  47. data/lib/mtk/midi/unimidi_input.rb +117 -0
  48. data/lib/mtk/midi/unimidi_output.rb +121 -0
  49. data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
  50. data/lib/mtk/patterns/chain.rb +49 -0
  51. data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
  52. data/lib/mtk/patterns/cycle.rb +18 -0
  53. data/lib/mtk/patterns/for_each.rb +71 -0
  54. data/lib/mtk/patterns/function.rb +39 -0
  55. data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
  56. data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
  57. data/lib/mtk/patterns/pattern.rb +171 -0
  58. data/lib/mtk/patterns/sequence.rb +20 -0
  59. data/lib/mtk/pitch.rb +7 -6
  60. data/lib/mtk/pitch_class.rb +124 -46
  61. data/lib/mtk/pitch_class_set.rb +58 -35
  62. data/lib/mtk/sequencers/event_builder.rb +131 -0
  63. data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
  64. data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
  65. data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
  66. data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
  67. data/lib/mtk/timeline.rb +39 -22
  68. data/lib/mtk/variable.rb +32 -0
  69. data/spec/mtk/chord_spec.rb +83 -0
  70. data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
  71. data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
  72. data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
  73. data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
  74. data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
  75. data/spec/mtk/duration_spec.rb +372 -0
  76. data/spec/mtk/events/event_spec.rb +234 -0
  77. data/spec/mtk/events/note_spec.rb +174 -0
  78. data/spec/mtk/events/parameter_spec.rb +220 -0
  79. data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
  80. data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
  81. data/spec/mtk/intensity_spec.rb +289 -0
  82. data/spec/mtk/interval_spec.rb +265 -0
  83. data/spec/mtk/lang/parser_spec.rb +597 -0
  84. data/spec/mtk/melody_spec.rb +223 -0
  85. data/spec/mtk/midi/file_spec.rb +16 -16
  86. data/spec/mtk/midi/jsound_input_spec.rb +11 -0
  87. data/spec/mtk/midi/jsound_output_spec.rb +11 -0
  88. data/spec/mtk/midi/output_spec.rb +102 -0
  89. data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
  90. data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
  91. data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
  92. data/spec/mtk/patterns/chain_spec.rb +110 -0
  93. data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
  94. data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
  95. data/spec/mtk/patterns/for_each_spec.rb +136 -0
  96. data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
  97. data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
  98. data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
  99. data/spec/mtk/patterns/pattern_spec.rb +132 -0
  100. data/spec/mtk/patterns/sequence_spec.rb +203 -0
  101. data/spec/mtk/pitch_class_set_spec.rb +23 -21
  102. data/spec/mtk/pitch_class_spec.rb +151 -39
  103. data/spec/mtk/pitch_spec.rb +22 -1
  104. data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
  105. data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
  106. data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
  107. data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
  108. data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
  109. data/spec/mtk/timeline_spec.rb +109 -16
  110. data/spec/mtk/variable_spec.rb +52 -0
  111. data/spec/spec_coverage.rb +2 -0
  112. data/spec/spec_helper.rb +3 -0
  113. metadata +188 -91
  114. data/lib/mtk/_constants/durations.rb +0 -80
  115. data/lib/mtk/_constants/intensities.rb +0 -81
  116. data/lib/mtk/_constants/intervals.rb +0 -85
  117. data/lib/mtk/_constants/pitch_classes.rb +0 -35
  118. data/lib/mtk/_constants/pitches.rb +0 -49
  119. data/lib/mtk/event.rb +0 -70
  120. data/lib/mtk/helper/collection.rb +0 -114
  121. data/lib/mtk/helper/event_builder.rb +0 -85
  122. data/lib/mtk/helper/pseudo_constants.rb +0 -26
  123. data/lib/mtk/lang/grammar.rb +0 -17
  124. data/lib/mtk/note.rb +0 -63
  125. data/lib/mtk/pattern/abstract_pattern.rb +0 -132
  126. data/lib/mtk/pattern/cycle.rb +0 -51
  127. data/lib/mtk/pattern/enumerator.rb +0 -26
  128. data/lib/mtk/pattern/function.rb +0 -46
  129. data/lib/mtk/pattern/sequence.rb +0 -30
  130. data/lib/mtk/pitch_set.rb +0 -84
  131. data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
  132. data/lib/mtk/transform/invertible.rb +0 -15
  133. data/lib/mtk/transform/mappable.rb +0 -18
  134. data/lib/mtk/transform/set_theory_operations.rb +0 -34
  135. data/lib/mtk/transform/transposable.rb +0 -14
  136. data/spec/mtk/event_spec.rb +0 -139
  137. data/spec/mtk/helper/event_builder_spec.rb +0 -92
  138. data/spec/mtk/lang/grammar_spec.rb +0 -100
  139. data/spec/mtk/note_spec.rb +0 -115
  140. data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
  141. data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
  142. data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
  143. data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
  144. data/spec/mtk/pattern/sequence_spec.rb +0 -151
  145. data/spec/mtk/pitch_set_spec.rb +0 -198
  146. data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
  147. data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +0 -49
@@ -1,30 +0,0 @@
1
- module MTK
2
- module Pattern
3
-
4
- # A finite list of elements, which can be enumerated one at a time.
5
- class Sequence < AbstractPattern
6
-
7
- # Reset the sequence to the beginning
8
- def rewind
9
- @index = -1
10
- super
11
- end
12
-
13
- ###################
14
- protected
15
-
16
- # (see AbstractPattern#advance!)
17
- def advance!
18
- super
19
- @index += 1
20
- raise StopIteration if @index >= @elements.length
21
- end
22
-
23
- # (see AbstractPattern#current)
24
- def current
25
- @elements[@index]
26
- end
27
- end
28
-
29
- end
30
- end
data/lib/mtk/pitch_set.rb DELETED
@@ -1,84 +0,0 @@
1
- module MTK
2
-
3
- # A set of {Pitch}es
4
- #
5
- class PitchSet
6
-
7
- include Helper::Collection
8
- include Transform::Mappable
9
- include Transform::Transposable
10
- include Transform::Invertible
11
-
12
- attr_reader :pitches
13
-
14
- def initialize(pitches)
15
- @pitches = pitches.to_a.uniq.sort.freeze
16
- end
17
-
18
- def elements
19
- @pitches
20
- end
21
-
22
- def self.from_a enumerable
23
- new enumerable
24
- end
25
-
26
- def to_pitch_class_set
27
- PitchClassSet.new @pitches.map{|p| p.pitch_class }
28
- end
29
-
30
- def pitch_classes
31
- @pitch_classes ||= @pitches.map{|p| p.pitch_class }.uniq
32
- end
33
-
34
- # generate a chord inversion (positive numbers move the lowest notes up an octave, negative moves the highest notes down)
35
- def inversion(number)
36
- number = number.to_i
37
- pitch_set = Array.new(@pitches)
38
- if number > 0
39
- number.times do |count|
40
- index = count % pitch_set.length
41
- pitch_set[index] += 12
42
- end
43
- else
44
- number.abs.times do |count|
45
- index = -(count + 1) % pitch_set.length # count from -1 downward to go backwards through the list starting at the end
46
- pitch_set[index] -= 12
47
- end
48
- end
49
- self.class.new pitch_set
50
- end
51
-
52
- def nearest(pitch_class)
53
- self.transpose @pitches.first.pitch_class.distance_to(pitch_class)
54
- end
55
-
56
- # @param other [#pitches, #to_a, Array]
57
- def == other
58
- if other.respond_to? :pitches
59
- @pitches == other.pitches
60
- elsif other.respond_to? :to_a
61
- @pitches == other.to_a
62
- else
63
- @pitches == other
64
- end
65
- end
66
-
67
- def to_s
68
- @pitches.inspect
69
- end
70
-
71
- end
72
-
73
- # Construct a {PitchSet} from any supported type
74
- def PitchSet(*anything)
75
- anything = anything.first if anything.size == 1
76
- case anything
77
- when Array then PitchSet.new(anything.map{|elem| Pitch(elem) })
78
- when PitchSet then anything
79
- else PitchSet.new([Pitch(anything)])
80
- end
81
- end
82
- module_function :PitchSet
83
-
84
- end
@@ -1,29 +0,0 @@
1
- module MTK
2
- module Sequencer
3
-
4
- # A Sequencer which uses a :rhythm type {Pattern} to determine the delta times between entries in the {Timeline}.
5
- class RhythmicSequencer < AbstractSequencer
6
-
7
- def initialize(patterns, options={})
8
- patterns = patterns.clone
9
- patterns.each_with_index do |pattern, index|
10
- if pattern.type == :rhythm
11
- @rhythm = pattern
12
- patterns.delete_at index # so we don't enumerate the rhythm values in EventBuilder
13
- end
14
- end
15
- super(patterns, options)
16
- end
17
-
18
- ########################
19
- protected
20
-
21
- # (see AbstractSequencer#advance!)
22
- def advance!
23
- @time += @rhythm.next
24
- end
25
-
26
- end
27
-
28
- end
29
- end
@@ -1,15 +0,0 @@
1
- module MTK::Transform
2
-
3
- # {Mappable} class whose elements can handle the :invert message
4
- # @note Classes including this module should include either MTK::Collection or provide a #first method
5
- module Invertible
6
-
7
- # Invert all elements around the given inversion point
8
- # @param inversion_point [Numeric] the value around which all elements will be inverted (defaults to the first element in the collection)
9
- def invert(inversion_point=first)
10
- map{|elem| elem.invert(inversion_point) }
11
- end
12
-
13
- end
14
-
15
- end
@@ -1,18 +0,0 @@
1
- module MTK::Transform
2
-
3
- # Similar to Enumerable, but relies on the including Class's from_a method to
4
- # provide an implementation of #map which returns an object of the same type.
5
- module Mappable
6
- include Enumerable
7
-
8
- # the original Enumerable#map implementation, which returns an Array
9
- alias enumerable_map map
10
-
11
- # the overriden #map implementation, which returns an object of the same type
12
- def map &block
13
- self.class.from_a(enumerable_map &block)
14
- end
15
-
16
- end
17
-
18
- end
@@ -1,34 +0,0 @@
1
- module MTK::Transform
2
-
3
- # {Helper::Collection} that supports set theory operations
4
- module SetTheoryOperations
5
-
6
- # the collection of elements present in both sets
7
- def intersection(other)
8
- self.class.from_a(to_a & other.to_a)
9
- end
10
-
11
- # the collection of all elements present in either set
12
- def union(other)
13
- self.class.from_a(to_a | other.to_a)
14
- end
15
-
16
- # the collection of elements from this set with any elements from the other set removed
17
- def difference(other)
18
- self.class.from_a(to_a - other.to_a)
19
- end
20
-
21
- # the collection of elements that are members of exactly one of the sets
22
- def symmetric_difference(other)
23
- union(other).difference( intersection(other) )
24
- end
25
-
26
- # the collection of elements that are not members of this set
27
- # @note this method requires that the including class define the class method .all(), which returns the collection of all possible elements
28
- def complement
29
- self.class.all.difference(self)
30
- end
31
-
32
- end
33
-
34
- end
@@ -1,14 +0,0 @@
1
- module MTK::Transform
2
-
3
- # {Mappable} class whose elements can handle the :transpose message
4
- module Transposable
5
-
6
- # Transpose all elements upward by the given interval
7
- # @param interval_in_semitones [Numeric] an interval in semitones
8
- def transpose interval_in_semitones
9
- map{|elem| elem + interval_in_semitones }
10
- end
11
-
12
- end
13
-
14
- end
@@ -1,139 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Event do
4
-
5
- let(:intensity) { mf }
6
- let(:duration) { 2.5 }
7
- let(:event) { Event.new(intensity, duration) }
8
-
9
- describe "#intensity" do
10
- it "is the intensity used to create the Event" do
11
- event.intensity.should == intensity
12
- end
13
-
14
- it "is a read-only attribute" do
15
- lambda{ event.intensity = 0 }.should raise_error
16
- end
17
- end
18
-
19
- describe "#duration" do
20
- it "is the duration used to create the Event" do
21
- event.duration.should == duration
22
- end
23
-
24
- it "is a read-only attribute" do
25
- lambda{ event.duration = 0 }.should raise_error
26
- end
27
-
28
- it "is always positive (absolute value of the duration used to construct the Event)" do
29
- Event.new(intensity, -duration).duration.should == duration
30
- end
31
- end
32
-
33
- describe "#rest?" do
34
- it "is true when the duration used to create the Event was negative" do
35
- Event.new(intensity, -duration).rest?.should be_true
36
- end
37
-
38
- it "is false when the duration used to create the Event was positive" do
39
- event.rest?.should be_false
40
- end
41
- end
42
-
43
- describe "from_hash" do
44
- it "constructs an Event using a hash" do
45
- Event.from_hash({ :intensity => intensity, :duration => duration }).should == event
46
- end
47
- end
48
-
49
- describe "#to_hash" do
50
- it "is a hash containing all the attributes of the Event" do
51
- event.to_hash.should == { :intensity => intensity, :duration => duration }
52
- end
53
- end
54
-
55
- describe "#clone_with" do
56
- it "clones the Event when given an empty hash" do
57
- event.clone_with({}).should == event
58
- end
59
-
60
- it "creates an Event with the given :intensity, and the current Event's duration if not provided" do
61
- event2 = event.clone_with :intensity => (intensity * 0.5)
62
- event2.intensity.should == (intensity * 0.5)
63
- event2.duration.should == duration
64
- end
65
-
66
- it "creates an Event with the given :duration, and the current Event's intensity if not provided" do
67
- event2 = event.clone_with :duration => (duration * 2)
68
- event2.intensity.should == intensity
69
- event2.duration.should == (duration * 2)
70
- end
71
- end
72
-
73
- describe '#scale_intensity' do
74
- it 'multiplies @intensity by the argument' do
75
- (event.scale_intensity 0.5).should == Event.new(intensity * 0.5, duration)
76
- end
77
- it 'does not affect the immutability of the Evebt' do
78
- (event.scale_intensity 0.5).should_not == event
79
- end
80
- end
81
-
82
- describe '#scale_duration' do
83
- it 'multiplies @duration by the argument' do
84
- (event.scale_duration 2).should == Event.new(intensity, duration*2)
85
- end
86
- it 'does not affect the immutability of the Event' do
87
- (event.scale_duration 0.5).should_not == event
88
- end
89
- end
90
-
91
- describe "#velocity" do
92
- it "converts intensities in the range 0.0-1.0 to a MIDI velocity in the range 0-127" do
93
- Event.new(0, 0).velocity.should == 0
94
- Event.new(1, 0).velocity.should == 127
95
- end
96
- it "rounds to the nearest MIDI velocity" do
97
- Event.new(0.5, 0).velocity.should == 64 # not be truncated to 63!
98
- end
99
- end
100
-
101
- describe "#duration_in_pulses" do
102
- it "converts beats to pulses, given pulses_per_beat" do
103
- Event.new(0,1).duration_in_pulses(60).should == 60
104
- end
105
-
106
- it "rounds to the nearest pulse" do
107
- Event.new(0,1.5).duration_in_pulses(59).should == 89
108
- end
109
-
110
- it "is always positive (uses absolute value of the duration used to construct the Event)" do
111
- Event.new(intensity, -1).duration_in_pulses(60).should == 60
112
- end
113
- end
114
-
115
- describe "#==" do
116
- it "is true when the intensities and durations are equal" do
117
- event.should == Event.new(intensity, duration)
118
- end
119
- it "is false when the intensities are not equal" do
120
- event.should_not == Event.new(intensity * 0.5, duration)
121
- end
122
- it "is false when the durations are not equal" do
123
- event.should_not == Event.new(intensity, duration * 2)
124
- end
125
- end
126
-
127
- describe "#to_s" do
128
- it "is the intensity and duration to 2-decimal places" do
129
- Event.new(0.454545, 0.789789).to_s.should == "0.45, 0.79"
130
- end
131
- end
132
-
133
- describe "#inspect" do
134
- it "is the string values of intensity and duration" do
135
- Event.new(0.454545, 0.789789).inspect.should == "0.454545, 0.789789"
136
- end
137
- end
138
-
139
- end
@@ -1,92 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Helper::EventBuilder do
4
-
5
- EVENT_BUILDER = MTK::Helper::EventBuilder
6
-
7
- let(:intensity) { EVENT_BUILDER::DEFAULT_INTENSITY }
8
- let(:duration) { EVENT_BUILDER::DEFAULT_DURATION }
9
-
10
- def notes(*pitches)
11
- pitches.map{|pitch| Note(pitch, intensity, duration) }
12
- end
13
-
14
-
15
- describe "#next" do
16
- it "builds a single-note list from a single-pitch list argument" do
17
- event_builder = EVENT_BUILDER.new [Pattern.Cycle(C4)]
18
- event_builder.next.should == notes(C4)
19
- end
20
-
21
- it "builds a list of notes from any pitches in the argument" do
22
- event_builder = EVENT_BUILDER.new [Pattern.Cycle(C4), Pattern.Cycle(D4)]
23
- event_builder.next.should == notes(C4, D4)
24
- end
25
-
26
- it "builds a list of notes from pitch sets" do
27
- event_builder = EVENT_BUILDER.new [ Pattern.Cycle( PitchSet(C4,D4) ) ]
28
- event_builder.next.should == notes(C4, D4)
29
- end
30
-
31
- it "builds notes from pitch classes and a default_pitch, selecting the nearest pitch class to the previous pitch" do
32
- event_builder = EVENT_BUILDER.new [Pattern.Sequence(C,G,B,Eb,D,C)], :default_pitch => D3
33
- notes = []
34
- loop do
35
- notes << event_builder.next
36
- end
37
- notes.flatten.should == notes(C3,G2,B2,Eb3,D3,C3)
38
- end
39
-
40
- it "defaults to a starting point of C4 (middle C)" do
41
- event_builder = EVENT_BUILDER.new [Pattern.Sequence(C4)]
42
- event_builder.next.should == notes(C4)
43
- end
44
-
45
- it "builds notes from pitch class sets, selecting the neartest pitch classes to the previous/default pitch" do
46
- pitch_class_sequence = Pattern::Sequence.new([PitchClassSet(C,G),PitchClassSet(B,Eb),PitchClassSet(D,C)])
47
- event_builder = EVENT_BUILDER.new [pitch_class_sequence], :default_pitch => D3
48
- event_builder.next.should == notes(C3,G3)
49
- event_builder.next.should == notes(B3,Eb3)
50
- event_builder.next.should == notes(D3,C3)
51
- end
52
-
53
- it "builds notes from by adding Numeric intervals in :pitch type Patterns to the previous Pitch" do
54
- event_builder = EVENT_BUILDER.new [ Pattern.PitchSequence( C4, M3, m3, -P5) ]
55
- nexts = []
56
- loop { nexts << event_builder.next }
57
- nexts.should == [notes(C4), notes(E4), notes(G4), notes(C4)]
58
- end
59
-
60
- it "builds notes from by adding Numeric intervals in :pitch type Patterns to all pitches in the previous PitchSet" do
61
- event_builder = EVENT_BUILDER.new [ Pattern.PitchSequence( PitchSet(C4,Eb4), M3, m3, -P5) ]
62
- nexts = []
63
- loop { nexts << event_builder.next }
64
- nexts.should == [notes(C4,Eb4), notes(E4,G4), notes(G4,Bb4), notes(C4,Eb4)]
65
- end
66
-
67
- it "builds notes from intensities" do
68
- event_builder = EVENT_BUILDER.new [ Pattern.PitchCycle(C4), Pattern.IntensitySequence(mf, p, fff) ]
69
- nexts = []
70
- loop { nexts += event_builder.next }
71
- nexts.should == [Note(C4, mf, duration), Note(C4, p, duration), Note(C4, fff, duration)]
72
- end
73
-
74
- it "builds notes from durations" do
75
- event_builder = EVENT_BUILDER.new [ Pattern.PitchCycle(C4), Pattern.DurationSequence(1,2,3) ]
76
- nexts = []
77
- loop { nexts += event_builder.next }
78
- nexts.should == [Note(C4, intensity, 1), Note(C4, intensity, 2), Note(C4, intensity, 3)]
79
- end
80
- end
81
-
82
- describe "#rewind" do
83
- it "resets the state of the EventBuilder" do
84
- event_builder = EVENT_BUILDER.new [ Pattern.PitchSequence(C,P8) ]
85
- event_builder.next.should == [Note(C4,intensity,duration)]
86
- event_builder.next.should == [Note(C5,intensity,duration)]
87
- event_builder.rewind
88
- event_builder.next.should == [Note(C4,intensity,duration)]
89
- end
90
- end
91
-
92
- end