mtk 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,223 @@
1
+ require 'spec_helper'
2
+
3
+ describe MTK::Melody do
4
+
5
+ let(:pitches) { [C4, D4, E4, D4] }
6
+ let(:melody) { Melody.new(pitches) }
7
+
8
+ it "is Enumerable" do
9
+ melody.should be_a Enumerable
10
+ end
11
+
12
+ describe ".new" do
13
+ it "maintains the pitches collection exactly (preserves order and keeps duplicates)" do
14
+ Melody.new([C4, E4, G4, E4, B3, C4]).pitches.should == [C4, E4, G4, E4, B3, C4]
15
+ end
16
+ end
17
+
18
+ describe ".from_pitch_classes" do
19
+ it "creates a pitch sequence from a list of pitch classes and starting point, selecting the nearest pitch to each pitch class" do
20
+ Melody.from_pitch_classes([C,G,B,Eb,D,C], D3).should == [C3,G2,B2,Eb3,D3,C3]
21
+ end
22
+
23
+ it "defaults to a starting point of C4 (middle C)" do
24
+ Melody.from_pitch_classes([C]).should == [C4]
25
+ end
26
+
27
+ it "doesn't travel within an octave above or below the starting point by default" do
28
+ Melody.from_pitch_classes([C,F,Bb,D,A,E,B]).should == [C4,F4,Bb4,D4,A3,E3,B3]
29
+ end
30
+
31
+ it "allows max distance above or below the starting point to be set via the third argument" do
32
+ Melody.from_pitch_classes([C,F,Bb,D,A,E,B], C4, 6).should == [C4,F4,Bb3,D4,A3,E4,B3]
33
+ end
34
+ end
35
+
36
+ describe '#pitches' do
37
+ it 'is the list of pitches used to construct the scale' do
38
+ melody.pitches.should == pitches
39
+ end
40
+
41
+ it "is immutable" do
42
+ lambda { melody.pitches << Db4 }.should raise_error
43
+ end
44
+
45
+ it "does not affect the immutabilty of the pitch list used to construct it" do
46
+ list = melody # force construction with the pitches array
47
+ expect { pitches << Db4 }.to change(pitches, :length).by(1)
48
+ end
49
+
50
+ it "is not affected by changes to the pitch list used to construct it" do
51
+ melody # force construction before we modify the pitches array
52
+ expect { pitches << Db4 }.to_not change(melody.pitches, :length)
53
+ end
54
+
55
+ end
56
+
57
+ describe "#to_a" do
58
+ it "is equal to #pitches" do
59
+ melody.to_a.should == melody.pitches
60
+ end
61
+
62
+ it "is mutable" do
63
+ (melody.to_a << Bb3).should == [C4, D4, E4, D4, Bb3]
64
+ end
65
+ end
66
+
67
+ describe "#each" do
68
+ it "yields each pitch" do
69
+ ps = []
70
+ melody.each{|p| ps << p }
71
+ ps.should == pitches
72
+ end
73
+ end
74
+
75
+ describe "#map" do
76
+ it "returns a Melody with each Pitch replaced with the results of the block" do
77
+ melody.map{|p| p + 2}.should == [D4, E4, Gb4, E4]
78
+ end
79
+ end
80
+
81
+ describe "#to_pitch_class_set" do
82
+ it "is a PitchClassSet" do
83
+ melody.to_pitch_class_set.should be_a PitchClassSet
84
+ end
85
+
86
+ it "contains all the distinct pitch_classes in this Melody by default" do
87
+ melody.to_pitch_class_set.pitch_classes.should == melody.pitch_classes.uniq
88
+ end
89
+
90
+ it "contains all the pitch_classes (including duplicates) when the argument is false" do
91
+ melody.to_pitch_class_set(false).pitch_classes.should == melody.pitch_classes
92
+ end
93
+ end
94
+
95
+
96
+ describe '#pitch_classes' do
97
+ it 'is the list of pitch classes for the pitches in this list' do
98
+ melody.pitch_classes.should == pitches.map { |p| p.pitch_class }
99
+ end
100
+ end
101
+
102
+ describe '#transpose' do
103
+ it 'transposes upward by the given semitones' do
104
+ melody.transpose(12).should == Melody.new([C5, D5, E5, D5])
105
+ end
106
+ end
107
+
108
+ describe '#invert' do
109
+ it 'inverts all pitches around the given center pitch' do
110
+ (melody.invert Gb4).should == Melody.new([C5, Bb4, Ab4, Bb4])
111
+ end
112
+
113
+ it 'inverts all pitches around the first pitch, when no center pitch is given' do
114
+ melody.invert.should == Melody.new([C4, Bb3, Ab3, Bb3])
115
+ end
116
+ end
117
+
118
+ describe '#include?' do
119
+ it 'returns true if the Pitch is in the Melody' do
120
+ (melody.include? C4).should be_true
121
+ end
122
+
123
+ it 'returns false if the Pitch is not in the Melody' do
124
+ (melody.include? Db4).should be_false
125
+ end
126
+ end
127
+
128
+ describe '#==' do
129
+ it "is true when all the pitches are equal" do
130
+ Melody.new([C4, E4, G4]).should == Melody.new([Pitch.from_i(60), Pitch.from_i(64), Pitch.from_i(67)])
131
+ end
132
+
133
+ it "is false when not all the pitches are equal" do
134
+ Melody.new([C4, E4, G4]).should_not == Melody.new([Pitch.from_i(60), Pitch.from_i(65), Pitch.from_i(67)])
135
+ end
136
+
137
+ it "is false when if otherwise equal Melodies don't contain the same number of duplicates" do
138
+ Melody.new([C4, E4, G4]).should_not == Melody.new([C4, C4, E4, G4])
139
+ end
140
+
141
+ it "is false when if otherwise equal Melodies aren't in the same order" do
142
+ Melody.new([C4, E4, G4]).should_not == Melody.new([C4, G4, E4])
143
+ end
144
+
145
+ it "is false when the argument is not compatible" do
146
+ Melody.new([C4, E4, G4]).should_not == :invalid
147
+ end
148
+
149
+ it "can be compared directly to Arrays" do
150
+ Melody.new([C4, E4, G4]).should == [C4, E4, G4]
151
+ end
152
+ end
153
+
154
+ describe "#=~" do
155
+ it "is true when all the pitches are equal" do
156
+ Melody.new([C4, E4, G4]).should =~ Melody.new([C4, E4, G4])
157
+ end
158
+
159
+ it "is true when all the pitches are equal, even with different numbers of duplicates" do
160
+ Melody.new([C4, E4, G4]).should =~ Melody.new([C4, C4, E4, G4])
161
+ end
162
+
163
+ it "is true when all the pitches are equal, even in a different order" do
164
+ Melody.new([C4, E4, G4]).should =~ Melody.new([C4, G4, E4])
165
+ end
166
+
167
+ it "is false when one Melody contains a Pitch not in the other" do
168
+ Melody.new([C4, E4, G4]).should_not =~ Melody.new([C4, E4])
169
+ end
170
+
171
+ it "can be compared directly to Arrays" do
172
+ Melody.new([C4, E4, G4]).should =~ [C4, E4, G4]
173
+ end
174
+ end
175
+
176
+ describe "#to_s" do
177
+ it "looks like an array of pitches" do
178
+ melody.to_s.should == "[C4, D4, E4, D4]"
179
+ end
180
+ end
181
+
182
+ end
183
+
184
+ describe MTK do
185
+
186
+ describe '#Melody' do
187
+
188
+ it "acts like new for a single Array argument" do
189
+ Melody([C4,D4]).should == Melody.new([C4,D4])
190
+ end
191
+
192
+ it "acts like new for multiple arguments, by treating them like an Array (splat)" do
193
+ Melody(C4,D4).should == Melody.new([C4,D4])
194
+ end
195
+
196
+ it "handles an Array with elements that can be converted to Pitches" do
197
+ Melody(['C4','D4']).should == Melody.new([C4,D4])
198
+ end
199
+
200
+ it "handles multiple arguments that can be converted to a Pitch" do
201
+ Melody(:C4,:D4).should == Melody.new([C4,D4])
202
+ end
203
+
204
+ it "handles a single Pitch" do
205
+ Melody(C4).should == Melody.new([C4])
206
+ end
207
+
208
+ it "handles single elements that can be converted to a Pitch" do
209
+ Melody('C4').should == Melody.new([C4])
210
+ end
211
+
212
+ it "handles a Melody" do
213
+ melody = Melody.new([C4,D4])
214
+ Melody(melody).should == [C4,D4]
215
+ end
216
+
217
+ it "raises an error for types it doesn't understand" do
218
+ lambda{ Melody({:not => :compatible}) }.should raise_error
219
+ end
220
+
221
+ end
222
+
223
+ end
@@ -33,10 +33,10 @@ describe MTK::MIDI::File do
33
33
 
