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
@@ -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
|