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,151 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Pattern::Sequence do
4
-
5
- SEQUENCE = MTK::Pattern::Sequence
6
-
7
- let(:elements) { [1,2,3] }
8
- let(:sequence) { SEQUENCE.new(elements) }
9
-
10
- it "is a MTK::Collection" do
11
- sequence.should be_a MTK::Helper::Collection
12
- # and now we won't test any other collection features here... see collection_spec
13
- end
14
-
15
- describe ".from_a" do
16
- it "acts like .new" do
17
- SEQUENCE.from_a(elements).should == sequence
18
- end
19
- end
20
-
21
- describe "#elements" do
22
- it "is the array the sequence was constructed with" do
23
- sequence.elements.should == elements
24
- end
25
- end
26
-
27
- describe "#next" do
28
- it "enumerates the elements" do
29
- nexts = []
30
- elements.length.times do
31
- nexts << sequence.next
32
- end
33
- nexts.should == elements
34
- end
35
-
36
- it "raises StopIteration when the end of the Sequence is reached" do
37
- elements.length.times{ sequence.next }
38
- lambda{ sequence.next }.should raise_error(StopIteration)
39
- end
40
-
41
- it "should automatically break out of Kernel#loop" do
42
- nexts = []
43
- loop do # loop rescues StopIteration and exits the loop
44
- nexts << sequence.next
45
- end
46
- nexts.should == elements
47
- end
48
-
49
- it "enumerates the elements in sub-sequences" do
50
- sub_sequence = SEQUENCE.new [2,3]
51
- sequence = SEQUENCE.new [1,sub_sequence,4]
52
- nexts = []
53
- loop { nexts << sequence.next }
54
- nexts.should == [1,2,3,4]
55
- end
56
-
57
- it "skips over empty sub-sequences" do
58
- sub_sequence = SEQUENCE.new []
59
- sequence = SEQUENCE.new [1,sub_sequence,4]
60
- nexts = []
61
- loop { nexts << sequence.next }
62
- nexts.should == [1,4]
63
- end
64
-
65
- end
66
-
67
- describe "#rewind" do
68
- it "restarts at the beginning of the sequence" do
69
- loop { sequence.next }
70
- sequence.rewind
71
- sequence.next.should == elements.first
72
- end
73
-
74
- it "returns self, so it can be chained to #next" do
75
- first = sequence.next
76
- sequence.rewind.next.should == first
77
- end
78
-
79
- it "causes sub-sequences to start from the beginning when encountered again after #rewind" do
80
- sub_sequence = SEQUENCE.new [2,3]
81
- sequence = SEQUENCE.new [1,sub_sequence,4]
82
- loop { sequence.next }
83
- sequence.rewind
84
- nexts = []
85
- loop { nexts << sequence.next }
86
- nexts.should == [1,2,3,4]
87
- end
88
- end
89
-
90
- end
91
-
92
-
93
- describe MTK::Pattern do
94
-
95
- describe "#Sequence" do
96
- it "creates a Sequence" do
97
- MTK::Pattern.Sequence(1,2,3).should be_a MTK::Pattern::Sequence
98
- end
99
-
100
- it "sets #elements from the varargs" do
101
- MTK::Pattern.Sequence(1,2,3).elements.should == [1,2,3]
102
- end
103
-
104
- it "does not set a type" do
105
- MTK::Pattern.Sequence(1,2,3).type.should be_nil
106
- end
107
- end
108
-
109
- describe "#PitchSequence" do
110
- it "creates a Sequence" do
111
- MTK::Pattern.PitchSequence(1,2,3).should be_a MTK::Pattern::Sequence
112
- end
113
-
114
- it "sets #elements from the varargs" do
115
- MTK::Pattern.PitchSequence(1,2,3).elements.should == [1,2,3]
116
- end
117
-
118
- it "sets #type to :pitch" do
119
- MTK::Pattern.PitchSequence([]).type.should == :pitch
120
- end
121
- end
122
-
123
- describe "#IntensitySequence" do
124
- it "creates a Sequence" do
125
- MTK::Pattern.IntensitySequence(1,2,3).should be_a MTK::Pattern::Sequence
126
- end
127
-
128
- it "sets #elements from the varargs" do
129
- MTK::Pattern.IntensitySequence(1,2,3).elements.should == [1,2,3]
130
- end
131
-
132
- it "sets #type to :pitch" do
133
- MTK::Pattern.IntensitySequence([]).type.should == :intensity
134
- end
135
- end
136
-
137
- describe "#DurationSequence" do
138
- it "creates a Sequence" do
139
- MTK::Pattern.DurationSequence(1,2,3).should be_a MTK::Pattern::Sequence
140
- end
141
-
142
- it "sets #elements from the varargs" do
143
- MTK::Pattern.DurationSequence(1,2,3).elements.should == [1,2,3]
144
- end
145
-
146
- it "sets #type to :pitch" do
147
- MTK::Pattern.DurationSequence([]).type.should == :duration
148
- end
149
- end
150
-
151
- end
@@ -1,198 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::PitchSet do
4
-
5
- let(:pitches) { [C4, D4, E4, F4, G4, A4, B4] }
6
- let(:pitch_set) { PitchSet.new(pitches) }
7
- let(:c_major) { PitchSet.new([C4,E4,G4]) }
8
-
9
- it "is Enumerable" do
10
- pitch_set.should be_a Enumerable
11
- end
12
-
13
- describe '#pitches' do
14
- it 'is the list of pitches used to construct the scale' do
15
- pitch_set.pitches.should == pitches
16
- end
17
-
18
- it "is immutable" do
19
- lambda { pitch_set.pitches << Db4 }.should raise_error
20
- end
21
-
22
- it "does not affect the immutabilty of the pitch list used to construct it" do
23
- pitches << Db4
24
- pitches.length.should == 8
25
- end
26
-
27
- it "is not affected by changes to the pitch list used to construct it" do
28
- pitch_set # force construction before we modify the pitches array
29
- pitches << Db4
30
- pitch_set.pitches.length.should == 7
31
- end
32
-
33
- it "does not include duplicates" do
34
- PitchSet.new([C4, E4, G4, C4]).pitches.should == [C4, E4, G4]
35
- end
36
-
37
- it "sorts the pitches" do
38
- PitchSet.new([G4, E4, C4]).pitches.should == [C4, E4, G4]
39
- end
40
- end
41
-
42
- describe "#to_a" do
43
- it "is equal to #pitches" do
44
- pitch_set.to_a.should == pitch_set.pitches
45
- end
46
-
47
- it "is mutable" do
48
- (c_major.to_a << Bb4).should == [C4, E4, G4, Bb4]
49
- end
50
- end
51
-
52
- describe "#each" do
53
- it "yields each pitch" do
54
- ps = []
55
- pitch_set.each{|p| ps << p }
56
- ps.should == pitches
57
- end
58
- end
59
-
60
- describe "#map" do
61
- it "returns a PitchSet with each Pitch replaced with the results of the block" do
62
- c_major.map{|p| p + 2}.should == [D4, Gb4, A4]
63
- end
64
- end
65
-
66
- describe "#to_pitch_class_set" do
67
- it "is a PitchClassSet" do
68
- pitch_set.to_pitch_class_set.should be_a PitchClassSet
69
- end
70
-
71
- it "contains all the pitch_classes in this PitchSet" do
72
- pitch_set.to_pitch_class_set.pitch_classes.should == pitch_set.pitch_classes
73
- end
74
- end
75
-
76
- describe '#pitch_classes' do
77
- it 'is the list of pitch classes' do
78
- pitch_set.pitch_classes.should == pitches.map { |p| p.pitch_class }
79
- end
80
-
81
- it "doesn't include duplicates" do
82
- PitchSet.new([C4, C5, D5, C6, D4]).pitch_classes.should == [C, D]
83
- end
84
- end
85
-
86
- describe '#transpose' do
87
- it 'transposes upward by the given semitones' do
88
- pitch_set.transpose(12).should == PitchSet.new([C5, D5, E5, F5, G5, A5, B5])
89
- end
90
- end
91
-
92
- describe '#invert' do
93
- it 'inverts all pitches around the given center pitch' do
94
- (pitch_set.invert Gb4).should == PitchSet.new([C5, Bb4, Ab4, G4, F4, Eb4, Db4])
95
- end
96
-
97
- it 'inverts all pitches around the first pitch, when no center pitch is given' do
98
- pitch_set.invert.should == PitchSet.new([C4, Bb3, Ab3, G3, F3, Eb3, Db3])
99
- end
100
- end
101
-
102
- describe '#include?' do
103
- it 'returns true if the Pitch is in the PitchList' do
104
- (pitch_set.include? C4).should be_true
105
- end
106
-
107
- it 'returns false if the Pitch is not in the PitchList' do
108
- (pitch_set.include? Db4).should be_false
109
- end
110
- end
111
-
112
- describe '#==' do
113
- it "is true when all the pitches are equal" do
114
- PitchSet.new([C4, E4, G4]).should == PitchSet.new([Pitch.from_i(60), Pitch.from_i(64), Pitch.from_i(67)])
115
- end
116
-
117
- it "doesn't consider duplicates in the comparison" do
118
- PitchSet.new([C4, C4]).should == PitchSet.new([C4])
119
- end
120
-
121
- it "doesn't consider the order of pitches" do
122
- PitchSet.new([G4, E4, C4]).should == PitchSet.new([C4, E4, G4])
123
- end
124
- end
125
-
126
- describe '#inversion' do
127
- it "adds an octave to the chord's pitches starting from the lowest, for each whole number in a postive argument" do
128
- c_major.inversion(2).should == PitchSet.new([G4,C5,E5])
129
- end
130
-
131
- it "subtracts an octave to the chord's pitches starting fromt he highest, for each whole number in a negative argument" do
132
- c_major.inversion(-2).should == PitchSet.new([E3,G3,C4])
133
- end
134
-
135
- it "wraps around to the lowest pitch when the argument is bigger than the number of pitches in the chord (positive argument)" do
136
- c_major.inversion(4).should == PitchSet.new([E5,G5,C6])
137
- end
138
-
139
- it "wraps around to the highest pitch when the magnitude of the argument is bigger than the number of pitches in the chord (negative argument)" do
140
- c_major.inversion(-4).should == PitchSet.new([G2,C3,E3])
141
- end
142
- end
143
-
144
- describe "#nearest" do
145
- it "returns the nearest PitchSet where the first Pitch has the given PitchClass" do
146
- c_major.nearest(F).should == c_major.transpose(5.semitones)
147
- c_major.nearest(G).should == c_major.transpose(-5.semitones)
148
- end
149
- end
150
-
151
- describe "#to_s" do
152
- it "looks like an array of pitches" do
153
- c_major.to_s.should == "[C4, E4, G4]"
154
- end
155
- end
156
-
157
- end
158
-
159
- describe MTK do
160
-
161
- describe '#PitchSet' do
162
-
163
- it "acts like new for a single Array argument" do
164
- PitchSet([C4,D4]).should == PitchSet.new([C4,D4])
165
- end
166
-
167
- it "acts like new for multiple arguments, by treating them like an Array (splat)" do
168
- PitchSet(C4,D4).should == PitchSet.new([C4,D4])
169
- end
170
-
171
- it "handles an Array with elements that can be converted to Pitches" do
172
- PitchSet(['C4','D4']).should == PitchSet.new([C4,D4])
173
- end
174
-
175
- it "handles multiple arguments that can be converted to a Pitch" do
176
- PitchSet(:C4,:D4).should == PitchSet.new([C4,D4])
177
- end
178
-
179
- it "handles a single Pitch" do
180
- PitchSet(C4).should == PitchSet.new([C4])
181
- end
182
-
183
- it "handles single elements that can be converted to a Pitch" do
184
- PitchSet('C4').should == PitchSet.new([C4])
185
- end
186
-
187
- it "returns the argument if it's already a PitchSet" do
188
- pitch_set = PitchSet.new([C4,D4])
189
- PitchSet(pitch_set).should be_equal pitch_set
190
- end
191
-
192
- it "raises an error for types it doesn't understand" do
193
- lambda{ PitchSet({:not => :compatible}) }.should raise_error
194
- end
195
-
196
- end
197
-
198
- end
@@ -1,159 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe MTK::Sequencer::AbstractSequencer do
4
-
5
- ABSTRACT_SEQUENCER = Sequencer::AbstractSequencer
6
-
7
- class MockEventBuilder < Helper::EventBuilder
8
- attr_accessor :mock_attribute
9
- end
10
-
11
- let(:patterns) { [Pattern.PitchCycle(C4,D4)] }
12
- let(:sequencer) { ABSTRACT_SEQUENCER.new patterns }
13
- let(:intensity) { Helper::EventBuilder::DEFAULT_INTENSITY }
14
- let(:duration) { Helper::EventBuilder::DEFAULT_DURATION }
15
-
16
- describe "#new" do
17
- it "defaults @max_steps to nil" do
18
- sequencer.max_steps.should be_nil
19
- end
20
-
21
- it "sets @max_steps from the options hash" do
22
- sequencer = RHYTHMIC_SEQUENCER.new patterns, :max_steps => 4
23
- sequencer.max_steps.should == 4
24
- end
25
-
26
- it "defaults @max_time to nil" do
27
- sequencer.max_time.should be_nil
28
- end
29
-
30
- it "sets @max_time from the options hash" do
31
- sequencer = RHYTHMIC_SEQUENCER.new patterns, :max_time => 4
32
- sequencer.max_time.should == 4
33
- end
34
-
35
- it "defaults @event_builder to MTK::Helper::EventBuilder" do
36
- sequencer.event_builder.should be_a MTK::Helper::EventBuilder
37
- end
38
-
39
- it "sets @event_buidler from the options hash" do
40
- sequencer = RHYTHMIC_SEQUENCER.new patterns, :event_builder => MockEventBuilder
41
- sequencer.event_builder.should be_a MockEventBuilder
42
- end
43
- end
44
-
45
- describe "#event_builder" do
46
- it "provides access to the internal EventBuilder" do
47
- sequencer = RHYTHMIC_SEQUENCER.new patterns, :event_builder => MockEventBuilder
48
- sequencer.event_builder.mock_attribute = :value
49
- sequencer.event_builder.mock_attribute.should == :value
50
- end
51
- end
52
-
53
- describe "#to_timeline" do
54
- it "combines pitch, intensity, and duration patterns into notes" do
55
- pitches = Pattern.PitchSequence(C4, D4, E4)
56
- intensities = Pattern.IntensitySequence(0.3, 0.7, 1.0)
57
- durations = Pattern.DurationSequence(1, 2, 3)
58
- sequencer = ABSTRACT_SEQUENCER.new [pitches, intensities, durations]
59
- # default implementation just increments the time by 1 for each event (more interesting behavior is provided by subclasses)
60
- sequencer.to_timeline.should == {
61
- 0 => [Note(C4,0.3,1)],
62
- 1 => [Note(D4,0.7,2)],
63
- 2 => [Note(E4,1.0,3)]
64
- }
65
- end
66
-
67
- it "combines patterns of different types and lengths" do
68
- pitches = Pattern.PitchSequence(C4, D4, E4, F4, G4, A4, B4, C5)
69
- intensities = Pattern.IntensityCycle(0.5, 1.0)
70
- durations = Pattern.DurationPalindrome(1, 2, 3)
71
- sequencer = ABSTRACT_SEQUENCER.new [pitches, intensities, durations]
72
- # default implementation just increments the time by 1 for each event (more interesting behavior is provided by subclasses)
73
- sequencer.to_timeline.should == {
74
- 0 => [Note(C4,0.5,1)],
75
- 1 => [Note(D4,1.0,2)],
76
- 2 => [Note(E4,0.5,3)],
77
- 3 => [Note(F4,1.0,2)],
78
- 4 => [Note(G4,0.5,1)],
79
- 5 => [Note(A4,1.0,2)],
80
- 6 => [Note(B4,0.5,3)],
81
- 7 => [Note(C5,1.0,2)]
82
- }
83
- end
84
-
85
- it "produces consistent results by reseting the patterns each time" do
86
- pitches = Pattern.PitchSequence(C4, D4, E4)
87
- intensities = Pattern.IntensityCycle(1)
88
- durations = Pattern.DurationCycle(1, 2)
89
- sequencer = ABSTRACT_SEQUENCER.new [pitches, intensities, durations]
90
- sequencer.to_timeline.should == sequencer.to_timeline
91
- end
92
- end
93
-
94
- describe "#time" do
95
- it "is the current timeline time that the sequencer is generating events for" do
96
- # AbstractSequencer just advances by 1 each step
97
- sequencer.next # time doesn't advance until the second #next call
98
- sequencer.time.should == 0
99
- sequencer.next
100
- sequencer.time.should == 1
101
- sequencer.next
102
- sequencer.time.should == 2
103
- end
104
- end
105
-
106
- describe "#step" do
107
- it "is the index for how many of times #next has been called (i.e. count starting from 0)" do
108
- sequencer.step.should == -1 # -1 indicates #next has not yet been called
109
- sequencer.next
110
- sequencer.step.should == 0
111
- sequencer.next
112
- sequencer.step.should == 1
113
- sequencer.next
114
- sequencer.step.should == 2
115
- end
116
- end
117
-
118
- describe "#next" do
119
- it "returns a list of notes formed from the patterns in the sequencer" do
120
- sequencer.next.should == [Note(C4,intensity,duration)]
121
- sequencer.next.should == [Note(D4,intensity,duration)]
122
- sequencer.next.should == [Note(C4,intensity,duration)]
123
- end
124
- end
125
-
126
- describe "#rewind" do
127
- it "resets the sequencer and its patterns" do
128
- sequencer.next
129
- sequencer.rewind
130
- sequencer.step.should == -1
131
- sequencer.time.should == 0
132
- sequencer.next.should == [Note(C4,intensity,duration)]
133
- end
134
-
135
- it "resets pitches properly for patterns that rely on previous pitches" do
136
- relative_pitch_pattern = Pattern.PitchSequence(C,P8)
137
- sequencer = ABSTRACT_SEQUENCER.new [relative_pitch_pattern]
138
- sequencer.next.should == [Note(C4,intensity,duration)]
139
- sequencer.next.should == [Note(C5,intensity,duration)]
140
- sequencer.rewind
141
- sequencer.next.should == [Note(C4,intensity,duration)] # if the internal EventBuilder is not properly reset, the Note would be C5
142
- end
143
- end
144
-
145
- describe "#max_steps" do
146
- it "controls the maximum number of entries in the generated timeline" do
147
- sequencer.max_steps = 2
148
- sequencer.to_timeline.times.length.should == 2
149
- end
150
- end
151
-
152
- describe "#max_time" do
153
- it "controls the maximum time in the generated timeline" do
154
- sequencer.max_time = 4
155
- sequencer.to_timeline.times.last.should == 4
156
- end
157
- end
158
-
159
- end