musicality 0.8.0 → 0.9.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 +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
|