34
34
  it "converts note on/off messages to Note events" do
35
35
  MIDI_File(test_mid).to_timelines.first.should == {
36
- 0.0 => [Note.new(C4, 126/127.0, 0.25)],
37
- 1.0 => [Note.new(Db4, 99/127.0, 0.5)],
38
- 2.0 => [Note.new(D4, 72/127.0, 0.75)],
39
- 3.0 => [Note.new(Eb4, 46/127.0, 1.0), Note.new(E4, 46/127.0, 1.0)]
36
+ 0.0 => [Note(C4, 0.25, 126/127.0)],
37
+ 1.0 => [Note(Db4, 0.5, 99/127.0)],
38
+ 2.0 => [Note(D4, 0.75, 72/127.0)],
39
+ 3.0 => [Note(Eb4, 1.0, 46/127.0), Note(E4, 1.0, 46/127.0)]
40
40
  }
41
41
  end
42
42
  end
@@ -45,9 +45,9 @@ describe MTK::MIDI::File do
45
45
  it 'writes monophonic Notes in a Timeline to a MIDI file' do
46
46
  MIDI_File(tempfile).write_timeline(
47
47
  Timeline.from_hash({
48
- 0 => Note.new(C4, 0.7, 1),
49
- 1.0 => Note.new(G4, 0.8, 1),
50
- 2 => Note.new(C5, 0.9, 1)
48
+ 0 => Note(C4, q, 0.7),
49
+ 1 => Note(G4, q, 0.8),
50
+ 2 => Note(C5, q, 0.9)
51
51
  })
52
52
  )
