musicality 0.1.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 +7 -0
- data/.gitignore +15 -0
- data/.rspec +2 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +47 -0
- data/Rakefile +65 -0
- data/bin/midify +78 -0
- data/examples/hip.rb +32 -0
- data/examples/missed_connection.rb +26 -0
- data/examples/song1.rb +33 -0
- data/examples/song2.rb +32 -0
- data/lib/musicality/errors.rb +9 -0
- data/lib/musicality/notation/conversion/change_conversion.rb +19 -0
- data/lib/musicality/notation/conversion/measure_note_map.rb +40 -0
- data/lib/musicality/notation/conversion/measured_score_conversion.rb +70 -0
- data/lib/musicality/notation/conversion/measured_score_converter.rb +95 -0
- data/lib/musicality/notation/conversion/note_time_converter.rb +68 -0
- data/lib/musicality/notation/conversion/tempo_conversion.rb +25 -0
- data/lib/musicality/notation/conversion/unmeasured_score_conversion.rb +47 -0
- data/lib/musicality/notation/conversion/unmeasured_score_converter.rb +64 -0
- data/lib/musicality/notation/model/articulations.rb +13 -0
- data/lib/musicality/notation/model/change.rb +62 -0
- data/lib/musicality/notation/model/dynamics.rb +12 -0
- data/lib/musicality/notation/model/link.rb +73 -0
- data/lib/musicality/notation/model/meter.rb +54 -0
- data/lib/musicality/notation/model/meters.rb +9 -0
- data/lib/musicality/notation/model/note.rb +120 -0
- data/lib/musicality/notation/model/part.rb +54 -0
- data/lib/musicality/notation/model/pitch.rb +163 -0
- data/lib/musicality/notation/model/pitches.rb +21 -0
- data/lib/musicality/notation/model/program.rb +53 -0
- data/lib/musicality/notation/model/score.rb +132 -0
- data/lib/musicality/notation/packing/change_packing.rb +46 -0
- data/lib/musicality/notation/packing/part_packing.rb +31 -0
- data/lib/musicality/notation/packing/program_packing.rb +16 -0
- data/lib/musicality/notation/packing/score_packing.rb +108 -0
- data/lib/musicality/notation/parsing/articulation_parsing.rb +264 -0
- data/lib/musicality/notation/parsing/articulation_parsing.treetop +59 -0
- data/lib/musicality/notation/parsing/convenience_methods.rb +74 -0
- data/lib/musicality/notation/parsing/duration_nodes.rb +21 -0
- data/lib/musicality/notation/parsing/duration_parsing.rb +205 -0
- data/lib/musicality/notation/parsing/duration_parsing.treetop +25 -0
- data/lib/musicality/notation/parsing/link_nodes.rb +35 -0
- data/lib/musicality/notation/parsing/link_parsing.rb +270 -0
- data/lib/musicality/notation/parsing/link_parsing.treetop +33 -0
- data/lib/musicality/notation/parsing/meter_parsing.rb +190 -0
- data/lib/musicality/notation/parsing/meter_parsing.treetop +29 -0
- data/lib/musicality/notation/parsing/note_node.rb +40 -0
- data/lib/musicality/notation/parsing/note_parsing.rb +229 -0
- data/lib/musicality/notation/parsing/note_parsing.treetop +28 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +289 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.treetop +29 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +64 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +17 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +86 -0
- data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.treetop +20 -0
- data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +503 -0
- data/lib/musicality/notation/parsing/numbers/positive_float_parsing.treetop +33 -0
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +95 -0
- data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +19 -0
- data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +84 -0
- data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.treetop +19 -0
- data/lib/musicality/notation/parsing/parseable.rb +30 -0
- data/lib/musicality/notation/parsing/pitch_node.rb +23 -0
- data/lib/musicality/notation/parsing/pitch_parsing.rb +448 -0
- data/lib/musicality/notation/parsing/pitch_parsing.treetop +52 -0
- data/lib/musicality/notation/parsing/segment_parsing.rb +141 -0
- data/lib/musicality/notation/parsing/segment_parsing.treetop +23 -0
- data/lib/musicality/notation/util/interpolation.rb +16 -0
- data/lib/musicality/notation/util/piecewise_function.rb +122 -0
- data/lib/musicality/notation/util/value_computer.rb +170 -0
- data/lib/musicality/performance/conversion/glissando_converter.rb +34 -0
- data/lib/musicality/performance/conversion/note_sequence_extractor.rb +98 -0
- data/lib/musicality/performance/conversion/portamento_converter.rb +24 -0
- data/lib/musicality/performance/conversion/score_collator.rb +126 -0
- data/lib/musicality/performance/midi/midi_events.rb +34 -0
- data/lib/musicality/performance/midi/midi_util.rb +31 -0
- data/lib/musicality/performance/midi/part_sequencer.rb +123 -0
- data/lib/musicality/performance/midi/score_sequencer.rb +45 -0
- data/lib/musicality/performance/model/note_attacks.rb +19 -0
- data/lib/musicality/performance/model/note_sequence.rb +111 -0
- data/lib/musicality/performance/util/note_linker.rb +28 -0
- data/lib/musicality/performance/util/optimization.rb +31 -0
- data/lib/musicality/validatable.rb +38 -0
- data/lib/musicality/version.rb +3 -0
- data/lib/musicality.rb +81 -0
- data/musicality.gemspec +30 -0
- data/spec/musicality_spec.rb +7 -0
- data/spec/notation/conversion/change_conversion_spec.rb +40 -0
- data/spec/notation/conversion/measure_note_map_spec.rb +73 -0
- data/spec/notation/conversion/measured_score_conversion_spec.rb +141 -0
- data/spec/notation/conversion/measured_score_converter_spec.rb +329 -0
- data/spec/notation/conversion/note_time_converter_spec.rb +81 -0
- data/spec/notation/conversion/tempo_conversion_spec.rb +40 -0
- data/spec/notation/conversion/unmeasured_score_conversion_spec.rb +71 -0
- data/spec/notation/conversion/unmeasured_score_converter_spec.rb +116 -0
- data/spec/notation/model/change_spec.rb +90 -0
- data/spec/notation/model/link_spec.rb +83 -0
- data/spec/notation/model/meter_spec.rb +97 -0
- data/spec/notation/model/note_spec.rb +183 -0
- data/spec/notation/model/part_spec.rb +69 -0
- data/spec/notation/model/pitch_spec.rb +180 -0
- data/spec/notation/model/program_spec.rb +50 -0
- data/spec/notation/model/score_spec.rb +211 -0
- data/spec/notation/packing/change_packing_spec.rb +153 -0
- data/spec/notation/packing/part_packing_spec.rb +66 -0
- data/spec/notation/packing/program_packing_spec.rb +33 -0
- data/spec/notation/packing/score_packing_spec.rb +301 -0
- data/spec/notation/parsing/articulation_parsing_spec.rb +23 -0
- data/spec/notation/parsing/convenience_methods_spec.rb +99 -0
- data/spec/notation/parsing/duration_nodes_spec.rb +83 -0
- data/spec/notation/parsing/duration_parsing_spec.rb +70 -0
- data/spec/notation/parsing/link_nodes_spec.rb +30 -0
- data/spec/notation/parsing/link_parsing_spec.rb +13 -0
- data/spec/notation/parsing/meter_parsing_spec.rb +23 -0
- data/spec/notation/parsing/note_node_spec.rb +87 -0
- data/spec/notation/parsing/note_parsing_spec.rb +46 -0
- data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +28 -0
- data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +11 -0
- data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +11 -0
- data/spec/notation/parsing/numbers/positive_float_spec.rb +28 -0
- data/spec/notation/parsing/numbers/positive_integer_spec.rb +28 -0
- data/spec/notation/parsing/numbers/positive_rational_spec.rb +28 -0
- data/spec/notation/parsing/pitch_node_spec.rb +38 -0
- data/spec/notation/parsing/pitch_parsing_spec.rb +14 -0
- data/spec/notation/parsing/segment_parsing_spec.rb +27 -0
- data/spec/notation/util/value_computer_spec.rb +146 -0
- data/spec/performance/conversion/glissando_converter_spec.rb +93 -0
- data/spec/performance/conversion/note_sequence_extractor_spec.rb +230 -0
- data/spec/performance/conversion/portamento_converter_spec.rb +91 -0
- data/spec/performance/conversion/score_collator_spec.rb +183 -0
- data/spec/performance/midi/midi_util_spec.rb +110 -0
- data/spec/performance/midi/part_sequencer_spec.rb +40 -0
- data/spec/performance/midi/score_sequencer_spec.rb +50 -0
- data/spec/performance/model/note_sequence_spec.rb +147 -0
- data/spec/performance/util/note_linker_spec.rb +68 -0
- data/spec/performance/util/optimization_spec.rb +73 -0
- data/spec/spec_helper.rb +43 -0
- metadata +323 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
module Pitches
|
4
|
+
# Define pitch objects for octaves octave 0 through 9
|
5
|
+
{
|
6
|
+
:Bb => 10, :B => 11,
|
7
|
+
:Cb => 11, :C => 0,
|
8
|
+
:Db => 1, :D => 2,
|
9
|
+
:Eb => 3, :E => 4,
|
10
|
+
:Fb => 4, :F => 5,
|
11
|
+
:Gb => 6, :G => 7,
|
12
|
+
:Ab => 8, :A => 9,
|
13
|
+
}.each do |sym,pc|
|
14
|
+
(0..9).each do |octave|
|
15
|
+
obj = Pitch.new octave: octave, semitone: pc
|
16
|
+
Pitches.const_set(:"#{sym}#{octave}",obj)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
# Program defines markers (by starting note offset) and subprograms (list which markers are played).
|
4
|
+
#
|
5
|
+
# @author James Tunnell
|
6
|
+
#
|
7
|
+
class Program
|
8
|
+
include Validatable
|
9
|
+
|
10
|
+
attr_accessor :segments
|
11
|
+
|
12
|
+
def initialize segments = []
|
13
|
+
@segments = segments
|
14
|
+
end
|
15
|
+
|
16
|
+
def check_methods
|
17
|
+
[:ensure_increasing_segments, :ensure_nonnegative_segments]
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [Float] the sum of all program segment lengths
|
21
|
+
def length
|
22
|
+
segments.inject(0.0) { |length, segment| length + (segment.last - segment.first) }
|
23
|
+
end
|
24
|
+
|
25
|
+
def == other
|
26
|
+
return other.respond_to?(:segments) && @segments == other.segments
|
27
|
+
end
|
28
|
+
|
29
|
+
def include? offset
|
30
|
+
@segments.each do |segment|
|
31
|
+
if segment.include?(offset)
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
end
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
|
38
|
+
def ensure_increasing_segments
|
39
|
+
non_increasing = @segments.select {|seg| seg.first >= seg.last }
|
40
|
+
if non_increasing.any?
|
41
|
+
raise NonIncreasingError, "Non-increasing segments found #{non_increasing}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def ensure_nonnegative_segments
|
46
|
+
negative = @segments.select {|seg| seg.first < 0 || seg.last < 0 }
|
47
|
+
if negative.any?
|
48
|
+
raise NegativeError, "Segments #{negative} have negative values"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
@@ -0,0 +1,132 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Score
|
4
|
+
include Validatable
|
5
|
+
attr_accessor :parts, :program
|
6
|
+
|
7
|
+
def initialize parts: {}, program: Program.new
|
8
|
+
@parts = parts
|
9
|
+
@program = program
|
10
|
+
yield(self) if block_given?
|
11
|
+
end
|
12
|
+
|
13
|
+
def validatables
|
14
|
+
[ @program ] + @parts.values
|
15
|
+
end
|
16
|
+
|
17
|
+
def clone
|
18
|
+
Marshal.load(Marshal.dump(self))
|
19
|
+
end
|
20
|
+
|
21
|
+
def ==(other)
|
22
|
+
return @parts == other.parts && @program == other.program
|
23
|
+
end
|
24
|
+
|
25
|
+
def duration
|
26
|
+
@parts.map {|p| p.duration }.max
|
27
|
+
end
|
28
|
+
|
29
|
+
def collated?
|
30
|
+
@program.segments.size == 1 && @program.segments[0].first == 0
|
31
|
+
end
|
32
|
+
|
33
|
+
class Timed < Score
|
34
|
+
end
|
35
|
+
|
36
|
+
class TempoBased < Score
|
37
|
+
attr_accessor :start_tempo, :tempo_changes
|
38
|
+
|
39
|
+
def initialize start_tempo, tempo_changes: {}, parts: {}, program: Program.new
|
40
|
+
@start_tempo = start_tempo
|
41
|
+
@tempo_changes = tempo_changes
|
42
|
+
super(parts: parts, program: program)
|
43
|
+
|
44
|
+
yield(self) if block_given?
|
45
|
+
end
|
46
|
+
|
47
|
+
def check_methods
|
48
|
+
[:check_start_tempo, :check_tempo_changes]
|
49
|
+
end
|
50
|
+
|
51
|
+
def ==(other)
|
52
|
+
return super(other) && @start_tempo == other.start_tempo &&
|
53
|
+
@tempo_changes == other.tempo_changes
|
54
|
+
end
|
55
|
+
|
56
|
+
def check_start_tempo
|
57
|
+
if @start_tempo <= 0
|
58
|
+
raise NonPositiveError, "start tempo (#{@start_tempo}) is not positive"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def check_tempo_changes
|
63
|
+
badvalues = @tempo_changes.select {|k,v| v.value <= 0 }
|
64
|
+
if badvalues.any?
|
65
|
+
raise NonPositiveError, "tempo changes (#{badvalues}) are not positive"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
# Tempo-based score without meter, bar lines, or fixed pulse (beat).
|
71
|
+
# Offsets are note-based, and tempo values are in quarter-notes-per-minute.
|
72
|
+
class Unmeasured < Score::TempoBased
|
73
|
+
end
|
74
|
+
|
75
|
+
# Tempo-based score with meter, bar lines, and a fixed pulse (beat).
|
76
|
+
# Offsets are measure-based, and tempo values are in beats-per-minute.
|
77
|
+
class Measured < Score::TempoBased
|
78
|
+
attr_accessor :start_meter, :meter_changes
|
79
|
+
|
80
|
+
def initialize start_meter, start_tempo, meter_changes: {}, tempo_changes: {}, parts: {}, program: Program.new
|
81
|
+
@start_meter = start_meter
|
82
|
+
@meter_changes = meter_changes
|
83
|
+
|
84
|
+
super(start_tempo, tempo_changes: tempo_changes,
|
85
|
+
program: program, parts: parts)
|
86
|
+
yield(self) if block_given?
|
87
|
+
end
|
88
|
+
|
89
|
+
def check_methods
|
90
|
+
super() + [:check_startmeter_type, :check_meterchange_types,
|
91
|
+
:check_meterchange_durs, :check_meterchange_offsets]
|
92
|
+
end
|
93
|
+
|
94
|
+
def validatables
|
95
|
+
super() + [ @start_meter ] + @meter_changes.values.map {|v| v.value}
|
96
|
+
end
|
97
|
+
|
98
|
+
def check_startmeter_type
|
99
|
+
unless @start_meter.is_a? Meter
|
100
|
+
raise TypeError, "start meter #{@start_meter} is not a Meter object"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def check_meterchange_types
|
105
|
+
badtypes = @meter_changes.select {|k,v| !v.value.is_a?(Meter) }
|
106
|
+
if badtypes.any?
|
107
|
+
raise TypeError, "meter change values #{nonmeter_values} are not Meter objects"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def check_meterchange_offsets
|
112
|
+
badoffsets = @meter_changes.select {|k,v| k != k.to_i }
|
113
|
+
if badoffsets.any?
|
114
|
+
raise NonIntegerError, "meter changes #{badoffsets} have non-integer offsets"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def check_meterchange_durs
|
119
|
+
nonzero_duration = @meter_changes.select {|k,v| !v.is_a?(Change::Immediate) }
|
120
|
+
if nonzero_duration.any?
|
121
|
+
raise NonZeroError, "meter changes #{nonzero_duration} are not immediate"
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def ==(other)
|
126
|
+
return super(other) && @start_meter == other.start_meter &&
|
127
|
+
@meter_changes == other.meter_changes
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Change
|
4
|
+
class Immediate < Change
|
5
|
+
def pack
|
6
|
+
pack_common
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.unpack packing
|
10
|
+
new(packing["value"])
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Gradual < Change
|
15
|
+
def pack
|
16
|
+
packing = pack_common.merge("impending" => @impending)
|
17
|
+
unless @remaining == 0
|
18
|
+
packing["remaining"] = @remaining
|
19
|
+
end
|
20
|
+
unless @elapsed == 0
|
21
|
+
packing["elapsed"] = @elapsed
|
22
|
+
end
|
23
|
+
return packing
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.unpack packing
|
27
|
+
elapsed = packing["elapsed"] || 0
|
28
|
+
remaining = packing["remaining"] || 0
|
29
|
+
new(packing["value"], packing["impending"], elapsed, remaining)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.unpack packing
|
34
|
+
type = const_get(packing["type"])
|
35
|
+
type.unpack(packing)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def pack_common
|
41
|
+
{ "type" => self.class.to_s.split("::")[-1],
|
42
|
+
"value" => @value }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Part
|
4
|
+
def pack
|
5
|
+
packed_notes = notes.map {|n| n.to_s }.join(" ")
|
6
|
+
packed_dcs = Hash[ dynamic_changes.map do |offset,change|
|
7
|
+
[ offset, change.pack ]
|
8
|
+
end ]
|
9
|
+
|
10
|
+
{
|
11
|
+
'notes' => packed_notes,
|
12
|
+
'start_dynamic' => start_dynamic,
|
13
|
+
'dynamic_changes' => packed_dcs
|
14
|
+
}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.unpack packing
|
18
|
+
unpacked_notes = Note.split_parse(packing["notes"])
|
19
|
+
unpacked_dcs = Hash[ packing["dynamic_changes"].map do |offset,change|
|
20
|
+
[ offset,Change.unpack(change) ]
|
21
|
+
end ]
|
22
|
+
|
23
|
+
new(
|
24
|
+
packing["start_dynamic"],
|
25
|
+
notes: unpacked_notes,
|
26
|
+
dynamic_changes: unpacked_dcs
|
27
|
+
)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
module Musicality
|
2
|
+
|
3
|
+
class Score
|
4
|
+
class Timed < Score
|
5
|
+
def pack
|
6
|
+
pack_common
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.unpack packing
|
10
|
+
score = Score.unpack_common(packing)
|
11
|
+
new(parts: score.parts, program: score.program)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class TempoBased < Score
|
16
|
+
def pack
|
17
|
+
packed_tcs = Hash[ tempo_changes.map do |offset,change|
|
18
|
+
[offset,change.pack]
|
19
|
+
end ]
|
20
|
+
|
21
|
+
pack_common.merge("start_tempo" => @start_tempo,
|
22
|
+
"tempo_changes" => packed_tcs)
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.unpack packing
|
26
|
+
score = Score.unpack_common(packing)
|
27
|
+
|
28
|
+
unpacked_tcs = Hash[ packing["tempo_changes"].map do |k,v|
|
29
|
+
[k, Change.unpack(v) ]
|
30
|
+
end ]
|
31
|
+
|
32
|
+
new(packing["start_tempo"],
|
33
|
+
tempo_changes: unpacked_tcs,
|
34
|
+
program: score.program,
|
35
|
+
parts: score.parts
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class Unmeasured < TempoBased
|
41
|
+
def pack
|
42
|
+
super()
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.unpack packing
|
46
|
+
score = superclass.unpack(packing)
|
47
|
+
new(score.start_tempo, program: score.program,
|
48
|
+
tempo_changes: score.tempo_changes, parts: score.parts)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
class Measured < TempoBased
|
53
|
+
def pack
|
54
|
+
return super().merge("start_meter" => start_meter.to_s,
|
55
|
+
"meter_changes" => Hash[ meter_changes.map do |off,change|
|
56
|
+
[off,change.pack.merge("value" => change.value.to_s)]
|
57
|
+
end ]
|
58
|
+
)
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.unpack packing
|
62
|
+
score = superclass.unpack(packing)
|
63
|
+
unpacked_start_meter = Meter.parse(packing["start_meter"])
|
64
|
+
unpacked_mcs = Hash[ packing["meter_changes"].map do |off,p|
|
65
|
+
[off, Change.unpack(p.merge("value" => Meter.parse(p["value"]))) ]
|
66
|
+
end ]
|
67
|
+
|
68
|
+
new(unpacked_start_meter, score.start_tempo,
|
69
|
+
parts: score.parts, program: score.program,
|
70
|
+
meter_changes: unpacked_mcs, tempo_changes: score.tempo_changes)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.unpack packing
|
75
|
+
type = const_get(packing["type"])
|
76
|
+
type.unpack(packing)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def pack_common
|
82
|
+
packed_parts = Hash[
|
83
|
+
@parts.map do |name,part|
|
84
|
+
[ name, part.pack ]
|
85
|
+
end
|
86
|
+
]
|
87
|
+
packed_prog = program.pack
|
88
|
+
|
89
|
+
{ "type" => self.class.to_s.split("::")[-1],
|
90
|
+
"program" => packed_prog,
|
91
|
+
"parts" => packed_parts,
|
92
|
+
}
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.unpack_common packing
|
96
|
+
unpacked_parts = Hash[ packing["parts"].map do |name,packed|
|
97
|
+
[name, Part.unpack(packed)]
|
98
|
+
end ]
|
99
|
+
|
100
|
+
unpacked_prog = Program.unpack packing["program"]
|
101
|
+
|
102
|
+
new(program: unpacked_prog,
|
103
|
+
parts: unpacked_parts
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,264 @@
|
|
1
|
+
# Autogenerated from a Treetop grammar. Edits may be lost.
|
2
|
+
|
3
|
+
|
4
|
+
module Musicality
|
5
|
+
module Parsing
|
6
|
+
|
7
|
+
module Articulation
|
8
|
+
include Treetop::Runtime
|
9
|
+
|
10
|
+
def root
|
11
|
+
@root ||= :articulation
|
12
|
+
end
|
13
|
+
|
14
|
+
def _nt_articulation
|
15
|
+
start_index = index
|
16
|
+
if node_cache[:articulation].has_key?(index)
|
17
|
+
cached = node_cache[:articulation][index]
|
18
|
+
if cached
|
19
|
+
node_cache[:articulation][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
20
|
+
@index = cached.interval.end
|
21
|
+
end
|
22
|
+
return cached
|
23
|
+
end
|
24
|
+
|
25
|
+
i0 = index
|
26
|
+
r1 = _nt_slur
|
27
|
+
if r1
|
28
|
+
r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
|
29
|
+
r0 = r1
|
30
|
+
else
|
31
|
+
r2 = _nt_legato
|
32
|
+
if r2
|
33
|
+
r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
|
34
|
+
r0 = r2
|
35
|
+
else
|
36
|
+
r3 = _nt_tenuto
|
37
|
+
if r3
|
38
|
+
r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
|
39
|
+
r0 = r3
|
40
|
+
else
|
41
|
+
r4 = _nt_portato
|
42
|
+
if r4
|
43
|
+
r4 = SyntaxNode.new(input, (index-1)...index) if r4 == true
|
44
|
+
r0 = r4
|
45
|
+
else
|
46
|
+
r5 = _nt_staccato
|
47
|
+
if r5
|
48
|
+
r5 = SyntaxNode.new(input, (index-1)...index) if r5 == true
|
49
|
+
r0 = r5
|
50
|
+
else
|
51
|
+
r6 = _nt_staccatissimo
|
52
|
+
if r6
|
53
|
+
r6 = SyntaxNode.new(input, (index-1)...index) if r6 == true
|
54
|
+
r0 = r6
|
55
|
+
else
|
56
|
+
@index = i0
|
57
|
+
r0 = nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
node_cache[:articulation][start_index] = r0
|
66
|
+
|
67
|
+
r0
|
68
|
+
end
|
69
|
+
|
70
|
+
module Slur0
|
71
|
+
def to_articulation
|
72
|
+
Musicality::Articulations::SLUR
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def _nt_slur
|
77
|
+
start_index = index
|
78
|
+
if node_cache[:slur].has_key?(index)
|
79
|
+
cached = node_cache[:slur][index]
|
80
|
+
if cached
|
81
|
+
node_cache[:slur][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
82
|
+
@index = cached.interval.end
|
83
|
+
end
|
84
|
+
return cached
|
85
|
+
end
|
86
|
+
|
87
|
+
if (match_len = has_terminal?("=", false, index))
|
88
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
89
|
+
r0.extend(Slur0)
|
90
|
+
@index += match_len
|
91
|
+
else
|
92
|
+
terminal_parse_failure("=")
|
93
|
+
r0 = nil
|
94
|
+
end
|
95
|
+
|
96
|
+
node_cache[:slur][start_index] = r0
|
97
|
+
|
98
|
+
r0
|
99
|
+
end
|
100
|
+
|
101
|
+
module Legato0
|
102
|
+
def to_articulation
|
103
|
+
Musicality::Articulations::LEGATO
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def _nt_legato
|
108
|
+
start_index = index
|
109
|
+
if node_cache[:legato].has_key?(index)
|
110
|
+
cached = node_cache[:legato][index]
|
111
|
+
if cached
|
112
|
+
node_cache[:legato][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
113
|
+
@index = cached.interval.end
|
114
|
+
end
|
115
|
+
return cached
|
116
|
+
end
|
117
|
+
|
118
|
+
if (match_len = has_terminal?("|", false, index))
|
119
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
120
|
+
r0.extend(Legato0)
|
121
|
+
@index += match_len
|
122
|
+
else
|
123
|
+
terminal_parse_failure("|")
|
124
|
+
r0 = nil
|
125
|
+
end
|
126
|
+
|
127
|
+
node_cache[:legato][start_index] = r0
|
128
|
+
|
129
|
+
r0
|
130
|
+
end
|
131
|
+
|
132
|
+
module Tenuto0
|
133
|
+
def to_articulation
|
134
|
+
Musicality::Articulations::TENUTO
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def _nt_tenuto
|
139
|
+
start_index = index
|
140
|
+
if node_cache[:tenuto].has_key?(index)
|
141
|
+
cached = node_cache[:tenuto][index]
|
142
|
+
if cached
|
143
|
+
node_cache[:tenuto][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
144
|
+
@index = cached.interval.end
|
145
|
+
end
|
146
|
+
return cached
|
147
|
+
end
|
148
|
+
|
149
|
+
if (match_len = has_terminal?("_", false, index))
|
150
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
151
|
+
r0.extend(Tenuto0)
|
152
|
+
@index += match_len
|
153
|
+
else
|
154
|
+
terminal_parse_failure("_")
|
155
|
+
r0 = nil
|
156
|
+
end
|
157
|
+
|
158
|
+
node_cache[:tenuto][start_index] = r0
|
159
|
+
|
160
|
+
r0
|
161
|
+
end
|
162
|
+
|
163
|
+
module Portato0
|
164
|
+
def to_articulation
|
165
|
+
Musicality::Articulations::PORTATO
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def _nt_portato
|
170
|
+
start_index = index
|
171
|
+
if node_cache[:portato].has_key?(index)
|
172
|
+
cached = node_cache[:portato][index]
|
173
|
+
if cached
|
174
|
+
node_cache[:portato][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
175
|
+
@index = cached.interval.end
|
176
|
+
end
|
177
|
+
return cached
|
178
|
+
end
|
179
|
+
|
180
|
+
if (match_len = has_terminal?("%", false, index))
|
181
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
182
|
+
r0.extend(Portato0)
|
183
|
+
@index += match_len
|
184
|
+
else
|
185
|
+
terminal_parse_failure("%")
|
186
|
+
r0 = nil
|
187
|
+
end
|
188
|
+
|
189
|
+
node_cache[:portato][start_index] = r0
|
190
|
+
|
191
|
+
r0
|
192
|
+
end
|
193
|
+
|
194
|
+
module Staccato0
|
195
|
+
def to_articulation
|
196
|
+
Musicality::Articulations::STACCATO
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
def _nt_staccato
|
201
|
+
start_index = index
|
202
|
+
if node_cache[:staccato].has_key?(index)
|
203
|
+
cached = node_cache[:staccato][index]
|
204
|
+
if cached
|
205
|
+
node_cache[:staccato][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
206
|
+
@index = cached.interval.end
|
207
|
+
end
|
208
|
+
return cached
|
209
|
+
end
|
210
|
+
|
211
|
+
if (match_len = has_terminal?(".", false, index))
|
212
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
213
|
+
r0.extend(Staccato0)
|
214
|
+
@index += match_len
|
215
|
+
else
|
216
|
+
terminal_parse_failure(".")
|
217
|
+
r0 = nil
|
218
|
+
end
|
219
|
+
|
220
|
+
node_cache[:staccato][start_index] = r0
|
221
|
+
|
222
|
+
r0
|
223
|
+
end
|
224
|
+
|
225
|
+
module Staccatissimo0
|
226
|
+
def to_articulation
|
227
|
+
Musicality::Articulations::STACCATISSIMO
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def _nt_staccatissimo
|
232
|
+
start_index = index
|
233
|
+
if node_cache[:staccatissimo].has_key?(index)
|
234
|
+
cached = node_cache[:staccatissimo][index]
|
235
|
+
if cached
|
236
|
+
node_cache[:staccatissimo][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
|
237
|
+
@index = cached.interval.end
|
238
|
+
end
|
239
|
+
return cached
|
240
|
+
end
|
241
|
+
|
242
|
+
if (match_len = has_terminal?("'", false, index))
|
243
|
+
r0 = instantiate_node(SyntaxNode,input, index...(index + match_len))
|
244
|
+
r0.extend(Staccatissimo0)
|
245
|
+
@index += match_len
|
246
|
+
else
|
247
|
+
terminal_parse_failure("'")
|
248
|
+
r0 = nil
|
249
|
+
end
|
250
|
+
|
251
|
+
node_cache[:staccatissimo][start_index] = r0
|
252
|
+
|
253
|
+
r0
|
254
|
+
end
|
255
|
+
|
256
|
+
end
|
257
|
+
|
258
|
+
class ArticulationParser < Treetop::Runtime::CompiledParser
|
259
|
+
include Articulation
|
260
|
+
end
|
261
|
+
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|