musicality 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/ChangeLog.md +27 -1
- data/README.md +153 -10
- data/bin/collidify +102 -0
- data/bin/lilify +57 -29
- data/bin/midify +64 -24
- data/bin/musicality +39 -0
- data/examples/composition/auto_counterpoint.rb +4 -5
- data/examples/composition/part_generator.rb +8 -2
- data/examples/composition/scale_exercise.rb +1 -1
- data/examples/notation/notes.rb +27 -0
- data/examples/notation/parts.rb +51 -0
- data/examples/notation/scores.rb +38 -0
- data/examples/notation/twinkle.rb +34 -0
- data/examples/notation/twinkle.score +33 -0
- data/lib/musicality.rb +46 -11
- data/lib/musicality/composition/dsl/score_dsl.rb +2 -2
- data/lib/musicality/composition/dsl/score_methods.rb +10 -7
- data/lib/musicality/notation/conversion/change_conversion.rb +1 -1
- data/lib/musicality/notation/conversion/note_time_converter.rb +6 -23
- data/lib/musicality/notation/conversion/score_conversion.rb +15 -15
- data/lib/musicality/notation/conversion/score_converter.rb +50 -67
- data/lib/musicality/notation/model/articulations.rb +3 -2
- data/lib/musicality/notation/model/change.rb +15 -6
- data/lib/musicality/notation/model/dynamics.rb +11 -8
- data/lib/musicality/notation/model/instrument.rb +61 -0
- data/lib/musicality/notation/model/instruments.rb +111 -0
- data/lib/musicality/notation/model/key.rb +137 -0
- data/lib/musicality/notation/model/keys.rb +37 -0
- data/lib/musicality/notation/model/link.rb +6 -19
- data/lib/musicality/notation/model/mark.rb +43 -0
- data/lib/musicality/notation/model/marks.rb +11 -0
- data/lib/musicality/notation/model/meter.rb +4 -0
- data/lib/musicality/notation/model/note.rb +42 -28
- data/lib/musicality/notation/model/part.rb +18 -5
- data/lib/musicality/notation/model/pitch.rb +13 -4
- data/lib/musicality/notation/model/score.rb +104 -66
- data/lib/musicality/notation/model/symbols.rb +16 -11
- data/lib/musicality/notation/parsing/articulation_parsing.rb +38 -38
- data/lib/musicality/notation/parsing/articulation_parsing.treetop +14 -14
- data/lib/musicality/notation/parsing/link_parsing.rb +6 -6
- data/lib/musicality/notation/parsing/link_parsing.treetop +3 -3
- data/lib/musicality/notation/parsing/mark_parsing.rb +138 -0
- data/lib/musicality/notation/parsing/mark_parsing.treetop +31 -0
- data/lib/musicality/notation/parsing/note_node.rb +19 -12
- data/lib/musicality/notation/parsing/note_parsing.rb +218 -87
- data/lib/musicality/notation/parsing/note_parsing.treetop +9 -5
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +7 -2
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +6 -4
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +1 -1
- data/lib/musicality/notation/util/function.rb +41 -18
- data/lib/musicality/packable.rb +156 -0
- data/lib/musicality/performance/conversion/glissando_converter.rb +2 -2
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +223 -70
- data/lib/musicality/performance/conversion/portamento_converter.rb +5 -2
- data/lib/musicality/performance/conversion/score_collator.rb +70 -64
- data/lib/musicality/performance/midi/midi_events.rb +3 -3
- data/lib/musicality/performance/midi/midi_settings.rb +127 -0
- data/lib/musicality/performance/midi/midi_util.rb +8 -2
- data/lib/musicality/performance/midi/part_sequencer.rb +19 -18
- data/lib/musicality/performance/midi/score_sequencer.rb +13 -9
- data/lib/musicality/performance/midi/score_sequencing.rb +5 -5
- data/lib/musicality/performance/model/attack.rb +8 -0
- data/lib/musicality/performance/model/duration_functions.rb +23 -0
- data/lib/musicality/performance/model/note_sequence.rb +52 -95
- data/lib/musicality/performance/model/separation.rb +10 -0
- data/lib/musicality/performance/supercollider/add_actions.rb +13 -0
- data/lib/musicality/performance/supercollider/bundle.rb +18 -0
- data/lib/musicality/performance/supercollider/conductor.rb +125 -0
- data/lib/musicality/performance/supercollider/group.rb +71 -0
- data/lib/musicality/performance/supercollider/message.rb +26 -0
- data/lib/musicality/performance/supercollider/node.rb +122 -0
- data/lib/musicality/performance/supercollider/performer.rb +123 -0
- data/lib/musicality/performance/supercollider/score_conducting.rb +17 -0
- data/lib/musicality/performance/supercollider/server.rb +8 -0
- data/lib/musicality/performance/supercollider/synth.rb +43 -0
- data/lib/musicality/performance/supercollider/synthdef.rb +57 -0
- data/lib/musicality/performance/supercollider/synthdef_settings.rb +23 -0
- data/lib/musicality/performance/supercollider/synthdefs.rb +1654 -0
- data/lib/musicality/{composition/model/pitch_class.rb → pitch_class.rb} +1 -1
- data/lib/musicality/{composition/model/pitch_classes.rb → pitch_classes.rb} +9 -9
- data/lib/musicality/printing/lilypond/clef.rb +12 -0
- data/lib/musicality/printing/lilypond/key_engraving.rb +9 -0
- data/lib/musicality/printing/lilypond/lilypond_settings.rb +105 -0
- data/lib/musicality/printing/lilypond/meter_engraving.rb +1 -1
- data/lib/musicality/printing/lilypond/note_engraving.rb +112 -30
- data/lib/musicality/printing/lilypond/part_engraver.rb +114 -3
- data/lib/musicality/printing/lilypond/pitch_class_engraving.rb +22 -0
- data/lib/musicality/printing/lilypond/pitch_engraving.rb +2 -15
- data/lib/musicality/printing/lilypond/score_engraver.rb +44 -73
- data/lib/musicality/printing/lilypond/score_engraving.rb +3 -3
- data/lib/musicality/project/create_tasks.rb +31 -0
- data/lib/musicality/project/file_cleaner.rb +19 -0
- data/lib/musicality/project/file_raker.rb +107 -0
- data/lib/musicality/project/load_config.rb +43 -0
- data/lib/musicality/project/project.rb +64 -0
- data/lib/musicality/version.rb +1 -1
- data/musicality.gemspec +3 -0
- data/spec/composition/util/random_sampler_spec.rb +1 -1
- data/spec/notation/conversion/measure_note_map_spec.rb +1 -1
- data/spec/notation/conversion/note_time_converter_spec.rb +5 -85
- data/spec/notation/conversion/score_conversion_spec.rb +6 -41
- data/spec/notation/conversion/score_converter_spec.rb +19 -137
- data/spec/notation/model/change_spec.rb +55 -0
- data/spec/notation/model/key_spec.rb +171 -0
- data/spec/notation/model/link_spec.rb +34 -5
- data/spec/notation/model/meter_spec.rb +15 -0
- data/spec/notation/model/note_spec.rb +33 -27
- data/spec/notation/model/part_spec.rb +53 -4
- data/spec/notation/model/pitch_spec.rb +15 -0
- data/spec/notation/model/score_spec.rb +64 -72
- data/spec/notation/parsing/link_nodes_spec.rb +3 -3
- data/spec/notation/parsing/link_parsing_spec.rb +6 -6
- data/spec/notation/parsing/note_node_spec.rb +34 -9
- data/spec/notation/parsing/note_parsing_spec.rb +11 -9
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +4 -0
- data/spec/notation/parsing/pitch_node_spec.rb +0 -1
- data/spec/notation/util/value_computer_spec.rb +2 -2
- data/spec/performance/conversion/glissando_converter_spec.rb +9 -9
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +48 -53
- data/spec/performance/conversion/portamento_converter_spec.rb +11 -9
- data/spec/performance/conversion/score_collator_spec.rb +59 -63
- data/spec/performance/midi/midi_util_spec.rb +22 -8
- data/spec/performance/midi/part_sequencer_spec.rb +2 -2
- data/spec/performance/midi/score_sequencer_spec.rb +12 -10
- data/spec/performance/midi/score_sequencing_spec.rb +2 -2
- data/spec/performance/model/note_sequence_spec.rb +41 -134
- data/spec/printing/note_engraving_spec.rb +204 -0
- data/spec/printing/score_engraver_spec.rb +40 -0
- data/spec/spec_helper.rb +1 -0
- metadata +69 -23
- data/examples/notation/hip.rb +0 -32
- data/examples/notation/missed_connection.rb +0 -26
- data/examples/notation/song1.rb +0 -33
- data/examples/notation/song2.rb +0 -32
- data/lib/musicality/notation/model/links.rb +0 -11
- data/lib/musicality/notation/packing/change_packing.rb +0 -56
- data/lib/musicality/notation/packing/part_packing.rb +0 -31
- data/lib/musicality/notation/packing/score_packing.rb +0 -123
- data/lib/musicality/performance/model/note_attacks.rb +0 -19
- data/lib/musicality/performance/util/note_linker.rb +0 -28
- data/spec/notation/packing/change_packing_spec.rb +0 -304
- data/spec/notation/packing/part_packing_spec.rb +0 -66
- data/spec/notation/packing/score_packing_spec.rb +0 -255
- data/spec/performance/util/note_linker_spec.rb +0 -68
@@ -17,54 +17,38 @@ describe NoteSequenceExtractor do
|
|
17
17
|
extr.notes.size.should eq 3
|
18
18
|
end
|
19
19
|
|
20
|
-
it 'should remove any
|
20
|
+
it 'should remove any links where the source pitch does not exist in the note' do
|
21
21
|
extr = NoteSequenceExtractor.new(
|
22
|
-
[ Note.quarter([
|
23
|
-
Note.quarter([E4]) ]
|
22
|
+
[ Note.quarter([E4], links: {C4 => Link::Tie.new}),
|
23
|
+
Note.quarter([C4,E4]) ]
|
24
24
|
)
|
25
25
|
extr.notes[0].links.should_not have_key(C4)
|
26
|
-
end
|
27
26
|
|
28
|
-
it 'should replace any good ties with slurs' do
|
29
27
|
extr = NoteSequenceExtractor.new(
|
30
|
-
[ Note.quarter([
|
31
|
-
Note.quarter([C4,E4]) ]
|
28
|
+
[ Note.quarter([E4], links: {C4 => Link::Glissando.new(G4)}),
|
29
|
+
Note.quarter([C4,E4,G4]) ]
|
32
30
|
)
|
33
|
-
extr.notes[0].links
|
34
|
-
extr.notes[0].links[E4].should be_a Link::Slur
|
35
|
-
end
|
31
|
+
extr.notes[0].links.should_not have_key(C4)
|
36
32
|
|
37
|
-
it 'should remove dead slur/legato (where target pitch is non-existent)' do
|
38
33
|
extr = NoteSequenceExtractor.new(
|
39
|
-
[ Note.quarter([
|
40
|
-
Note.quarter([C4]) ]
|
34
|
+
[ Note.quarter([E4], links: {C4 => Link::Portamento.new(G4)}),
|
35
|
+
Note.quarter([C4,E4,G4]) ]
|
41
36
|
)
|
42
|
-
extr.notes[0].links.
|
37
|
+
extr.notes[0].links.should_not have_key(C4)
|
43
38
|
end
|
44
39
|
|
45
|
-
it 'should
|
40
|
+
it 'should keep glissando/portamento links even when the target pitch does not exist in the next note.' do
|
46
41
|
extr = NoteSequenceExtractor.new(
|
47
|
-
[ Note.quarter([C4
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
}),
|
52
|
-
Note.quarter([C4,D4,E4,F4,G4])
|
53
|
-
])
|
54
|
-
extr.notes[0].links.should be_empty
|
55
|
-
end
|
42
|
+
[ Note.quarter([C4], links: {C4 => Link::Glissando.new(G4)}),
|
43
|
+
Note.quarter([E4]) ]
|
44
|
+
)
|
45
|
+
extr.notes[0].links.should have_key(C4)
|
56
46
|
|
57
|
-
it 'should not remove portamento and glissando with non-existent target pitches' do
|
58
47
|
extr = NoteSequenceExtractor.new(
|
59
|
-
[ Note.quarter([C4,
|
60
|
-
Note.quarter([
|
61
|
-
C4 => Link::Tie.new, D4 => Link::Slur.new(Eb4),
|
62
|
-
E4 => Link::Legato.new(Gb4), F4 => Link::Glissando.new(A5),
|
63
|
-
G4 => Link::Portamento.new(Bb5)}) ]
|
48
|
+
[ Note.quarter([C4], links: {C4 => Link::Portamento.new(G4)}),
|
49
|
+
Note.quarter([E4]) ]
|
64
50
|
)
|
65
|
-
extr.notes[
|
66
|
-
extr.notes[-1].links.should have_key(F4)
|
67
|
-
extr.notes[-1].links.should have_key(G4)
|
51
|
+
extr.notes[0].links.should have_key(C4)
|
68
52
|
end
|
69
53
|
end
|
70
54
|
|
@@ -94,18 +78,19 @@ describe NoteSequenceExtractor do
|
|
94
78
|
@seqs.size.should eq 1
|
95
79
|
end
|
96
80
|
|
97
|
-
it 'should start offset 0' do
|
81
|
+
it 'should have start offset of 0' do
|
98
82
|
@seqs[0].start.should eq 0
|
99
83
|
end
|
100
84
|
|
101
|
-
it 'should stop offset <= note duration' do
|
85
|
+
it 'should have stop offset <= note duration' do
|
102
86
|
@seqs[0].stop.should be <= @note.duration
|
103
87
|
end
|
104
88
|
end
|
105
89
|
|
106
90
|
context 'array with two slurred notes, single pitch' do
|
107
91
|
before :all do
|
108
|
-
@notes = [ Note.quarter([C5],
|
92
|
+
@notes = [ Note.quarter([C5], marks: [BEGIN_SLUR]),
|
93
|
+
Note.quarter([D5], marks: [END_SLUR]) ]
|
109
94
|
@seqs = NoteSequenceExtractor.new(@notes).extract_sequences
|
110
95
|
end
|
111
96
|
|
@@ -113,11 +98,11 @@ describe NoteSequenceExtractor do
|
|
113
98
|
@seqs.size.should eq 1
|
114
99
|
end
|
115
100
|
|
116
|
-
it 'should start offset 0' do
|
101
|
+
it 'should have start offset of 0' do
|
117
102
|
@seqs[0].start.should eq 0
|
118
103
|
end
|
119
104
|
|
120
|
-
it 'should stop offset <= combined duration of the two notes' do
|
105
|
+
it 'should have stop offset <= combined duration of the two notes' do
|
121
106
|
@seqs[0].stop.should be <= (@notes[0].duration + @notes[1].duration)
|
122
107
|
end
|
123
108
|
end
|
@@ -140,32 +125,42 @@ describe NoteSequenceExtractor do
|
|
140
125
|
@seqs.each {|s| s.stop.should be <= @note.duration }
|
141
126
|
end
|
142
127
|
|
143
|
-
it 'should put one
|
144
|
-
@seqs.each {|s| s.
|
128
|
+
it 'should put one element in each seq' do
|
129
|
+
@seqs.each {|s| s.elements.size.should eq(1) }
|
145
130
|
end
|
146
131
|
|
147
132
|
it 'should assign a different pitch to each' do
|
148
|
-
@seqs.map {|seq| seq.
|
133
|
+
@seqs.map {|seq| seq.elements.first.pitch }.sort.should eq @note.pitches.sort
|
149
134
|
end
|
150
135
|
end
|
151
136
|
|
152
137
|
context 'array with multiple notes and links' do
|
153
138
|
before :all do
|
154
|
-
@notes = [
|
155
|
-
|
156
|
-
|
139
|
+
@notes = [
|
140
|
+
Note.quarter([C3,E3], links: { C3 => Link::Tie.new,
|
141
|
+
E3 => Link::Glissando.new(G3)}),
|
142
|
+
Note.eighth([C3,G3])
|
143
|
+
]
|
157
144
|
@seqs = NoteSequenceExtractor.new(@notes).extract_sequences
|
158
145
|
end
|
159
146
|
|
160
|
-
it 'should create a sequence for linked notes' do
|
147
|
+
it 'should create a single sequence for linked notes' do
|
161
148
|
@seqs.size.should eq(2)
|
162
149
|
end
|
163
150
|
|
164
|
-
it 'should
|
165
|
-
@seqs[0].
|
166
|
-
@
|
167
|
-
|
168
|
-
|
151
|
+
it 'should set first element pitch to match first note' do
|
152
|
+
@seqs[0].elements.first.pitch.should eq(@notes[0].pitches[0])
|
153
|
+
@seqs[1].elements.first.pitch.should eq(@notes[0].pitches[1])
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should collapse tie link to a single element' do
|
157
|
+
@seqs[0].elements.size.should eq(1)
|
158
|
+
@seqs[0].duration.should be <= (@notes[0].duration + @notes[1].duration)
|
159
|
+
end
|
160
|
+
|
161
|
+
it 'should expand the glissando into multiple elements' do
|
162
|
+
@seqs[1].elements.size.should be > 2
|
163
|
+
@seqs[1].duration.should be <= (@notes[0].duration + @notes[1].duration)
|
169
164
|
end
|
170
165
|
end
|
171
166
|
|
@@ -180,7 +175,7 @@ describe NoteSequenceExtractor do
|
|
180
175
|
end
|
181
176
|
|
182
177
|
it 'should include pitches up to (not including) target pitch' do
|
183
|
-
@seqs[0].
|
178
|
+
@seqs[0].elements.map{|e| e.pitch}.should include(D3,Eb3,E3,F3,Gb3)
|
184
179
|
end
|
185
180
|
|
186
181
|
it 'should produce sequence with duration <= note duration' do
|
@@ -199,7 +194,7 @@ describe NoteSequenceExtractor do
|
|
199
194
|
end
|
200
195
|
|
201
196
|
it 'should include pitches down to (not including) target pitch' do
|
202
|
-
@seqs[0].
|
197
|
+
@seqs[0].elements.map{|e| e.pitch}.should include(D3,Db3,C3,B2,Bb2)
|
203
198
|
end
|
204
199
|
|
205
200
|
it 'should produce sequence with duration <= note duration' do
|
@@ -219,7 +214,7 @@ describe NoteSequenceExtractor do
|
|
219
214
|
end
|
220
215
|
|
221
216
|
it 'should includes pitches up through target pitch' do
|
222
|
-
@seqs[0].
|
217
|
+
@seqs[0].elements.map{|e| e.pitch}.should include(D3,Eb3,E3,F3,Gb3,G3)
|
223
218
|
end
|
224
219
|
|
225
220
|
it 'should produce sequence with duration <= note1dur + note2dur' do
|
@@ -68,12 +68,12 @@ describe PortamentoConverter do
|
|
68
68
|
describe '.portamento_elements' do
|
69
69
|
before :all do
|
70
70
|
@dur = Rational(3,2)
|
71
|
-
@
|
72
|
-
@els = PortamentoConverter.portamento_elements(C4,F4,25,@dur,@
|
71
|
+
@att = Attack::NONE
|
72
|
+
@els = PortamentoConverter.portamento_elements(C4,F4,25,@dur,@att)
|
73
73
|
end
|
74
74
|
|
75
|
-
it 'should return an array of
|
76
|
-
@els.each {|el| el.should be_a
|
75
|
+
it 'should return an array of NoteSequence::Element objects' do
|
76
|
+
@els.each {|el| el.should be_a NoteSequence::Element }
|
77
77
|
end
|
78
78
|
|
79
79
|
it 'should split up duration among elements' do
|
@@ -81,11 +81,13 @@ describe PortamentoConverter do
|
|
81
81
|
sum.should eq(@dur)
|
82
82
|
end
|
83
83
|
|
84
|
-
it 'should set
|
85
|
-
els = PortamentoConverter.portamento_elements(C4,D4,10,1,
|
86
|
-
els.
|
87
|
-
els
|
88
|
-
els
|
84
|
+
it 'should set attack as given for first element only and set others to NONE' do
|
85
|
+
els = PortamentoConverter.portamento_elements(C4,D4,10,1,Attack::ACCENT)
|
86
|
+
els.first.attack.should eq(Attack::ACCENT)
|
87
|
+
els[1..-1].each {|el| el.attack.should eq(Attack::NONE) }
|
88
|
+
els = PortamentoConverter.portamento_elements(C4,D4,10,1,Attack::TENUTO)
|
89
|
+
els.first.attack.should eq(Attack::TENUTO)
|
90
|
+
els[1..-1].each {|el| el.attack.should eq(Attack::NONE) }
|
89
91
|
end
|
90
92
|
end
|
91
93
|
end
|
@@ -13,31 +13,31 @@ describe ScoreCollator do
|
|
13
13
|
context 'first note starts before the segment start' do
|
14
14
|
context 'first note ends right at segment start' do
|
15
15
|
it 'should not be included in the part' do
|
16
|
-
score = Score::
|
16
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
17
17
|
parts: {1 => @part},
|
18
18
|
program: ["1/4".to_r..."5/4".to_r])
|
19
19
|
collator = ScoreCollator.new(score)
|
20
20
|
parts = collator.collate_parts
|
21
21
|
notes = parts[1].notes
|
22
|
-
notes.size.
|
23
|
-
notes[0].pitches[0].
|
24
|
-
notes[1].pitches[0].
|
22
|
+
expect(notes.size).to eq(@part.notes.size - 1)
|
23
|
+
expect(notes[0].pitches[0]).to eq D2
|
24
|
+
expect(notes[1].pitches[0]).to eq E2
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
28
|
context 'first note ends after segment start' do
|
29
29
|
it 'should not be included in the part, and a rest is inserted' do
|
30
|
-
score = Score::
|
30
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
31
31
|
parts: {1 => @part},
|
32
32
|
program: ["1/8".to_r..."5/4".to_r])
|
33
33
|
collator = ScoreCollator.new(score)
|
34
34
|
parts = collator.collate_parts
|
35
35
|
notes = parts[1].notes
|
36
|
-
notes.size.
|
37
|
-
notes[0].pitches.
|
38
|
-
notes[0].duration.
|
39
|
-
notes[1].pitches[0].
|
40
|
-
notes[2].pitches[0].
|
36
|
+
expect(notes.size).to eq(@part.notes.size)
|
37
|
+
expect(notes[0].pitches).to be_empty
|
38
|
+
expect(notes[0].duration).to eq "1/8".to_r
|
39
|
+
expect(notes[1].pitches[0]).to eq D2
|
40
|
+
expect(notes[2].pitches[0]).to eq E2
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -45,47 +45,47 @@ describe ScoreCollator do
|
|
45
45
|
context 'first note starts at segment start' do
|
46
46
|
context 'last note starts at program end' do
|
47
47
|
it 'should not be included in the part' do
|
48
|
-
score = Score::
|
48
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
49
49
|
parts: {1 => @part},
|
50
50
|
program: [0.to_r..."3/4".to_r])
|
51
51
|
collator = ScoreCollator.new(score)
|
52
52
|
parts = collator.collate_parts
|
53
53
|
notes = parts[1].notes
|
54
|
-
notes.size.
|
54
|
+
expect(notes.size).to eq(@part.notes.size - 1)
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
58
|
context 'last note start before program end, but lasts until after' do
|
59
59
|
it 'should be included in the part, but truncated' do
|
60
|
-
score = Score::
|
60
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
61
61
|
parts: {1 => @part},
|
62
62
|
program: [0.to_r...1.to_r])
|
63
63
|
collator = ScoreCollator.new(score)
|
64
64
|
parts = collator.collate_parts
|
65
65
|
notes = parts[1].notes
|
66
|
-
notes.size.
|
67
|
-
notes[-1].duration.
|
66
|
+
expect(notes.size).to eq(@part.notes.size)
|
67
|
+
expect(notes[-1].duration).to eq("1/4".to_r)
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
71
|
context 'last note ends before program segment end' do
|
72
72
|
it 'should insert a rest between last note end and segment end' do
|
73
|
-
score = Score::
|
73
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
74
74
|
parts: {1 => @part},
|
75
75
|
program: [0.to_r..."6/4".to_r])
|
76
76
|
collator = ScoreCollator.new(score)
|
77
77
|
parts = collator.collate_parts
|
78
78
|
notes = parts[1].notes
|
79
|
-
notes.size.
|
80
|
-
notes[-1].pitches.
|
81
|
-
notes[-1].duration.
|
79
|
+
expect(notes.size).to eq(@part.notes.size + 1)
|
80
|
+
expect(notes[-1].pitches).to be_empty
|
81
|
+
expect(notes[-1].duration).to eq("1/4".to_r)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
86
|
context 'part contains trimmed gradual changes' do
|
87
87
|
it 'should exclude the change when it is not at all in a program segment' do
|
88
|
-
score = Score::
|
88
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
89
89
|
parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
|
90
90
|
2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,0)
|
91
91
|
}) },
|
@@ -94,19 +94,19 @@ describe ScoreCollator do
|
|
94
94
|
collator = ScoreCollator.new(score)
|
95
95
|
parts = collator.collate_parts
|
96
96
|
dcs = parts[1].dynamic_changes
|
97
|
-
dcs.size.
|
98
|
-
|
97
|
+
expect(dcs.size).to eq(0)
|
98
|
+
expect(parts[1].start_dynamic).to be_within(1e-5).of(Dynamics::PP)
|
99
99
|
|
100
100
|
score.program = [0...1]
|
101
101
|
collator = ScoreCollator.new(score)
|
102
102
|
parts = collator.collate_parts
|
103
103
|
dcs = parts[1].dynamic_changes
|
104
|
-
dcs.size.
|
105
|
-
|
104
|
+
expect(dcs.size).to eq(0)
|
105
|
+
expect(parts[1].start_dynamic).to be_within(1e-5).of(Dynamics::FF)
|
106
106
|
end
|
107
107
|
|
108
108
|
it 'should trim the change further if needed' do
|
109
|
-
score = Score::
|
109
|
+
score = Score::Tempo.new(FOUR_FOUR, 120,
|
110
110
|
parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
|
111
111
|
2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,1)
|
112
112
|
}) },
|
@@ -115,14 +115,14 @@ describe ScoreCollator do
|
|
115
115
|
collator = ScoreCollator.new(score)
|
116
116
|
parts = collator.collate_parts
|
117
117
|
dcs = parts[1].dynamic_changes
|
118
|
-
dcs.size.
|
119
|
-
dcs[0.to_r].
|
118
|
+
expect(dcs.size).to eq(1)
|
119
|
+
expect(dcs[0.to_r]).to eq(Change::Gradual.linear(Dynamics::PP,5).trim(2,2))
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
123
|
it 'should preserve links' do
|
124
|
-
notes = Note.split_parse("1Db4
|
125
|
-
score = Score::
|
124
|
+
notes = Note.split_parse("1Db4;Bb4")
|
125
|
+
score = Score::Tempo.new(
|
126
126
|
FOUR_FOUR,120,
|
127
127
|
parts: { "lead" => Part.new(Dynamics::MP, notes: notes) },
|
128
128
|
program: [0..1,0..1],
|
@@ -131,10 +131,10 @@ describe ScoreCollator do
|
|
131
131
|
parts = collator.collate_parts
|
132
132
|
|
133
133
|
notes = parts["lead"].notes
|
134
|
-
notes.size.
|
134
|
+
expect(notes.size).to eq 2
|
135
135
|
notes.each do |note|
|
136
|
-
note.links.
|
137
|
-
note.links[Db4].
|
136
|
+
expect(note.links).to have_key(Db4)
|
137
|
+
expect(note.links[Db4]).to be_a Link::Glissando
|
138
138
|
end
|
139
139
|
end
|
140
140
|
end
|
@@ -148,59 +148,56 @@ describe ScoreCollator do
|
|
148
148
|
|
149
149
|
context 'tempo change starts at end of program segment' do
|
150
150
|
it 'should not be included in the tempo changes' do
|
151
|
-
score = Score::
|
152
|
-
1 => @change1, 2 => @change2 }, program: [0
|
151
|
+
score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
|
152
|
+
1 => @change1, 2 => @change2 }, program: [0...2])
|
153
153
|
collator = ScoreCollator.new(score)
|
154
|
-
tcs = collator.collate_tempo_changes
|
155
|
-
tcs.size.
|
156
|
-
tcs[
|
157
|
-
tcs[1.to_r].should eq @change1
|
154
|
+
st, tcs = collator.collate_tempo_changes
|
155
|
+
expect(tcs.size).to eq 1
|
156
|
+
expect(tcs[1.to_r]).to eq @change1
|
158
157
|
end
|
159
158
|
end
|
160
159
|
|
161
160
|
context 'tempo change starts and ends before segment' do
|
162
161
|
before :all do
|
163
|
-
score = Score::
|
162
|
+
score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
|
164
163
|
2 => @change2 }, program: [4..5])
|
165
164
|
collator = ScoreCollator.new(score)
|
166
|
-
@tcs = collator.collate_tempo_changes
|
165
|
+
@st, @tcs = collator.collate_tempo_changes
|
167
166
|
end
|
168
167
|
|
169
168
|
it 'should not be included in the tempo changes' do
|
170
|
-
@tcs.size.
|
171
|
-
@tcs[0.to_r].should be_a Change::Immediate
|
169
|
+
expect(@tcs.size).to eq 0
|
172
170
|
end
|
173
171
|
|
174
|
-
it 'should be used as
|
175
|
-
@
|
172
|
+
it 'should be used as start tempo' do
|
173
|
+
expect(@st).to be_within(1e-5).of @change2.end_value
|
176
174
|
end
|
177
175
|
end
|
178
176
|
|
179
177
|
context 'tempo change starts before segment, but ends during segment' do
|
180
178
|
it 'should e included in the tempo changes, but truncated' do
|
181
|
-
score = Score::
|
179
|
+
score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
|
182
180
|
1.5.to_r => @change2 }, program: [2..4])
|
183
181
|
collator = ScoreCollator.new(score)
|
184
|
-
tcs = collator.collate_tempo_changes
|
185
|
-
tcs.size.
|
186
|
-
tcs[0.to_r].
|
187
|
-
tcs[0.to_r].end_value.
|
188
|
-
tcs[0.to_r].remaining.
|
182
|
+
st, tcs = collator.collate_tempo_changes
|
183
|
+
expect(tcs.size).to eq 1
|
184
|
+
expect(tcs[0.to_r]).to be_a Change::Gradual::Trimmed
|
185
|
+
expect(tcs[0.to_r].end_value).to eq @change2.end_value
|
186
|
+
expect(tcs[0.to_r].remaining).to eq(0.5)
|
189
187
|
end
|
190
188
|
end
|
191
189
|
|
192
190
|
context 'tempo change starts during segment, lasts until after' do
|
193
191
|
it 'should be included in the tempo changes, but truncated' do
|
194
|
-
score = Score::
|
192
|
+
score = Score::Tempo.new(FOUR_FOUR, 120, tempo_changes: {
|
195
193
|
1 => @change1, 2 => @change2 }, program: [0..2.5])
|
196
194
|
collator = ScoreCollator.new(score)
|
197
|
-
tcs = collator.collate_tempo_changes
|
198
|
-
tcs.size.
|
199
|
-
tcs[
|
200
|
-
tcs[
|
201
|
-
tcs[2.to_r].
|
202
|
-
tcs[2.to_r].
|
203
|
-
tcs[2.to_r].remaining.should eq(0.5)
|
195
|
+
st, tcs = collator.collate_tempo_changes
|
196
|
+
expect(tcs.size).to eq 2
|
197
|
+
expect(tcs[1.to_r]).to eq @change1
|
198
|
+
expect(tcs[2.to_r]).to be_a Change::Gradual::Trimmed
|
199
|
+
expect(tcs[2.to_r].end_value).to eq @change2.end_value
|
200
|
+
expect(tcs[2.to_r].remaining).to eq(0.5)
|
204
201
|
end
|
205
202
|
end
|
206
203
|
end
|
@@ -210,13 +207,12 @@ describe ScoreCollator do
|
|
210
207
|
change0 = Change::Immediate.new(FOUR_FOUR)
|
211
208
|
change1 = Change::Immediate.new(THREE_FOUR)
|
212
209
|
change2 = Change::Immediate.new(SIX_EIGHT)
|
213
|
-
score = Score::
|
210
|
+
score = Score::Tempo.new(FOUR_FOUR, 120, meter_changes: {
|
214
211
|
1 => change1, 2 => change2 }, program: [0...2])
|
215
212
|
collator = ScoreCollator.new(score)
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
tcs[1.to_r].should eq change1
|
213
|
+
sm, mcs = collator.collate_meter_changes
|
214
|
+
expect(mcs.size).to eq 1
|
215
|
+
expect(mcs[1.to_r]).to eq change1
|
220
216
|
end
|
221
217
|
end
|
222
218
|
end
|