musicality 0.2.0 → 0.3.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 +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
|