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
@@ -83,6 +83,43 @@ describe ScoreCollator do
|
|
83
83
|
end
|
84
84
|
end
|
85
85
|
|
86
|
+
context 'part contains trimmed gradual changes' do
|
87
|
+
it 'should exclude the change when it is not at all in a program segment' do
|
88
|
+
score = Score::Measured.new(FOUR_FOUR, 120,
|
89
|
+
parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
|
90
|
+
2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,0)
|
91
|
+
}) },
|
92
|
+
program: Program.new([7...9])
|
93
|
+
)
|
94
|
+
collator = ScoreCollator.new(score)
|
95
|
+
parts = collator.collate_parts
|
96
|
+
dcs = parts[1].dynamic_changes
|
97
|
+
dcs.size.should eq(1)
|
98
|
+
dcs[0.to_r].should eq(Change::Immediate.new(Dynamics::PP))
|
99
|
+
|
100
|
+
score.program = Program.new([0...1])
|
101
|
+
collator = ScoreCollator.new(score)
|
102
|
+
parts = collator.collate_parts
|
103
|
+
dcs = parts[1].dynamic_changes
|
104
|
+
dcs.size.should eq(1)
|
105
|
+
dcs[0.to_r].should eq(Change::Immediate.new(Dynamics::FF))
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should trim the change further if needed' do
|
109
|
+
score = Score::Measured.new(FOUR_FOUR, 120,
|
110
|
+
parts: { 1 => Part.new(Dynamics::FF, dynamic_changes: {
|
111
|
+
2 => Change::Gradual.linear(Dynamics::PP,5).trim(1,1)
|
112
|
+
}) },
|
113
|
+
program: Program.new([3...4])
|
114
|
+
)
|
115
|
+
collator = ScoreCollator.new(score)
|
116
|
+
parts = collator.collate_parts
|
117
|
+
dcs = parts[1].dynamic_changes
|
118
|
+
dcs.size.should eq(1)
|
119
|
+
dcs[0.to_r].should eq(Change::Gradual.linear(Dynamics::PP,5).trim(2,2))
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
86
123
|
it 'should preserve links' do
|
87
124
|
notes = Note.split_parse("1Db4~Bb4")
|
88
125
|
score = Score::Measured.new(
|
@@ -106,7 +143,7 @@ describe ScoreCollator do
|
|
106
143
|
before :all do
|
107
144
|
@change0 = Change::Immediate.new(120)
|
108
145
|
@change1 = Change::Immediate.new(200)
|
109
|
-
@change2 = Change::Gradual.
|
146
|
+
@change2 = Change::Gradual.linear(100,1)
|
110
147
|
end
|
111
148
|
|
112
149
|
context 'tempo change starts at end of program segment' do
|
@@ -134,8 +171,8 @@ describe ScoreCollator do
|
|
134
171
|
@tcs[0.to_r].should be_a Change::Immediate
|
135
172
|
end
|
136
173
|
|
137
|
-
it 'should be used as starting tempo change
|
138
|
-
@tcs[0.to_r].
|
174
|
+
it 'should be used as starting tempo change end_value' do
|
175
|
+
@tcs[0.to_r].end_value.should eq @change2.end_value
|
139
176
|
end
|
140
177
|
end
|
141
178
|
|
@@ -146,8 +183,9 @@ describe ScoreCollator do
|
|
146
183
|
collator = ScoreCollator.new(score)
|
147
184
|
tcs = collator.collate_tempo_changes
|
148
185
|
tcs.size.should eq 1
|
149
|
-
tcs[0.to_r].
|
150
|
-
tcs[0.to_r].
|
186
|
+
tcs[0.to_r].should be_a Change::Gradual::Trimmed
|
187
|
+
tcs[0.to_r].end_value.should eq @change2.end_value
|
188
|
+
tcs[0.to_r].remaining.should eq(0.5)
|
151
189
|
end
|
152
190
|
end
|
153
191
|
|
@@ -160,8 +198,9 @@ describe ScoreCollator do
|
|
160
198
|
tcs.size.should eq 3
|
161
199
|
tcs[0.to_r].should eq @change0
|
162
200
|
tcs[1.to_r].should eq @change1
|
163
|
-
tcs[2.to_r].
|
164
|
-
tcs[2.to_r].
|
201
|
+
tcs[2.to_r].should be_a Change::Gradual::Trimmed
|
202
|
+
tcs[2.to_r].end_value.should eq @change2.end_value
|
203
|
+
tcs[2.to_r].remaining.should eq(0.5)
|
165
204
|
end
|
166
205
|
end
|
167
206
|
end
|
@@ -3,7 +3,8 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
|
3
3
|
describe PartSequencer do
|
4
4
|
describe '#make_midi_track' do
|
5
5
|
before :all do
|
6
|
-
part = Part.new(Dynamics::PP, notes: "/4C4 /4D4 /8 /8D4 /8E4 /2C4".to_notes * 2
|
6
|
+
part = Part.new(Dynamics::PP, notes: "/4C4 /4D4 /8 /8D4 /8E4 /2C4".to_notes * 2,
|
7
|
+
dynamic_changes: { 1 => Change::Gradual.linear(Dynamics::FF,2) })
|
7
8
|
@midi_seq = MIDI::Sequence.new
|
8
9
|
@part_name = "mypart"
|
9
10
|
@channel = 2
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: musicality
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Tunnell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '2.9'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: pry
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: treetop
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +123,7 @@ files:
|
|
109
123
|
- .gitignore
|
110
124
|
- .rspec
|
111
125
|
- .ruby-version
|
126
|
+
- ChangeLog.md
|
112
127
|
- Gemfile
|
113
128
|
- LICENSE.txt
|
114
129
|
- README.md
|
@@ -122,12 +137,10 @@ files:
|
|
122
137
|
- lib/musicality/errors.rb
|
123
138
|
- lib/musicality/notation/conversion/change_conversion.rb
|
124
139
|
- lib/musicality/notation/conversion/measure_note_map.rb
|
125
|
-
- lib/musicality/notation/conversion/measured_score_conversion.rb
|
126
|
-
- lib/musicality/notation/conversion/measured_score_converter.rb
|
127
140
|
- lib/musicality/notation/conversion/note_time_converter.rb
|
141
|
+
- lib/musicality/notation/conversion/score_conversion.rb
|
142
|
+
- lib/musicality/notation/conversion/score_converter.rb
|
128
143
|
- lib/musicality/notation/conversion/tempo_conversion.rb
|
129
|
-
- lib/musicality/notation/conversion/unmeasured_score_conversion.rb
|
130
|
-
- lib/musicality/notation/conversion/unmeasured_score_converter.rb
|
131
144
|
- lib/musicality/notation/model/articulations.rb
|
132
145
|
- lib/musicality/notation/model/change.rb
|
133
146
|
- lib/musicality/notation/model/dynamics.rb
|
@@ -176,8 +189,10 @@ files:
|
|
176
189
|
- lib/musicality/notation/parsing/pitch_parsing.treetop
|
177
190
|
- lib/musicality/notation/parsing/segment_parsing.rb
|
178
191
|
- lib/musicality/notation/parsing/segment_parsing.treetop
|
192
|
+
- lib/musicality/notation/util/function.rb
|
179
193
|
- lib/musicality/notation/util/interpolation.rb
|
180
194
|
- lib/musicality/notation/util/piecewise_function.rb
|
195
|
+
- lib/musicality/notation/util/transition.rb
|
181
196
|
- lib/musicality/notation/util/value_computer.rb
|
182
197
|
- lib/musicality/performance/conversion/glissando_converter.rb
|
183
198
|
- lib/musicality/performance/conversion/note_sequence_extractor.rb
|
@@ -197,12 +212,10 @@ files:
|
|
197
212
|
- spec/musicality_spec.rb
|
198
213
|
- spec/notation/conversion/change_conversion_spec.rb
|
199
214
|
- spec/notation/conversion/measure_note_map_spec.rb
|
200
|
-
- spec/notation/conversion/measured_score_conversion_spec.rb
|
201
|
-
- spec/notation/conversion/measured_score_converter_spec.rb
|
202
215
|
- spec/notation/conversion/note_time_converter_spec.rb
|
216
|
+
- spec/notation/conversion/score_conversion_spec.rb
|
217
|
+
- spec/notation/conversion/score_converter_spec.rb
|
203
218
|
- spec/notation/conversion/tempo_conversion_spec.rb
|
204
|
-
- spec/notation/conversion/unmeasured_score_conversion_spec.rb
|
205
|
-
- spec/notation/conversion/unmeasured_score_converter_spec.rb
|
206
219
|
- spec/notation/model/change_spec.rb
|
207
220
|
- spec/notation/model/link_spec.rb
|
208
221
|
- spec/notation/model/meter_spec.rb
|
@@ -233,6 +246,8 @@ files:
|
|
233
246
|
- spec/notation/parsing/pitch_node_spec.rb
|
234
247
|
- spec/notation/parsing/pitch_parsing_spec.rb
|
235
248
|
- spec/notation/parsing/segment_parsing_spec.rb
|
249
|
+
- spec/notation/util/function_spec.rb
|
250
|
+
- spec/notation/util/transition_spec.rb
|
236
251
|
- spec/notation/util/value_computer_spec.rb
|
237
252
|
- spec/performance/conversion/glissando_converter_spec.rb
|
238
253
|
- spec/performance/conversion/note_sequence_extractor_spec.rb
|
@@ -273,12 +288,10 @@ test_files:
|
|
273
288
|
- spec/musicality_spec.rb
|
274
289
|
- spec/notation/conversion/change_conversion_spec.rb
|
275
290
|
- spec/notation/conversion/measure_note_map_spec.rb
|
276
|
-
- spec/notation/conversion/measured_score_conversion_spec.rb
|
277
|
-
- spec/notation/conversion/measured_score_converter_spec.rb
|
278
291
|
- spec/notation/conversion/note_time_converter_spec.rb
|
292
|
+
- spec/notation/conversion/score_conversion_spec.rb
|
293
|
+
- spec/notation/conversion/score_converter_spec.rb
|
279
294
|
- spec/notation/conversion/tempo_conversion_spec.rb
|
280
|
-
- spec/notation/conversion/unmeasured_score_conversion_spec.rb
|
281
|
-
- spec/notation/conversion/unmeasured_score_converter_spec.rb
|
282
295
|
- spec/notation/model/change_spec.rb
|
283
296
|
- spec/notation/model/link_spec.rb
|
284
297
|
- spec/notation/model/meter_spec.rb
|
@@ -309,6 +322,8 @@ test_files:
|
|
309
322
|
- spec/notation/parsing/pitch_node_spec.rb
|
310
323
|
- spec/notation/parsing/pitch_parsing_spec.rb
|
311
324
|
- spec/notation/parsing/segment_parsing_spec.rb
|
325
|
+
- spec/notation/util/function_spec.rb
|
326
|
+
- spec/notation/util/transition_spec.rb
|
312
327
|
- spec/notation/util/value_computer_spec.rb
|
313
328
|
- spec/performance/conversion/glissando_converter_spec.rb
|
314
329
|
- spec/performance/conversion/note_sequence_extractor_spec.rb
|
@@ -1,70 +0,0 @@
|
|
1
|
-
module Musicality
|
2
|
-
|
3
|
-
class Score
|
4
|
-
class Measured < TempoBased
|
5
|
-
# Convert to unmeasured score by converting measure-based offsets to
|
6
|
-
# note-based offsets, and eliminating the use of meters. Also, tempo is
|
7
|
-
# coverted from beats-per-minute to quarter-notes per minute.
|
8
|
-
def to_unmeasured
|
9
|
-
MeasuredScoreConverter.new(self).convert_score
|
10
|
-
end
|
11
|
-
|
12
|
-
def to_timed tempo_sample_rate
|
13
|
-
unmeasured = MeasuredScoreConverter.new(self).convert_score
|
14
|
-
unmeasured.to_timed(tempo_sample_rate)
|
15
|
-
end
|
16
|
-
|
17
|
-
def measure_note_map
|
18
|
-
Conversion::measure_note_map(measure_offsets,measure_durations)
|
19
|
-
end
|
20
|
-
|
21
|
-
def measure_offsets
|
22
|
-
moffs = Set.new([0.to_r])
|
23
|
-
|
24
|
-
@tempo_changes.each do |moff,change|
|
25
|
-
moffs += change.offsets(moff)
|
26
|
-
end
|
27
|
-
|
28
|
-
@meter_changes.keys.each {|moff| moffs.add(moff) }
|
29
|
-
|
30
|
-
@parts.values.each do |part|
|
31
|
-
part.dynamic_changes.each do |moff,change|
|
32
|
-
moffs += change.offsets(moff)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
@program.segments.each do |seg|
|
37
|
-
moffs.add(seg.first)
|
38
|
-
moffs.add(seg.last)
|
39
|
-
end
|
40
|
-
|
41
|
-
return moffs.sort
|
42
|
-
end
|
43
|
-
|
44
|
-
def beat_durations
|
45
|
-
bdurs = @meter_changes.map do |offset,change|
|
46
|
-
[ offset, change.value.beat_duration ]
|
47
|
-
end.sort
|
48
|
-
|
49
|
-
if bdurs.empty? || bdurs[0][0] != 0
|
50
|
-
bdurs.unshift([0,@start_meter.beat_duration])
|
51
|
-
end
|
52
|
-
|
53
|
-
return bdurs
|
54
|
-
end
|
55
|
-
|
56
|
-
def measure_durations
|
57
|
-
mdurs = @meter_changes.map do |offset,change|
|
58
|
-
[ offset, change.value.measure_duration ]
|
59
|
-
end.sort
|
60
|
-
|
61
|
-
if mdurs.empty? || mdurs[0][0] != 0
|
62
|
-
mdurs.unshift([0,@start_meter.measure_duration])
|
63
|
-
end
|
64
|
-
|
65
|
-
return Hash[ mdurs ]
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
end
|
@@ -1,95 +0,0 @@
|
|
1
|
-
module Musicality
|
2
|
-
|
3
|
-
# Converts measured score to unmeasured by converting measure-based offsets
|
4
|
-
# and durations to note-based offsets, and eliminating the use of meters.
|
5
|
-
# Also, tempo is coverted from beats-per-minute to quarter-notes per minute.
|
6
|
-
class MeasuredScoreConverter
|
7
|
-
def initialize score
|
8
|
-
unless score.valid?
|
9
|
-
raise NotValidError, "The given score can not be converted because \
|
10
|
-
it is invalid, with these errors: #{score.errors}"
|
11
|
-
end
|
12
|
-
|
13
|
-
@score = score
|
14
|
-
@mnoff_map = score.measure_note_map
|
15
|
-
end
|
16
|
-
|
17
|
-
def convert_score
|
18
|
-
Score::Unmeasured.new(convert_start_tempo,
|
19
|
-
parts: convert_parts, program: convert_program,
|
20
|
-
tempo_changes: convert_tempo_changes)
|
21
|
-
end
|
22
|
-
|
23
|
-
def convert_parts
|
24
|
-
Hash[ @score.parts.map do |name,part|
|
25
|
-
new_dcs = Hash[ part.dynamic_changes.map do |moff,change|
|
26
|
-
case change
|
27
|
-
when Change::Immediate
|
28
|
-
[@mnoff_map[moff],change.clone]
|
29
|
-
when Change::Gradual
|
30
|
-
noff1, noff2, noff3, noff4 = change.offsets(moff).map {|x| @mnoff_map[x] }
|
31
|
-
[noff2, Change::Gradual.new(change.value,
|
32
|
-
noff3-noff2, noff2-noff1, noff4-noff3)]
|
33
|
-
end
|
34
|
-
end ]
|
35
|
-
new_notes = part.notes.map {|n| n.clone }
|
36
|
-
[name, Part.new(part.start_dynamic,
|
37
|
-
notes: new_notes, dynamic_changes: new_dcs)]
|
38
|
-
end ]
|
39
|
-
end
|
40
|
-
|
41
|
-
def convert_program
|
42
|
-
Program.new(
|
43
|
-
@score.program.segments.map do |seg|
|
44
|
-
@mnoff_map[seg.first]...@mnoff_map[seg.last]
|
45
|
-
end
|
46
|
-
)
|
47
|
-
end
|
48
|
-
|
49
|
-
def convert_start_tempo
|
50
|
-
Tempo::BPM.to_qnpm(@score.start_tempo, @score.start_meter.beat_duration)
|
51
|
-
end
|
52
|
-
|
53
|
-
def convert_tempo_changes
|
54
|
-
tcs = {}
|
55
|
-
bdurs = @score.beat_durations
|
56
|
-
|
57
|
-
@score.tempo_changes.each do |moff,change|
|
58
|
-
bdur = bdurs.select {|x,y| x <= moff}.max[1]
|
59
|
-
tempo = change.value
|
60
|
-
|
61
|
-
case change
|
62
|
-
when Change::Immediate
|
63
|
-
tcs[@mnoff_map[moff]] = Change::Immediate.new(Tempo::BPM.to_qnpm(tempo,bdur))
|
64
|
-
when Change::Gradual
|
65
|
-
start_moff, end_moff = moff, moff + change.duration
|
66
|
-
start_noff, end_noff = @mnoff_map[start_moff], @mnoff_map[end_moff]
|
67
|
-
|
68
|
-
initial_moff, final_moff = start_moff - change.elapsed, end_moff + change.remaining
|
69
|
-
initial_noff, final_noff = @mnoff_map[initial_moff], @mnoff_map[final_moff]
|
70
|
-
|
71
|
-
more_bdurs = bdurs.select {|x,y| x > start_moff && x < end_moff }
|
72
|
-
cur_noff, cur_bdur = start_noff, bdur
|
73
|
-
|
74
|
-
more_bdurs.each do |next_moff, next_bdur|
|
75
|
-
next_noff = @mnoff_map[next_moff]
|
76
|
-
elapsed = cur_noff - initial_noff
|
77
|
-
impending = next_noff - cur_noff
|
78
|
-
remaining = final_noff - next_noff
|
79
|
-
tempo2 = Tempo::BPM.to_qnpm(tempo, cur_bdur)
|
80
|
-
tcs[cur_noff] = Change::Gradual.new(tempo2, impending, elapsed, remaining)
|
81
|
-
cur_noff, cur_bdur = next_noff, next_bdur
|
82
|
-
end
|
83
|
-
elapsed = cur_noff - initial_noff
|
84
|
-
impending = end_noff - cur_noff
|
85
|
-
remaining = final_noff - end_noff
|
86
|
-
tempo2 = Tempo::BPM.to_qnpm(tempo, cur_bdur)
|
87
|
-
tcs[cur_noff] = Change::Gradual.new(tempo2, impending, elapsed, remaining)
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
return tcs
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
end
|
@@ -1,47 +0,0 @@
|
|
1
|
-
module Musicality
|
2
|
-
|
3
|
-
class Score
|
4
|
-
class Unmeasured < TempoBased
|
5
|
-
# Convert to unmeasured score by converting measure-based offsets to
|
6
|
-
# note-based offsets, and eliminating the use of meters. Also, tempo is
|
7
|
-
# coverted from beats-per-minute to quarter-notes per minute.
|
8
|
-
def to_timed tempo_sample_rate
|
9
|
-
UnmeasuredScoreConverter.new(self,tempo_sample_rate).convert_score
|
10
|
-
end
|
11
|
-
|
12
|
-
def note_time_map tempo_sample_rate
|
13
|
-
tempo_computer = ValueComputer.new(@start_tempo, @tempo_changes)
|
14
|
-
ntc = NoteTimeConverter.new(tempo_computer, tempo_sample_rate)
|
15
|
-
ntc.note_time_map(note_offsets)
|
16
|
-
end
|
17
|
-
|
18
|
-
def note_offsets
|
19
|
-
noffs = Set.new([0.to_r])
|
20
|
-
|
21
|
-
@tempo_changes.each do |noff,change|
|
22
|
-
noffs += change.offsets(noff)
|
23
|
-
end
|
24
|
-
|
25
|
-
@parts.values.each do |part|
|
26
|
-
noff = 0.to_r
|
27
|
-
part.notes.each do |note|
|
28
|
-
noff += note.duration
|
29
|
-
noffs.add(noff)
|
30
|
-
end
|
31
|
-
|
32
|
-
part.dynamic_changes.each do |noff,change|
|
33
|
-
noffs += change.offsets(noff)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
@program.segments.each do |seg|
|
38
|
-
noffs.add(seg.first)
|
39
|
-
noffs.add(seg.last)
|
40
|
-
end
|
41
|
-
|
42
|
-
return noffs.sort
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module Musicality
|
4
|
-
|
5
|
-
# Converts unmeasured score to timed score, by converting note-based offsets
|
6
|
-
# and durations to time-based, and eliminating the use of tempo.
|
7
|
-
class UnmeasuredScoreConverter
|
8
|
-
|
9
|
-
def initialize score, tempo_sample_rate
|
10
|
-
unless score.valid?
|
11
|
-
raise NotValidError, "The given score can not be converted because \
|
12
|
-
it is invalid, with these errors: #{score.errors}"
|
13
|
-
end
|
14
|
-
|
15
|
-
@score = score
|
16
|
-
@note_time_map = score.note_time_map(tempo_sample_rate)
|
17
|
-
end
|
18
|
-
|
19
|
-
def convert_score
|
20
|
-
Score::Timed.new(parts: convert_parts, program: convert_program)
|
21
|
-
end
|
22
|
-
|
23
|
-
# Convert note-based offsets & durations to time-based.
|
24
|
-
def convert_parts
|
25
|
-
Hash[ @score.parts.map do |name,part|
|
26
|
-
offset = 0.to_r
|
27
|
-
|
28
|
-
new_notes = part.notes.map do |note|
|
29
|
-
starttime = @note_time_map[offset]
|
30
|
-
endtime = @note_time_map[offset + note.duration]
|
31
|
-
offset += note.duration
|
32
|
-
newnote = note.clone
|
33
|
-
newnote.duration = endtime - starttime
|
34
|
-
newnote
|
35
|
-
end
|
36
|
-
|
37
|
-
new_dcs = Hash[ part.dynamic_changes.map do |noff,change|
|
38
|
-
case change
|
39
|
-
when Change::Immediate
|
40
|
-
[@note_time_map[noff],change.clone]
|
41
|
-
when Change::Gradual
|
42
|
-
toff1, toff2, toff3, toff4 = change.offsets(noff).map {|x| @note_time_map[x] }
|
43
|
-
[toff2, Change::Gradual.new(change.value,
|
44
|
-
toff3-toff2, toff2-toff1, toff4-toff3)]
|
45
|
-
end
|
46
|
-
end ]
|
47
|
-
|
48
|
-
[name, Part.new(part.start_dynamic,
|
49
|
-
notes: new_notes, dynamic_changes: new_dcs)]
|
50
|
-
end]
|
51
|
-
end
|
52
|
-
|
53
|
-
# Convert note-based offsets & durations to time-based.
|
54
|
-
def convert_program
|
55
|
-
newsegments = @score.program.segments.map do |segment|
|
56
|
-
first = @note_time_map[segment.first]
|
57
|
-
last = @note_time_map[segment.last]
|
58
|
-
first...last
|
59
|
-
end
|
60
|
-
Program.new(newsegments)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
end
|