mtk 0.0.1 → 0.0.2
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.
- data/.yardopts +9 -0
- data/INTRO.md +73 -0
- data/LICENSE.txt +27 -0
- data/README.md +93 -18
- data/Rakefile +13 -1
- data/examples/crescendo.rb +20 -0
- data/examples/dynamic_pattern.rb +39 -0
- data/examples/play_midi.rb +19 -0
- data/examples/print_midi.rb +13 -0
- data/examples/random_tone_row.rb +18 -0
- data/examples/tone_row_melody.rb +21 -0
- data/lib/mtk/_constants/durations.rb +80 -0
- data/lib/mtk/_constants/intensities.rb +81 -0
- data/lib/mtk/{constants → _constants}/intervals.rb +10 -1
- data/lib/mtk/_constants/pitch_classes.rb +35 -0
- data/lib/mtk/_constants/pitches.rb +49 -0
- data/lib/mtk/{numeric_extensions.rb → _numeric_extensions.rb} +0 -0
- data/lib/mtk/event.rb +14 -5
- data/lib/mtk/helper/collection.rb +114 -0
- data/lib/mtk/helper/event_builder.rb +85 -0
- data/lib/mtk/{constants → helper}/pseudo_constants.rb +7 -6
- data/lib/mtk/lang/grammar.rb +17 -0
- data/lib/mtk/lang/mtk_grammar.citrus +60 -0
- data/lib/mtk/midi/file.rb +10 -15
- data/lib/mtk/midi/jsound_input.rb +68 -0
- data/lib/mtk/midi/jsound_output.rb +80 -0
- data/lib/mtk/note.rb +22 -3
- data/lib/mtk/pattern/abstract_pattern.rb +132 -0
- data/lib/mtk/pattern/choice.rb +25 -9
- data/lib/mtk/pattern/cycle.rb +51 -0
- data/lib/mtk/pattern/enumerator.rb +26 -0
- data/lib/mtk/pattern/function.rb +46 -0
- data/lib/mtk/pattern/lines.rb +60 -0
- data/lib/mtk/pattern/palindrome.rb +42 -0
- data/lib/mtk/pattern/sequence.rb +15 -50
- data/lib/mtk/pitch.rb +45 -6
- data/lib/mtk/pitch_class.rb +36 -35
- data/lib/mtk/pitch_class_set.rb +46 -14
- data/lib/mtk/pitch_set.rb +20 -31
- data/lib/mtk/sequencer/abstract_sequencer.rb +85 -0
- data/lib/mtk/sequencer/rhythmic_sequencer.rb +29 -0
- data/lib/mtk/sequencer/step_sequencer.rb +26 -0
- data/lib/mtk/timeline.rb +75 -22
- data/lib/mtk/transform/invertible.rb +15 -0
- data/lib/mtk/{util → transform}/mappable.rb +6 -2
- data/lib/mtk/transform/set_theory_operations.rb +34 -0
- data/lib/mtk/transform/transposable.rb +14 -0
- data/lib/mtk.rb +56 -22
- data/spec/mtk/_constants/durations_spec.rb +118 -0
- data/spec/mtk/{constants/dynamics_spec.rb → _constants/intensities_spec.rb} +48 -17
- data/spec/mtk/{constants → _constants}/intervals_spec.rb +21 -0
- data/spec/mtk/_constants/pitch_classes_spec.rb +58 -0
- data/spec/mtk/_constants/pitches_spec.rb +52 -0
- data/spec/mtk/{numeric_extensions_spec.rb → _numeric_extensions_spec.rb} +0 -0
- data/spec/mtk/event_spec.rb +19 -0
- data/spec/mtk/helper/collection_spec.rb +291 -0
- data/spec/mtk/helper/event_builder_spec.rb +92 -0
- data/spec/mtk/helper/pseudo_constants_spec.rb +20 -0
- data/spec/mtk/lang/grammar_spec.rb +100 -0
- data/spec/mtk/midi/file_spec.rb +41 -6
- data/spec/mtk/note_spec.rb +53 -3
- data/spec/mtk/pattern/abstract_pattern_spec.rb +45 -0
- data/spec/mtk/pattern/choice_spec.rb +89 -3
- data/spec/mtk/pattern/cycle_spec.rb +133 -0
- data/spec/mtk/pattern/function_spec.rb +133 -0
- data/spec/mtk/pattern/lines_spec.rb +93 -0
- data/spec/mtk/pattern/note_cycle_spec.rb.bak +116 -0
- data/spec/mtk/pattern/palindrome_spec.rb +124 -0
- data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +47 -0
- data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +37 -0
- data/spec/mtk/pattern/sequence_spec.rb +128 -31
- data/spec/mtk/pitch_class_set_spec.rb +240 -7
- data/spec/mtk/pitch_class_spec.rb +84 -18
- data/spec/mtk/pitch_set_spec.rb +45 -10
- data/spec/mtk/pitch_spec.rb +59 -0
- data/spec/mtk/sequencer/abstract_sequencer_spec.rb +159 -0
- data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +49 -0
- data/spec/mtk/sequencer/step_sequencer_spec.rb +71 -0
- data/spec/mtk/timeline_spec.rb +118 -15
- data/spec/spec_helper.rb +4 -3
- metadata +59 -22
- data/lib/mtk/chord.rb +0 -47
- data/lib/mtk/constants/dynamics.rb +0 -56
- data/lib/mtk/constants/pitch_classes.rb +0 -18
- data/lib/mtk/constants/pitches.rb +0 -24
- data/lib/mtk/pattern/note_sequence.rb +0 -60
- data/lib/mtk/pattern/pitch_sequence.rb +0 -22
- data/lib/mtk/patterns.rb +0 -4
- data/spec/mtk/chord_spec.rb +0 -74
- data/spec/mtk/constants/pitch_classes_spec.rb +0 -35
- data/spec/mtk/constants/pitches_spec.rb +0 -23
- data/spec/mtk/pattern/note_sequence_spec.rb +0 -121
- data/spec/mtk/pattern/pitch_sequence_spec.rb +0 -47
data/spec/mtk/timeline_spec.rb
CHANGED
@@ -8,6 +8,15 @@ describe MTK::Timeline do
|
|
8
8
|
let(:timeline_hash) { { 0 => [note1], 1 => [note1, note2] } }
|
9
9
|
let(:timeline) { Timeline.from_hash(timeline_raw_data) }
|
10
10
|
|
11
|
+
let(:unquantized_data) { { 0.0 => [note1], 0.7 => [note1], 1.24 => [note1], 1.25 => [note1] } }
|
12
|
+
let(:unquantized_timeline) { Timeline.from_hash(unquantized_data) }
|
13
|
+
let(:quantization_interval) { 0.5 }
|
14
|
+
let(:quantized_data) { { 0.0 => [note1], 0.5 => [note1], 1.0 => [note1], 1.5 => [note1] } }
|
15
|
+
|
16
|
+
let(:shifted_data) { { 5 => [note1], 6 => [note1, note2] } }
|
17
|
+
let(:reverse_shifted_data) { { -5 => [note1], -4 => [note1, note2] } }
|
18
|
+
let(:shift_amount) { 5 }
|
19
|
+
|
11
20
|
it "is Enumerable" do
|
12
21
|
Timeline.new.should be_a Enumerable
|
13
22
|
end
|
@@ -35,7 +44,9 @@ describe MTK::Timeline do
|
|
35
44
|
end
|
36
45
|
|
37
46
|
describe "from_a" do
|
38
|
-
it "creates a timeline from an Enumerable"
|
47
|
+
it "creates a timeline from an Enumerable" do
|
48
|
+
Timeline.from_a(timeline_hash.to_a).should == timeline
|
49
|
+
end
|
39
50
|
end
|
40
51
|
|
41
52
|
describe "#to_hash" do
|
@@ -51,7 +62,9 @@ describe MTK::Timeline do
|
|
51
62
|
end
|
52
63
|
|
53
64
|
describe "#merge" do
|
54
|
-
it "merges all the time,event pairs in the given Enumerable into this Timeline"
|
65
|
+
it "merges all the time,event pairs in the given Enumerable into this Timeline" do
|
66
|
+
timeline.merge({ 3 => note2 }).should == Timeline.from_hash( timeline_raw_data.merge({ 3 => note2 }) )
|
67
|
+
end
|
55
68
|
end
|
56
69
|
|
57
70
|
describe "#empty?" do
|
@@ -98,7 +111,10 @@ describe MTK::Timeline do
|
|
98
111
|
timeline[5].should == [note1, note2]
|
99
112
|
end
|
100
113
|
|
101
|
-
it "accepts
|
114
|
+
it "accepts a list of events as its second argument" do
|
115
|
+
timeline.add 5, [note1, note2]
|
116
|
+
timeline[5].should == [note1, note2]
|
117
|
+
end
|
102
118
|
end
|
103
119
|
|
104
120
|
describe "#delete" do
|
@@ -142,24 +158,16 @@ describe MTK::Timeline do
|
|
142
158
|
end
|
143
159
|
|
144
160
|
describe "#each" do
|
145
|
-
it "yields each |time,single_event| pair" do
|
146
|
-
yielded = []
|
147
|
-
timeline.each{|t,e| yielded << [t,e] }
|
148
|
-
yielded.should == [ [0,note1], [1,note1], [1,note2] ]
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
describe "#each_time" do
|
153
161
|
it "yields each |time,event_list| pair" do
|
154
162
|
yielded = []
|
155
|
-
timeline.
|
163
|
+
timeline.each{|time,events| yielded << [time,events] }
|
156
164
|
yielded.should == [ [0,[note1]], [1,[note1,note2]] ]
|
157
165
|
end
|
158
166
|
end
|
159
167
|
|
160
168
|
describe "#map" do
|
161
169
|
it "returns a new Timeline where each [time,event] pair is replaced by the result of block" do
|
162
|
-
mapped = timeline.map{|time,
|
170
|
+
mapped = timeline.map{|time,events| [time+1, events.map{|e| e.transpose(time+2) }] }
|
163
171
|
mapped.should == { 1 => [note1.transpose(2)], 2 => [note1.transpose(3), note2.transpose(3)] }
|
164
172
|
end
|
165
173
|
|
@@ -171,7 +179,7 @@ describe MTK::Timeline do
|
|
171
179
|
|
172
180
|
describe "#map!" do
|
173
181
|
it "maps the Timeline in place" do
|
174
|
-
timeline.map! {|time,
|
182
|
+
timeline.map! {|time,events| [time+1, events.map{|e| e.transpose(time+2) }] }
|
175
183
|
timeline.should == { 1 => [note1.transpose(2)], 2 => [note1.transpose(3), note2.transpose(3)] }
|
176
184
|
end
|
177
185
|
end
|
@@ -203,7 +211,86 @@ describe MTK::Timeline do
|
|
203
211
|
timeline.should == timeline_hash
|
204
212
|
end
|
205
213
|
end
|
206
|
-
|
214
|
+
|
215
|
+
describe "#quantize" do
|
216
|
+
it "maps all times to the nearest multiple of the given interval" do
|
217
|
+
unquantized_timeline.quantize(quantization_interval).should == quantized_data
|
218
|
+
end
|
219
|
+
it "returns a new Timeline and does not modify the original" do
|
220
|
+
unquantized_timeline.quantize(quantization_interval)
|
221
|
+
unquantized_timeline.should == unquantized_data
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe "#quantize!" do
|
226
|
+
it "maps all times to the nearest multiple of the given interval" do
|
227
|
+
unquantized_timeline.quantize!(quantization_interval).should == quantized_data
|
228
|
+
end
|
229
|
+
|
230
|
+
it "modifies the Timeline in place" do
|
231
|
+
unquantized_timeline.quantize!(quantization_interval)
|
232
|
+
unquantized_timeline.should == quantized_data
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
describe "#shift" do
|
237
|
+
it "shifts all times by the given amount" do
|
238
|
+
timeline.shift(shift_amount).should == shifted_data
|
239
|
+
end
|
240
|
+
|
241
|
+
it "goes back in time for negative arguments" do
|
242
|
+
timeline.shift(-shift_amount).should == reverse_shifted_data
|
243
|
+
end
|
244
|
+
|
245
|
+
it "returns an instance of the same type" do
|
246
|
+
timeline.shift(shift_amount).should be_a timeline.class
|
247
|
+
end
|
248
|
+
|
249
|
+
it "returns a new Timeline and does not modify the original" do
|
250
|
+
timeline.shift(shift_amount).should_not equal timeline
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
describe "#shift!" do
|
255
|
+
it "shifts all times by the given amount" do
|
256
|
+
timeline.shift!(shift_amount).should == shifted_data
|
257
|
+
end
|
258
|
+
|
259
|
+
it "goes back in time for negative arguments" do
|
260
|
+
timeline.shift!(-shift_amount).should == reverse_shifted_data
|
261
|
+
end
|
262
|
+
|
263
|
+
it "modifies the timeline in place" do
|
264
|
+
timeline.shift!(shift_amount).should equal timeline
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "#shift_to" do
|
269
|
+
it "shifts so the start is at the given time" do
|
270
|
+
Timeline.from_hash(shifted_data).shift_to(0).should == timeline
|
271
|
+
Timeline.from_hash(reverse_shifted_data).shift_to(0).should == timeline
|
272
|
+
end
|
273
|
+
|
274
|
+
it "returns an instance of the same type" do
|
275
|
+
timeline.shift_to(shift_amount).should be_a timeline.class
|
276
|
+
end
|
277
|
+
|
278
|
+
it "returns a new Timeline and does not modify the original" do
|
279
|
+
timeline.shift_to(shift_amount).should_not equal timeline
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "#shift_to!" do
|
284
|
+
it "shifts so the start is at the given time" do
|
285
|
+
Timeline.from_hash(shifted_data).shift_to!(0).should == timeline
|
286
|
+
Timeline.from_hash(reverse_shifted_data).shift_to!(0).should == timeline
|
287
|
+
end
|
288
|
+
|
289
|
+
it "modifies the timeline in place" do
|
290
|
+
timeline.shift_to!(shift_amount).should equal timeline
|
291
|
+
end
|
292
|
+
end
|
293
|
+
|
207
294
|
describe "#flatten" do
|
208
295
|
it "flattens nested timelines so that all nested subtimes are converted to absolute times in a single timeline" do
|
209
296
|
timeline[10] = Timeline.from_hash({ 0 => note2, 1 => note1 })
|
@@ -230,5 +317,21 @@ describe MTK::Timeline do
|
|
230
317
|
timeline.clone.should_not equal(timeline)
|
231
318
|
end
|
232
319
|
end
|
320
|
+
|
321
|
+
describe ".quantize_time" do
|
322
|
+
it "takes a time and an interval, and returns the nearest multiple of the interval to the time" do
|
323
|
+
Timeline.quantize_time(23,10).should == 20
|
324
|
+
Timeline.quantize_time(27,10).should == 30
|
325
|
+
Timeline.quantize_time(30,10).should == 30
|
326
|
+
end
|
327
|
+
|
328
|
+
it "rounds up when exactly between 2 intervals" do
|
329
|
+
Timeline.quantize_time(25,10).should == 30
|
330
|
+
end
|
331
|
+
|
332
|
+
it "handles fractional intervals" do
|
333
|
+
Timeline.quantize_time(13,2.5).should == 12.5
|
334
|
+
end
|
335
|
+
end
|
233
336
|
end
|
234
337
|
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: mtk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0.
|
5
|
+
version: 0.0.2
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Adam Murray
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-07-09 00:00:00 Z
|
14
14
|
dependencies: []
|
15
15
|
|
16
16
|
description:
|
@@ -23,49 +23,86 @@ extra_rdoc_files: []
|
|
23
23
|
|
24
24
|
files:
|
25
25
|
- Rakefile
|
26
|
+
- INTRO.md
|
26
27
|
- README.md
|
27
|
-
-
|
28
|
-
-
|
29
|
-
- lib/mtk/
|
30
|
-
- lib/mtk/
|
31
|
-
- lib/mtk/
|
32
|
-
- lib/mtk/
|
28
|
+
- LICENSE.txt
|
29
|
+
- .yardopts
|
30
|
+
- lib/mtk/_constants/durations.rb
|
31
|
+
- lib/mtk/_constants/intensities.rb
|
32
|
+
- lib/mtk/_constants/intervals.rb
|
33
|
+
- lib/mtk/_constants/pitch_classes.rb
|
34
|
+
- lib/mtk/_constants/pitches.rb
|
35
|
+
- lib/mtk/_numeric_extensions.rb
|
33
36
|
- lib/mtk/event.rb
|
37
|
+
- lib/mtk/helper/collection.rb
|
38
|
+
- lib/mtk/helper/event_builder.rb
|
39
|
+
- lib/mtk/helper/pseudo_constants.rb
|
40
|
+
- lib/mtk/lang/grammar.rb
|
41
|
+
- lib/mtk/lang/mtk_grammar.citrus
|
34
42
|
- lib/mtk/midi/file.rb
|
43
|
+
- lib/mtk/midi/jsound_input.rb
|
44
|
+
- lib/mtk/midi/jsound_output.rb
|
35
45
|
- lib/mtk/note.rb
|
36
|
-
- lib/mtk/
|
46
|
+
- lib/mtk/pattern/abstract_pattern.rb
|
37
47
|
- lib/mtk/pattern/choice.rb
|
38
|
-
- lib/mtk/pattern/
|
39
|
-
- lib/mtk/pattern/
|
48
|
+
- lib/mtk/pattern/cycle.rb
|
49
|
+
- lib/mtk/pattern/enumerator.rb
|
50
|
+
- lib/mtk/pattern/function.rb
|
51
|
+
- lib/mtk/pattern/lines.rb
|
52
|
+
- lib/mtk/pattern/palindrome.rb
|
40
53
|
- lib/mtk/pattern/sequence.rb
|
41
|
-
- lib/mtk/patterns.rb
|
42
54
|
- lib/mtk/pitch.rb
|
43
55
|
- lib/mtk/pitch_class.rb
|
44
56
|
- lib/mtk/pitch_class_set.rb
|
45
57
|
- lib/mtk/pitch_set.rb
|
58
|
+
- lib/mtk/sequencer/abstract_sequencer.rb
|
59
|
+
- lib/mtk/sequencer/rhythmic_sequencer.rb
|
60
|
+
- lib/mtk/sequencer/step_sequencer.rb
|
46
61
|
- lib/mtk/timeline.rb
|
47
|
-
- lib/mtk/
|
62
|
+
- lib/mtk/transform/invertible.rb
|
63
|
+
- lib/mtk/transform/mappable.rb
|
64
|
+
- lib/mtk/transform/set_theory_operations.rb
|
65
|
+
- lib/mtk/transform/transposable.rb
|
48
66
|
- lib/mtk.rb
|
49
|
-
- spec/mtk/
|
50
|
-
- spec/mtk/
|
51
|
-
- spec/mtk/
|
52
|
-
- spec/mtk/
|
53
|
-
- spec/mtk/
|
67
|
+
- spec/mtk/_constants/durations_spec.rb
|
68
|
+
- spec/mtk/_constants/intensities_spec.rb
|
69
|
+
- spec/mtk/_constants/intervals_spec.rb
|
70
|
+
- spec/mtk/_constants/pitch_classes_spec.rb
|
71
|
+
- spec/mtk/_constants/pitches_spec.rb
|
72
|
+
- spec/mtk/_numeric_extensions_spec.rb
|
54
73
|
- spec/mtk/event_spec.rb
|
74
|
+
- spec/mtk/helper/collection_spec.rb
|
75
|
+
- spec/mtk/helper/event_builder_spec.rb
|
76
|
+
- spec/mtk/helper/pseudo_constants_spec.rb
|
77
|
+
- spec/mtk/lang/grammar_spec.rb
|
55
78
|
- spec/mtk/midi/file_spec.rb
|
56
79
|
- spec/mtk/note_spec.rb
|
57
|
-
- spec/mtk/
|
80
|
+
- spec/mtk/pattern/abstract_pattern_spec.rb
|
58
81
|
- spec/mtk/pattern/choice_spec.rb
|
59
|
-
- spec/mtk/pattern/
|
60
|
-
- spec/mtk/pattern/
|
82
|
+
- spec/mtk/pattern/cycle_spec.rb
|
83
|
+
- spec/mtk/pattern/function_spec.rb
|
84
|
+
- spec/mtk/pattern/lines_spec.rb
|
85
|
+
- spec/mtk/pattern/note_cycle_spec.rb.bak
|
86
|
+
- spec/mtk/pattern/palindrome_spec.rb
|
87
|
+
- spec/mtk/pattern/pitch_cycle_spec.rb.bak
|
88
|
+
- spec/mtk/pattern/pitch_sequence_spec.rb.bak
|
61
89
|
- spec/mtk/pattern/sequence_spec.rb
|
62
90
|
- spec/mtk/pitch_class_set_spec.rb
|
63
91
|
- spec/mtk/pitch_class_spec.rb
|
64
92
|
- spec/mtk/pitch_set_spec.rb
|
65
93
|
- spec/mtk/pitch_spec.rb
|
94
|
+
- spec/mtk/sequencer/abstract_sequencer_spec.rb
|
95
|
+
- spec/mtk/sequencer/rhythmic_sequencer_spec.rb
|
96
|
+
- spec/mtk/sequencer/step_sequencer_spec.rb
|
66
97
|
- spec/mtk/timeline_spec.rb
|
67
98
|
- spec/spec_helper.rb
|
68
99
|
- spec/test.mid
|
100
|
+
- examples/crescendo.rb
|
101
|
+
- examples/dynamic_pattern.rb
|
102
|
+
- examples/play_midi.rb
|
103
|
+
- examples/print_midi.rb
|
104
|
+
- examples/random_tone_row.rb
|
105
|
+
- examples/tone_row_melody.rb
|
69
106
|
homepage: http://github.com/adamjmurray/mtk
|
70
107
|
licenses: []
|
71
108
|
|
@@ -92,6 +129,6 @@ rubyforge_project:
|
|
92
129
|
rubygems_version: 1.8.5
|
93
130
|
signing_key:
|
94
131
|
specification_version: 3
|
95
|
-
summary:
|
132
|
+
summary: Music ToolKit for Ruby
|
96
133
|
test_files: []
|
97
134
|
|
data/lib/mtk/chord.rb
DELETED
@@ -1,47 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
|
3
|
-
# A multi-pitch, note-like {Event} defined by a {PitchSet}, intensity, and duration
|
4
|
-
class Chord < Event
|
5
|
-
|
6
|
-
# the {PitchSet} of the chord
|
7
|
-
attr_reader :pitch_set
|
8
|
-
|
9
|
-
def initialize(pitches, intensity, duration)
|
10
|
-
@pitch_set = if pitches.is_a? PitchSet
|
11
|
-
pitches
|
12
|
-
else
|
13
|
-
PitchSet.new(pitches)
|
14
|
-
end
|
15
|
-
super(intensity, duration)
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.from_hash(hash)
|
19
|
-
new hash[:pitch_set], hash[:intensity], hash[:duration]
|
20
|
-
end
|
21
|
-
|
22
|
-
def to_hash
|
23
|
-
super.merge({ :pitch_set => @pitch_set })
|
24
|
-
end
|
25
|
-
|
26
|
-
def pitches
|
27
|
-
@pitch_set.pitches
|
28
|
-
end
|
29
|
-
|
30
|
-
def transpose(interval)
|
31
|
-
self.class.new(@pitch_set + interval, @intensity, @duration)
|
32
|
-
end
|
33
|
-
|
34
|
-
def == other
|
35
|
-
super and other.respond_to? :pitch_set and @pitch_set == other.pitch_set
|
36
|
-
end
|
37
|
-
|
38
|
-
def to_s
|
39
|
-
"Chord(#{pitch_set}, #{super})"
|
40
|
-
end
|
41
|
-
|
42
|
-
def inspect
|
43
|
-
"Chord(#{pitch_set}, #{super})"
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
|
3
|
-
# Defines values for standard dynamic symbols.
|
4
|
-
#
|
5
|
-
# These can be thought of like constants, but in order to distinguish 'f' (forte) from the {PitchClass} 'F'
|
6
|
-
# it was necessary to use lower-case names and therefore define them as "pseudo constant" methods.
|
7
|
-
# The methods are available either throught the module (MTK::Dynamics::f) or via mixin (include MTK::Dynamics; f)
|
8
|
-
#
|
9
|
-
# These values are intensities in the range 0.0 - 1.0, so they can be easily scaled (unlike MIDI velocities).
|
10
|
-
#
|
11
|
-
# @note Including this module shadows Ruby's built-in p() method.
|
12
|
-
# If you include this module, you can access the built-in p() method via Kernel.p()
|
13
|
-
#
|
14
|
-
# @see Note
|
15
|
-
module Dynamics
|
16
|
-
extend MTK::PseudoConstants
|
17
|
-
|
18
|
-
# NOTE: the yard doc macros here only fill in [$2] with the actual value when generating docs under Ruby 1.9+
|
19
|
-
|
20
|
-
# pianississimo
|
21
|
-
# @macro [attach] dynamics.define_constant
|
22
|
-
# @attribute [r]
|
23
|
-
# @return [$2] intensity value for $1
|
24
|
-
define_constant 'ppp', 0.125
|
25
|
-
|
26
|
-
# pianissimo
|
27
|
-
define_constant 'pp', 0.25
|
28
|
-
|
29
|
-
# piano
|
30
|
-
# @note Including this module shadows Ruby's built-in p() method.
|
31
|
-
# If you include this module, you can access the built-in p() method via Kernel.p()
|
32
|
-
define_constant 'p', 0.375
|
33
|
-
|
34
|
-
# mezzo-piano
|
35
|
-
define_constant 'mp', 0.5
|
36
|
-
|
37
|
-
# mezzo-forte
|
38
|
-
define_constant 'mf', 0.625
|
39
|
-
|
40
|
-
# forte
|
41
|
-
define_constant 'f', 0.75
|
42
|
-
|
43
|
-
# fortissimo
|
44
|
-
define_constant 'ff', 0.875
|
45
|
-
|
46
|
-
# fortississimo
|
47
|
-
define_constant 'fff', 1.0
|
48
|
-
|
49
|
-
def self.[](name)
|
50
|
-
send name
|
51
|
-
rescue
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
|
3
|
-
# Defines a constant for each {PitchClass} in the Western chromatic scale.
|
4
|
-
|
5
|
-
module PitchClasses
|
6
|
-
|
7
|
-
# An array of all pitch class constants defined in this module
|
8
|
-
PITCH_CLASSES = []
|
9
|
-
|
10
|
-
for name in PitchClass::NAMES
|
11
|
-
pc = PitchClass.from_name name
|
12
|
-
PITCH_CLASSES << pc
|
13
|
-
const_set name, pc
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
|
3
|
-
# Defines a constants for each {Pitch} in the standard MIDI range using scientific pitch notation.
|
4
|
-
#
|
5
|
-
# See http://en.wikipedia.org/wiki/Scientific_pitch_notation
|
6
|
-
#
|
7
|
-
# Note that because the character '#' cannot be used in the name of a constant,
|
8
|
-
# The "black key" pitches are all named as flats with 'b' (for example, Gb3 or Cb4)
|
9
|
-
|
10
|
-
module Pitches
|
11
|
-
|
12
|
-
# An array of all the pitch constants defined in this module
|
13
|
-
PITCHES = []
|
14
|
-
|
15
|
-
128.times do |note_number|
|
16
|
-
pitch = Pitch.from_i( note_number )
|
17
|
-
PITCHES << pitch
|
18
|
-
octave_str = pitch.octave.to_s.sub(/-/,'_') # '_1' for -1
|
19
|
-
const_set "#{pitch.pitch_class}#{octave_str}", pitch
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Pattern
|
3
|
-
|
4
|
-
# A {Sequence} of {Note}s
|
5
|
-
class NoteSequence
|
6
|
-
|
7
|
-
attr_reader :pitch_sequence, :intensity_sequence, :duration_sequence
|
8
|
-
|
9
|
-
attr_accessor :pitch, :intensity, :duration
|
10
|
-
|
11
|
-
def initialize(pitches, intensities=nil, durations=nil, defaults={})
|
12
|
-
@pitch_sequence = PitchSequence.new(pitches)
|
13
|
-
@intensity_sequence = Sequence.new(intensities)
|
14
|
-
@duration_sequence = Sequence.new(durations)
|
15
|
-
@default = {:pitch => Pitches::C4, :intensity => Dynamics::mf, :duration => 1}.merge defaults
|
16
|
-
reset
|
17
|
-
end
|
18
|
-
|
19
|
-
def pitches
|
20
|
-
@pitch_sequence.elements
|
21
|
-
end
|
22
|
-
|
23
|
-
def intensities
|
24
|
-
@intensity_sequence.elements
|
25
|
-
end
|
26
|
-
|
27
|
-
def durations
|
28
|
-
@duration_sequence.elements
|
29
|
-
end
|
30
|
-
|
31
|
-
# reset the Sequence to the beginning
|
32
|
-
def reset
|
33
|
-
@pitch_sequence.reset
|
34
|
-
@intensity_sequence.reset
|
35
|
-
@duration_sequence.reset
|
36
|
-
|
37
|
-
@pitch = @default[:pitch]
|
38
|
-
@intensity = @default[:intensity]
|
39
|
-
@duration = @default[:duration]
|
40
|
-
end
|
41
|
-
|
42
|
-
# return next {Note} in sequence
|
43
|
-
def next
|
44
|
-
@pitch = @pitch_sequence.next || @pitch
|
45
|
-
@intensity = @intensity_sequence.next || @intensity
|
46
|
-
@duration = @duration_sequence.next || @duration
|
47
|
-
|
48
|
-
|
49
|
-
case @pitch
|
50
|
-
when PitchSet,Array then Chord.new(@pitch, @intensity, @duration)
|
51
|
-
else Note.new(@pitch, @intensity, @duration)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
|
@@ -1,22 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Pattern
|
3
|
-
|
4
|
-
# A {Sequence} of pitch-related elements, which may be {Pitch}es, {PitchClass}es, {PitchSet}s, or {Intervals} (Numeric)
|
5
|
-
class PitchSequence < Sequence
|
6
|
-
|
7
|
-
protected
|
8
|
-
|
9
|
-
# extend value_of to handle intervals and PitchClasses
|
10
|
-
def value_of element
|
11
|
-
element = super # eval Procs
|
12
|
-
case element
|
13
|
-
when Numeric then @value + element if @value # add interval
|
14
|
-
when PitchClass then @value.nearest(element) if @value
|
15
|
-
else element
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
end
|
20
|
-
|
21
|
-
end
|
22
|
-
end
|
data/lib/mtk/patterns.rb
DELETED
data/spec/mtk/chord_spec.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MTK::Chord do
|
4
|
-
|
5
|
-
let(:pitch_set) { PitchSet.new [C4, E4, G4] }
|
6
|
-
let(:intensity) { mf }
|
7
|
-
let(:duration) { 2.5 }
|
8
|
-
let(:chord) { Chord.new(pitch_set, intensity, duration) }
|
9
|
-
|
10
|
-
it "can be constructed with a PitchSet" do
|
11
|
-
pitch_set = PitchSet.new([C4])
|
12
|
-
Chord.new( pitch_set, intensity, duration ).pitch_set.should == pitch_set
|
13
|
-
end
|
14
|
-
|
15
|
-
it "can be constructed with an Array of Pitches" do
|
16
|
-
Chord.new( [C4], intensity, duration ).pitch_set.should == PitchSet.new([C4])
|
17
|
-
end
|
18
|
-
|
19
|
-
describe "#pitch_set" do
|
20
|
-
it "is the pitch_set used to create the Chord" do
|
21
|
-
chord.pitch_set.should == pitch_set
|
22
|
-
end
|
23
|
-
|
24
|
-
it "is a read-only attribute" do
|
25
|
-
lambda{ chord.pitch_set = PitchSet.new }.should raise_error
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "#pitches" do
|
30
|
-
it "is the list of pitches in the pitch_set" do
|
31
|
-
chord.pitches.should == chord.pitch_set.pitches
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
describe "from_hash" do
|
36
|
-
it "constructs a Chord using a hash" do
|
37
|
-
Chord.from_hash({ :pitch_set => pitch_set, :intensity => intensity, :duration => duration }).should == chord
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe "#to_hash" do
|
42
|
-
it "is a hash containing all the attributes of the Chord" do
|
43
|
-
chord.to_hash.should == { :pitch_set => pitch_set, :intensity => intensity, :duration => duration }
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
describe '#transpose' do
|
48
|
-
it 'adds the given interval to the @pitch_set' do
|
49
|
-
(chord.transpose 2.semitones).should == Chord.new(pitch_set+2, intensity, duration)
|
50
|
-
end
|
51
|
-
it 'does not affect the immutability of the Chord' do
|
52
|
-
(chord.transpose 2.semitones).should_not == chord
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
describe "#==" do
|
57
|
-
it "is true when the pitch_sets, intensities, and durations are equal" do
|
58
|
-
chord.should == Chord.new(pitch_set, intensity, duration)
|
59
|
-
end
|
60
|
-
|
61
|
-
it "is false when the pitch_sets are not equal" do
|
62
|
-
chord.should_not == Chord.new(pitch_set + 1, intensity, duration)
|
63
|
-
end
|
64
|
-
|
65
|
-
it "is false when the intensities are not equal" do
|
66
|
-
chord.should_not == Chord.new(pitch_set, intensity * 0.5, duration)
|
67
|
-
end
|
68
|
-
|
69
|
-
it "is false when the durations are not equal" do
|
70
|
-
chord.should_not == Chord.new(pitch_set, intensity, duration * 2)
|
71
|
-
end
|
72
|
-
end
|
73
|
-
|
74
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MTK::PitchClasses do
|
4
|
-
let(:cases) {
|
5
|
-
[
|
6
|
-
[PitchClasses::C, 'C', 0],
|
7
|
-
[PitchClasses::Db, 'Db', 1],
|
8
|
-
[PitchClasses::D, 'D', 2],
|
9
|
-
[PitchClasses::Eb, 'Eb', 3],
|
10
|
-
[PitchClasses::E, 'E', 4],
|
11
|
-
[PitchClasses::F, 'F', 5],
|
12
|
-
[PitchClasses::Gb, 'Gb', 6],
|
13
|
-
[PitchClasses::G, 'G', 7],
|
14
|
-
[PitchClasses::Ab, 'Ab', 8],
|
15
|
-
[PitchClasses::A, 'A', 9],
|
16
|
-
[PitchClasses::Bb, 'Bb', 10],
|
17
|
-
[PitchClasses::B, 'B', 11],
|
18
|
-
]
|
19
|
-
}
|
20
|
-
|
21
|
-
it "defines constants for the 12 pitch classes in the twelve-tone octave" do
|
22
|
-
cases.length.should == 12
|
23
|
-
cases.each do |const, name, int_value|
|
24
|
-
const.name.should == name
|
25
|
-
const.to_i.should == int_value
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
describe "PITCH_CLASSES" do
|
30
|
-
it "contains the 12 pitch class constants" do
|
31
|
-
PitchClasses::PITCH_CLASSES.length.should == 12
|
32
|
-
PitchClasses::PITCH_CLASSES.should == cases.map{ |const,_,__| const }
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|