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.
- data/.yardopts +3 -2
- data/DEVELOPMENT_NOTES.md +114 -0
- data/INTRO.md +64 -8
- data/LICENSE.txt +1 -1
- data/README.md +31 -102
- data/Rakefile +56 -18
- data/bin/mtk +215 -0
- data/examples/crescendo.rb +5 -5
- data/examples/drum_pattern1.rb +23 -0
- data/examples/dynamic_pattern.rb +8 -11
- data/examples/gets_and_play.rb +26 -0
- data/examples/notation.rb +22 -0
- data/examples/play_midi.rb +8 -10
- data/examples/random_tone_row.rb +2 -2
- data/examples/syntax_to_midi.rb +28 -0
- data/examples/test_output.rb +8 -0
- data/examples/tone_row_melody.rb +6 -6
- data/lib/mtk.rb +52 -40
- data/lib/mtk/chord.rb +55 -0
- data/lib/mtk/constants/durations.rb +57 -0
- data/lib/mtk/constants/intensities.rb +61 -0
- data/lib/mtk/constants/intervals.rb +73 -0
- data/lib/mtk/constants/pitch_classes.rb +29 -0
- data/lib/mtk/constants/pitches.rb +52 -0
- data/lib/mtk/duration.rb +211 -0
- data/lib/mtk/events/event.rb +119 -0
- data/lib/mtk/events/note.rb +112 -0
- data/lib/mtk/events/parameter.rb +54 -0
- data/lib/mtk/helpers/collection.rb +164 -0
- data/lib/mtk/helpers/convert.rb +36 -0
- data/lib/mtk/helpers/lilypond.rb +162 -0
- data/lib/mtk/helpers/output_selector.rb +67 -0
- data/lib/mtk/helpers/pitch_collection.rb +23 -0
- data/lib/mtk/helpers/pseudo_constants.rb +26 -0
- data/lib/mtk/intensity.rb +156 -0
- data/lib/mtk/interval.rb +155 -0
- data/lib/mtk/lang/mtk_grammar.citrus +190 -13
- data/lib/mtk/lang/parser.rb +29 -0
- data/lib/mtk/melody.rb +94 -0
- data/lib/mtk/midi/dls_synth_device.rb +144 -0
- data/lib/mtk/midi/dls_synth_output.rb +62 -0
- data/lib/mtk/midi/file.rb +67 -32
- data/lib/mtk/midi/input.rb +97 -0
- data/lib/mtk/midi/jsound_input.rb +36 -17
- data/lib/mtk/midi/jsound_output.rb +48 -46
- data/lib/mtk/midi/output.rb +195 -0
- data/lib/mtk/midi/unimidi_input.rb +117 -0
- data/lib/mtk/midi/unimidi_output.rb +121 -0
- data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
- data/lib/mtk/patterns/chain.rb +49 -0
- data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
- data/lib/mtk/patterns/cycle.rb +18 -0
- data/lib/mtk/patterns/for_each.rb +71 -0
- data/lib/mtk/patterns/function.rb +39 -0
- data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
- data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
- data/lib/mtk/patterns/pattern.rb +171 -0
- data/lib/mtk/patterns/sequence.rb +20 -0
- data/lib/mtk/pitch.rb +7 -6
- data/lib/mtk/pitch_class.rb +124 -46
- data/lib/mtk/pitch_class_set.rb +58 -35
- data/lib/mtk/sequencers/event_builder.rb +131 -0
- data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
- data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
- data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
- data/lib/mtk/timeline.rb +39 -22
- data/lib/mtk/variable.rb +32 -0
- data/spec/mtk/chord_spec.rb +83 -0
- data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
- data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
- data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
- data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
- data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
- data/spec/mtk/duration_spec.rb +372 -0
- data/spec/mtk/events/event_spec.rb +234 -0
- data/spec/mtk/events/note_spec.rb +174 -0
- data/spec/mtk/events/parameter_spec.rb +220 -0
- data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
- data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
- data/spec/mtk/intensity_spec.rb +289 -0
- data/spec/mtk/interval_spec.rb +265 -0
- data/spec/mtk/lang/parser_spec.rb +597 -0
- data/spec/mtk/melody_spec.rb +223 -0
- data/spec/mtk/midi/file_spec.rb +16 -16
- data/spec/mtk/midi/jsound_input_spec.rb +11 -0
- data/spec/mtk/midi/jsound_output_spec.rb +11 -0
- data/spec/mtk/midi/output_spec.rb +102 -0
- data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
- data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
- data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
- data/spec/mtk/patterns/chain_spec.rb +110 -0
- data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
- data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
- data/spec/mtk/patterns/for_each_spec.rb +136 -0
- data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
- data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
- data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
- data/spec/mtk/patterns/pattern_spec.rb +132 -0
- data/spec/mtk/patterns/sequence_spec.rb +203 -0
- data/spec/mtk/pitch_class_set_spec.rb +23 -21
- data/spec/mtk/pitch_class_spec.rb +151 -39
- data/spec/mtk/pitch_spec.rb +22 -1
- data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
- data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
- data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
- data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
- data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
- data/spec/mtk/timeline_spec.rb +109 -16
- data/spec/mtk/variable_spec.rb +52 -0
- data/spec/spec_coverage.rb +2 -0
- data/spec/spec_helper.rb +3 -0
- metadata +188 -91
- data/lib/mtk/_constants/durations.rb +0 -80
- data/lib/mtk/_constants/intensities.rb +0 -81
- data/lib/mtk/_constants/intervals.rb +0 -85
- data/lib/mtk/_constants/pitch_classes.rb +0 -35
- data/lib/mtk/_constants/pitches.rb +0 -49
- data/lib/mtk/event.rb +0 -70
- data/lib/mtk/helper/collection.rb +0 -114
- data/lib/mtk/helper/event_builder.rb +0 -85
- data/lib/mtk/helper/pseudo_constants.rb +0 -26
- data/lib/mtk/lang/grammar.rb +0 -17
- data/lib/mtk/note.rb +0 -63
- data/lib/mtk/pattern/abstract_pattern.rb +0 -132
- data/lib/mtk/pattern/cycle.rb +0 -51
- data/lib/mtk/pattern/enumerator.rb +0 -26
- data/lib/mtk/pattern/function.rb +0 -46
- data/lib/mtk/pattern/sequence.rb +0 -30
- data/lib/mtk/pitch_set.rb +0 -84
- data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
- data/lib/mtk/transform/invertible.rb +0 -15
- data/lib/mtk/transform/mappable.rb +0 -18
- data/lib/mtk/transform/set_theory_operations.rb +0 -34
- data/lib/mtk/transform/transposable.rb +0 -14
- data/spec/mtk/event_spec.rb +0 -139
- data/spec/mtk/helper/event_builder_spec.rb +0 -92
- data/spec/mtk/lang/grammar_spec.rb +0 -100
- data/spec/mtk/note_spec.rb +0 -115
- data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
- data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
- data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
- data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
- data/spec/mtk/pattern/sequence_spec.rb +0 -151
- data/spec/mtk/pitch_set_spec.rb +0 -198
- data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
- data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +0 -49
@@ -26,6 +26,12 @@ describe MTK::PitchClassSet do
|
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
describe ".new" do
|
30
|
+
it "maintains the pitch class collection exactly (preserves order and keeps duplicates)" do
|
31
|
+
PitchClassSet.new([C, E, G, E, B, C]).pitch_classes.should == [C, E, G, E, B, C]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
29
35
|
describe "#pitch_classes" do
|
30
36
|
it "is the list of pitch_classes contained in this set" do
|
31
37
|
pitch_class_set.pitch_classes.should == pitch_classes
|
@@ -45,10 +51,6 @@ describe MTK::PitchClassSet do
|
|
45
51
|
pitch_classes << D
|
46
52
|
pitch_class_set.pitch_classes.length.should == 3
|
47
53
|
end
|
48
|
-
|
49
|
-
it "does not include duplicates" do
|
50
|
-
PitchClassSet.new([C, E, G, C]).pitch_classes.should == [C, E, G]
|
51
|
-
end
|
52
54
|
end
|
53
55
|
|
54
56
|
describe "#to_a" do
|
@@ -113,7 +115,7 @@ describe MTK::PitchClassSet do
|
|
113
115
|
|
114
116
|
describe '#transpose' do
|
115
117
|
it 'transposes by the given semitones' do
|
116
|
-
(pitch_class_set.transpose 4
|
118
|
+
(pitch_class_set.transpose 4).should == PitchClassSet(E, Ab, B)
|
117
119
|
end
|
118
120
|
end
|
119
121
|
|
@@ -169,12 +171,6 @@ describe MTK::PitchClassSet do
|
|
169
171
|
end
|
170
172
|
end
|
171
173
|
|
172
|
-
describe "#repeat" do
|
173
|
-
it "does nothing to PitchClassSets, since duplicates are removed from Sets" do
|
174
|
-
pitch_class_set.repeat.should == pitch_class_set
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
174
|
describe "#rotate" do
|
179
175
|
it "produces a PitchClassSet that is rotated by the given offset" do
|
180
176
|
pitch_class_set.rotate(2).should == PitchClassSet(G,C,E)
|
@@ -205,8 +201,8 @@ describe MTK::PitchClassSet do
|
|
205
201
|
end
|
206
202
|
|
207
203
|
describe "#concat" do
|
208
|
-
it "appends the
|
209
|
-
pitch_class_set.concat(PitchClassSet(D,E,F)).should == PitchClassSet(C,E,G,D,F)
|
204
|
+
it "appends the pitch classes from the other set" do
|
205
|
+
pitch_class_set.concat(PitchClassSet(D,E,F)).should == PitchClassSet(C,E,G,D,E,F)
|
210
206
|
end
|
211
207
|
end
|
212
208
|
|
@@ -249,6 +245,10 @@ describe MTK::PitchClassSet do
|
|
249
245
|
pitch_class_set.should_not == PitchClassSet(C,G,E)
|
250
246
|
end
|
251
247
|
|
248
|
+
it "is false when if otherwise equal pitch class sets don't contain the same number of duplicates" do
|
249
|
+
PitchClassSet.new([C, E, G]).should_not == PitchClassSet.new([C, C, E, G])
|
250
|
+
end
|
251
|
+
|
252
252
|
it "is false if two pitch class sets do not contain the same pitch classes" do
|
253
253
|
pitch_class_set.should_not == PitchClassSet(C,E)
|
254
254
|
end
|
@@ -263,6 +263,10 @@ describe MTK::PitchClassSet do
|
|
263
263
|
pitch_class_set.should =~ PitchClassSet(C,E,G)
|
264
264
|
end
|
265
265
|
|
266
|
+
it "is true when all the pitch classes are equal, even with different numbers of duplicates" do
|
267
|
+
Melody.new([C, E, G]).should =~ Melody.new([C, C, E, G])
|
268
|
+
end
|
269
|
+
|
266
270
|
it "is true if two pitch class sets are not in the same order" do
|
267
271
|
pitch_class_set.should =~ PitchClassSet(C,G,E)
|
268
272
|
end
|
@@ -286,18 +290,16 @@ describe MTK::PitchClassSet do
|
|
286
290
|
end
|
287
291
|
end
|
288
292
|
|
289
|
-
describe ".span_for" do
|
290
|
-
it "measure the distance between the first and last pitch classes" do
|
291
|
-
PitchClassSet.span_for([C,D,E,F,G]).should == 7
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
293
|
end
|
296
294
|
|
297
295
|
describe MTK do
|
298
296
|
|
299
297
|
describe '#PitchClassSet' do
|
300
298
|
|
299
|
+
it "constructs a PitchClassSet" do
|
300
|
+
PitchClassSet(C,D).should be_a PitchClassSet
|
301
|
+
end
|
302
|
+
|
301
303
|
it "acts like new for a single Array argument" do
|
302
304
|
PitchClassSet([C,D]).should == PitchClassSet.new([C,D])
|
303
305
|
end
|
@@ -322,9 +324,9 @@ describe MTK do
|
|
322
324
|
PitchClassSet('C').should == PitchClassSet.new([C])
|
323
325
|
end
|
324
326
|
|
325
|
-
it "
|
327
|
+
it "handles a a PitchClassSet" do
|
326
328
|
pitch_set = PitchClassSet.new([C,D])
|
327
|
-
PitchClassSet(pitch_set).should
|
329
|
+
PitchClassSet(pitch_set).should == PitchClassSet([C,D])
|
328
330
|
end
|
329
331
|
|
330
332
|
it "raises an error for types it doesn't understand" do
|
@@ -2,26 +2,29 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe MTK::PitchClass do
|
4
4
|
|
5
|
-
let(:
|
5
|
+
let(:enharmonic_spellings_grouped_by_value) {
|
6
|
+
# not sure how to test this without re-coding these names here
|
6
7
|
[
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
]
|
8
|
+
%w( B# C Dbb ),
|
9
|
+
%w( B## C# Db ),
|
10
|
+
%w( C## D Ebb ),
|
11
|
+
%w( D# Eb Fbb ),
|
12
|
+
%w( D## E Fb ),
|
13
|
+
%w( E# F Gbb ),
|
14
|
+
%w( E## F# Gb ),
|
15
|
+
%w( F## G Abb ),
|
16
|
+
%w( G# Ab ),
|
17
|
+
%w( G## A Bbb ),
|
18
|
+
%w( A# Bb Cbb ),
|
19
|
+
%w( A## B Cb )
|
20
|
+
]
|
20
21
|
}
|
22
|
+
let(:enharmonic_spellings) { enharmonic_spellings_grouped_by_value.flatten }
|
21
23
|
|
24
|
+
|
22
25
|
describe 'NAMES' do
|
23
26
|
it "is the 12 note names in western chromatic scale" do
|
24
|
-
PitchClass::NAMES =~
|
27
|
+
PitchClass::NAMES.should =~ %w( C Db D Eb E F Gb G Ab A Bb B )
|
25
28
|
end
|
26
29
|
|
27
30
|
it "is immutable" do
|
@@ -29,60 +32,111 @@ describe MTK::PitchClass do
|
|
29
32
|
end
|
30
33
|
end
|
31
34
|
|
35
|
+
|
36
|
+
describe 'VALID_NAMES_BY_VALUE' do
|
37
|
+
it 'contains enharmonic spellings of NAMES' do
|
38
|
+
PitchClass::VALID_NAMES_BY_VALUE.should =~ enharmonic_spellings_grouped_by_value
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'organized such that the index of each equivalent spelling matches the index in NAMES' do
|
42
|
+
PitchClass::NAMES.each.with_index do |name,index|
|
43
|
+
PitchClass::VALID_NAMES_BY_VALUE[index].should include(name)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'is immutable' do
|
48
|
+
lambda{ PitchClass::VALID_NAMES_BY_VALUE << 'H' }.should raise_error
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
|
32
53
|
describe 'VALID_NAMES' do
|
33
|
-
it
|
34
|
-
PitchClass::VALID_NAMES =~
|
54
|
+
it 'is all enharmonic spellings of NAMES including sharps, flats, double-sharps, and double-flats' do
|
55
|
+
PitchClass::VALID_NAMES.should =~ enharmonic_spellings.flatten
|
35
56
|
end
|
36
57
|
|
37
|
-
it
|
58
|
+
it 'is immutable' do
|
38
59
|
lambda{ PitchClass::VALID_NAMES << 'H' }.should raise_error
|
39
60
|
end
|
40
61
|
end
|
41
62
|
|
63
|
+
|
64
|
+
describe 'PITCH_CLASSES' do
|
65
|
+
it 'is the 12 pitch classes in the chromatic scale, indexed by value' do
|
66
|
+
for pc in PitchClass::PITCH_CLASSES
|
67
|
+
pc.should == PitchClass::PITCH_CLASSES[pc.value]
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'is immutable' do
|
72
|
+
lambda{ PitchClass::PITCH_CLASSES << C }.should raise_error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
42
77
|
describe '.new' do
|
43
78
|
it "is private" do
|
44
79
|
lambda{ PitchClass.new('C',0) }.should raise_error
|
45
80
|
end
|
46
81
|
end
|
47
82
|
|
48
|
-
|
83
|
+
|
84
|
+
describe '.[]' do
|
49
85
|
context "the argument is a valid name" do
|
50
86
|
it "returns a PitchClass" do
|
51
|
-
|
87
|
+
enharmonic_spellings.each { |name| PitchClass[name].should be_a PitchClass }
|
52
88
|
end
|
53
89
|
it "returns an object with that name" do
|
54
|
-
|
90
|
+
enharmonic_spellings.each { |name| PitchClass[name].name.should == name }
|
55
91
|
end
|
56
92
|
it "ignores case" do
|
57
|
-
for name in
|
93
|
+
for name in enharmonic_spellings
|
58
94
|
PitchClass[name.upcase].name.should == name
|
59
95
|
PitchClass[name.downcase].name.should == name
|
60
96
|
end
|
61
97
|
end
|
62
98
|
end
|
63
99
|
context "the argument is not a valid name" do
|
64
|
-
it "
|
65
|
-
PitchClass['z'].should
|
100
|
+
it "raises a NameError if the name doesn't exist" do
|
101
|
+
lambda{ PitchClass['z'] }.should raise_error ArgumentError
|
66
102
|
end
|
67
103
|
end
|
68
104
|
end
|
69
105
|
|
106
|
+
|
70
107
|
describe '.from_s' do
|
71
|
-
it "
|
72
|
-
for name in
|
73
|
-
PitchClass.from_s(name)
|
108
|
+
it "returns a PitchClass for any valid name" do
|
109
|
+
for name in enharmonic_spellings
|
110
|
+
pc = PitchClass.from_s(name)
|
111
|
+
pc.should be_a PitchClass
|
112
|
+
pc.name.should == name
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does case-insensitive matching" do
|
117
|
+
for name in enharmonic_spellings
|
118
|
+
pc = PitchClass.from_s(name.downcase)
|
119
|
+
pc.should be_a PitchClass
|
120
|
+
pc.name.should == name
|
74
121
|
end
|
75
122
|
end
|
123
|
+
|
124
|
+
it "raises a ArgumentError for invalid arguments" do
|
125
|
+
lambda{ PitchClass.from_s('H') }.should raise_error ArgumentError
|
126
|
+
end
|
76
127
|
end
|
77
128
|
|
129
|
+
|
78
130
|
describe '.from_name' do
|
79
|
-
it "acts like .
|
80
|
-
for name in
|
81
|
-
PitchClass.from_name(name).should == PitchClass
|
131
|
+
it "acts like .from_s" do
|
132
|
+
for name in enharmonic_spellings
|
133
|
+
PitchClass.from_name(name).should == PitchClass.from_s(name)
|
82
134
|
end
|
135
|
+
lambda{ PitchClass.from_name('H') }.should raise_error ArgumentError
|
83
136
|
end
|
84
137
|
end
|
85
138
|
|
139
|
+
|
86
140
|
describe '.from_i' do
|
87
141
|
it "returns the PitchClass with that value" do
|
88
142
|
PitchClass.from_i(2).should == D
|
@@ -94,29 +148,59 @@ describe MTK::PitchClass do
|
|
94
148
|
end
|
95
149
|
end
|
96
150
|
|
151
|
+
|
152
|
+
describe '.from_value' do
|
153
|
+
it 'acts like .from_i' do
|
154
|
+
(0..11).each{|v| PitchClass.from_value(v).should == PitchClass.from_i(v) }
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
97
158
|
describe '#name' do
|
98
159
|
it "is the name of the pitch class" do
|
99
160
|
C.name.should == 'C'
|
100
161
|
end
|
101
162
|
end
|
102
163
|
|
164
|
+
|
165
|
+
describe '#value' do
|
166
|
+
it "is the value of the pitch class" do
|
167
|
+
PitchClass::NAMES.each.with_index do |name,value|
|
168
|
+
PitchClass[name].value.should == value
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
|
103
174
|
describe '#to_i' do
|
104
175
|
it "is the integer value of the pitch class" do
|
105
|
-
|
106
|
-
|
107
|
-
|
176
|
+
PitchClass::NAMES.each.with_index do |name,value|
|
177
|
+
PitchClass[name].to_i.should == value
|
178
|
+
PitchClass[name].to_i.should be_an Integer
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
|
184
|
+
describe '#to_f' do
|
185
|
+
it "is the floating point value of the pitch class" do
|
186
|
+
PitchClass::NAMES.each.with_index do |name,value|
|
187
|
+
PitchClass[name].to_f.should == value
|
188
|
+
PitchClass[name].to_f.should be_a Float
|
189
|
+
end
|
108
190
|
end
|
109
191
|
end
|
110
192
|
|
193
|
+
|
111
194
|
describe '#to_s' do
|
112
195
|
it "returns the name" do
|
113
196
|
C.to_s.should == C.name
|
114
|
-
for name in
|
197
|
+
for name in enharmonic_spellings
|
115
198
|
PitchClass.from_s(name).to_s.should == name
|
116
199
|
end
|
117
200
|
end
|
118
201
|
end
|
119
202
|
|
203
|
+
|
120
204
|
describe '#==' do
|
121
205
|
it "checks for equality" do
|
122
206
|
C.should == C
|
@@ -128,6 +212,7 @@ describe MTK::PitchClass do
|
|
128
212
|
end
|
129
213
|
end
|
130
214
|
|
215
|
+
|
131
216
|
describe "#<=>" do
|
132
217
|
it "compares the underlying int value" do
|
133
218
|
(C <=> D).should < 0
|
@@ -135,32 +220,46 @@ describe MTK::PitchClass do
|
|
135
220
|
end
|
136
221
|
end
|
137
222
|
|
223
|
+
|
138
224
|
describe '#+' do
|
139
|
-
it "adds
|
225
|
+
it "adds an integer argument to the pitch class's value" do
|
140
226
|
(C + 4).should == E
|
141
227
|
end
|
142
228
|
|
143
229
|
it "'wraps around' the range 0-11" do
|
144
230
|
(D + 10).should == C
|
145
231
|
end
|
232
|
+
|
233
|
+
it "adds a floating point argument to the pitch class's value, and rounds to the nearest pitch class" do
|
234
|
+
(C + 0.49).should == C
|
235
|
+
(C + 0.50).should == Db
|
236
|
+
end
|
146
237
|
end
|
147
238
|
|
239
|
+
|
148
240
|
describe "#transpose" do
|
149
241
|
it "behaves like #+" do
|
150
|
-
C.transpose(2
|
242
|
+
C.transpose(2).should == C + 2
|
151
243
|
end
|
152
244
|
end
|
153
245
|
|
246
|
+
|
154
247
|
describe '#-' do
|
155
|
-
it "subtracts
|
248
|
+
it "subtracts an integer argument from the pitch class's value" do
|
156
249
|
(E - 2).should == D
|
157
250
|
end
|
158
251
|
|
159
252
|
it "'wraps around' the range 0-11" do
|
160
253
|
(C - 8).should == E
|
161
254
|
end
|
255
|
+
|
256
|
+
it "subtracts a floating point argument from the pitch class's value, and rounds to the nearest pitch class'" do
|
257
|
+
(E - 0.50).should == E
|
258
|
+
(E - 0.51).should == Eb
|
259
|
+
end
|
162
260
|
end
|
163
261
|
|
262
|
+
|
164
263
|
describe "#invert" do
|
165
264
|
it 'inverts the pitch class around the given center pitch class' do
|
166
265
|
E.invert(D).should == C
|
@@ -173,8 +272,13 @@ describe MTK::PitchClass do
|
|
173
272
|
it "returns the pitch class when the argument is the same pitch class" do
|
174
273
|
E.invert(E).should == E
|
175
274
|
end
|
275
|
+
|
276
|
+
it 'can invert pitch classes around the halfway point between 2 pitch classes' do
|
277
|
+
C.invert(0.5).should == Db
|
278
|
+
end
|
176
279
|
end
|
177
280
|
|
281
|
+
|
178
282
|
describe "#distance_to" do
|
179
283
|
it "is the distance in semitones between 2 PitchClass objects" do
|
180
284
|
C.distance_to(D).should == 2
|
@@ -215,7 +319,7 @@ describe MTK do
|
|
215
319
|
PitchClass(:D).should == PitchClass.from_s('D')
|
216
320
|
end
|
217
321
|
|
218
|
-
it "acts like from_i if the argument is a
|
322
|
+
it "acts like from_i if the argument is a Numeric" do
|
219
323
|
PitchClass(3).should == PitchClass.from_i(3)
|
220
324
|
end
|
221
325
|
|
@@ -223,8 +327,16 @@ describe MTK do
|
|
223
327
|
PitchClass(C).should be_equal C
|
224
328
|
end
|
225
329
|
|
330
|
+
it "raises an error for Strings it doesn't understand" do
|
331
|
+
lambda{ PitchClass('H') }.should raise_error ArgumentError
|
332
|
+
end
|
333
|
+
|
334
|
+
it "raises an error for Symbols it doesn't understand" do
|
335
|
+
lambda{ PitchClass(:H) }.should raise_error ArgumentError
|
336
|
+
end
|
337
|
+
|
226
338
|
it "raises an error for types it doesn't understand" do
|
227
|
-
lambda{ PitchClass({:not => :compatible}) }.should raise_error
|
339
|
+
lambda{ PitchClass({:not => :compatible}) }.should raise_error ArgumentError
|
228
340
|
end
|
229
341
|
end
|
230
342
|
|
data/spec/mtk/pitch_spec.rb
CHANGED
@@ -69,6 +69,10 @@ describe MTK::Pitch do
|
|
69
69
|
it("converts 'B#4' to middle c") { Pitch.from_s('B#4').should == middle_c }
|
70
70
|
it("converts 'C-1' to a low c, 5 octaves below middle C") { Pitch.from_s('C-1').should == middle_c - 60 }
|
71
71
|
it("converts 'C4+50.0cents' to middle C and 50 cents") { Pitch.from_s('C4+50.0cents').should == middle_c_and_50_cents }
|
72
|
+
|
73
|
+
it "raises an ArgumentError for invalid arguments" do
|
74
|
+
lambda{ Pitch.from_s('H4') }.should raise_error ArgumentError
|
75
|
+
end
|
72
76
|
end
|
73
77
|
|
74
78
|
describe '.from_name' do
|
@@ -137,6 +141,15 @@ describe MTK::Pitch do
|
|
137
141
|
end
|
138
142
|
end
|
139
143
|
|
144
|
+
describe '#inspect' do
|
145
|
+
it 'is "#<MTK::Pitch:{object_id} @value={value}>"' do
|
146
|
+
for value in [0, 60, 60.5, 127]
|
147
|
+
pitch = Pitch.from_f(value)
|
148
|
+
pitch.inspect.should == "#<MTK::Pitch:#{pitch.object_id} @value=#{value}>"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
140
153
|
describe '#+' do
|
141
154
|
it 'adds the integer value of the argument and #to_i' do
|
142
155
|
(middle_c + 2).should == Pitch.from_i(62)
|
@@ -156,7 +169,7 @@ describe MTK::Pitch do
|
|
156
169
|
|
157
170
|
describe "#transpose" do
|
158
171
|
it "behaves like #+" do
|
159
|
-
middle_c.transpose(2
|
172
|
+
middle_c.transpose(2).should == middle_c + 2
|
160
173
|
end
|
161
174
|
end
|
162
175
|
|
@@ -268,6 +281,14 @@ describe MTK do
|
|
268
281
|
Pitch(C, 4, 0.5).should == Pitch.new(C, 4, 0.5)
|
269
282
|
end
|
270
283
|
|
284
|
+
it "raises an error for Strings it doesn't understand" do
|
285
|
+
lambda{ Pitch('H4') }.should raise_error
|
286
|
+
end
|
287
|
+
|
288
|
+
it "raises an error for Symbols it doesn't understand" do
|
289
|
+
lambda{ Pitch(:H4) }.should raise_error
|
290
|
+
end
|
291
|
+
|
271
292
|
it "raises an error for types it doesn't understand" do
|
272
293
|
lambda{ Pitch({:not => :compatible}) }.should raise_error
|
273
294
|
end
|