musicality 0.11.1 → 0.12.0
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.
- 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
|
|