53
53
 
@@ -85,8 +85,8 @@ describe MTK::MIDI::File do
85
85
  it 'writes polyphonic (simultaneous) Notes in a Timeline to a MIDI file' do
86
86
  MIDI_File(tempfile).write_timeline(
87
87
  Timeline.from_hash({
88
- 0 => [Note(C4,0.5,1), Note(E4,0.5,1)],
89
- 2.0 => [Note(G4,1,2), Note(B4,1,2), Note(D5,1,2)]
88
+ 0 => [Note(C4,q,0.5), Note(E4,q,0.5)],
89
+ 2.0 => [Note(G4,h,1), Note(B4,h,1), Note(D5,h,1)]
90
90
  })
91
91
  )
92
92
 
@@ -136,9 +136,9 @@ describe MTK::MIDI::File do
136
136
  it 'ignores rests (events with negative duration)' do
137
137
  MIDI_File(tempfile).write_timeline(
138
138
  Timeline.from_hash({
139
- 0 => Note.new(C4, 0.7, 1),
140
- 1 => Note.new(G4, 0.8, -1), # this is a rest because it has a negative duration
141
- 2 => Note.new(C5, 0.9, 1)
139
+ 0 => Note(C4, q, 0.7),
140
+ 1 => Note(G4, -q, 0.8), # this is a rest because it has a negative duration
141
+ 2 => Note(C5, q, 0.9)
142
142
  })
143
143
  )
144
144
 
@@ -172,12 +172,12 @@ describe MTK::MIDI::File do
172
172
  it "writes a multitrack MIDI file" do
173
173
  MIDI_File(tempfile).write_timelines([
174
174
  Timeline.from_hash({
175
- 0 => Note.new(C4, 0.7, 1),
176
- 1.0 => Note.new(G4, 0.8, 1),
175
+ 0 => Note(C4, q, 0.7),
176
+ 1.0 => Note(G4, q, 0.8),
177
177
  }),
178
178
  Timeline.from_hash({
179
- 1 => Note.new(C5, 0.9, 2),
180
- 2 => Note.new(D5, 1, 2),
179
+ 1 => Note(C5, h, 0.9),
180
+ 2 => Note(D5, h, 1),
181
181
  }),
182
182
  ])
