musicality 0.11.1 → 0.12.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.coveralls.yml +1 -0
- data/.ruby-version +1 -1
- data/.travis.yml +4 -0
- data/ChangeLog.md +11 -0
- data/README.md +3 -0
- data/Rakefile +11 -3
- data/lib/musicality/composition/model/rhythm.rb +33 -0
- data/lib/musicality/composition/model/rhythm_class.rb +30 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_kit.rb +18 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_machine.rb +59 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_parts.rb +21 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_pattern.rb +66 -0
- data/lib/musicality/composition/sequencing/drum_machine/drum_patterns/pop_drum_patterns.rb +146 -0
- data/lib/musicality/composition/sequencing/note_array.rb +33 -0
- data/lib/musicality/composition/sequencing/note_fifo.rb +73 -0
- data/lib/musicality/composition/sequencing/sequenceable.rb +9 -0
- data/lib/musicality/composition/sequencing/sequencer.rb +35 -0
- data/lib/musicality/errors.rb +2 -2
- data/lib/musicality/notation/model/dynamics.rb +2 -2
- data/lib/musicality/notation/model/key.rb +42 -91
- data/lib/musicality/notation/model/keys.rb +35 -34
- data/lib/musicality/notation/model/note.rb +31 -9
- data/lib/musicality/notation/model/pitch.rb +2 -2
- data/lib/musicality/notation/parsing/convenience_methods.rb +23 -12
- data/lib/musicality/notation/parsing/duration_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/key_parsing.rb +150 -0
- data/lib/musicality/notation/parsing/key_parsing.treetop +37 -0
- data/lib/musicality/notation/parsing/meter_parsing.rb +3 -3
- data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +3 -1
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +1 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +4 -1
- data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +1 -1
- data/lib/musicality/notation/parsing/parseable.rb +13 -17
- data/lib/musicality/notation/parsing/pitch_parsing.rb +7 -0
- data/lib/musicality/notation/parsing/segment_parsing.rb +3 -0
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +82 -134
- data/lib/musicality/performance/model/note_sequence.rb +22 -3
- data/lib/musicality/performance/supercollider/performer.rb +2 -2
- data/lib/musicality/performance/supercollider/sc_drum_kits.rb +29 -0
- data/lib/musicality/performance/supercollider/synthdefs/bass.rb +211 -0
- data/lib/musicality/performance/supercollider/synthdefs/claps.rb +80 -0
- data/lib/musicality/performance/supercollider/synthdefs/cymbals.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdefs/hihats.rb +67 -0
- data/lib/musicality/performance/supercollider/synthdefs/kicks.rb +158 -0
- data/lib/musicality/performance/supercollider/synthdefs/mario.rb +49 -0
- data/lib/musicality/performance/supercollider/{synthdefs.rb → synthdefs/other.rb} +0 -767
- data/lib/musicality/performance/supercollider/synthdefs/pianos.rb +46 -0
- data/lib/musicality/performance/supercollider/synthdefs/snares.rb +169 -0
- data/lib/musicality/performance/supercollider/synthdefs/toms.rb +25 -0
- data/lib/musicality/performance/supercollider/synthdefs/volume.rb +20 -0
- data/lib/musicality/pitch_class.rb +1 -1
- data/lib/musicality/pitch_classes.rb +3 -5
- data/lib/musicality/version.rb +1 -1
- data/lib/musicality.rb +25 -1
- data/musicality.gemspec +3 -2
- data/spec/composition/convenience_methods_spec.rb +8 -8
- data/spec/composition/generation/random_rhythm_generator_spec.rb +5 -5
- data/spec/composition/model/pitch_class_spec.rb +22 -16
- data/spec/composition/model/pitch_classes_spec.rb +5 -5
- data/spec/composition/model/rhythm_class_spec.rb +42 -0
- data/spec/composition/model/rhythm_spec.rb +43 -0
- data/spec/composition/model/scale_class_spec.rb +26 -26
- data/spec/composition/model/scale_spec.rb +38 -38
- data/spec/composition/sequencing/drum_machine/drum_machine_spec.rb +67 -0
- data/spec/composition/sequencing/drum_machine/drum_pattern_spec.rb +58 -0
- data/spec/composition/sequencing/note_array_spec.rb +94 -0
- data/spec/composition/sequencing/note_fifo_spec.rb +183 -0
- data/spec/composition/sequencing/sequencer_spec.rb +76 -0
- data/spec/composition/util/adding_sequence_spec.rb +33 -33
- data/spec/composition/util/compound_sequence_spec.rb +6 -6
- data/spec/composition/util/note_generation_spec.rb +34 -34
- data/spec/composition/util/probabilities_spec.rb +7 -7
- data/spec/composition/util/random_sampler_spec.rb +3 -3
- data/spec/composition/util/repeating_sequence_spec.rb +28 -28
- data/spec/musicality_spec.rb +1 -1
- data/spec/notation/conversion/change_conversion_spec.rb +87 -87
- data/spec/notation/conversion/note_time_converter_spec.rb +22 -22
- data/spec/notation/conversion/score_conversion_spec.rb +1 -1
- data/spec/notation/conversion/score_converter_spec.rb +31 -31
- data/spec/notation/conversion/tempo_conversion_spec.rb +11 -11
- data/spec/notation/model/change_spec.rb +80 -80
- data/spec/notation/model/key_spec.rb +135 -69
- data/spec/notation/model/link_spec.rb +27 -27
- data/spec/notation/model/meter_spec.rb +28 -28
- data/spec/notation/model/note_spec.rb +68 -47
- data/spec/notation/model/part_spec.rb +19 -19
- data/spec/notation/model/pitch_spec.rb +69 -68
- data/spec/notation/model/score_spec.rb +50 -47
- data/spec/notation/parsing/articulation_parsing_spec.rb +4 -4
- data/spec/notation/parsing/convenience_methods_spec.rb +49 -10
- data/spec/notation/parsing/duration_nodes_spec.rb +13 -13
- data/spec/notation/parsing/duration_parsing_spec.rb +10 -10
- data/spec/notation/parsing/key_parsing_spec.rb +19 -0
- data/spec/notation/parsing/link_nodes_spec.rb +7 -7
- data/spec/notation/parsing/link_parsing_spec.rb +4 -4
- data/spec/notation/parsing/meter_parsing_spec.rb +5 -5
- data/spec/notation/parsing/note_node_spec.rb +19 -19
- data/spec/notation/parsing/note_parsing_spec.rb +4 -4
- data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +2 -2
- data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +1 -1
- data/spec/notation/parsing/numbers/positive_float_spec.rb +8 -8
- data/spec/notation/parsing/numbers/positive_integer_spec.rb +6 -6
- data/spec/notation/parsing/numbers/positive_rational_spec.rb +6 -6
- data/spec/notation/parsing/pitch_node_spec.rb +7 -7
- data/spec/notation/parsing/pitch_parsing_spec.rb +2 -2
- data/spec/notation/parsing/segment_parsing_spec.rb +3 -3
- data/spec/notation/util/function_spec.rb +15 -15
- data/spec/notation/util/transition_spec.rb +12 -12
- data/spec/notation/util/value_computer_spec.rb +35 -36
- data/spec/performance/conversion/glissando_converter_spec.rb +24 -24
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +39 -39
- data/spec/performance/conversion/portamento_converter_spec.rb +23 -23
- data/spec/performance/midi/midi_util_spec.rb +41 -41
- data/spec/performance/midi/part_sequencer_spec.rb +10 -10
- data/spec/performance/midi/score_sequencer_spec.rb +15 -15
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/util/optimization_spec.rb +9 -9
- data/spec/printing/note_engraving_spec.rb +16 -16
- data/spec/printing/score_engraver_spec.rb +5 -5
- data/spec/spec_helper.rb +5 -0
- metadata +85 -30
@@ -4,11 +4,11 @@ describe Parsing::PitchParser do
|
|
4
4
|
before :all do
|
5
5
|
@parser = Parsing::PitchParser.new
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
["C4","C#9","Ab0","G#2","E2+22","Cb5-99","G200","Bb9951+3920"
|
9
9
|
].each do |str|
|
10
10
|
it "should parse #{str}" do
|
11
|
-
@parser.
|
11
|
+
expect(@parser).to parse(str)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -16,11 +16,11 @@ describe Parsing::SegmentParser do
|
|
16
16
|
str,tgt = str_tgt
|
17
17
|
res = parser.parse(str)
|
18
18
|
it 'should parse' do
|
19
|
-
res.
|
19
|
+
expect(res).to_not be nil
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
it 'should return node that converts to exclusive range via #to_range' do
|
23
|
-
res.to_range.
|
23
|
+
expect(res.to_range).to eq tgt
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -3,33 +3,33 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
3
3
|
describe Function::Constant do
|
4
4
|
it 'should always return the same value' do
|
5
5
|
f = Function::Constant.new(20)
|
6
|
-
f.at(0).
|
7
|
-
f.at(-1000).
|
8
|
-
f.at(1000).
|
6
|
+
expect(f.at(0)).to eq(20)
|
7
|
+
expect(f.at(-1000)).to eq(20)
|
8
|
+
expect(f.at(1000)).to eq(20)
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
12
|
describe Function::Linear do
|
13
13
|
it 'should evaluate along the line going between the two initial points' do
|
14
14
|
f = Function::Linear.new([5,10],[7,11])
|
15
|
-
f.at(4).
|
16
|
-
f.at(5).
|
17
|
-
f.at(6).
|
18
|
-
f.at(7).
|
19
|
-
f.at(8).
|
15
|
+
expect(f.at(4)).to eq(9.5)
|
16
|
+
expect(f.at(5)).to eq(10)
|
17
|
+
expect(f.at(6)).to eq(10.5)
|
18
|
+
expect(f.at(7)).to eq(11)
|
19
|
+
expect(f.at(8)).to eq(11.5)
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
describe Function::Sigmoid do
|
24
24
|
it 'should evaluate along the line going between the two initial points' do
|
25
25
|
f = Function::Sigmoid.new([5,10],[7,11])
|
26
|
-
f.at(4).
|
27
|
-
f.at(5).
|
28
|
-
f.at(6).
|
29
|
-
f.at(7).
|
30
|
-
f.at(8).
|
26
|
+
expect(f.at(4)).to be < 10
|
27
|
+
expect(f.at(5)).to eq(10)
|
28
|
+
expect(f.at(6)).to eq(10.5)
|
29
|
+
expect(f.at(7)).to eq(11)
|
30
|
+
expect(f.at(8)).to be > 11
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
33
|
describe '.find_y0' do
|
34
34
|
it 'should return the starting y-value for the given sigmoid domain' do
|
35
35
|
x0, x1 = 3, 6
|
@@ -37,7 +37,7 @@ describe Function::Sigmoid do
|
|
37
37
|
f = Function::Sigmoid.new([x0,y0],[x1,y1])
|
38
38
|
pt = [4,f.at(4)]
|
39
39
|
y0_ = Function::Sigmoid.find_y0(x0..x1, pt, y1)
|
40
|
-
y0_.
|
40
|
+
expect(y0_).to eq(y0)
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -5,47 +5,47 @@ describe Transition do
|
|
5
5
|
context 'zero-length domain' do
|
6
6
|
it 'should create one piece' do
|
7
7
|
t = Transition.new(Function::Constant.new(3),5..5)
|
8
|
-
t.pieces.size.
|
8
|
+
expect(t.pieces.size).to eq(1)
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
context 'positive-length domain' do
|
13
13
|
it 'should create two pieces' do
|
14
14
|
t = Transition.new(Function::Linear.new([0,0],[2,1]),3..5)
|
15
|
-
t.pieces.size.
|
15
|
+
expect(t.pieces.size).to eq(2)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
describe '#at' do
|
21
21
|
before :all do
|
22
22
|
@f = Function::Linear.new([0,0],[2,1])
|
23
23
|
@d = 3..5
|
24
24
|
@t = Transition.new(@f,@d)
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
context 'given value before transition domain starts' do
|
28
28
|
it 'should raise DomainError' do
|
29
29
|
expect { @t.at(@d.first - 1e-5) }.to raise_error(DomainError)
|
30
30
|
expect { @t.at(@d.first - 1e5) }.to raise_error(DomainError)
|
31
31
|
end
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
context 'given value in transition domain' do
|
35
35
|
it 'should not raise DomainError' do
|
36
36
|
@d.entries.each {|x| expect { @t.at(x) }.to_not raise_error }
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
it 'should calculate return value using the transition function' do
|
40
|
-
@d.entries.each {|x| @t.at(x).
|
40
|
+
@d.entries.each {|x| expect(@t.at(x)).to eq(@f.at(x)) }
|
41
41
|
end
|
42
42
|
end
|
43
|
-
|
43
|
+
|
44
44
|
context 'given value after transition domain' do
|
45
45
|
it 'should return same value as at the end of transition domain' do
|
46
|
-
@t.at(@d.last + 1e-5).
|
47
|
-
@t.at(@d.last + 1e5).
|
46
|
+
expect(@t.at(@d.last + 1e-5)).to eq(@t.at(@d.last))
|
47
|
+
expect(@t.at(@d.last + 1e5)).to eq(@t.at(@d.last))
|
48
48
|
end
|
49
49
|
end
|
50
50
|
end
|
51
|
-
end
|
51
|
+
end
|
@@ -7,68 +7,68 @@ describe ValueComputer do
|
|
7
7
|
@lin_change = Change::Gradual.linear(0.6, 1.0)
|
8
8
|
@sigm_change = Change::Gradual.sigmoid(0.6, 1.0)
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
context "constant value" do
|
12
12
|
before :each do
|
13
13
|
@comp = ValueComputer.new 0.5
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
it "should always return default value if no changes are given" do
|
17
17
|
[ValueComputer::DOMAIN_MIN, -1000, 0, 1, 5, 100, 10000].each do |offset|
|
18
|
-
@comp.at(offset).
|
18
|
+
expect(@comp.at(offset)).to eq(0.5)
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
context "one change, no transition" do
|
24
24
|
before :each do
|
25
25
|
@comp = ValueComputer.new 0.5, 1.0 => @immed_change
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
it "should be the default value just before the first change" do
|
29
|
-
@comp.at(0.999).
|
29
|
+
expect(@comp.at(0.999)).to eq(0.5)
|
30
30
|
end
|
31
|
-
|
31
|
+
|
32
32
|
it "should transition to the second value immediately" do
|
33
|
-
@comp.at(1.0).
|
33
|
+
expect(@comp.at(1.0)).to eq(0.6)
|
34
34
|
end
|
35
35
|
|
36
36
|
it "should be the first value for all time before" do
|
37
|
-
@comp.at(ValueComputer::DOMAIN_MIN).
|
37
|
+
expect(@comp.at(ValueComputer::DOMAIN_MIN)).to eq(0.5)
|
38
38
|
end
|
39
|
-
|
39
|
+
|
40
40
|
it "should be at the second value for all time after" do
|
41
|
-
@comp.at(100_000).
|
41
|
+
expect(@comp.at(100_000)).to eq(0.6)
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
44
|
+
|
45
45
|
context "one change, linear transition" do
|
46
46
|
before :each do
|
47
47
|
@comp = ValueComputer.new 0.2, 1.0 => @lin_change
|
48
48
|
end
|
49
|
-
|
49
|
+
|
50
50
|
it "should be the first (starting) value just before the second value" do
|
51
|
-
@comp.at(0.999).
|
51
|
+
expect(@comp.at(0.999)).to eq(0.2)
|
52
52
|
end
|
53
|
-
|
53
|
+
|
54
54
|
it "should be the first (starting) value exactly at the second value" do
|
55
|
-
@comp.at(1.0).
|
55
|
+
expect(@comp.at(1.0)).to eq(0.2)
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
it "should be 1/4 to the second value after 1/4 transition duration has elapsed" do
|
59
|
-
@comp.at(Rational(5,4).to_f).
|
59
|
+
expect(@comp.at(Rational(5,4).to_f)).to eq(0.3)
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
it "should be 1/2 to the second value after 1/2 transition duration has elapsed" do
|
63
|
-
@comp.at(Rational(6,4).to_f).
|
63
|
+
expect(@comp.at(Rational(6,4).to_f)).to eq(0.4)
|
64
64
|
end
|
65
|
-
|
65
|
+
|
66
66
|
it "should be 3/4 to the second value after 3/4 transition duration has elapsed" do
|
67
|
-
@comp.at(Rational(7,4).to_f).
|
67
|
+
expect(@comp.at(Rational(7,4).to_f)).to eq(0.5)
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
it "should be at the second value after transition duration has elapsed" do
|
71
|
-
@comp.at(Rational(8,4).to_f).
|
71
|
+
expect(@comp.at(Rational(8,4).to_f)).to eq(0.6)
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -76,27 +76,26 @@ describe ValueComputer do
|
|
76
76
|
before :each do
|
77
77
|
@comp = ValueComputer.new 0.2, 1.0 => @sigm_change
|
78
78
|
end
|
79
|
-
|
79
|
+
|
80
80
|
it "should be the first (starting) value just before the second value" do
|
81
|
-
@comp.at(0.999).
|
81
|
+
expect(@comp.at(0.999)).to eq(0.2)
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
it "should be the first (starting) value exactly at the second value" do
|
85
|
-
@comp.at(1.0).
|
85
|
+
expect(@comp.at(1.0)).to eq(0.2)
|
86
86
|
end
|
87
|
-
|
87
|
+
|
88
88
|
it "should be 1/2 to the second value after 1/2 transition duration has elapsed" do
|
89
|
-
@comp.at(1.5).
|
89
|
+
expect(@comp.at(1.5)).to be_within(1e-5).of(0.4)
|
90
90
|
end
|
91
|
-
|
91
|
+
|
92
92
|
it "should be at the second value exactly where transition duration has elapsed" do
|
93
|
-
@comp.at(2).
|
93
|
+
expect(@comp.at(2)).to eq(0.6)
|
94
94
|
end
|
95
|
-
|
95
|
+
|
96
96
|
it "should be at the second value just after transition duration has elapsed" do
|
97
|
-
@comp.at(2.001).
|
98
|
-
end
|
97
|
+
expect(@comp.at(2.001)).to eq(0.6)
|
98
|
+
end
|
99
99
|
end
|
100
100
|
end
|
101
101
|
end
|
102
|
-
|
@@ -15,27 +15,27 @@ describe GlissandoConverter do
|
|
15
15
|
].each do |start,finish|
|
16
16
|
context "start at #{start.to_s}, target #{finish.to_s}" do
|
17
17
|
pitches = GlissandoConverter.glissando_pitches(start,finish)
|
18
|
-
|
18
|
+
|
19
19
|
it 'should begin with start pitch' do
|
20
|
-
pitches.first.
|
20
|
+
expect(pitches.first).to eq(start)
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it 'should move up to next whole (zero-cent) pitches' do
|
24
24
|
(1...pitches.size).each do |i|
|
25
|
-
pitches[i].cent.
|
26
|
-
pitches[i].diff(pitches[i-1]).
|
25
|
+
expect(pitches[i].cent).to eq(0)
|
26
|
+
expect(pitches[i].diff(pitches[i-1])).to be <= 1
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
it 'should end on the whole (zero-cent) pitch below target pitch' do
|
31
|
-
pitches.last.cent.
|
31
|
+
expect(pitches.last.cent).to eq(0)
|
32
32
|
diff = finish.total_cents - pitches.last.total_cents
|
33
|
-
diff.
|
33
|
+
expect(diff).to be <= 100
|
34
34
|
end
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
38
|
+
|
39
39
|
context 'start pitch > target pitch' do
|
40
40
|
[
|
41
41
|
[B3,F3],
|
@@ -48,46 +48,46 @@ describe GlissandoConverter do
|
|
48
48
|
].each do |start,finish|
|
49
49
|
context "start at #{start.to_s}, target #{finish.to_s}" do
|
50
50
|
pitches = GlissandoConverter.glissando_pitches(start,finish)
|
51
|
-
|
51
|
+
|
52
52
|
it 'should move down to next whole (zero-cent) pitches' do
|
53
53
|
(1...pitches.size).each do |i|
|
54
|
-
pitches[i].cent.
|
55
|
-
pitches[i-1].diff(pitches[i]).
|
54
|
+
expect(pitches[i].cent).to eq(0)
|
55
|
+
expect(pitches[i-1].diff(pitches[i])).to be <= 1
|
56
56
|
end
|
57
57
|
end
|
58
|
-
|
58
|
+
|
59
59
|
it 'should end on the whole (zero-cent) pitch above target pitch' do
|
60
|
-
pitches.last.cent.
|
60
|
+
expect(pitches.last.cent).to eq(0)
|
61
61
|
diff = pitches.last.total_cents - finish.total_cents
|
62
|
-
diff.
|
62
|
+
expect(diff).to be <= 100
|
63
63
|
end
|
64
64
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
end
|
68
68
|
end
|
69
|
-
|
69
|
+
|
70
70
|
describe '.glissando_elements' do
|
71
71
|
before :all do
|
72
72
|
@dur = Rational(3,2)
|
73
73
|
@att = Attack::TENUTO
|
74
74
|
@els = GlissandoConverter.glissando_elements(C4,A4,@dur,@att)
|
75
75
|
end
|
76
|
-
|
76
|
+
|
77
77
|
it 'should return an array of NoteSequence::Element objects' do
|
78
|
-
@els.each {|el| el.
|
78
|
+
@els.each {|el| expect(el).to be_a NoteSequence::Element }
|
79
79
|
end
|
80
|
-
|
80
|
+
|
81
81
|
it 'should split up duration among elements' do
|
82
82
|
sum = @els.map {|el| el.duration }.inject(0,:+)
|
83
|
-
sum.
|
83
|
+
expect(sum).to eq(@dur)
|
84
84
|
end
|
85
|
-
|
85
|
+
|
86
86
|
it 'should set attack as given for each element' do
|
87
87
|
els = GlissandoConverter.glissando_elements(C4,A4,1,Attack::TENUTO)
|
88
|
-
els.each {|el| el.attack.
|
88
|
+
els.each {|el| expect(el.attack).to eq(Attack::TENUTO) }
|
89
89
|
els = GlissandoConverter.glissando_elements(C4,A4,1,Attack::ACCENT)
|
90
|
-
els.each {|el| el.attack.
|
90
|
+
els.each {|el| expect(el.attack).to eq(Attack::ACCENT) }
|
91
91
|
end
|
92
92
|
end
|
93
|
-
end
|
93
|
+
end
|
@@ -6,15 +6,15 @@ describe NoteSequenceExtractor do
|
|
6
6
|
it 'should clone original notes' do
|
7
7
|
notes = [ Note.quarter([C2]), Note.half, Note.half ]
|
8
8
|
extr = NoteSequenceExtractor.new(notes)
|
9
|
-
extr.notes[0].
|
9
|
+
expect(extr.notes[0]).to eq(notes[0])
|
10
10
|
notes[0].transpose!(1)
|
11
|
-
extr.notes[0].
|
11
|
+
expect(extr.notes[0]).to_not eq(notes[0])
|
12
12
|
end
|
13
13
|
|
14
14
|
it 'should maintain the same number of notes' do
|
15
15
|
extr = NoteSequenceExtractor.new(
|
16
16
|
[ Note.quarter, Note.half, Note.half ])
|
17
|
-
extr.notes.size.
|
17
|
+
expect(extr.notes.size).to eq 3
|
18
18
|
end
|
19
19
|
|
20
20
|
it 'should remove any links where the source pitch does not exist in the note' do
|
@@ -22,19 +22,19 @@ describe NoteSequenceExtractor do
|
|
22
22
|
[ Note.quarter([E4], links: {C4 => Link::Tie.new}),
|
23
23
|
Note.quarter([C4,E4]) ]
|
24
24
|
)
|
25
|
-
extr.notes[0].links.
|
25
|
+
expect(extr.notes[0].links).to_not have_key(C4)
|
26
26
|
|
27
27
|
extr = NoteSequenceExtractor.new(
|
28
28
|
[ Note.quarter([E4], links: {C4 => Link::Glissando.new(G4)}),
|
29
29
|
Note.quarter([C4,E4,G4]) ]
|
30
30
|
)
|
31
|
-
extr.notes[0].links.
|
31
|
+
expect(extr.notes[0].links).to_not have_key(C4)
|
32
32
|
|
33
33
|
extr = NoteSequenceExtractor.new(
|
34
34
|
[ Note.quarter([E4], links: {C4 => Link::Portamento.new(G4)}),
|
35
35
|
Note.quarter([C4,E4,G4]) ]
|
36
36
|
)
|
37
|
-
extr.notes[0].links.
|
37
|
+
expect(extr.notes[0].links).to_not have_key(C4)
|
38
38
|
end
|
39
39
|
|
40
40
|
it 'should keep glissando/portamento links even when the target pitch does not exist in the next note.' do
|
@@ -42,13 +42,13 @@ describe NoteSequenceExtractor do
|
|
42
42
|
[ Note.quarter([C4], links: {C4 => Link::Glissando.new(G4)}),
|
43
43
|
Note.quarter([E4]) ]
|
44
44
|
)
|
45
|
-
extr.notes[0].links.
|
45
|
+
expect(extr.notes[0].links).to have_key(C4)
|
46
46
|
|
47
47
|
extr = NoteSequenceExtractor.new(
|
48
48
|
[ Note.quarter([C4], links: {C4 => Link::Portamento.new(G4)}),
|
49
49
|
Note.quarter([E4]) ]
|
50
50
|
)
|
51
|
-
extr.notes[0].links.
|
51
|
+
expect(extr.notes[0].links).to have_key(C4)
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
@@ -56,7 +56,7 @@ describe NoteSequenceExtractor do
|
|
56
56
|
context 'empty note array' do
|
57
57
|
it 'should return empty' do
|
58
58
|
seqs = NoteSequenceExtractor.new([]).extract_sequences
|
59
|
-
seqs.
|
59
|
+
expect(seqs).to be_empty
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -64,7 +64,7 @@ describe NoteSequenceExtractor do
|
|
64
64
|
it 'should return empty' do
|
65
65
|
notes = [ Note::quarter, Note::quarter ]
|
66
66
|
seqs = NoteSequenceExtractor.new(notes).extract_sequences
|
67
|
-
seqs.
|
67
|
+
expect(seqs).to be_empty
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
@@ -75,19 +75,19 @@ describe NoteSequenceExtractor do
|
|
75
75
|
end
|
76
76
|
|
77
77
|
it 'should return array with one sequence' do
|
78
|
-
@seqs.size.
|
78
|
+
expect(@seqs.size).to eq 1
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'should have start offset of 0' do
|
82
|
-
@seqs[0].start.
|
82
|
+
expect(@seqs[0].start).to eq 0
|
83
83
|
end
|
84
84
|
|
85
85
|
it 'should have stop offset <= note duration' do
|
86
|
-
@seqs[0].stop.
|
86
|
+
expect(@seqs[0].stop).to be <= @note.duration
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
-
context 'array with two slurred notes, single pitch' do
|
90
|
+
context 'array with two slurred notes, single pitch each' do
|
91
91
|
before :all do
|
92
92
|
@notes = [ Note.quarter([C5], marks: [BEGIN_SLUR]),
|
93
93
|
Note.quarter([D5], marks: [END_SLUR]) ]
|
@@ -95,15 +95,15 @@ describe NoteSequenceExtractor do
|
|
95
95
|
end
|
96
96
|
|
97
97
|
it 'should return array with one sequence' do
|
98
|
-
@seqs.size.
|
98
|
+
expect(@seqs.size).to eq 1
|
99
99
|
end
|
100
100
|
|
101
101
|
it 'should have start offset of 0' do
|
102
|
-
@seqs[0].start.
|
102
|
+
expect(@seqs[0].start).to eq 0
|
103
103
|
end
|
104
104
|
|
105
105
|
it 'should have stop offset <= combined duration of the two notes' do
|
106
|
-
@seqs[0].stop.
|
106
|
+
expect(@seqs[0].stop).to be <= (@notes[0].duration + @notes[1].duration)
|
107
107
|
end
|
108
108
|
end
|
109
109
|
|
@@ -114,30 +114,30 @@ describe NoteSequenceExtractor do
|
|
114
114
|
end
|
115
115
|
|
116
116
|
it 'should return array with as many sequences as pitches' do
|
117
|
-
@seqs.size.
|
117
|
+
expect(@seqs.size).to eq @note.pitches.size
|
118
118
|
end
|
119
119
|
|
120
120
|
it 'should start the sequences at 0' do
|
121
|
-
@seqs.each {|s| s.start.
|
121
|
+
@seqs.each {|s| expect(s.start).to eq(0) }
|
122
122
|
end
|
123
123
|
|
124
124
|
it 'should end each sequence at or before note duration' do
|
125
|
-
@seqs.each {|s| s.stop.
|
125
|
+
@seqs.each {|s| expect(s.stop).to be <= @note.duration }
|
126
126
|
end
|
127
127
|
|
128
128
|
it 'should put one element in each seq' do
|
129
|
-
@seqs.each {|s| s.elements.size.
|
129
|
+
@seqs.each {|s| expect(s.elements.size).to eq(1) }
|
130
130
|
end
|
131
131
|
|
132
132
|
it 'should assign a different pitch to each' do
|
133
|
-
@seqs.map {|seq| seq.elements.first.pitch }.sort.
|
133
|
+
expect(@seqs.map {|seq| seq.elements.first.pitch }.sort).to eq @note.pitches.sort
|
134
134
|
end
|
135
135
|
end
|
136
136
|
|
137
137
|
context 'array with multiple notes and links' do
|
138
138
|
before :all do
|
139
139
|
@notes = [
|
140
|
-
Note.quarter([C3,E3], links: { C3 => Link::Tie.new,
|
140
|
+
Note.quarter([C3,E3], links: { C3 => Link::Tie.new,
|
141
141
|
E3 => Link::Glissando.new(G3)}),
|
142
142
|
Note.eighth([C3,G3])
|
143
143
|
]
|
@@ -145,22 +145,22 @@ describe NoteSequenceExtractor do
|
|
145
145
|
end
|
146
146
|
|
147
147
|
it 'should create a single sequence for linked notes' do
|
148
|
-
@seqs.size.
|
148
|
+
expect(@seqs.size).to eq(2)
|
149
149
|
end
|
150
150
|
|
151
151
|
it 'should set first element pitch to match first note' do
|
152
|
-
@seqs[0].elements.first.pitch.
|
153
|
-
@seqs[1].elements.first.pitch.
|
152
|
+
expect(@seqs[0].elements.first.pitch).to eq(@notes[0].pitches[0])
|
153
|
+
expect(@seqs[1].elements.first.pitch).to eq(@notes[0].pitches[1])
|
154
154
|
end
|
155
155
|
|
156
156
|
it 'should collapse tie link to a single element' do
|
157
|
-
@seqs[0].elements.size.
|
158
|
-
@seqs[0].duration.
|
157
|
+
expect(@seqs[0].elements.size).to eq(1)
|
158
|
+
expect(@seqs[0].duration).to be <= (@notes[0].duration + @notes[1].duration)
|
159
159
|
end
|
160
160
|
|
161
161
|
it 'should expand the glissando into multiple elements' do
|
162
|
-
@seqs[1].elements.size.
|
163
|
-
@seqs[1].duration.
|
162
|
+
expect(@seqs[1].elements.size).to be > 2
|
163
|
+
expect(@seqs[1].duration).to be <= (@notes[0].duration + @notes[1].duration)
|
164
164
|
end
|
165
165
|
end
|
166
166
|
|
@@ -171,15 +171,15 @@ describe NoteSequenceExtractor do
|
|
171
171
|
end
|
172
172
|
|
173
173
|
it 'should produce one sequence' do
|
174
|
-
@seqs.size.
|
174
|
+
expect(@seqs.size).to eq(1)
|
175
175
|
end
|
176
176
|
|
177
177
|
it 'should include pitches up to (not including) target pitch' do
|
178
|
-
@seqs[0].elements.map{|e| e.pitch}.
|
178
|
+
expect(@seqs[0].elements.map{|e| e.pitch}).to include(D3,Eb3,E3,F3,Gb3)
|
179
179
|
end
|
180
180
|
|
181
181
|
it 'should produce sequence with duration <= note duration' do
|
182
|
-
@seqs[0].duration.
|
182
|
+
expect(@seqs[0].duration).to be <= @note.duration
|
183
183
|
end
|
184
184
|
end
|
185
185
|
|
@@ -190,15 +190,15 @@ describe NoteSequenceExtractor do
|
|
190
190
|
end
|
191
191
|
|
192
192
|
it 'should produce one sequence' do
|
193
|
-
@seqs.size.
|
193
|
+
expect(@seqs.size).to eq(1)
|
194
194
|
end
|
195
195
|
|
196
196
|
it 'should include pitches down to (not including) target pitch' do
|
197
|
-
@seqs[0].elements.map{|e| e.pitch}.
|
197
|
+
expect(@seqs[0].elements.map{|e| e.pitch}).to include(D3,Db3,C3,B2,Bb2)
|
198
198
|
end
|
199
199
|
|
200
200
|
it 'should produce sequence with duration <= note duration' do
|
201
|
-
@seqs[0].duration.
|
201
|
+
expect(@seqs[0].duration).to be <= @note.duration
|
202
202
|
end
|
203
203
|
end
|
204
204
|
|
@@ -210,15 +210,15 @@ describe NoteSequenceExtractor do
|
|
210
210
|
end
|
211
211
|
|
212
212
|
it 'should produce a single sequence' do
|
213
|
-
@seqs.size.
|
213
|
+
expect(@seqs.size).to eq(1)
|
214
214
|
end
|
215
215
|
|
216
216
|
it 'should includes pitches up through target pitch' do
|
217
|
-
@seqs[0].elements.map{|e| e.pitch}.
|
217
|
+
expect(@seqs[0].elements.map{|e| e.pitch}).to include(D3,Eb3,E3,F3,Gb3,G3)
|
218
218
|
end
|
219
219
|
|
220
220
|
it 'should produce sequence with duration <= note1dur + note2dur' do
|
221
|
-
@seqs[0].duration.
|
221
|
+
expect(@seqs[0].duration).to be <= (@notes[0].duration + @notes[1].duration)
|
222
222
|
end
|
223
223
|
end
|
224
224
|
|