musicality 0.2.0 → 0.3.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 +30 -0
- data/lib/musicality/errors.rb +1 -0
- data/lib/musicality/notation/conversion/change_conversion.rb +63 -3
- data/lib/musicality/notation/conversion/note_time_converter.rb +23 -5
- data/lib/musicality/notation/conversion/score_conversion.rb +60 -0
- data/lib/musicality/notation/conversion/score_converter.rb +105 -0
- data/lib/musicality/notation/model/change.rb +98 -28
- data/lib/musicality/notation/model/part.rb +1 -1
- data/lib/musicality/notation/model/score.rb +4 -4
- data/lib/musicality/notation/packing/change_packing.rb +35 -25
- data/lib/musicality/notation/packing/score_packing.rb +2 -2
- data/lib/musicality/notation/util/function.rb +99 -0
- data/lib/musicality/notation/util/piecewise_function.rb +79 -99
- data/lib/musicality/notation/util/transition.rb +12 -0
- data/lib/musicality/notation/util/value_computer.rb +12 -152
- data/lib/musicality/performance/conversion/score_collator.rb +35 -20
- data/lib/musicality/performance/midi/part_sequencer.rb +2 -5
- data/lib/musicality/validatable.rb +6 -1
- data/lib/musicality/version.rb +1 -1
- data/lib/musicality.rb +4 -4
- data/musicality.gemspec +1 -0
- data/spec/notation/conversion/change_conversion_spec.rb +216 -9
- data/spec/notation/conversion/measure_note_map_spec.rb +2 -2
- data/spec/notation/conversion/note_time_converter_spec.rb +91 -9
- data/spec/notation/conversion/{measured_score_conversion_spec.rb → score_conversion_spec.rb} +44 -9
- data/spec/notation/conversion/score_converter_spec.rb +246 -0
- data/spec/notation/model/change_spec.rb +139 -36
- data/spec/notation/model/part_spec.rb +3 -3
- data/spec/notation/model/score_spec.rb +4 -4
- data/spec/notation/packing/change_packing_spec.rb +222 -71
- data/spec/notation/packing/part_packing_spec.rb +1 -1
- data/spec/notation/packing/score_packing_spec.rb +3 -2
- data/spec/notation/util/function_spec.rb +43 -0
- data/spec/notation/util/transition_spec.rb +51 -0
- data/spec/notation/util/value_computer_spec.rb +43 -87
- data/spec/performance/conversion/score_collator_spec.rb +46 -7
- data/spec/performance/midi/part_sequencer_spec.rb +2 -1
- metadata +29 -14
- data/lib/musicality/notation/conversion/measured_score_conversion.rb +0 -70
- data/lib/musicality/notation/conversion/measured_score_converter.rb +0 -95
- data/lib/musicality/notation/conversion/unmeasured_score_conversion.rb +0 -47
- data/lib/musicality/notation/conversion/unmeasured_score_converter.rb +0 -64
- data/spec/notation/conversion/measured_score_converter_spec.rb +0 -329
- data/spec/notation/conversion/unmeasured_score_conversion_spec.rb +0 -71
- data/spec/notation/conversion/unmeasured_score_converter_spec.rb +0 -116
@@ -1,329 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
describe MeasuredScoreConverter do
|
4
|
-
describe '#initialize' do
|
5
|
-
context 'current score is invalid' do
|
6
|
-
it 'should raise NotValidError' do
|
7
|
-
score = Score::Measured.new(1, 120)
|
8
|
-
expect { MeasuredScoreConverter.new(score) }.to raise_error(NotValidError)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
describe '#convert_parts' do
|
14
|
-
before :each do
|
15
|
-
@changeA = Change::Immediate.new(Dynamics::PP)
|
16
|
-
@changeB = Change::Gradual.new(Dynamics::F, 2)
|
17
|
-
@score = Score::Measured.new(FOUR_FOUR, 120,
|
18
|
-
parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => @changeA, 3 => @changeB })}
|
19
|
-
)
|
20
|
-
end
|
21
|
-
|
22
|
-
it 'should return Hash with original part names' do
|
23
|
-
parts = MeasuredScoreConverter.new(@score).convert_parts
|
24
|
-
parts.should be_a Hash
|
25
|
-
parts.keys.sort.should eq(@score.parts.keys.sort)
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should convert part dynamic change offsets from measure-based to note-based' do
|
29
|
-
parts = MeasuredScoreConverter.new(@score).convert_parts
|
30
|
-
parts.should have_key("simple")
|
31
|
-
part = parts["simple"]
|
32
|
-
part.dynamic_changes.keys.sort.should eq([1,3])
|
33
|
-
change = part.dynamic_changes[Rational(1,1)]
|
34
|
-
change.value.should eq(@changeA.value)
|
35
|
-
change.duration.should eq(0)
|
36
|
-
change = part.dynamic_changes[Rational(3,1)]
|
37
|
-
change.value.should eq(@changeB.value)
|
38
|
-
change.duration.should eq(2)
|
39
|
-
|
40
|
-
@score.start_meter = THREE_FOUR
|
41
|
-
parts = MeasuredScoreConverter.new(@score).convert_parts
|
42
|
-
parts.should have_key("simple")
|
43
|
-
part = parts["simple"]
|
44
|
-
part.dynamic_changes.keys.sort.should eq([Rational(3,4),Rational(9,4)])
|
45
|
-
change = part.dynamic_changes[Rational(3,4)]
|
46
|
-
change.value.should eq(@changeA.value)
|
47
|
-
change.duration.should eq(0)
|
48
|
-
change = part.dynamic_changes[Rational(9,4)]
|
49
|
-
change.value.should eq(@changeB.value)
|
50
|
-
change.duration.should eq(1.5)
|
51
|
-
end
|
52
|
-
|
53
|
-
context 'gradual changes with positive elapsed and/or remaining' do
|
54
|
-
it 'should change elapsed and remaining so they reflect note-based offsets' do
|
55
|
-
score = Score::Measured.new(THREE_FOUR,120, parts: {
|
56
|
-
"abc" => Part.new(Dynamics::P, dynamic_changes: {
|
57
|
-
2 => Change::Gradual.new(Dynamics::F,2,1,3),
|
58
|
-
7 => Change::Gradual.new(Dynamics::F,1,4,5)
|
59
|
-
})
|
60
|
-
})
|
61
|
-
converter = MeasuredScoreConverter.new(score)
|
62
|
-
parts = converter.convert_parts
|
63
|
-
dcs = parts["abc"].dynamic_changes
|
64
|
-
|
65
|
-
dcs.keys.should eq([Rational(6,4), Rational(21,4)])
|
66
|
-
dcs[Rational(3,2)].should eq(Change::Gradual.new(Dynamics::F,Rational(6,4),Rational(3,4),Rational(9,4)))
|
67
|
-
dcs[Rational(21,4)].should eq(Change::Gradual.new(Dynamics::F,Rational(3,4),Rational(12,4),Rational(15,4)))
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
describe '#convert_program' do
|
73
|
-
before :each do
|
74
|
-
@prog = Program.new([0...4,2...5])
|
75
|
-
@score = Score::Measured.new(FOUR_FOUR, 120, program: @prog)
|
76
|
-
@converter = MeasuredScoreConverter.new(@score)
|
77
|
-
end
|
78
|
-
|
79
|
-
it 'shuld return Program with same number of segments' do
|
80
|
-
prog = @converter.convert_program
|
81
|
-
prog.should be_a Program
|
82
|
-
prog.segments.size.should eq(@score.program.segments.size)
|
83
|
-
end
|
84
|
-
|
85
|
-
it 'should convert program segments offsets from measure-based to note-based' do
|
86
|
-
prog = MeasuredScoreConverter.new(@score).convert_program
|
87
|
-
prog.segments.size.should eq(2)
|
88
|
-
prog.segments[0].first.should eq(0)
|
89
|
-
prog.segments[0].last.should eq(4)
|
90
|
-
prog.segments[1].first.should eq(2)
|
91
|
-
prog.segments[1].last.should eq(5)
|
92
|
-
|
93
|
-
@score.start_meter = THREE_FOUR
|
94
|
-
prog = MeasuredScoreConverter.new(@score).convert_program
|
95
|
-
prog.segments.size.should eq(2)
|
96
|
-
prog.segments[0].first.should eq(0)
|
97
|
-
prog.segments[0].last.should eq(3)
|
98
|
-
prog.segments[1].first.should eq(1.5)
|
99
|
-
prog.segments[1].last.should eq(3.75)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
describe '#convert_start_tempo' do
|
104
|
-
it 'should return a converted tempo object, with same type as givn tempo class' do
|
105
|
-
score = Score::Measured.new(SIX_EIGHT, 120)
|
106
|
-
converter = MeasuredScoreConverter.new(score)
|
107
|
-
tempo = converter.convert_start_tempo
|
108
|
-
tempo.should eq(180)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
describe '#convert_tempo_changes' do
|
113
|
-
context 'immediate tempo changes' do
|
114
|
-
before :all do
|
115
|
-
@score = Score::Measured.new(THREE_FOUR, 120,
|
116
|
-
tempo_changes: { 1 => Change::Immediate.new(100),
|
117
|
-
2.5 => Change::Immediate.new(90)}
|
118
|
-
)
|
119
|
-
@tcs = MeasuredScoreConverter.new(@score).convert_tempo_changes
|
120
|
-
end
|
121
|
-
|
122
|
-
it 'should change offset from measure-based to note-based' do
|
123
|
-
@tcs.keys.sort.should eq([0.75, 1.875])
|
124
|
-
end
|
125
|
-
|
126
|
-
it 'should change tempo value using Tempo::BPM.to_qnpm' do
|
127
|
-
@tcs.entries.first[1].value.should eq(Tempo::BPM.to_qnpm(100,Rational(1,4)))
|
128
|
-
@tcs.entries.last[1].value.should eq(Tempo::BPM.to_qnpm(90,Rational(1,4)))
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
context 'gradual tempo changes' do
|
133
|
-
context 'no meter changes within tempo change duration' do
|
134
|
-
before :all do
|
135
|
-
@score = Score::Measured.new(THREE_FOUR, 120,
|
136
|
-
tempo_changes: { 2 => Change::Gradual.new(100,2) },
|
137
|
-
meter_changes: { 1 => Change::Immediate.new(TWO_FOUR),
|
138
|
-
4 => Change::Immediate.new(SIX_EIGHT) }
|
139
|
-
)
|
140
|
-
@tcs = MeasuredScoreConverter.new(@score).convert_tempo_changes
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'should change tempo change offset to note-based' do
|
144
|
-
@tcs.keys.should eq([Rational(5,4)])
|
145
|
-
end
|
146
|
-
|
147
|
-
it 'should convert the tempo change' do
|
148
|
-
@tcs[Rational(5,4)].value.should eq(Tempo::BPM.to_qnpm(100,Rational(1,4)))
|
149
|
-
end
|
150
|
-
|
151
|
-
it 'should convert change duration to note-based' do
|
152
|
-
@tcs[Rational(5,4)].duration.should eq(1)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
context 'single meter change within tempo change duration' do
|
157
|
-
before :all do
|
158
|
-
@tc_moff, @mc_moff = 2, 4
|
159
|
-
@tc = Change::Gradual.new(100,4)
|
160
|
-
@score = Score::Measured.new(THREE_FOUR, 120,
|
161
|
-
tempo_changes: { @tc_moff => @tc },
|
162
|
-
meter_changes: { @mc_moff => Change::Immediate.new(SIX_EIGHT) }
|
163
|
-
)
|
164
|
-
@tcs = MeasuredScoreConverter.new(@score).convert_tempo_changes
|
165
|
-
@mnoff_map = @score.measure_note_map
|
166
|
-
|
167
|
-
mend = @tc_moff + @tc.impending + @tc.remaining
|
168
|
-
@ndur = @mnoff_map[mend] - @mnoff_map[mend - @tc.total_duration]
|
169
|
-
end
|
170
|
-
|
171
|
-
it 'should split the one gradual change into two, durations adding to original total' do
|
172
|
-
@tcs.size.should eq(2)
|
173
|
-
@tcs.values.each {|x| x.should be_a Change::Gradual }
|
174
|
-
end
|
175
|
-
|
176
|
-
it 'should make each with same total duration' do
|
177
|
-
@tcs.values.each {|x| x.total_duration.should eq(@ndur) }
|
178
|
-
end
|
179
|
-
|
180
|
-
it 'should make durations so they sum to make the total duration' do
|
181
|
-
@tcs.values.map {|x| x.duration }.inject(0,:+).should eq(@ndur)
|
182
|
-
end
|
183
|
-
|
184
|
-
it 'should start first split change where original change would start' do
|
185
|
-
@tcs.should have_key(@mnoff_map[@tc_moff])
|
186
|
-
end
|
187
|
-
|
188
|
-
it 'should stop first split, and start second split where inner meter change occurs' do
|
189
|
-
pc1_start_noff = @mnoff_map[@tc_moff]
|
190
|
-
pc1_end_noff = pc1_start_noff + @tcs[pc1_start_noff].duration
|
191
|
-
|
192
|
-
pc2_start_noff = @mnoff_map[@mc_moff]
|
193
|
-
@tcs.should have_key(pc2_start_noff)
|
194
|
-
pc1_end_noff.should eq(pc2_start_noff)
|
195
|
-
end
|
196
|
-
|
197
|
-
it 'should stop second split change where original change would end' do
|
198
|
-
pc2_start_noff = @mnoff_map[@mc_moff]
|
199
|
-
pc2_end_noff = pc2_start_noff + @tcs[pc2_start_noff].duration
|
200
|
-
pc2_end_noff.should eq(@mnoff_map[@tc_moff + @tc.duration])
|
201
|
-
end
|
202
|
-
end
|
203
|
-
|
204
|
-
context 'two meter changes within tempo change duration' do
|
205
|
-
before :all do
|
206
|
-
@tc_moff, @mc1_moff, @mc2_moff = 2, 4, 5
|
207
|
-
@tc = Change::Gradual.new(100,5)
|
208
|
-
@score = Score::Measured.new(THREE_FOUR, 120,
|
209
|
-
tempo_changes: { @tc_moff => @tc},
|
210
|
-
meter_changes: { @mc1_moff => Change::Immediate.new(SIX_EIGHT),
|
211
|
-
@mc2_moff => Change::Immediate.new(TWO_FOUR) }
|
212
|
-
)
|
213
|
-
@tcs = MeasuredScoreConverter.new(@score).convert_tempo_changes
|
214
|
-
@mnoff_map = @score.measure_note_map
|
215
|
-
|
216
|
-
mend = @tc_moff + @tc.impending + @tc.remaining
|
217
|
-
@ndur = @mnoff_map[mend] - @mnoff_map[mend - @tc.total_duration]
|
218
|
-
end
|
219
|
-
|
220
|
-
it 'should split the one gradual change into three' do
|
221
|
-
@tcs.size.should eq(3)
|
222
|
-
@tcs.values.each {|x| x.should be_a Change::Gradual }
|
223
|
-
end
|
224
|
-
|
225
|
-
it 'should make each with same total duration' do
|
226
|
-
@tcs.values.each {|x| x.total_duration.should eq(@ndur) }
|
227
|
-
end
|
228
|
-
|
229
|
-
it 'should make durations so they sum to make the total duration' do
|
230
|
-
@tcs.values.map {|x| x.duration }.inject(0,:+).should eq(@ndur)
|
231
|
-
end
|
232
|
-
|
233
|
-
it 'should start first split change where original change would start' do
|
234
|
-
@tcs.should have_key(@mnoff_map[@tc_moff])
|
235
|
-
end
|
236
|
-
|
237
|
-
it 'should stop first split, and start second split change where 1st meter change occurs' do
|
238
|
-
pc1_start_noff = @mnoff_map[@tc_moff]
|
239
|
-
pc1_end_noff = pc1_start_noff + @tcs[pc1_start_noff].duration
|
240
|
-
|
241
|
-
pc2_start_noff = @mnoff_map[@mc1_moff]
|
242
|
-
@tcs.should have_key(pc2_start_noff)
|
243
|
-
pc1_end_noff.should eq(pc2_start_noff)
|
244
|
-
end
|
245
|
-
|
246
|
-
it 'should stop second split, and start third split change where 2st meter change occurs' do
|
247
|
-
pc2_start_noff = @mnoff_map[@mc1_moff]
|
248
|
-
pc2_end_noff = pc2_start_noff + @tcs[pc2_start_noff].duration
|
249
|
-
|
250
|
-
pc3_start_noff = @mnoff_map[@mc2_moff]
|
251
|
-
@tcs.should have_key(pc3_start_noff)
|
252
|
-
pc2_end_noff.should eq(pc3_start_noff)
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'should stop third split change where original change would end' do
|
256
|
-
pc3_start_noff = @mnoff_map[@mc2_moff]
|
257
|
-
pc3_end_noff = pc3_start_noff + @tcs[pc3_start_noff].duration
|
258
|
-
pc3_end_noff.should eq(@mnoff_map[@tc_moff + @tc.duration])
|
259
|
-
end
|
260
|
-
end
|
261
|
-
end
|
262
|
-
|
263
|
-
context 'gradual tempo changes with positive elapsed and/or remaining' do
|
264
|
-
context 'no meter change during tempo change' do
|
265
|
-
it 'should simply change elapsed and remaining so they reflect note-based offsets' do
|
266
|
-
score = Score::Measured.new(THREE_FOUR,120, tempo_changes: {
|
267
|
-
3 => Change::Gradual.new(100,5,2,3)
|
268
|
-
})
|
269
|
-
converter = MeasuredScoreConverter.new(score)
|
270
|
-
tcs = converter.convert_tempo_changes
|
271
|
-
|
272
|
-
tcs.keys.should eq([Rational(9,4)])
|
273
|
-
tcs[Rational(9,4)].should eq(Change::Gradual.new(100,Rational(15,4),Rational(6,4),Rational(9,4)))
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
context 'meter changes during tempo change' do
|
278
|
-
it 'should split tempo change, converting and adjusting elapsed/remaining with each sub-change' do
|
279
|
-
score = Score::Measured.new(THREE_FOUR,120,
|
280
|
-
meter_changes: { 4 => Change::Immediate.new(SIX_EIGHT),
|
281
|
-
6 => Change::Immediate.new(TWO_FOUR) },
|
282
|
-
tempo_changes: { 3 => Change::Gradual.new(100,5,2,3) }
|
283
|
-
)
|
284
|
-
converter = MeasuredScoreConverter.new(score)
|
285
|
-
tcs = converter.convert_tempo_changes
|
286
|
-
|
287
|
-
tcs.keys.should eq([Rational(9,4), Rational(12,4), Rational(18,4)])
|
288
|
-
tcs[Rational(9,4)].should eq(Change::Gradual.new(100,0.75,1.5,4))
|
289
|
-
tcs[Rational(12,4)].should eq(Change::Gradual.new(Tempo::BPM.to_qnpm(100,SIX_EIGHT.beat_duration),1.5,2.25,2.5))
|
290
|
-
tcs[Rational(18,4)].should eq(Change::Gradual.new(Tempo::BPM.to_qnpm(100,TWO_FOUR.beat_duration),1,3.75,1.5))
|
291
|
-
end
|
292
|
-
end
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
describe '#convert_score' do
|
297
|
-
it 'should return an unmeasured score' do
|
298
|
-
score = Score::Measured.new(FOUR_FOUR, 120)
|
299
|
-
converter = MeasuredScoreConverter.new(score)
|
300
|
-
converter.convert_score.should be_a Score::Unmeasured
|
301
|
-
end
|
302
|
-
|
303
|
-
it 'should use output from convert_start_tempo' do
|
304
|
-
score = Score::Measured.new(FOUR_FOUR, 120)
|
305
|
-
converter = MeasuredScoreConverter.new(score)
|
306
|
-
nscore = converter.convert_score
|
307
|
-
nscore.start_tempo.should eq(converter.convert_start_tempo)
|
308
|
-
end
|
309
|
-
|
310
|
-
it 'should use output from convert_program' do
|
311
|
-
prog = Program.new([0...4,2...5])
|
312
|
-
score = Score::Measured.new(FOUR_FOUR, 120, program: prog)
|
313
|
-
converter = MeasuredScoreConverter.new(score)
|
314
|
-
nscore = converter.convert_score
|
315
|
-
nscore.program.should eq(converter.convert_program)
|
316
|
-
end
|
317
|
-
|
318
|
-
it 'should use output from convert_parts' do
|
319
|
-
changeA = Change::Immediate.new(Dynamics::PP)
|
320
|
-
changeB = Change::Gradual.new(Dynamics::F, 2)
|
321
|
-
score = Score::Measured.new(FOUR_FOUR, 120,
|
322
|
-
parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => changeA, 3 => changeB })}
|
323
|
-
)
|
324
|
-
converter = MeasuredScoreConverter.new(score)
|
325
|
-
nscore = converter.convert_score
|
326
|
-
nscore.parts.should eq(converter.convert_parts)
|
327
|
-
end
|
328
|
-
end
|
329
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
describe Score::Unmeasured do
|
4
|
-
before :all do
|
5
|
-
@parts = {
|
6
|
-
"piano" => Part.new(Dynamics::MP,
|
7
|
-
notes: [Note.quarter(C4), Note.eighth(F3), Note.whole(C4), Note.half(D4)]*12,
|
8
|
-
dynamic_changes: {
|
9
|
-
1 => Change::Immediate.new(Dynamics::MF),
|
10
|
-
5 => Change::Immediate.new(Dynamics::FF),
|
11
|
-
6 => Change::Gradual.new(Dynamics::MF,2),
|
12
|
-
14 => Change::Immediate.new(Dynamics::PP),
|
13
|
-
}
|
14
|
-
)
|
15
|
-
}
|
16
|
-
@prog = Program.new([0...3,4...7,1...20,17..."45/2".to_r])
|
17
|
-
tcs = {
|
18
|
-
0 => Change::Immediate.new(120),
|
19
|
-
4 => Change::Gradual.new(60,2),
|
20
|
-
11 => Change::Immediate.new(110)
|
21
|
-
}
|
22
|
-
@score = Score::Unmeasured.new(120,
|
23
|
-
parts: @parts,
|
24
|
-
program: @prog,
|
25
|
-
tempo_changes: tcs,
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
describe '#note_offsets' do
|
30
|
-
before(:all){ @noffs = @score.note_offsets }
|
31
|
-
|
32
|
-
it 'should return an already-sorted array' do
|
33
|
-
@noffs.should eq @noffs.sort
|
34
|
-
end
|
35
|
-
|
36
|
-
it 'should start with offset from start tempo/dynamic' do
|
37
|
-
@noffs[0].should eq(0)
|
38
|
-
end
|
39
|
-
|
40
|
-
it 'should include offsets from tempo changes' do
|
41
|
-
@score.tempo_changes.each do |noff,change|
|
42
|
-
@noffs.should include(noff)
|
43
|
-
@noffs.should include(noff + change.duration)
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should include offsets from each part's dynamic changes" do
|
48
|
-
@score.parts.values.each do |part|
|
49
|
-
part.dynamic_changes.each do |noff,change|
|
50
|
-
@noffs.should include(noff)
|
51
|
-
change.offsets(noff).each {|offset| @noffs.should include(offset) }
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
it 'should include offsets from program segments' do
|
57
|
-
@score.program.segments.each do |seg|
|
58
|
-
@noffs.should include(seg.first)
|
59
|
-
@noffs.should include(seg.last)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
describe '#to_timed' do
|
65
|
-
it 'should use UnmeasuredScoreConverter#convert_score' do
|
66
|
-
nscore1 = @score.to_timed(200)
|
67
|
-
nscore2 = UnmeasuredScoreConverter.new(@score,200).convert_score
|
68
|
-
nscore1.should eq(nscore2)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
-
|
3
|
-
describe UnmeasuredScoreConverter do
|
4
|
-
describe '#initialize' do
|
5
|
-
context 'current score is invalid' do
|
6
|
-
it 'should raise NotValidError' do
|
7
|
-
score = Score::Unmeasured.new(-1)
|
8
|
-
expect { UnmeasuredScoreConverter.new(score,200) }.to raise_error(NotValidError)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
describe '#convert_parts' do
|
14
|
-
before :each do
|
15
|
-
@changeA = Change::Immediate.new(Dynamics::PP)
|
16
|
-
@changeB = Change::Gradual.new(Dynamics::F, 2)
|
17
|
-
@score = Score::Unmeasured.new(120,
|
18
|
-
parts: {
|
19
|
-
"normal" => Part.new(Dynamics::MP,
|
20
|
-
dynamic_changes: { 1 => @changeA, 3 => @changeB },
|
21
|
-
notes: "/4C2 /8D2 /8E2 /2C2".to_notes * 4),
|
22
|
-
"empty" => Part.new(Dynamics::PP)
|
23
|
-
}
|
24
|
-
)
|
25
|
-
@parts = UnmeasuredScoreConverter.new(@score,200).convert_parts
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'should return Hash with original part names' do
|
29
|
-
@parts.should be_a Hash
|
30
|
-
@parts.keys.sort.should eq(@score.parts.keys.sort)
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'should convert part dynamic change offsets from note-based to time-based' do
|
34
|
-
part = @parts["normal"]
|
35
|
-
part.dynamic_changes.keys.sort.should eq([2,6])
|
36
|
-
change = part.dynamic_changes[2.0]
|
37
|
-
change.value.should eq(@changeA.value)
|
38
|
-
change.duration.should eq(0)
|
39
|
-
change = part.dynamic_changes[6.0]
|
40
|
-
change.value.should eq(@changeB.value)
|
41
|
-
change.duration.should eq(4.0)
|
42
|
-
end
|
43
|
-
|
44
|
-
it 'should convert note durations to time durations' do
|
45
|
-
part = @parts["normal"]
|
46
|
-
part.notes.map {|x| x.duration }.should eq([0.5,0.25,0.25,1]*4)
|
47
|
-
end
|
48
|
-
|
49
|
-
context 'gradual changes with positive elapsed and/or remaining' do
|
50
|
-
it 'should change elapsed and remaining so they reflect time-based duration' do
|
51
|
-
score = Score::Unmeasured.new(120, parts: {
|
52
|
-
"abc" => Part.new(Dynamics::P, dynamic_changes: {
|
53
|
-
2 => Change::Gradual.new(Dynamics::F,2,1,3),
|
54
|
-
7 => Change::Gradual.new(Dynamics::F,1,4,5)
|
55
|
-
})
|
56
|
-
})
|
57
|
-
converter = UnmeasuredScoreConverter.new(score,200)
|
58
|
-
parts = converter.convert_parts
|
59
|
-
dcs = parts["abc"].dynamic_changes
|
60
|
-
|
61
|
-
dcs.keys.should eq([4,14])
|
62
|
-
dcs[4.0].should eq(Change::Gradual.new(Dynamics::F,4,2,6))
|
63
|
-
dcs[14.0].should eq(Change::Gradual.new(Dynamics::F,2,8,10))
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
describe '#convert_program' do
|
69
|
-
before :each do
|
70
|
-
@prog = Program.new([0...4,2...5])
|
71
|
-
@score = Score::Unmeasured.new(120, program: @prog)
|
72
|
-
@converter = UnmeasuredScoreConverter.new(@score,200)
|
73
|
-
@prog2 = @converter.convert_program
|
74
|
-
end
|
75
|
-
|
76
|
-
it 'should return Program with same number of segments' do
|
77
|
-
@prog2.should be_a Program
|
78
|
-
@prog2.segments.size.should eq(@prog.segments.size)
|
79
|
-
end
|
80
|
-
|
81
|
-
it 'should convert program segments offsets from note-based to time-based' do
|
82
|
-
prog = @prog2
|
83
|
-
prog.segments[0].first.should eq(0)
|
84
|
-
prog.segments[0].last.should eq(8)
|
85
|
-
prog.segments[1].first.should eq(4)
|
86
|
-
prog.segments[1].last.should eq(10)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
describe '#convert_score' do
|
91
|
-
it 'should return an timed score' do
|
92
|
-
score = Score::Unmeasured.new(120)
|
93
|
-
converter = UnmeasuredScoreConverter.new(score,200)
|
94
|
-
converter.convert_score.should be_a Score::Timed
|
95
|
-
end
|
96
|
-
|
97
|
-
it 'should use output from convert_program' do
|
98
|
-
prog = Program.new([0...4,2...5])
|
99
|
-
score = Score::Unmeasured.new(120, program: prog)
|
100
|
-
converter = UnmeasuredScoreConverter.new(score,200)
|
101
|
-
nscore = converter.convert_score
|
102
|
-
nscore.program.should eq(converter.convert_program)
|
103
|
-
end
|
104
|
-
|
105
|
-
it 'should use output from convert_parts' do
|
106
|
-
changeA = Change::Immediate.new(Dynamics::PP)
|
107
|
-
changeB = Change::Gradual.new(Dynamics::F, 2)
|
108
|
-
score = Score::Unmeasured.new(120,
|
109
|
-
parts: {"simple" => Part.new(Dynamics::MP, dynamic_changes: { 1 => changeA, 3 => changeB })}
|
110
|
-
)
|
111
|
-
converter = UnmeasuredScoreConverter.new(score,200)
|
112
|
-
nscore = converter.convert_score
|
113
|
-
nscore.parts.should eq(converter.convert_parts)
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|