183
183
 
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'spec_helper'
3
+ require 'mtk/midi/input'
4
+ require 'mtk/midi/jsound_input'
5
+
6
+ describe MTK::MIDI::JSoundInput do
7
+
8
+ end
9
+
10
+
11
+ rescue LoadError; end # only run the test when the required gems are available
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'spec_helper'
3
+ require 'mtk/midi/output'
4
+ require 'mtk/midi/jsound_output'
5
+
6
+ describe MTK::MIDI::JSoundOutput do
7
+
8
+ end
9
+
10
+
11
+ rescue LoadError; end # only run the test when the required gems are available
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+ require 'mtk/midi/output'
3
+
4
+ describe MTK::MIDI::Output do
5
+
6
+ class MockOuput < MTK::MIDI::Output
7
+ public_class_method :new
8
+ end
9
+
10
+ let(:subject) { MockOuput.new(mock_device) }
11
+
12
+ let(:mock_device) do
13
+ mock_device = mock(:device)
14
+ mock_device.stub(:open)
15
+ mock_device
16
+ end
17
+
18
+ let(:scheduler) do
19
+ scheduler = mock(:scheduler)
20
+ Gamelan::Scheduler.stub(:new).and_return scheduler
21
+ scheduler
22
+ end
23
+
24
+
25
+ def timeline_with_param_event(event_type, event_options={})
26
+ event = MTK::Events::Parameter.new event_type, event_options
27
+ MTK::Timeline.from_hash 0 => event
28
+ end
29
+
30
+ def should_be_scheduled timed_data
31
+ timed_data.each do |time,data|
32
+ scheduler.should_receive(:at) do |scheduled_time,&callback|
33
+ scheduled_time.should == time
34
+ callback.yield.should == data
35
+ end
36
+ end
37
+ scheduler.should_receive(:at) # end time, don't care about this here...
38
+ scheduler.should_receive(:run).and_return mock(:thread,:join=>nil)
39
+ end
40
+
41
+
42
+ describe ".new" do
43
+ it "opens the given device" do
44
+ mock_device.should_receive(:open)
45
+ subject
46
+ end
47
+ end
48
+
49
+ describe "#play" do
50
+
51
+ it "handles note events" do
52
+ should_be_scheduled 0 => [:note_on, 60, 127, 0],
53
+ 1 => [:note_off, 60, 127, 0]
54
+ subject.play MTK::Timeline.from_hash( 0 => Note(C4,fff,1) )
55
+ end
56
+
57
+ it "handles control events" do
58
+ should_be_scheduled 0 => [:control, 5, 32, 3]
59
+ subject.play timeline_with_param_event(:control, number:5, value:0.25, channel:3)
60
+ end
61
+
62
+ it "handles channel pressure events" do
63
+ should_be_scheduled 0 => [:channel_pressure, 64, 0]
64
+ subject.play timeline_with_param_event(:pressure, value:0.5)
65
+ end
66
+
67
+ it "handles poly pressure events" do
68
+ should_be_scheduled 0 => [:poly_pressure, 60, 127, 0]
69
+ subject.play timeline_with_param_event(:pressure, number:60, value:1)
70
+ end
71
+
72
+ it "handles bend events" do
73
+ should_be_scheduled 0 => [:bend, 0, 0]
74
+ subject.play timeline_with_param_event(:bend, value: -1)
75
+ end
76
+
77
+ it "handles program events" do
78
+ should_be_scheduled 0 => [:program, 7, 9]
79
+ subject.play timeline_with_param_event(:program, number:7, channel:9)
80
+ end
81
+
82
+ it "handles simultaneous events" do
83
+ should_be_scheduled [
84
+ [0, [:note_on, 60, 127, 0]],
85
+ [1, [:note_off, 60, 127, 0]],
86
+ [0, [:note_on, 67, 127, 0]],
87
+ [1, [:note_off, 67, 127, 0]]
88
+ ]
89
+ subject.play [Note(C4,fff,1),Note(G4,fff,1)]
90
+ end
91
+
92
+ it "handles a list of timelines" do
93
+ should_be_scheduled 0 => [:note_on, 60, 127, 0],
94
+ 1 => [:note_off, 60, 127, 0],
95
+ 2 => [:note_on, 67, 127, 0],
96
+ 3 => [:note_off, 67, 127, 0]
97
+ subject.play [MTK::Timeline.from_hash( 0 => Note(C4,fff,1) ), MTK::Timeline.from_hash( 2 => Note(G4,fff,1) )]
98
+ end
99
+
100
+ end
101
+
102
+ end
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'spec_helper'
3
+ require 'mtk/midi/input'
4
+ require 'mtk/midi/unimidi_input'
5
+
6
+ describe MTK::MIDI::UniMIDIInput do
7
+
8
+ end
9
+
10
+
11
+ rescue LoadError; end # only run the test when the required gems are available
@@ -0,0 +1,11 @@
1
+ begin
2
+ require 'spec_helper'
3
+ require 'mtk/midi/output'
4
+ require 'mtk/midi/unimidi_output'
5
+
6
+ describe MTK::MIDI::UniMIDIOutput do
7
+
8
+ end
9
+
10
+
11
+ rescue LoadError; end # only run the test when the required gems are available
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'mtk/numeric_extensions'
2
3
 
3
4
  describe Numeric do
4
5