mtk 0.0.3.2 → 0.0.3.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 +2 -2
- data/DEVELOPMENT_NOTES.md +20 -0
- data/README.md +9 -3
- data/Rakefile +47 -13
- data/bin/mtk +55 -20
- data/examples/crescendo.rb +4 -4
- data/examples/{drum_pattern1.rb → drum_pattern.rb} +8 -8
- data/examples/dynamic_pattern.rb +5 -5
- data/examples/gets_and_play.rb +3 -2
- data/examples/notation.rb +3 -3
- data/examples/play_midi.rb +4 -4
- data/examples/print_midi.rb +2 -2
- data/examples/random_tone_row.rb +3 -3
- data/examples/syntax_to_midi.rb +2 -2
- data/examples/test_output.rb +4 -5
- data/examples/tone_row_melody.rb +7 -5
- data/lib/mtk/core/duration.rb +213 -0
- data/lib/mtk/core/intensity.rb +158 -0
- data/lib/mtk/core/interval.rb +157 -0
- data/lib/mtk/core/pitch.rb +154 -0
- data/lib/mtk/core/pitch_class.rb +194 -0
- data/lib/mtk/events/event.rb +4 -4
- data/lib/mtk/events/note.rb +12 -12
- data/lib/mtk/events/timeline.rb +232 -0
- data/lib/mtk/groups/chord.rb +56 -0
- data/lib/mtk/{helpers → groups}/collection.rb +33 -1
- data/lib/mtk/groups/melody.rb +96 -0
- data/lib/mtk/groups/pitch_class_set.rb +163 -0
- data/lib/mtk/{helpers → groups}/pitch_collection.rb +1 -1
- data/lib/mtk/{midi → io}/dls_synth_device.rb +3 -1
- data/lib/mtk/{midi → io}/dls_synth_output.rb +10 -10
- data/lib/mtk/{midi → io}/jsound_input.rb +2 -2
- data/lib/mtk/{midi → io}/jsound_output.rb +9 -9
- data/lib/mtk/{midi/file.rb → io/midi_file.rb} +13 -13
- data/lib/mtk/{midi/input.rb → io/midi_input.rb} +4 -4
- data/lib/mtk/{midi/output.rb → io/midi_output.rb} +8 -8
- data/lib/mtk/{helpers/lilypond.rb → io/notation.rb} +5 -5
- data/lib/mtk/{midi → io}/unimidi_input.rb +2 -2
- data/lib/mtk/{midi → io}/unimidi_output.rb +14 -9
- data/lib/mtk/{constants → lang}/durations.rb +11 -11
- data/lib/mtk/{constants → lang}/intensities.rb +11 -11
- data/lib/mtk/{constants → lang}/intervals.rb +17 -17
- data/lib/mtk/lang/mtk_grammar.citrus +9 -9
- data/lib/mtk/{constants → lang}/pitch_classes.rb +5 -5
- data/lib/mtk/{constants → lang}/pitches.rb +7 -7
- data/lib/mtk/{helpers → lang}/pseudo_constants.rb +1 -1
- data/lib/mtk/{variable.rb → lang/variable.rb} +1 -1
- data/lib/mtk/numeric_extensions.rb +40 -47
- data/lib/mtk/patterns/for_each.rb +1 -1
- data/lib/mtk/patterns/pattern.rb +3 -3
- data/lib/mtk/sequencers/event_builder.rb +16 -15
- data/lib/mtk/sequencers/legato_sequencer.rb +1 -1
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +1 -1
- data/lib/mtk/sequencers/sequencer.rb +8 -8
- data/lib/mtk/sequencers/step_sequencer.rb +2 -2
- data/lib/mtk.rb +33 -39
- data/spec/mtk/{duration_spec.rb → core/duration_spec.rb} +3 -3
- data/spec/mtk/{intensity_spec.rb → core/intensity_spec.rb} +3 -3
- data/spec/mtk/{interval_spec.rb → core/interval_spec.rb} +1 -1
- data/spec/mtk/{pitch_class_spec.rb → core/pitch_class_spec.rb} +1 -1
- data/spec/mtk/{pitch_spec.rb → core/pitch_spec.rb} +8 -8
- data/spec/mtk/events/event_spec.rb +4 -4
- data/spec/mtk/events/note_spec.rb +8 -8
- data/spec/mtk/{timeline_spec.rb → events/timeline_spec.rb} +47 -47
- data/spec/mtk/{chord_spec.rb → groups/chord_spec.rb} +18 -16
- data/spec/mtk/{helpers → groups}/collection_spec.rb +3 -3
- data/spec/mtk/{melody_spec.rb → groups/melody_spec.rb} +36 -34
- data/spec/mtk/{pitch_class_set_spec.rb → groups/pitch_class_set_spec.rb} +57 -55
- data/spec/mtk/{midi/file_spec.rb → io/midi_file_spec.rb} +17 -17
- data/spec/mtk/{midi/output_spec.rb → io/midi_output_spec.rb} +6 -6
- data/spec/mtk/{constants → lang}/durations_spec.rb +1 -1
- data/spec/mtk/{constants → lang}/intensities_spec.rb +1 -1
- data/spec/mtk/{constants → lang}/intervals_spec.rb +1 -1
- data/spec/mtk/lang/parser_spec.rb +12 -6
- data/spec/mtk/{constants → lang}/pitch_classes_spec.rb +1 -1
- data/spec/mtk/{constants → lang}/pitches_spec.rb +1 -1
- data/spec/mtk/{helpers → lang}/pseudo_constants_spec.rb +2 -2
- data/spec/mtk/{variable_spec.rb → lang/variable_spec.rb} +4 -4
- data/spec/mtk/numeric_extensions_spec.rb +35 -55
- data/spec/mtk/patterns/for_each_spec.rb +1 -1
- data/spec/mtk/patterns/sequence_spec.rb +1 -1
- data/spec/mtk/sequencers/legato_sequencer_spec.rb +2 -2
- data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +4 -4
- data/spec/mtk/sequencers/step_sequencer_spec.rb +5 -5
- data/spec/spec_helper.rb +7 -6
- metadata +75 -61
- data/ext/mkrf_conf.rb +0 -25
- data/lib/mtk/chord.rb +0 -55
- data/lib/mtk/duration.rb +0 -211
- data/lib/mtk/helpers/convert.rb +0 -36
- data/lib/mtk/helpers/output_selector.rb +0 -67
- data/lib/mtk/intensity.rb +0 -156
- data/lib/mtk/interval.rb +0 -155
- data/lib/mtk/melody.rb +0 -94
- data/lib/mtk/pitch.rb +0 -152
- data/lib/mtk/pitch_class.rb +0 -192
- data/lib/mtk/pitch_class_set.rb +0 -161
- data/lib/mtk/timeline.rb +0 -230
- data/spec/mtk/midi/jsound_input_spec.rb +0 -11
- data/spec/mtk/midi/jsound_output_spec.rb +0 -11
- data/spec/mtk/midi/unimidi_input_spec.rb +0 -11
- data/spec/mtk/midi/unimidi_output_spec.rb +0 -11
@@ -1,34 +1,36 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::Chord do
|
3
|
+
describe MTK::Groups::Chord do
|
4
4
|
|
5
|
-
|
5
|
+
CHORD = MTK::Groups::Chord
|
6
|
+
|
7
|
+
let(:c_major) { CHORD.new([C4,E4,G4]) }
|
6
8
|
|
7
9
|
describe ".new" do
|
8
10
|
it "removes duplicates" do
|
9
|
-
|
11
|
+
CHORD.new([C4, E4, G4, C4]).pitches.should == [C4, E4, G4]
|
10
12
|
end
|
11
13
|
|
12
14
|
it "sorts the pitches" do
|
13
|
-
|
15
|
+
CHORD.new([F4, G4, E4, D4, C4]).pitches.should == [C4, D4, E4, F4, G4]
|
14
16
|
end
|
15
17
|
end
|
16
18
|
|
17
19
|
describe '#inversion' do
|
18
20
|
it "adds an octave to the chord's pitches starting from the lowest, for each whole number in a postive argument" do
|
19
|
-
c_major.inversion(2).should ==
|
21
|
+
c_major.inversion(2).should == CHORD.new([G4,C5,E5])
|
20
22
|
end
|
21
23
|
|
22
24
|
it "subtracts an octave to the chord's pitches starting fromt he highest, for each whole number in a negative argument" do
|
23
|
-
c_major.inversion(-2).should ==
|
25
|
+
c_major.inversion(-2).should == CHORD.new([E3,G3,C4])
|
24
26
|
end
|
25
27
|
|
26
28
|
it "wraps around to the lowest pitch when the argument is bigger than the number of pitches in the chord (positive argument)" do
|
27
|
-
c_major.inversion(4).should ==
|
29
|
+
c_major.inversion(4).should == CHORD.new([E5,G5,C6])
|
28
30
|
end
|
29
31
|
|
30
32
|
it "wraps around to the highest pitch when the magnitude of the argument is bigger than the number of pitches in the chord (negative argument)" do
|
31
|
-
c_major.inversion(-4).should ==
|
33
|
+
c_major.inversion(-4).should == CHORD.new([G2,C3,E3])
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -46,32 +48,32 @@ describe MTK do
|
|
46
48
|
describe '#Chord' do
|
47
49
|
|
48
50
|
it "acts like new for a single Array argument" do
|
49
|
-
Chord([C4,D4]).should ==
|
51
|
+
Chord([C4,D4]).should == CHORD.new([C4,D4])
|
50
52
|
end
|
51
53
|
|
52
54
|
it "acts like new for multiple arguments, by treating them like an Array (splat)" do
|
53
|
-
Chord(C4,D4).should ==
|
55
|
+
Chord(C4,D4).should == CHORD.new([C4,D4])
|
54
56
|
end
|
55
57
|
|
56
58
|
it "handles an Array with elements that can be converted to Pitches" do
|
57
|
-
Chord(['C4','D4']).should ==
|
59
|
+
Chord(['C4','D4']).should == CHORD.new([C4,D4])
|
58
60
|
end
|
59
61
|
|
60
62
|
it "handles multiple arguments that can be converted to a Pitch" do
|
61
|
-
Chord(:C4,:D4).should ==
|
63
|
+
Chord(:C4,:D4).should == CHORD.new([C4,D4])
|
62
64
|
end
|
63
65
|
|
64
66
|
it "handles a single Pitch" do
|
65
|
-
Chord(C4).should ==
|
67
|
+
Chord(C4).should == CHORD.new([C4])
|
66
68
|
end
|
67
69
|
|
68
70
|
it "handles single elements that can be converted to a Pitch" do
|
69
|
-
Chord('C4').should ==
|
71
|
+
Chord('C4').should == CHORD.new([C4])
|
70
72
|
end
|
71
73
|
|
72
74
|
it "returns the argument if it's already a Chord" do
|
73
|
-
pitch_set =
|
74
|
-
Chord(pitch_set).should ==
|
75
|
+
pitch_set = CHORD.new([C4,D4,D4])
|
76
|
+
Chord(pitch_set).should == CHORD.new([C4,D4])
|
75
77
|
end
|
76
78
|
|
77
79
|
it "raises an error for types it doesn't understand" do
|
@@ -1,16 +1,16 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::
|
3
|
+
describe MTK::Groups::Collection do
|
4
4
|
|
5
5
|
class MockCollection
|
6
|
-
include MTK::
|
6
|
+
include MTK::Groups::Collection
|
7
7
|
attr_reader :elements
|
8
8
|
def initialize(elements); @elements = elements end
|
9
9
|
def self.from_a(elements); new(elements) end
|
10
10
|
end
|
11
11
|
|
12
12
|
class MockCollectionWithOptions
|
13
|
-
include MTK::
|
13
|
+
include MTK::Groups::Collection
|
14
14
|
attr_reader :elements, :options
|
15
15
|
def initialize(elements, options={})
|
16
16
|
@elements = elements
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::Melody do
|
3
|
+
describe MTK::Groups::Melody do
|
4
|
+
|
5
|
+
MELODY = MTK::Groups::Melody
|
4
6
|
|
5
7
|
let(:pitches) { [C4, D4, E4, D4] }
|
6
|
-
let(:melody) { Melody.new(pitches) }
|
8
|
+
let(:melody) { MTK::Groups::Melody.new(pitches) }
|
7
9
|
|
8
10
|
it "is Enumerable" do
|
9
11
|
melody.should be_a Enumerable
|
@@ -11,25 +13,25 @@ describe MTK::Melody do
|
|
11
13
|
|
12
14
|
describe ".new" do
|
13
15
|
it "maintains the pitches collection exactly (preserves order and keeps duplicates)" do
|
14
|
-
|
16
|
+
MELODY.new([C4, E4, G4, E4, B3, C4]).pitches.should == [C4, E4, G4, E4, B3, C4]
|
15
17
|
end
|
16
18
|
end
|
17
19
|
|
18
20
|
describe ".from_pitch_classes" do
|
19
21
|
it "creates a pitch sequence from a list of pitch classes and starting point, selecting the nearest pitch to each pitch class" do
|
20
|
-
|
22
|
+
MELODY.from_pitch_classes([C,G,B,Eb,D,C], D3).should == [C3,G2,B2,Eb3,D3,C3]
|
21
23
|
end
|
22
24
|
|
23
25
|
it "defaults to a starting point of C4 (middle C)" do
|
24
|
-
|
26
|
+
MELODY.from_pitch_classes([C]).should == [C4]
|
25
27
|
end
|
26
28
|
|
27
29
|
it "doesn't travel within an octave above or below the starting point by default" do
|
28
|
-
|
30
|
+
MELODY.from_pitch_classes([C,F,Bb,D,A,E,B]).should == [C4,F4,Bb4,D4,A3,E3,B3]
|
29
31
|
end
|
30
32
|
|
31
33
|
it "allows max distance above or below the starting point to be set via the third argument" do
|
32
|
-
|
34
|
+
MELODY.from_pitch_classes([C,F,Bb,D,A,E,B], C4, 6).should == [C4,F4,Bb3,D4,A3,E4,B3]
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -73,17 +75,17 @@ describe MTK::Melody do
|
|
73
75
|
end
|
74
76
|
|
75
77
|
describe "#map" do
|
76
|
-
it "returns a
|
78
|
+
it "returns a MELODY with each Pitch replaced with the results of the block" do
|
77
79
|
melody.map{|p| p + 2}.should == [D4, E4, Gb4, E4]
|
78
80
|
end
|
79
81
|
end
|
80
82
|
|
81
83
|
describe "#to_pitch_class_set" do
|
82
84
|
it "is a PitchClassSet" do
|
83
|
-
melody.to_pitch_class_set.should be_a PitchClassSet
|
85
|
+
melody.to_pitch_class_set.should be_a MTK::Groups::PitchClassSet
|
84
86
|
end
|
85
87
|
|
86
|
-
it "contains all the distinct pitch_classes in this
|
88
|
+
it "contains all the distinct pitch_classes in this MELODY by default" do
|
87
89
|
melody.to_pitch_class_set.pitch_classes.should == melody.pitch_classes.uniq
|
88
90
|
end
|
89
91
|
|
@@ -101,75 +103,75 @@ describe MTK::Melody do
|
|
101
103
|
|
102
104
|
describe '#transpose' do
|
103
105
|
it 'transposes upward by the given semitones' do
|
104
|
-
melody.transpose(12).should ==
|
106
|
+
melody.transpose(12).should == MELODY.new([C5, D5, E5, D5])
|
105
107
|
end
|
106
108
|
end
|
107
109
|
|
108
110
|
describe '#invert' do
|
109
111
|
it 'inverts all pitches around the given center pitch' do
|
110
|
-
(melody.invert Gb4).should ==
|
112
|
+
(melody.invert Gb4).should == MELODY.new([C5, Bb4, Ab4, Bb4])
|
111
113
|
end
|
112
114
|
|
113
115
|
it 'inverts all pitches around the first pitch, when no center pitch is given' do
|
114
|
-
melody.invert.should ==
|
116
|
+
melody.invert.should == MELODY.new([C4, Bb3, Ab3, Bb3])
|
115
117
|
end
|
116
118
|
end
|
117
119
|
|
118
120
|
describe '#include?' do
|
119
|
-
it 'returns true if the Pitch is in the
|
121
|
+
it 'returns true if the Pitch is in the MELODY' do
|
120
122
|
(melody.include? C4).should be_true
|
121
123
|
end
|
122
124
|
|
123
|
-
it 'returns false if the Pitch is not in the
|
125
|
+
it 'returns false if the Pitch is not in the MELODY' do
|
124
126
|
(melody.include? Db4).should be_false
|
125
127
|
end
|
126
128
|
end
|
127
129
|
|
128
130
|
describe '#==' do
|
129
131
|
it "is true when all the pitches are equal" do
|
130
|
-
|
132
|
+
MELODY.new([C4, E4, G4]).should == MELODY.new([Pitch.from_i(60), Pitch.from_i(64), Pitch.from_i(67)])
|
131
133
|
end
|
132
134
|
|
133
135
|
it "is false when not all the pitches are equal" do
|
134
|
-
|
136
|
+
MELODY.new([C4, E4, G4]).should_not == MELODY.new([Pitch.from_i(60), Pitch.from_i(65), Pitch.from_i(67)])
|
135
137
|
end
|
136
138
|
|
137
139
|
it "is false when if otherwise equal Melodies don't contain the same number of duplicates" do
|
138
|
-
|
140
|
+
MELODY.new([C4, E4, G4]).should_not == MELODY.new([C4, C4, E4, G4])
|
139
141
|
end
|
140
142
|
|
141
143
|
it "is false when if otherwise equal Melodies aren't in the same order" do
|
142
|
-
|
144
|
+
MELODY.new([C4, E4, G4]).should_not == MELODY.new([C4, G4, E4])
|
143
145
|
end
|
144
146
|
|
145
147
|
it "is false when the argument is not compatible" do
|
146
|
-
|
148
|
+
MELODY.new([C4, E4, G4]).should_not == :invalid
|
147
149
|
end
|
148
150
|
|
149
151
|
it "can be compared directly to Arrays" do
|
150
|
-
|
152
|
+
MELODY.new([C4, E4, G4]).should == [C4, E4, G4]
|
151
153
|
end
|
152
154
|
end
|
153
155
|
|
154
156
|
describe "#=~" do
|
155
157
|
it "is true when all the pitches are equal" do
|
156
|
-
|
158
|
+
MELODY.new([C4, E4, G4]).should =~ MELODY.new([C4, E4, G4])
|
157
159
|
end
|
158
160
|
|
159
161
|
it "is true when all the pitches are equal, even with different numbers of duplicates" do
|
160
|
-
|
162
|
+
MELODY.new([C4, E4, G4]).should =~ MELODY.new([C4, C4, E4, G4])
|
161
163
|
end
|
162
164
|
|
163
165
|
it "is true when all the pitches are equal, even in a different order" do
|
164
|
-
|
166
|
+
MELODY.new([C4, E4, G4]).should =~ MELODY.new([C4, G4, E4])
|
165
167
|
end
|
166
168
|
|
167
|
-
it "is false when one
|
168
|
-
|
169
|
+
it "is false when one MELODY contains a Pitch not in the other" do
|
170
|
+
MELODY.new([C4, E4, G4]).should_not =~ MELODY.new([C4, E4])
|
169
171
|
end
|
170
172
|
|
171
173
|
it "can be compared directly to Arrays" do
|
172
|
-
|
174
|
+
MELODY.new([C4, E4, G4]).should =~ [C4, E4, G4]
|
173
175
|
end
|
174
176
|
end
|
175
177
|
|
@@ -186,31 +188,31 @@ describe MTK do
|
|
186
188
|
describe '#Melody' do
|
187
189
|
|
188
190
|
it "acts like new for a single Array argument" do
|
189
|
-
Melody([C4,D4]).should == Melody.new([C4,D4])
|
191
|
+
Melody([C4,D4]).should == MTK::Groups::Melody.new([C4,D4])
|
190
192
|
end
|
191
193
|
|
192
194
|
it "acts like new for multiple arguments, by treating them like an Array (splat)" do
|
193
|
-
Melody(C4,D4).should == Melody.new([C4,D4])
|
195
|
+
Melody(C4,D4).should == MTK::Groups::Melody.new([C4,D4])
|
194
196
|
end
|
195
197
|
|
196
198
|
it "handles an Array with elements that can be converted to Pitches" do
|
197
|
-
Melody(['C4','D4']).should == Melody.new([C4,D4])
|
199
|
+
Melody(['C4','D4']).should == MTK::Groups::Melody.new([C4,D4])
|
198
200
|
end
|
199
201
|
|
200
202
|
it "handles multiple arguments that can be converted to a Pitch" do
|
201
|
-
Melody(:C4,:D4).should == Melody.new([C4,D4])
|
203
|
+
Melody(:C4,:D4).should == MTK::Groups::Melody.new([C4,D4])
|
202
204
|
end
|
203
205
|
|
204
206
|
it "handles a single Pitch" do
|
205
|
-
Melody(C4).should == Melody.new([C4])
|
207
|
+
Melody(C4).should == MTK::Groups::Melody.new([C4])
|
206
208
|
end
|
207
209
|
|
208
210
|
it "handles single elements that can be converted to a Pitch" do
|
209
|
-
Melody('C4').should == Melody.new([C4])
|
211
|
+
Melody('C4').should == MTK::Groups::Melody.new([C4])
|
210
212
|
end
|
211
213
|
|
212
214
|
it "handles a Melody" do
|
213
|
-
melody = Melody.new([C4,D4])
|
215
|
+
melody = MTK::Groups::Melody.new([C4,D4])
|
214
216
|
Melody(melody).should == [C4,D4]
|
215
217
|
end
|
216
218
|
|
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe MTK::PitchClassSet do
|
3
|
+
describe MTK::Groups::PitchClassSet do
|
4
|
+
|
5
|
+
PITCH_CLASS_SET = MTK::Groups::PitchClassSet
|
4
6
|
|
5
7
|
let(:pitch_classes) { [C,E,G] }
|
6
|
-
let(:pitch_class_set) { PitchClassSet.new(pitch_classes) }
|
8
|
+
let(:pitch_class_set) { MTK::Groups::PitchClassSet.new(pitch_classes) }
|
7
9
|
|
8
10
|
it "is Enumerable" do
|
9
11
|
pitch_class_set.should be_a Enumerable
|
@@ -11,24 +13,24 @@ describe MTK::PitchClassSet do
|
|
11
13
|
|
12
14
|
describe ".random_row" do
|
13
15
|
it "generates a 12-tone row" do
|
14
|
-
|
16
|
+
PITCH_CLASS_SET.random_row.should =~ PitchClasses::PITCH_CLASSES
|
15
17
|
end
|
16
18
|
|
17
19
|
it "generates a random 12-tone row (NOTE: very slight expected chance of test failure, if this fails run it again!)" do
|
18
20
|
# there's a 1/479_001_600 chance this will fail... whaddyagonnado??
|
19
|
-
|
21
|
+
PITCH_CLASS_SET.random_row.should_not == PITCH_CLASS_SET.random_row
|
20
22
|
end
|
21
23
|
end
|
22
24
|
|
23
25
|
describe ".all" do
|
24
26
|
it "is the set of all 12 pitch classes" do
|
25
|
-
|
27
|
+
PITCH_CLASS_SET.all.should == MTK.PitchClassSet(PitchClasses::PITCH_CLASSES)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
describe ".new" do
|
30
32
|
it "maintains the pitch class collection exactly (preserves order and keeps duplicates)" do
|
31
|
-
|
33
|
+
PITCH_CLASS_SET.new([C, E, G, E, B, C]).pitch_classes.should == [C, E, G, E, B, C]
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -108,30 +110,30 @@ describe MTK::PitchClassSet do
|
|
108
110
|
end
|
109
111
|
|
110
112
|
describe "#map" do
|
111
|
-
it "returns a
|
113
|
+
it "returns a PITCH_CLASS_SET with each PitchClass replaced with the results of the block" do
|
112
114
|
pitch_class_set.map{|pc| pc + 2}.should == [D, Gb, A]
|
113
115
|
end
|
114
116
|
end
|
115
117
|
|
116
118
|
describe '#transpose' do
|
117
119
|
it 'transposes by the given semitones' do
|
118
|
-
(pitch_class_set.transpose 4).should == PitchClassSet(E, Ab, B)
|
120
|
+
(pitch_class_set.transpose 4).should == MTK.PitchClassSet(E, Ab, B)
|
119
121
|
end
|
120
122
|
end
|
121
123
|
|
122
124
|
describe "#invert" do
|
123
125
|
it 'inverts all pitch_classes around the given center pitch' do
|
124
|
-
pitch_class_set.invert(G).should == PitchClassSet(D,Bb,G)
|
126
|
+
pitch_class_set.invert(G).should == MTK.PitchClassSet(D,Bb,G)
|
125
127
|
end
|
126
128
|
|
127
129
|
it 'inverts all pitches around the first pitch, when no center pitch is given' do
|
128
|
-
pitch_class_set.invert.should == PitchClassSet(C,Ab,F)
|
130
|
+
pitch_class_set.invert.should == MTK.PitchClassSet(C,Ab,F)
|
129
131
|
end
|
130
132
|
end
|
131
133
|
|
132
134
|
describe "#reverse" do
|
133
|
-
it "produces a
|
134
|
-
pitch_class_set.reverse.should == PitchClassSet(G,E,C)
|
135
|
+
it "produces a PITCH_CLASS_SET with pitch classes in reverse order" do
|
136
|
+
pitch_class_set.reverse.should == MTK.PitchClassSet(G,E,C)
|
135
137
|
end
|
136
138
|
end
|
137
139
|
|
@@ -142,39 +144,39 @@ describe MTK::PitchClassSet do
|
|
142
144
|
end
|
143
145
|
|
144
146
|
describe "#intersection" do
|
145
|
-
it "produces a
|
146
|
-
pitch_class_set.intersection(PitchClassSet(E,G,B)).should == PitchClassSet(E,G)
|
147
|
+
it "produces a PITCH_CLASS_SET containing the common pitch classes from self and the argument" do
|
148
|
+
pitch_class_set.intersection(MTK.PitchClassSet(E,G,B)).should == MTK.PitchClassSet(E,G)
|
147
149
|
end
|
148
150
|
end
|
149
151
|
|
150
152
|
describe "#union" do
|
151
|
-
it "produces a
|
152
|
-
pitch_class_set.union(PitchClassSet(E,G,B)).should == PitchClassSet(C,E,G,B)
|
153
|
+
it "produces a PITCH_CLASS_SET containing the all pitch classes from either self or the argument" do
|
154
|
+
pitch_class_set.union(MTK.PitchClassSet(E,G,B)).should == MTK.PitchClassSet(C,E,G,B)
|
153
155
|
end
|
154
156
|
end
|
155
157
|
|
156
158
|
describe "#difference" do
|
157
|
-
it "produces a
|
158
|
-
pitch_class_set.difference(PitchClassSet(E)).should == PitchClassSet(C,G)
|
159
|
+
it "produces a PITCH_CLASS_SET with the pitch classes from the argument removed" do
|
160
|
+
pitch_class_set.difference(MTK.PitchClassSet(E)).should == MTK.PitchClassSet(C,G)
|
159
161
|
end
|
160
162
|
end
|
161
163
|
|
162
164
|
describe "#symmetric_difference" do
|
163
|
-
it "produces a
|
164
|
-
pitch_class_set.symmetric_difference(PitchClassSet(E,G,B)).should == PitchClassSet(C,B)
|
165
|
+
it "produces a PITCH_CLASS_SET containing the pitch classes only in self or only in the argument" do
|
166
|
+
pitch_class_set.symmetric_difference(MTK.PitchClassSet(E,G,B)).should == MTK.PitchClassSet(C,B)
|
165
167
|
end
|
166
168
|
end
|
167
169
|
|
168
170
|
describe "#complement" do
|
169
171
|
it "produces the set of all PitchClasses not in the current set" do
|
170
|
-
pitch_class_set.complement.should =~ PitchClassSet(Db,D,Eb,F,Gb,Ab,A,Bb,B)
|
172
|
+
pitch_class_set.complement.should =~ MTK.PitchClassSet(Db,D,Eb,F,Gb,Ab,A,Bb,B)
|
171
173
|
end
|
172
174
|
end
|
173
175
|
|
174
176
|
describe "#rotate" do
|
175
|
-
it "produces a
|
176
|
-
pitch_class_set.rotate(2).should == PitchClassSet(G,C,E)
|
177
|
-
pitch_class_set.rotate(-2).should == PitchClassSet(E,G,C)
|
177
|
+
it "produces a PITCH_CLASS_SET that is rotated by the given offset" do
|
178
|
+
pitch_class_set.rotate(2).should == MTK.PitchClassSet(G,C,E)
|
179
|
+
pitch_class_set.rotate(-2).should == MTK.PitchClassSet(E,G,C)
|
178
180
|
end
|
179
181
|
|
180
182
|
it "rotates by 1 if no argument is given" do
|
@@ -183,8 +185,8 @@ describe MTK::PitchClassSet do
|
|
183
185
|
end
|
184
186
|
|
185
187
|
describe "#permute" do
|
186
|
-
it "randomly rearranges the
|
187
|
-
all_pcs = PitchClassSet(PitchClasses::PITCH_CLASSES)
|
188
|
+
it "randomly rearranges the PITCH_CLASS_SET order (NOTE: very slight expected chance of test failure, if this fails run it again!)" do
|
189
|
+
all_pcs = MTK.PitchClassSet(PitchClasses::PITCH_CLASSES)
|
188
190
|
permuted = all_pcs.permute
|
189
191
|
permuted.should =~ all_pcs
|
190
192
|
permuted.should_not == all_pcs # there's a 1/479_001_600 chance this will fail...
|
@@ -193,7 +195,7 @@ describe MTK::PitchClassSet do
|
|
193
195
|
|
194
196
|
describe "#shuffle" do
|
195
197
|
it "behaves like permute (NOTE: very slight expected chance of test failure, if this fails run it again!)" do
|
196
|
-
all_pcs = PitchClassSet(PitchClasses::PITCH_CLASSES)
|
198
|
+
all_pcs = MTK.PitchClassSet(PitchClasses::PITCH_CLASSES)
|
197
199
|
shuffled = all_pcs.shuffle
|
198
200
|
shuffled.should =~ all_pcs
|
199
201
|
shuffled.should_not == all_pcs # there's a 1/479_001_600 chance this will fail...
|
@@ -202,55 +204,55 @@ describe MTK::PitchClassSet do
|
|
202
204
|
|
203
205
|
describe "#concat" do
|
204
206
|
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)
|
207
|
+
pitch_class_set.concat(MTK.PitchClassSet(D,E,F)).should == MTK.PitchClassSet(C,E,G,D,E,F)
|
206
208
|
end
|
207
209
|
end
|
208
210
|
|
209
211
|
describe "#normal_order" do
|
210
212
|
it "permutes the set so that the first and last pitch classes are as close together as possible" do
|
211
|
-
|
213
|
+
PITCH_CLASS_SET.new([E,A,C]).normal_order.should == [A,C,E]
|
212
214
|
end
|
213
215
|
|
214
216
|
it "breaks ties by minimizing the distance between the first and second-to-last pitch class" do
|
215
217
|
# 0,4,8,9,11
|
216
|
-
|
218
|
+
PITCH_CLASS_SET.new([C,E,Ab,A,B]).normal_order.should == [Ab,A,B,C,E]
|
217
219
|
end
|
218
220
|
|
219
221
|
end
|
220
222
|
|
221
223
|
describe "#normal_form" do
|
222
224
|
it "is transposes the #normal_order so that the first pitch class set is 0 (C)" do
|
223
|
-
|
225
|
+
PITCH_CLASS_SET.new([E,A,C]).normal_form.should == [0,3,7]
|
224
226
|
end
|
225
227
|
|
226
228
|
it "is invariant across reorderings of the pitch classes" do
|
227
|
-
|
228
|
-
|
229
|
-
|
229
|
+
PITCH_CLASS_SET.new([C,E,G]).normal_form.should == [0,4,7]
|
230
|
+
PITCH_CLASS_SET.new([E,C,G]).normal_form.should == [0,4,7]
|
231
|
+
PITCH_CLASS_SET.new([G,E,C]).normal_form.should == [0,4,7]
|
230
232
|
end
|
231
233
|
|
232
234
|
it "is invariant across transpositions" do
|
233
|
-
|
234
|
-
|
235
|
-
|
235
|
+
PITCH_CLASS_SET.new([C,Eb,G]).normal_form.should == [0,3,7]
|
236
|
+
PITCH_CLASS_SET.new([Db,E,Ab]).normal_form.should == [0,3,7]
|
237
|
+
PITCH_CLASS_SET.new([Bb,F,Db]).normal_form.should == [0,3,7]
|
236
238
|
end
|
237
239
|
end
|
238
240
|
|
239
241
|
describe "#==" do
|
240
242
|
it "is true if two pitch class sets contain the same set in the same order" do
|
241
|
-
pitch_class_set.should == PitchClassSet(C,E,G)
|
243
|
+
pitch_class_set.should == MTK.PitchClassSet(C,E,G)
|
242
244
|
end
|
243
245
|
|
244
246
|
it "is false if two pitch class sets are not in the same order" do
|
245
|
-
pitch_class_set.should_not == PitchClassSet(C,G,E)
|
247
|
+
pitch_class_set.should_not == MTK.PitchClassSet(C,G,E)
|
246
248
|
end
|
247
249
|
|
248
250
|
it "is false when if otherwise equal pitch class sets don't contain the same number of duplicates" do
|
249
|
-
|
251
|
+
PITCH_CLASS_SET.new([C, E, G]).should_not == PITCH_CLASS_SET.new([C, C, E, G])
|
250
252
|
end
|
251
253
|
|
252
254
|
it "is false if two pitch class sets do not contain the same pitch classes" do
|
253
|
-
pitch_class_set.should_not == PitchClassSet(C,E)
|
255
|
+
pitch_class_set.should_not == MTK.PitchClassSet(C,E)
|
254
256
|
end
|
255
257
|
|
256
258
|
it "allows for direct comparison with Arrays" do
|
@@ -260,19 +262,19 @@ describe MTK::PitchClassSet do
|
|
260
262
|
|
261
263
|
describe "#=~" do
|
262
264
|
it "is true if two pitch class sets contain the same set in the same order" do
|
263
|
-
pitch_class_set.should =~ PitchClassSet(C,E,G)
|
265
|
+
pitch_class_set.should =~ MTK.PitchClassSet(C,E,G)
|
264
266
|
end
|
265
267
|
|
266
268
|
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])
|
269
|
+
MTK::Groups::Melody.new([C, E, G]).should =~ MTK::Groups::Melody.new([C, C, E, G])
|
268
270
|
end
|
269
271
|
|
270
272
|
it "is true if two pitch class sets are not in the same order" do
|
271
|
-
pitch_class_set.should =~ PitchClassSet(C,G,E)
|
273
|
+
pitch_class_set.should =~ MTK.PitchClassSet(C,G,E)
|
272
274
|
end
|
273
275
|
|
274
276
|
it "is false if two pitch class sets do not contain the same pitch classes" do
|
275
|
-
pitch_class_set.should_not =~ PitchClassSet(C,E)
|
277
|
+
pitch_class_set.should_not =~ MTK.PitchClassSet(C,E)
|
276
278
|
end
|
277
279
|
|
278
280
|
it "allows for direct comparison with Arrays" do
|
@@ -282,11 +284,11 @@ describe MTK::PitchClassSet do
|
|
282
284
|
|
283
285
|
describe ".span_between" do
|
284
286
|
it "is the distance in semitones between 2 pitch classes" do
|
285
|
-
|
287
|
+
PITCH_CLASS_SET.span_between(F, Bb).should == 5
|
286
288
|
end
|
287
289
|
|
288
290
|
it "assumes an ascending interval between the arguments (order of arguments matters)" do
|
289
|
-
|
291
|
+
PITCH_CLASS_SET.span_between(Bb, F).should == 7
|
290
292
|
end
|
291
293
|
end
|
292
294
|
|
@@ -297,35 +299,35 @@ describe MTK do
|
|
297
299
|
describe '#PitchClassSet' do
|
298
300
|
|
299
301
|
it "constructs a PitchClassSet" do
|
300
|
-
PitchClassSet(C,D).should be_a
|
302
|
+
PitchClassSet(C,D).should be_a PITCH_CLASS_SET
|
301
303
|
end
|
302
304
|
|
303
305
|
it "acts like new for a single Array argument" do
|
304
|
-
PitchClassSet([C,D]).should ==
|
306
|
+
PitchClassSet([C,D]).should == PITCH_CLASS_SET.new([C,D])
|
305
307
|
end
|
306
308
|
|
307
309
|
it "acts like new for multiple arguments, by treating them like an Array (splat)" do
|
308
|
-
PitchClassSet(C,D).should ==
|
310
|
+
PitchClassSet(C,D).should == PITCH_CLASS_SET.new([C,D])
|
309
311
|
end
|
310
312
|
|
311
313
|
it "handles an Array with elements that can be converted to Pitches" do
|
312
|
-
PitchClassSet(['C','D']).should ==
|
314
|
+
PitchClassSet(['C','D']).should == PITCH_CLASS_SET.new([C,D])
|
313
315
|
end
|
314
316
|
|
315
317
|
it "handles multiple arguments that can be converted to a Pitch" do
|
316
|
-
PitchClassSet(:C,:D).should ==
|
318
|
+
PitchClassSet(:C,:D).should == PITCH_CLASS_SET.new([C,D])
|
317
319
|
end
|
318
320
|
|
319
321
|
it "handles a single Pitch" do
|
320
|
-
PitchClassSet(C).should ==
|
322
|
+
PitchClassSet(C).should == PITCH_CLASS_SET.new([C])
|
321
323
|
end
|
322
324
|
|
323
325
|
it "handles single elements that can be converted to a Pitch" do
|
324
|
-
PitchClassSet('C').should ==
|
326
|
+
PitchClassSet('C').should == PITCH_CLASS_SET.new([C])
|
325
327
|
end
|
326
328
|
|
327
329
|
it "handles a a PitchClassSet" do
|
328
|
-
pitch_set =
|
330
|
+
pitch_set = PITCH_CLASS_SET.new([C,D])
|
329
331
|
PitchClassSet(pitch_set).should == PitchClassSet([C,D])
|
330
332
|
end
|
331
333
|
|