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
@@ -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