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
@@ -1,151 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MTK::Pattern::Sequence do
|
4
|
-
|
5
|
-
SEQUENCE = MTK::Pattern::Sequence
|
6
|
-
|
7
|
-
let(:elements) { [1,2,3] }
|
8
|
-
let(:sequence) { SEQUENCE.new(elements) }
|
9
|
-
|
10
|
-
it "is a MTK::Collection" do
|
11
|
-
sequence.should be_a MTK::Helper::Collection
|
12
|
-
# and now we won't test any other collection features here... see collection_spec
|
13
|
-
end
|
14
|
-
|
15
|
-
describe ".from_a" do
|
16
|
-
it "acts like .new" do
|
17
|
-
SEQUENCE.from_a(elements).should == sequence
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
describe "#elements" do
|
22
|
-
it "is the array the sequence was constructed with" do
|
23
|
-
sequence.elements.should == elements
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
describe "#next" do
|
28
|
-
it "enumerates the elements" do
|
29
|
-
nexts = []
|
30
|
-
elements.length.times do
|
31
|
-
nexts << sequence.next
|
32
|
-
end
|
33
|
-
nexts.should == elements
|
34
|
-
end
|
35
|
-
|
36
|
-
it "raises StopIteration when the end of the Sequence is reached" do
|
37
|
-
elements.length.times{ sequence.next }
|
38
|
-
lambda{ sequence.next }.should raise_error(StopIteration)
|
39
|
-
end
|
40
|
-
|
41
|
-
it "should automatically break out of Kernel#loop" do
|
42
|
-
nexts = []
|
43
|
-
loop do # loop rescues StopIteration and exits the loop
|
44
|
-
nexts << sequence.next
|
45
|
-
end
|
46
|
-
nexts.should == elements
|
47
|
-
end
|
48
|
-
|
49
|
-
it "enumerates the elements in sub-sequences" do
|
50
|
-
sub_sequence = SEQUENCE.new [2,3]
|
51
|
-
sequence = SEQUENCE.new [1,sub_sequence,4]
|
52
|
-
nexts = []
|
53
|
-
loop { nexts << sequence.next }
|
54
|
-
nexts.should == [1,2,3,4]
|
55
|
-
end
|
56
|
-
|
57
|
-
it "skips over empty sub-sequences" do
|
58
|
-
sub_sequence = SEQUENCE.new []
|
59
|
-
sequence = SEQUENCE.new [1,sub_sequence,4]
|
60
|
-
nexts = []
|
61
|
-
loop { nexts << sequence.next }
|
62
|
-
nexts.should == [1,4]
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "#rewind" do
|
68
|
-
it "restarts at the beginning of the sequence" do
|
69
|
-
loop { sequence.next }
|
70
|
-
sequence.rewind
|
71
|
-
sequence.next.should == elements.first
|
72
|
-
end
|
73
|
-
|
74
|
-
it "returns self, so it can be chained to #next" do
|
75
|
-
first = sequence.next
|
76
|
-
sequence.rewind.next.should == first
|
77
|
-
end
|
78
|
-
|
79
|
-
it "causes sub-sequences to start from the beginning when encountered again after #rewind" do
|
80
|
-
sub_sequence = SEQUENCE.new [2,3]
|
81
|
-
sequence = SEQUENCE.new [1,sub_sequence,4]
|
82
|
-
loop { sequence.next }
|
83
|
-
sequence.rewind
|
84
|
-
nexts = []
|
85
|
-
loop { nexts << sequence.next }
|
86
|
-
nexts.should == [1,2,3,4]
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
end
|
91
|
-
|
92
|
-
|
93
|
-
describe MTK::Pattern do
|
94
|
-
|
95
|
-
describe "#Sequence" do
|
96
|
-
it "creates a Sequence" do
|
97
|
-
MTK::Pattern.Sequence(1,2,3).should be_a MTK::Pattern::Sequence
|
98
|
-
end
|
99
|
-
|
100
|
-
it "sets #elements from the varargs" do
|
101
|
-
MTK::Pattern.Sequence(1,2,3).elements.should == [1,2,3]
|
102
|
-
end
|
103
|
-
|
104
|
-
it "does not set a type" do
|
105
|
-
MTK::Pattern.Sequence(1,2,3).type.should be_nil
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
109
|
-
describe "#PitchSequence" do
|
110
|
-
it "creates a Sequence" do
|
111
|
-
MTK::Pattern.PitchSequence(1,2,3).should be_a MTK::Pattern::Sequence
|
112
|
-
end
|
113
|
-
|
114
|
-
it "sets #elements from the varargs" do
|
115
|
-
MTK::Pattern.PitchSequence(1,2,3).elements.should == [1,2,3]
|
116
|
-
end
|
117
|
-
|
118
|
-
it "sets #type to :pitch" do
|
119
|
-
MTK::Pattern.PitchSequence([]).type.should == :pitch
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
describe "#IntensitySequence" do
|
124
|
-
it "creates a Sequence" do
|
125
|
-
MTK::Pattern.IntensitySequence(1,2,3).should be_a MTK::Pattern::Sequence
|
126
|
-
end
|
127
|
-
|
128
|
-
it "sets #elements from the varargs" do
|
129
|
-
MTK::Pattern.IntensitySequence(1,2,3).elements.should == [1,2,3]
|
130
|
-
end
|
131
|
-
|
132
|
-
it "sets #type to :pitch" do
|
133
|
-
MTK::Pattern.IntensitySequence([]).type.should == :intensity
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
describe "#DurationSequence" do
|
138
|
-
it "creates a Sequence" do
|
139
|
-
MTK::Pattern.DurationSequence(1,2,3).should be_a MTK::Pattern::Sequence
|
140
|
-
end
|
141
|
-
|
142
|
-
it "sets #elements from the varargs" do
|
143
|
-
MTK::Pattern.DurationSequence(1,2,3).elements.should == [1,2,3]
|
144
|
-
end
|
145
|
-
|
146
|
-
it "sets #type to :pitch" do
|
147
|
-
MTK::Pattern.DurationSequence([]).type.should == :duration
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
end
|
data/spec/mtk/pitch_set_spec.rb
DELETED
@@ -1,198 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MTK::PitchSet do
|
4
|
-
|
5
|
-
let(:pitches) { [C4, D4, E4, F4, G4, A4, B4] }
|
6
|
-
let(:pitch_set) { PitchSet.new(pitches) }
|
7
|
-
let(:c_major) { PitchSet.new([C4,E4,G4]) }
|
8
|
-
|
9
|
-
it "is Enumerable" do
|
10
|
-
pitch_set.should be_a Enumerable
|
11
|
-
end
|
12
|
-
|
13
|
-
describe '#pitches' do
|
14
|
-
it 'is the list of pitches used to construct the scale' do
|
15
|
-
pitch_set.pitches.should == pitches
|
16
|
-
end
|
17
|
-
|
18
|
-
it "is immutable" do
|
19
|
-
lambda { pitch_set.pitches << Db4 }.should raise_error
|
20
|
-
end
|
21
|
-
|
22
|
-
it "does not affect the immutabilty of the pitch list used to construct it" do
|
23
|
-
pitches << Db4
|
24
|
-
pitches.length.should == 8
|
25
|
-
end
|
26
|
-
|
27
|
-
it "is not affected by changes to the pitch list used to construct it" do
|
28
|
-
pitch_set # force construction before we modify the pitches array
|
29
|
-
pitches << Db4
|
30
|
-
pitch_set.pitches.length.should == 7
|
31
|
-
end
|
32
|
-
|
33
|
-
it "does not include duplicates" do
|
34
|
-
PitchSet.new([C4, E4, G4, C4]).pitches.should == [C4, E4, G4]
|
35
|
-
end
|
36
|
-
|
37
|
-
it "sorts the pitches" do
|
38
|
-
PitchSet.new([G4, E4, C4]).pitches.should == [C4, E4, G4]
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
describe "#to_a" do
|
43
|
-
it "is equal to #pitches" do
|
44
|
-
pitch_set.to_a.should == pitch_set.pitches
|
45
|
-
end
|
46
|
-
|
47
|
-
it "is mutable" do
|
48
|
-
(c_major.to_a << Bb4).should == [C4, E4, G4, Bb4]
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
describe "#each" do
|
53
|
-
it "yields each pitch" do
|
54
|
-
ps = []
|
55
|
-
pitch_set.each{|p| ps << p }
|
56
|
-
ps.should == pitches
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
describe "#map" do
|
61
|
-
it "returns a PitchSet with each Pitch replaced with the results of the block" do
|
62
|
-
c_major.map{|p| p + 2}.should == [D4, Gb4, A4]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
describe "#to_pitch_class_set" do
|
67
|
-
it "is a PitchClassSet" do
|
68
|
-
pitch_set.to_pitch_class_set.should be_a PitchClassSet
|
69
|
-
end
|
70
|
-
|
71
|
-
it "contains all the pitch_classes in this PitchSet" do
|
72
|
-
pitch_set.to_pitch_class_set.pitch_classes.should == pitch_set.pitch_classes
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
describe '#pitch_classes' do
|
77
|
-
it 'is the list of pitch classes' do
|
78
|
-
pitch_set.pitch_classes.should == pitches.map { |p| p.pitch_class }
|
79
|
-
end
|
80
|
-
|
81
|
-
it "doesn't include duplicates" do
|
82
|
-
PitchSet.new([C4, C5, D5, C6, D4]).pitch_classes.should == [C, D]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
describe '#transpose' do
|
87
|
-
it 'transposes upward by the given semitones' do
|
88
|
-
pitch_set.transpose(12).should == PitchSet.new([C5, D5, E5, F5, G5, A5, B5])
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
describe '#invert' do
|
93
|
-
it 'inverts all pitches around the given center pitch' do
|
94
|
-
(pitch_set.invert Gb4).should == PitchSet.new([C5, Bb4, Ab4, G4, F4, Eb4, Db4])
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'inverts all pitches around the first pitch, when no center pitch is given' do
|
98
|
-
pitch_set.invert.should == PitchSet.new([C4, Bb3, Ab3, G3, F3, Eb3, Db3])
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
describe '#include?' do
|
103
|
-
it 'returns true if the Pitch is in the PitchList' do
|
104
|
-
(pitch_set.include? C4).should be_true
|
105
|
-
end
|
106
|
-
|
107
|
-
it 'returns false if the Pitch is not in the PitchList' do
|
108
|
-
(pitch_set.include? Db4).should be_false
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe '#==' do
|
113
|
-
it "is true when all the pitches are equal" do
|
114
|
-
PitchSet.new([C4, E4, G4]).should == PitchSet.new([Pitch.from_i(60), Pitch.from_i(64), Pitch.from_i(67)])
|
115
|
-
end
|
116
|
-
|
117
|
-
it "doesn't consider duplicates in the comparison" do
|
118
|
-
PitchSet.new([C4, C4]).should == PitchSet.new([C4])
|
119
|
-
end
|
120
|
-
|
121
|
-
it "doesn't consider the order of pitches" do
|
122
|
-
PitchSet.new([G4, E4, C4]).should == PitchSet.new([C4, E4, G4])
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe '#inversion' do
|
127
|
-
it "adds an octave to the chord's pitches starting from the lowest, for each whole number in a postive argument" do
|
128
|
-
c_major.inversion(2).should == PitchSet.new([G4,C5,E5])
|
129
|
-
end
|
130
|
-
|
131
|
-
it "subtracts an octave to the chord's pitches starting fromt he highest, for each whole number in a negative argument" do
|
132
|
-
c_major.inversion(-2).should == PitchSet.new([E3,G3,C4])
|
133
|
-
end
|
134
|
-
|
135
|
-
it "wraps around to the lowest pitch when the argument is bigger than the number of pitches in the chord (positive argument)" do
|
136
|
-
c_major.inversion(4).should == PitchSet.new([E5,G5,C6])
|
137
|
-
end
|
138
|
-
|
139
|
-
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
|
140
|
-
c_major.inversion(-4).should == PitchSet.new([G2,C3,E3])
|
141
|
-
end
|
142
|
-
end
|
143
|
-
|
144
|
-
describe "#nearest" do
|
145
|
-
it "returns the nearest PitchSet where the first Pitch has the given PitchClass" do
|
146
|
-
c_major.nearest(F).should == c_major.transpose(5.semitones)
|
147
|
-
c_major.nearest(G).should == c_major.transpose(-5.semitones)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
describe "#to_s" do
|
152
|
-
it "looks like an array of pitches" do
|
153
|
-
c_major.to_s.should == "[C4, E4, G4]"
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
end
|
158
|
-
|
159
|
-
describe MTK do
|
160
|
-
|
161
|
-
describe '#PitchSet' do
|
162
|
-
|
163
|
-
it "acts like new for a single Array argument" do
|
164
|
-
PitchSet([C4,D4]).should == PitchSet.new([C4,D4])
|
165
|
-
end
|
166
|
-
|
167
|
-
it "acts like new for multiple arguments, by treating them like an Array (splat)" do
|
168
|
-
PitchSet(C4,D4).should == PitchSet.new([C4,D4])
|
169
|
-
end
|
170
|
-
|
171
|
-
it "handles an Array with elements that can be converted to Pitches" do
|
172
|
-
PitchSet(['C4','D4']).should == PitchSet.new([C4,D4])
|
173
|
-
end
|
174
|
-
|
175
|
-
it "handles multiple arguments that can be converted to a Pitch" do
|
176
|
-
PitchSet(:C4,:D4).should == PitchSet.new([C4,D4])
|
177
|
-
end
|
178
|
-
|
179
|
-
it "handles a single Pitch" do
|
180
|
-
PitchSet(C4).should == PitchSet.new([C4])
|
181
|
-
end
|
182
|
-
|
183
|
-
it "handles single elements that can be converted to a Pitch" do
|
184
|
-
PitchSet('C4').should == PitchSet.new([C4])
|
185
|
-
end
|
186
|
-
|
187
|
-
it "returns the argument if it's already a PitchSet" do
|
188
|
-
pitch_set = PitchSet.new([C4,D4])
|
189
|
-
PitchSet(pitch_set).should be_equal pitch_set
|
190
|
-
end
|
191
|
-
|
192
|
-
it "raises an error for types it doesn't understand" do
|
193
|
-
lambda{ PitchSet({:not => :compatible}) }.should raise_error
|
194
|
-
end
|
195
|
-
|
196
|
-
end
|
197
|
-
|
198
|
-
end
|
@@ -1,159 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe MTK::Sequencer::AbstractSequencer do
|
4
|
-
|
5
|
-
ABSTRACT_SEQUENCER = Sequencer::AbstractSequencer
|
6
|
-
|
7
|
-
class MockEventBuilder < Helper::EventBuilder
|
8
|
-
attr_accessor :mock_attribute
|
9
|
-
end
|
10
|
-
|
11
|
-
let(:patterns) { [Pattern.PitchCycle(C4,D4)] }
|
12
|
-
let(:sequencer) { ABSTRACT_SEQUENCER.new patterns }
|
13
|
-
let(:intensity) { Helper::EventBuilder::DEFAULT_INTENSITY }
|
14
|
-
let(:duration) { Helper::EventBuilder::DEFAULT_DURATION }
|
15
|
-
|
16
|
-
describe "#new" do
|
17
|
-
it "defaults @max_steps to nil" do
|
18
|
-
sequencer.max_steps.should be_nil
|
19
|
-
end
|
20
|
-
|
21
|
-
it "sets @max_steps from the options hash" do
|
22
|
-
sequencer = RHYTHMIC_SEQUENCER.new patterns, :max_steps => 4
|
23
|
-
sequencer.max_steps.should == 4
|
24
|
-
end
|
25
|
-
|
26
|
-
it "defaults @max_time to nil" do
|
27
|
-
sequencer.max_time.should be_nil
|
28
|
-
end
|
29
|
-
|
30
|
-
it "sets @max_time from the options hash" do
|
31
|
-
sequencer = RHYTHMIC_SEQUENCER.new patterns, :max_time => 4
|
32
|
-
sequencer.max_time.should == 4
|
33
|
-
end
|
34
|
-
|
35
|
-
it "defaults @event_builder to MTK::Helper::EventBuilder" do
|
36
|
-
sequencer.event_builder.should be_a MTK::Helper::EventBuilder
|
37
|
-
end
|
38
|
-
|
39
|
-
it "sets @event_buidler from the options hash" do
|
40
|
-
sequencer = RHYTHMIC_SEQUENCER.new patterns, :event_builder => MockEventBuilder
|
41
|
-
sequencer.event_builder.should be_a MockEventBuilder
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
describe "#event_builder" do
|
46
|
-
it "provides access to the internal EventBuilder" do
|
47
|
-
sequencer = RHYTHMIC_SEQUENCER.new patterns, :event_builder => MockEventBuilder
|
48
|
-
sequencer.event_builder.mock_attribute = :value
|
49
|
-
sequencer.event_builder.mock_attribute.should == :value
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
describe "#to_timeline" do
|
54
|
-
it "combines pitch, intensity, and duration patterns into notes" do
|
55
|
-
pitches = Pattern.PitchSequence(C4, D4, E4)
|
56
|
-
intensities = Pattern.IntensitySequence(0.3, 0.7, 1.0)
|
57
|
-
durations = Pattern.DurationSequence(1, 2, 3)
|
58
|
-
sequencer = ABSTRACT_SEQUENCER.new [pitches, intensities, durations]
|
59
|
-
# default implementation just increments the time by 1 for each event (more interesting behavior is provided by subclasses)
|
60
|
-
sequencer.to_timeline.should == {
|
61
|
-
0 => [Note(C4,0.3,1)],
|
62
|
-
1 => [Note(D4,0.7,2)],
|
63
|
-
2 => [Note(E4,1.0,3)]
|
64
|
-
}
|
65
|
-
end
|
66
|
-
|
67
|
-
it "combines patterns of different types and lengths" do
|
68
|
-
pitches = Pattern.PitchSequence(C4, D4, E4, F4, G4, A4, B4, C5)
|
69
|
-
intensities = Pattern.IntensityCycle(0.5, 1.0)
|
70
|
-
durations = Pattern.DurationPalindrome(1, 2, 3)
|
71
|
-
sequencer = ABSTRACT_SEQUENCER.new [pitches, intensities, durations]
|
72
|
-
# default implementation just increments the time by 1 for each event (more interesting behavior is provided by subclasses)
|
73
|
-
sequencer.to_timeline.should == {
|
74
|
-
0 => [Note(C4,0.5,1)],
|
75
|
-
1 => [Note(D4,1.0,2)],
|
76
|
-
2 => [Note(E4,0.5,3)],
|
77
|
-
3 => [Note(F4,1.0,2)],
|
78
|
-
4 => [Note(G4,0.5,1)],
|
79
|
-
5 => [Note(A4,1.0,2)],
|
80
|
-
6 => [Note(B4,0.5,3)],
|
81
|
-
7 => [Note(C5,1.0,2)]
|
82
|
-
}
|
83
|
-
end
|
84
|
-
|
85
|
-
it "produces consistent results by reseting the patterns each time" do
|
86
|
-
pitches = Pattern.PitchSequence(C4, D4, E4)
|
87
|
-
intensities = Pattern.IntensityCycle(1)
|
88
|
-
durations = Pattern.DurationCycle(1, 2)
|
89
|
-
sequencer = ABSTRACT_SEQUENCER.new [pitches, intensities, durations]
|
90
|
-
sequencer.to_timeline.should == sequencer.to_timeline
|
91
|
-
end
|
92
|
-
end
|
93
|
-
|
94
|
-
describe "#time" do
|
95
|
-
it "is the current timeline time that the sequencer is generating events for" do
|
96
|
-
# AbstractSequencer just advances by 1 each step
|
97
|
-
sequencer.next # time doesn't advance until the second #next call
|
98
|
-
sequencer.time.should == 0
|
99
|
-
sequencer.next
|
100
|
-
sequencer.time.should == 1
|
101
|
-
sequencer.next
|
102
|
-
sequencer.time.should == 2
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
describe "#step" do
|
107
|
-
it "is the index for how many of times #next has been called (i.e. count starting from 0)" do
|
108
|
-
sequencer.step.should == -1 # -1 indicates #next has not yet been called
|
109
|
-
sequencer.next
|
110
|
-
sequencer.step.should == 0
|
111
|
-
sequencer.next
|
112
|
-
sequencer.step.should == 1
|
113
|
-
sequencer.next
|
114
|
-
sequencer.step.should == 2
|
115
|
-
end
|
116
|
-
end
|
117
|
-
|
118
|
-
describe "#next" do
|
119
|
-
it "returns a list of notes formed from the patterns in the sequencer" do
|
120
|
-
sequencer.next.should == [Note(C4,intensity,duration)]
|
121
|
-
sequencer.next.should == [Note(D4,intensity,duration)]
|
122
|
-
sequencer.next.should == [Note(C4,intensity,duration)]
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe "#rewind" do
|
127
|
-
it "resets the sequencer and its patterns" do
|
128
|
-
sequencer.next
|
129
|
-
sequencer.rewind
|
130
|
-
sequencer.step.should == -1
|
131
|
-
sequencer.time.should == 0
|
132
|
-
sequencer.next.should == [Note(C4,intensity,duration)]
|
133
|
-
end
|
134
|
-
|
135
|
-
it "resets pitches properly for patterns that rely on previous pitches" do
|
136
|
-
relative_pitch_pattern = Pattern.PitchSequence(C,P8)
|
137
|
-
sequencer = ABSTRACT_SEQUENCER.new [relative_pitch_pattern]
|
138
|
-
sequencer.next.should == [Note(C4,intensity,duration)]
|
139
|
-
sequencer.next.should == [Note(C5,intensity,duration)]
|
140
|
-
sequencer.rewind
|
141
|
-
sequencer.next.should == [Note(C4,intensity,duration)] # if the internal EventBuilder is not properly reset, the Note would be C5
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
describe "#max_steps" do
|
146
|
-
it "controls the maximum number of entries in the generated timeline" do
|
147
|
-
sequencer.max_steps = 2
|
148
|
-
sequencer.to_timeline.times.length.should == 2
|
149
|
-
end
|
150
|
-
end
|
151
|
-
|
152
|
-
describe "#max_time" do
|
153
|
-
it "controls the maximum time in the generated timeline" do
|
154
|
-
sequencer.max_time = 4
|
155
|
-
sequencer.to_timeline.times.last.should == 4
|
156
|
-
end
|
157
|
-
end
|
158
|
-
|
159
|
-
end
|