jmtk 0.0.3.3-java
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 +10 -0
- data/DEVELOPMENT_NOTES.md +115 -0
- data/INTRO.md +129 -0
- data/LICENSE.txt +27 -0
- data/README.md +50 -0
- data/Rakefile +102 -0
- data/bin/jmtk +250 -0
- data/bin/mtk +250 -0
- data/examples/crescendo.rb +20 -0
- data/examples/drum_pattern.rb +23 -0
- data/examples/dynamic_pattern.rb +36 -0
- data/examples/gets_and_play.rb +27 -0
- data/examples/notation.rb +22 -0
- data/examples/play_midi.rb +17 -0
- data/examples/print_midi.rb +13 -0
- data/examples/random_tone_row.rb +18 -0
- data/examples/syntax_to_midi.rb +28 -0
- data/examples/test_output.rb +7 -0
- data/examples/tone_row_melody.rb +23 -0
- data/lib/mtk.rb +76 -0
- 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 +119 -0
- data/lib/mtk/events/note.rb +112 -0
- data/lib/mtk/events/parameter.rb +54 -0
- data/lib/mtk/events/timeline.rb +232 -0
- data/lib/mtk/groups/chord.rb +56 -0
- data/lib/mtk/groups/collection.rb +196 -0
- data/lib/mtk/groups/melody.rb +96 -0
- data/lib/mtk/groups/pitch_class_set.rb +163 -0
- data/lib/mtk/groups/pitch_collection.rb +23 -0
- data/lib/mtk/io/dls_synth_device.rb +146 -0
- data/lib/mtk/io/dls_synth_output.rb +62 -0
- data/lib/mtk/io/jsound_input.rb +87 -0
- data/lib/mtk/io/jsound_output.rb +82 -0
- data/lib/mtk/io/midi_file.rb +209 -0
- data/lib/mtk/io/midi_input.rb +97 -0
- data/lib/mtk/io/midi_output.rb +195 -0
- data/lib/mtk/io/notation.rb +162 -0
- data/lib/mtk/io/unimidi_input.rb +117 -0
- data/lib/mtk/io/unimidi_output.rb +140 -0
- data/lib/mtk/lang/durations.rb +57 -0
- data/lib/mtk/lang/intensities.rb +61 -0
- data/lib/mtk/lang/intervals.rb +73 -0
- data/lib/mtk/lang/mtk_grammar.citrus +237 -0
- data/lib/mtk/lang/parser.rb +29 -0
- data/lib/mtk/lang/pitch_classes.rb +29 -0
- data/lib/mtk/lang/pitches.rb +52 -0
- data/lib/mtk/lang/pseudo_constants.rb +26 -0
- data/lib/mtk/lang/variable.rb +32 -0
- data/lib/mtk/numeric_extensions.rb +66 -0
- data/lib/mtk/patterns/chain.rb +49 -0
- data/lib/mtk/patterns/choice.rb +43 -0
- 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/patterns/lines.rb +54 -0
- data/lib/mtk/patterns/palindrome.rb +45 -0
- data/lib/mtk/patterns/pattern.rb +171 -0
- data/lib/mtk/patterns/sequence.rb +20 -0
- data/lib/mtk/sequencers/event_builder.rb +132 -0
- data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
- data/lib/mtk/sequencers/sequencer.rb +111 -0
- data/lib/mtk/sequencers/step_sequencer.rb +26 -0
- data/spec/mtk/core/duration_spec.rb +372 -0
- data/spec/mtk/core/intensity_spec.rb +289 -0
- data/spec/mtk/core/interval_spec.rb +265 -0
- data/spec/mtk/core/pitch_class_spec.rb +343 -0
- data/spec/mtk/core/pitch_spec.rb +297 -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/events/timeline_spec.rb +430 -0
- data/spec/mtk/groups/chord_spec.rb +85 -0
- data/spec/mtk/groups/collection_spec.rb +374 -0
- data/spec/mtk/groups/melody_spec.rb +225 -0
- data/spec/mtk/groups/pitch_class_set_spec.rb +340 -0
- data/spec/mtk/io/midi_file_spec.rb +243 -0
- data/spec/mtk/io/midi_output_spec.rb +102 -0
- data/spec/mtk/lang/durations_spec.rb +89 -0
- data/spec/mtk/lang/intensities_spec.rb +101 -0
- data/spec/mtk/lang/intervals_spec.rb +143 -0
- data/spec/mtk/lang/parser_spec.rb +603 -0
- data/spec/mtk/lang/pitch_classes_spec.rb +62 -0
- data/spec/mtk/lang/pitches_spec.rb +56 -0
- data/spec/mtk/lang/pseudo_constants_spec.rb +20 -0
- data/spec/mtk/lang/variable_spec.rb +52 -0
- data/spec/mtk/numeric_extensions_spec.rb +83 -0
- data/spec/mtk/patterns/chain_spec.rb +110 -0
- data/spec/mtk/patterns/choice_spec.rb +97 -0
- data/spec/mtk/patterns/cycle_spec.rb +123 -0
- data/spec/mtk/patterns/for_each_spec.rb +136 -0
- data/spec/mtk/patterns/function_spec.rb +120 -0
- data/spec/mtk/patterns/lines_spec.rb +77 -0
- data/spec/mtk/patterns/palindrome_spec.rb +108 -0
- data/spec/mtk/patterns/pattern_spec.rb +132 -0
- data/spec/mtk/patterns/sequence_spec.rb +203 -0
- 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/sequencers/step_sequencer_spec.rb +93 -0
- data/spec/spec_coverage.rb +2 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/test.mid +0 -0
- metadata +226 -0
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Lang::PitchClasses do
|
4
|
+
let(:cases) {
|
5
|
+
[
|
6
|
+
[PitchClass['C'], 'C', 0],
|
7
|
+
[PitchClass['Db'], 'Db', 1],
|
8
|
+
[PitchClass['D'], 'D', 2],
|
9
|
+
[PitchClass['Eb'], 'Eb', 3],
|
10
|
+
[PitchClass['E'], 'E', 4],
|
11
|
+
[PitchClass['F'], 'F', 5],
|
12
|
+
[PitchClass['Gb'], 'Gb', 6],
|
13
|
+
[PitchClass['G'], 'G', 7],
|
14
|
+
[PitchClass['Ab'], 'Ab', 8],
|
15
|
+
[PitchClass['A'], 'A', 9],
|
16
|
+
[PitchClass['Bb'], 'Bb', 10],
|
17
|
+
[PitchClass['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, value|
|
24
|
+
const.name.should == name
|
25
|
+
const.value.should == 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
|
+
|
35
|
+
it "is immutable" do
|
36
|
+
lambda{ PitchClasses::PITCH_CLASSES << :something }.should raise_error
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "PITCH_CLASS_NAMES" do
|
41
|
+
it "contains the names of the 12 pitch class constants" do
|
42
|
+
PitchClasses::PITCH_CLASS_NAMES.length.should == 12
|
43
|
+
PitchClasses::PITCH_CLASS_NAMES.should == cases.map{ |_,name,__| name }
|
44
|
+
end
|
45
|
+
|
46
|
+
it "is immutable" do
|
47
|
+
lambda{ PitchClasses::PITCH_CLASS_NAMES << :something }.should raise_error
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe ".[]" do
|
52
|
+
it "acts like PitchClass.[]" do
|
53
|
+
for name in PitchClasses::PITCH_CLASS_NAMES
|
54
|
+
PitchClasses[name].should == PitchClass[name]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns nil for arguments it doesn't understand" do
|
59
|
+
PitchClasses[:invalid].should be_nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Lang::Pitches do
|
4
|
+
|
5
|
+
it "defines constants for the 128 notes in MIDI" do
|
6
|
+
Pitches.constants.length.should == 130 # there's also the PITCHES and PITCH_NAMES constants
|
7
|
+
Pitches::C_1.should == Pitch.from_s('C-1')
|
8
|
+
Pitches::D0.should == Pitch.from_s('D0')
|
9
|
+
Pitches::Eb1.should == Pitch.from_s('Eb1')
|
10
|
+
Pitches::G9.should == Pitch.from_s('g9')
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "PITCHES" do
|
14
|
+
it "contains all 128 pitch constants" do
|
15
|
+
Pitches::PITCHES.length.should == 128
|
16
|
+
Pitches::PITCHES.should include Pitches::C_1
|
17
|
+
Pitches::PITCHES.should include Pitches::D0
|
18
|
+
Pitches::PITCHES.should include Pitches::Eb1
|
19
|
+
Pitches::PITCHES.should include Pitches::G9
|
20
|
+
end
|
21
|
+
|
22
|
+
it "is immutable" do
|
23
|
+
lambda{ Pitches::PITCHES << :something }.should raise_error
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "PITCH_NAMES" do
|
28
|
+
it "contains all 128 pitch constants" do
|
29
|
+
Pitches::PITCH_NAMES.length.should == 128
|
30
|
+
Pitches::PITCH_NAMES.should include 'C_1'
|
31
|
+
Pitches::PITCH_NAMES.should include 'D0'
|
32
|
+
Pitches::PITCH_NAMES.should include 'Eb1'
|
33
|
+
Pitches::PITCH_NAMES.should include 'G9'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "is immutable" do
|
37
|
+
lambda{ Pitches::PITCH_NAMES << :something }.should raise_error
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe ".[]" do
|
42
|
+
it "acts like Pitch.from_s for the names in PITCH_NAMES, and also treats '_' like '-'" do
|
43
|
+
for name in Pitches::PITCH_NAMES
|
44
|
+
Pitches[name].should == Pitch.from_s(name.sub('_','-')) # the constant names need to use underscores, but Pitch.from_s doesn't understand that
|
45
|
+
if name =~ /_/
|
46
|
+
Pitches[name.sub('_','-')].should == Pitch.from_s(name.sub('_','-')) # make sure '-' works too
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "returns nil for arguments it doesn't understand" do
|
52
|
+
Pitches[:invalid].should be_nil
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Lang::PseudoConstants do
|
4
|
+
|
5
|
+
module MockConstants
|
6
|
+
extend MTK::Lang::PseudoConstants
|
7
|
+
define_constant 'constant', :value
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "define_constant" do
|
11
|
+
it "defines a method method in the module" do
|
12
|
+
MockConstants::constant.should == :value
|
13
|
+
end
|
14
|
+
|
15
|
+
it "defines a 'module_function'" do
|
16
|
+
MockConstants.constant.should == :value
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Lang::Variable do
|
4
|
+
|
5
|
+
def var(*args)
|
6
|
+
::MTK::Lang::Variable.new(*args)
|
7
|
+
end
|
8
|
+
|
9
|
+
describe '#name' do
|
10
|
+
it 'is the name the variable was constructed with' do
|
11
|
+
var('$').name.should == '$'
|
12
|
+
var('$$').name.should == '$$'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'cannot be changed after the variable is created' do
|
16
|
+
lambda{ var('$').name = '$$$' }.should raise_error
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#value' do
|
21
|
+
it 'is the value the variable was constructed with' do
|
22
|
+
var(:name, :value).value.should == :value
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can be changed after the variable is created' do
|
26
|
+
v = var(:name, :value)
|
27
|
+
v.value = 'foo'
|
28
|
+
v.value.should == 'foo'
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#==' do
|
33
|
+
it "is true when two variables' names are equal" do
|
34
|
+
var('$').should == var('$')
|
35
|
+
end
|
36
|
+
|
37
|
+
it "is false when two variables' names are not equal" do
|
38
|
+
var('$').should_not == var('$$')
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe '#to_s' do
|
43
|
+
it "includes just the variable name when there's no value" do
|
44
|
+
var('$').to_s.should == 'MTK::Lang::Variable<$>'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "includes just the variable name and value when there's a value" do
|
48
|
+
var('x',1).to_s.should == 'MTK::Lang::Variable<x=1>'
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mtk/numeric_extensions'
|
3
|
+
|
4
|
+
describe Numeric do
|
5
|
+
|
6
|
+
describe "#to_pitch" do
|
7
|
+
it "acts like Pitch.from_f applied to the Numeric value" do
|
8
|
+
12.3.to_pitch.should == MTK::Core::Pitch.from_f(12.3)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
describe "#to_pitch_class" do
|
14
|
+
it "acts like PitchClass.from_f applied to the Numeric value" do
|
15
|
+
6.to_pitch_class.should == MTK::Core::PitchClass.from_f(6)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
describe "#to_duration" do
|
21
|
+
it "acts like Duration.from_f applied to the Numeric value" do
|
22
|
+
1.5.to_duration.should == MTK::Core::Duration.from_f(1.5)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "#beat" do
|
27
|
+
it "acts like #to_duration" do
|
28
|
+
1.beat.should == 1.to_duration
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#beats" do
|
33
|
+
it "acts like #to_duration" do
|
34
|
+
2.beats.should == 2.to_duration
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
describe "#to_intensity" do
|
40
|
+
it "acts like Intensity.from_f applied to the Numeric value" do
|
41
|
+
0.75.to_intensity.should == MTK::Core::Intensity.from_f(0.75)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#percent_intensity" do
|
46
|
+
it "acts like Intensity.from_f applied to 1/100 of the Numeric value" do
|
47
|
+
75.percent_intensity.should == MTK::Core::Intensity.from_f(0.75)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
|
52
|
+
describe "#to_interval" do
|
53
|
+
it "acts like Interval.from_f applied to the Numeric value" do
|
54
|
+
3.5.to_interval.should == MTK::Core::Interval.from_f(3.5)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe '#semitone' do
|
59
|
+
it "acts like #to_interval" do
|
60
|
+
1.semitone.should == 1.to_interval
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe '#semitones' do
|
65
|
+
it "acts like #to_interval" do
|
66
|
+
2.semitones.should == 2.to_interval
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#cents" do
|
71
|
+
it "acts like Interval.from_f applied to 1/100 of the Numeric value" do
|
72
|
+
50.cents.should == MTK::Core::Interval.from_f(0.5)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#octaves" do
|
77
|
+
it "acts like Interval.from_f applied to 12 times the Numeric value" do
|
78
|
+
2.octaves.should == MTK::Core::Interval.from_f(24)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MTK::Patterns::Chain do
|
4
|
+
|
5
|
+
CHAIN = MTK::Patterns::Chain
|
6
|
+
|
7
|
+
describe '#next' do
|
8
|
+
it 'combines 2 basic attributes together' do
|
9
|
+
chain = CHAIN.new [C,q]
|
10
|
+
chain.next.should == [C,q]
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'combines 3 basic attributes together' do
|
14
|
+
chain = CHAIN.new [C,q,mp]
|
15
|
+
chain.next.should == [C,q,mp]
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'combines many basic attributes together, including duplicate types' do
|
19
|
+
chain = CHAIN.new [C,q,D,h,s,mp,fff]
|
20
|
+
chain.next.should == [C,q,D,h,s,mp,fff]
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'raises StopIteration after a basic-attribute-only chain has called #next more than once' do
|
24
|
+
chain = CHAIN.new [C,q]
|
25
|
+
chain.next
|
26
|
+
lambda{ chain.next }.should raise_error StopIteration
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'combines a basic attribute with a pattern' do
|
30
|
+
chain = CHAIN.new [Patterns.Sequence(C,D,E), q]
|
31
|
+
chain.next.should == [C,q]
|
32
|
+
chain.next.should == [D,q]
|
33
|
+
chain.next.should == [E,q]
|
34
|
+
lambda{ chain.next }.should raise_error StopIteration
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'combines 2 patterns' do
|
38
|
+
chain = CHAIN.new [Patterns.Sequence(C,D,E), Patterns.Sequence(w,h,q)]
|
39
|
+
chain.next.should == [C,w]
|
40
|
+
chain.next.should == [D,h]
|
41
|
+
chain.next.should == [E,q]
|
42
|
+
lambda{ chain.next }.should raise_error StopIteration
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'combines 2 patterns, and returns #next until the last StopIteration of a nested Pattern occurs' do
|
46
|
+
chain = CHAIN.new [Patterns.Sequence(C,D,E), Patterns.Sequence(w,h,q,i)]
|
47
|
+
chain.next.should == [C,w]
|
48
|
+
chain.next.should == [D,h]
|
49
|
+
chain.next.should == [E,q]
|
50
|
+
chain.next.should == [C,i]
|
51
|
+
lambda{ chain.next }.should raise_error StopIteration
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
# TODO: more than 2 patterns, and more than 2 + basic attribute(s)
|
56
|
+
|
57
|
+
|
58
|
+
it 'combines Choice patterns with max_cycles' do
|
59
|
+
chain = CHAIN.new [Patterns.Choice(i,s), Patterns.Choice(C,D,E)], max_cycles:100
|
60
|
+
100.times do |time|
|
61
|
+
attrs = chain.next
|
62
|
+
attrs.length.should == 2
|
63
|
+
(attrs[0]==i or attrs[0]==s).should be_true
|
64
|
+
(attrs[1]==C or attrs[1]==D or attrs[1]==E).should be_true
|
65
|
+
end
|
66
|
+
lambda{ chain.next }.should raise_error StopIteration
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'combines Choice patterns and emits a only single combination of attributes by default' do
|
70
|
+
chain = CHAIN.new [Patterns.Choice(i,s), Patterns.Choice(C,D,E)]
|
71
|
+
chain.next
|
72
|
+
lambda{ chain.next }.should raise_error StopIteration
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'flattens attribute lists with nested chains' do
|
76
|
+
chain = CHAIN.new( [1, 2, CHAIN.new([3, CHAIN.new([4,5])])] )
|
77
|
+
chain.next.should == [1,2,3,4,5]
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'throws StopIteration when any subpattern throws StopIteration with max_elements_exceeded' do
|
81
|
+
chain = CHAIN.new [Patterns.Sequence(C,D,E,F,G), Patterns.Sequence(w,h,q,i, max_elements:3)]
|
82
|
+
chain.next.should == [C,w]
|
83
|
+
chain.next.should == [D,h]
|
84
|
+
chain.next.should == [E,q]
|
85
|
+
lambda{ chain.next }.should raise_error StopIteration
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'throws StopIteration with max_elements_exceeded (edge case actual element length == max_elements)' do
|
89
|
+
chain = CHAIN.new [Patterns.Sequence(C,D,E,F,G), Patterns.Sequence(w,h,q, max_elements:3)]
|
90
|
+
chain.next.should == [C,w]
|
91
|
+
chain.next.should == [D,h]
|
92
|
+
chain.next.should == [E,q]
|
93
|
+
lambda{ chain.next }.should raise_error StopIteration
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
describe '#rewind' do
|
98
|
+
it 'resets the state of the Chain' do
|
99
|
+
# compare with the #next, raises StopIteration test above
|
100
|
+
chain = CHAIN.new [C,q]
|
101
|
+
chain.next
|
102
|
+
chain.rewind
|
103
|
+
lambda{ chain.next }.should_not raise_error StopIteration
|
104
|
+
lambda{ chain.next }.should raise_error StopIteration
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# TODO: test the chain builder method in Patterns module
|
109
|
+
|
110
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'set'
|
3
|
+
|
4
|
+
describe MTK::Patterns::Choice do
|
5
|
+
|
6
|
+
CHOICE = MTK::Patterns::Choice
|
7
|
+
|
8
|
+
let(:elements) { [1,2,3] }
|
9
|
+
let(:choice) { CHOICE.new elements, max_cycles:500 }
|
10
|
+
|
11
|
+
describe "#next" do
|
12
|
+
it "throws StopIteration on the second call to #next, by default" do
|
13
|
+
choice = CHOICE.new elements
|
14
|
+
choice.next
|
15
|
+
lambda{ choice.next }.should raise_error StopIteration
|
16
|
+
end
|
17
|
+
|
18
|
+
it "randomly chooses one of the elements" do
|
19
|
+
choosen = Set.new
|
20
|
+
100.times do
|
21
|
+
element = choice.next
|
22
|
+
choosen << element
|
23
|
+
end
|
24
|
+
choosen.to_a.should =~ elements
|
25
|
+
end
|
26
|
+
|
27
|
+
it "does a weighted random selection when a weights list is passed in via constructor options[:weights]" do
|
28
|
+
choice = CHOICE.new elements, max_cycles:100, weights:[1,3,0] # only choose first 2 elements, and choose the second three times as often
|
29
|
+
choosen = Set.new
|
30
|
+
first_count, second_count = 0,0
|
31
|
+
100.times do
|
32
|
+
element = choice.next
|
33
|
+
choosen << element
|
34
|
+
first_count += 1 if element == elements[0]
|
35
|
+
second_count += 1 if element == elements[1]
|
36
|
+
end
|
37
|
+
choosen.to_a.should =~ elements[0..1]
|
38
|
+
(first_count + 10).should < second_count # this may occasional fail, but it seems unlikely
|
39
|
+
end
|
40
|
+
|
41
|
+
it "enumerates a choosen sub-sequence" do
|
42
|
+
choice = CHOICE.new [MTK::Patterns.Sequence(4,5,6)], max_cycles:10
|
43
|
+
choice.next.should == 4
|
44
|
+
choice.next.should == 5
|
45
|
+
choice.next.should == 6
|
46
|
+
choice.next.should == 4 # now it will select a new choice, but there's only one, so it will be the same
|
47
|
+
choice.next.should == 5
|
48
|
+
choice.next.should == 6
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
|
55
|
+
describe MTK::Patterns do
|
56
|
+
|
57
|
+
describe "#Choice" do
|
58
|
+
it "creates a Choice" do
|
59
|
+
MTK::Patterns.Choice(1,2,3).should be_a MTK::Patterns::Choice
|
60
|
+
end
|
61
|
+
|
62
|
+
it "sets #elements from the varargs" do
|
63
|
+
MTK::Patterns.Choice(1,2,3).elements.should == [1,2,3]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe "#PitchChoice" do
|
68
|
+
it "creates a Choice" do
|
69
|
+
MTK::Patterns.PitchChoice(1,2,3).should be_a MTK::Patterns::Choice
|
70
|
+
end
|
71
|
+
|
72
|
+
it "sets #elements from the varargs" do
|
73
|
+
MTK::Patterns.PitchChoice(1,2,3).elements.should == [Pitch(1),Pitch(2),Pitch(3)]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "#IntensityChoice" do
|
78
|
+
it "creates a Choice" do
|
79
|
+
MTK::Patterns.IntensityChoice(1,2,3).should be_a MTK::Patterns::Choice
|
80
|
+
end
|
81
|
+
|
82
|
+
it "sets #elements from the varargs" do
|
83
|
+
MTK::Patterns.IntensityChoice(1,2,3).elements.should == [Intensity(1),Intensity(2),Intensity(3)]
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#DurationChoice" do
|
88
|
+
it "creates a Choice" do
|
89
|
+
MTK::Patterns.DurationChoice(1,2,3).should be_a MTK::Patterns::Choice
|
90
|
+
end
|
91
|
+
|
92
|
+
it "sets #elements from the varargs" do
|
93
|
+
MTK::Patterns.DurationChoice(1,2,3).elements.should == [q,h,h+q]
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|