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.
Files changed (141) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +15 -0
  3. data/.rspec +2 -0
  4. data/.ruby-version +1 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +47 -0
  8. data/Rakefile +65 -0
  9. data/bin/midify +78 -0
  10. data/examples/hip.rb +32 -0
  11. data/examples/missed_connection.rb +26 -0
  12. data/examples/song1.rb +33 -0
  13. data/examples/song2.rb +32 -0
  14. data/lib/musicality/errors.rb +9 -0
  15. data/lib/musicality/notation/conversion/change_conversion.rb +19 -0
  16. data/lib/musicality/notation/conversion/measure_note_map.rb +40 -0
  17. data/lib/musicality/notation/conversion/measured_score_conversion.rb +70 -0
  18. data/lib/musicality/notation/conversion/measured_score_converter.rb +95 -0
  19. data/lib/musicality/notation/conversion/note_time_converter.rb +68 -0
  20. data/lib/musicality/notation/conversion/tempo_conversion.rb +25 -0
  21. data/lib/musicality/notation/conversion/unmeasured_score_conversion.rb +47 -0
  22. data/lib/musicality/notation/conversion/unmeasured_score_converter.rb +64 -0
  23. data/lib/musicality/notation/model/articulations.rb +13 -0
  24. data/lib/musicality/notation/model/change.rb +62 -0
  25. data/lib/musicality/notation/model/dynamics.rb +12 -0
  26. data/lib/musicality/notation/model/link.rb +73 -0
  27. data/lib/musicality/notation/model/meter.rb +54 -0
  28. data/lib/musicality/notation/model/meters.rb +9 -0
  29. data/lib/musicality/notation/model/note.rb +120 -0
  30. data/lib/musicality/notation/model/part.rb +54 -0
  31. data/lib/musicality/notation/model/pitch.rb +163 -0
  32. data/lib/musicality/notation/model/pitches.rb +21 -0
  33. data/lib/musicality/notation/model/program.rb +53 -0
  34. data/lib/musicality/notation/model/score.rb +132 -0
  35. data/lib/musicality/notation/packing/change_packing.rb +46 -0
  36. data/lib/musicality/notation/packing/part_packing.rb +31 -0
  37. data/lib/musicality/notation/packing/program_packing.rb +16 -0
  38. data/lib/musicality/notation/packing/score_packing.rb +108 -0
  39. data/lib/musicality/notation/parsing/articulation_parsing.rb +264 -0
  40. data/lib/musicality/notation/parsing/articulation_parsing.treetop +59 -0
  41. data/lib/musicality/notation/parsing/convenience_methods.rb +74 -0
  42. data/lib/musicality/notation/parsing/duration_nodes.rb +21 -0
  43. data/lib/musicality/notation/parsing/duration_parsing.rb +205 -0
  44. data/lib/musicality/notation/parsing/duration_parsing.treetop +25 -0
  45. data/lib/musicality/notation/parsing/link_nodes.rb +35 -0
  46. data/lib/musicality/notation/parsing/link_parsing.rb +270 -0
  47. data/lib/musicality/notation/parsing/link_parsing.treetop +33 -0
  48. data/lib/musicality/notation/parsing/meter_parsing.rb +190 -0
  49. data/lib/musicality/notation/parsing/meter_parsing.treetop +29 -0
  50. data/lib/musicality/notation/parsing/note_node.rb +40 -0
  51. data/lib/musicality/notation/parsing/note_parsing.rb +229 -0
  52. data/lib/musicality/notation/parsing/note_parsing.treetop +28 -0
  53. data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.rb +289 -0
  54. data/lib/musicality/notation/parsing/numbers/nonnegative_float_parsing.treetop +29 -0
  55. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.rb +64 -0
  56. data/lib/musicality/notation/parsing/numbers/nonnegative_integer_parsing.treetop +17 -0
  57. data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.rb +86 -0
  58. data/lib/musicality/notation/parsing/numbers/nonnegative_rational_parsing.treetop +20 -0
  59. data/lib/musicality/notation/parsing/numbers/positive_float_parsing.rb +503 -0
  60. data/lib/musicality/notation/parsing/numbers/positive_float_parsing.treetop +33 -0
  61. data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.rb +95 -0
  62. data/lib/musicality/notation/parsing/numbers/positive_integer_parsing.treetop +19 -0
  63. data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.rb +84 -0
  64. data/lib/musicality/notation/parsing/numbers/positive_rational_parsing.treetop +19 -0
  65. data/lib/musicality/notation/parsing/parseable.rb +30 -0
  66. data/lib/musicality/notation/parsing/pitch_node.rb +23 -0
  67. data/lib/musicality/notation/parsing/pitch_parsing.rb +448 -0
  68. data/lib/musicality/notation/parsing/pitch_parsing.treetop +52 -0
  69. data/lib/musicality/notation/parsing/segment_parsing.rb +141 -0
  70. data/lib/musicality/notation/parsing/segment_parsing.treetop +23 -0
  71. data/lib/musicality/notation/util/interpolation.rb +16 -0
  72. data/lib/musicality/notation/util/piecewise_function.rb +122 -0
  73. data/lib/musicality/notation/util/value_computer.rb +170 -0
  74. data/lib/musicality/performance/conversion/glissando_converter.rb +34 -0
  75. data/lib/musicality/performance/conversion/note_sequence_extractor.rb +98 -0
  76. data/lib/musicality/performance/conversion/portamento_converter.rb +24 -0
  77. data/lib/musicality/performance/conversion/score_collator.rb +126 -0
  78. data/lib/musicality/performance/midi/midi_events.rb +34 -0
  79. data/lib/musicality/performance/midi/midi_util.rb +31 -0
  80. data/lib/musicality/performance/midi/part_sequencer.rb +123 -0
  81. data/lib/musicality/performance/midi/score_sequencer.rb +45 -0
  82. data/lib/musicality/performance/model/note_attacks.rb +19 -0
  83. data/lib/musicality/performance/model/note_sequence.rb +111 -0
  84. data/lib/musicality/performance/util/note_linker.rb +28 -0
  85. data/lib/musicality/performance/util/optimization.rb +31 -0
  86. data/lib/musicality/validatable.rb +38 -0
  87. data/lib/musicality/version.rb +3 -0
  88. data/lib/musicality.rb +81 -0
  89. data/musicality.gemspec +30 -0
  90. data/spec/musicality_spec.rb +7 -0
  91. data/spec/notation/conversion/change_conversion_spec.rb +40 -0
  92. data/spec/notation/conversion/measure_note_map_spec.rb +73 -0
  93. data/spec/notation/conversion/measured_score_conversion_spec.rb +141 -0
  94. data/spec/notation/conversion/measured_score_converter_spec.rb +329 -0
  95. data/spec/notation/conversion/note_time_converter_spec.rb +81 -0
  96. data/spec/notation/conversion/tempo_conversion_spec.rb +40 -0
  97. data/spec/notation/conversion/unmeasured_score_conversion_spec.rb +71 -0
  98. data/spec/notation/conversion/unmeasured_score_converter_spec.rb +116 -0
  99. data/spec/notation/model/change_spec.rb +90 -0
  100. data/spec/notation/model/link_spec.rb +83 -0
  101. data/spec/notation/model/meter_spec.rb +97 -0
  102. data/spec/notation/model/note_spec.rb +183 -0
  103. data/spec/notation/model/part_spec.rb +69 -0
  104. data/spec/notation/model/pitch_spec.rb +180 -0
  105. data/spec/notation/model/program_spec.rb +50 -0
  106. data/spec/notation/model/score_spec.rb +211 -0
  107. data/spec/notation/packing/change_packing_spec.rb +153 -0
  108. data/spec/notation/packing/part_packing_spec.rb +66 -0
  109. data/spec/notation/packing/program_packing_spec.rb +33 -0
  110. data/spec/notation/packing/score_packing_spec.rb +301 -0
  111. data/spec/notation/parsing/articulation_parsing_spec.rb +23 -0
  112. data/spec/notation/parsing/convenience_methods_spec.rb +99 -0
  113. data/spec/notation/parsing/duration_nodes_spec.rb +83 -0
  114. data/spec/notation/parsing/duration_parsing_spec.rb +70 -0
  115. data/spec/notation/parsing/link_nodes_spec.rb +30 -0
  116. data/spec/notation/parsing/link_parsing_spec.rb +13 -0
  117. data/spec/notation/parsing/meter_parsing_spec.rb +23 -0
  118. data/spec/notation/parsing/note_node_spec.rb +87 -0
  119. data/spec/notation/parsing/note_parsing_spec.rb +46 -0
  120. data/spec/notation/parsing/numbers/nonnegative_float_spec.rb +28 -0
  121. data/spec/notation/parsing/numbers/nonnegative_integer_spec.rb +11 -0
  122. data/spec/notation/parsing/numbers/nonnegative_rational_spec.rb +11 -0
  123. data/spec/notation/parsing/numbers/positive_float_spec.rb +28 -0
  124. data/spec/notation/parsing/numbers/positive_integer_spec.rb +28 -0
  125. data/spec/notation/parsing/numbers/positive_rational_spec.rb +28 -0
  126. data/spec/notation/parsing/pitch_node_spec.rb +38 -0
  127. data/spec/notation/parsing/pitch_parsing_spec.rb +14 -0
  128. data/spec/notation/parsing/segment_parsing_spec.rb +27 -0
  129. data/spec/notation/util/value_computer_spec.rb +146 -0
  130. data/spec/performance/conversion/glissando_converter_spec.rb +93 -0
  131. data/spec/performance/conversion/note_sequence_extractor_spec.rb +230 -0
  132. data/spec/performance/conversion/portamento_converter_spec.rb +91 -0
  133. data/spec/performance/conversion/score_collator_spec.rb +183 -0
  134. data/spec/performance/midi/midi_util_spec.rb +110 -0
  135. data/spec/performance/midi/part_sequencer_spec.rb +40 -0
  136. data/spec/performance/midi/score_sequencer_spec.rb +50 -0
  137. data/spec/performance/model/note_sequence_spec.rb +147 -0
  138. data/spec/performance/util/note_linker_spec.rb +68 -0
  139. data/spec/performance/util/optimization_spec.rb +73 -0
  140. data/spec/spec_helper.rb +43 -0
  141. 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,16 @@
1
+ module Musicality
2
+
3
+ class Program
4
+ def pack
5
+ @segments.map do |seg|
6
+ seg.to_s
7
+ end
8
+ end
9
+
10
+ def self.unpack packing
11
+ segments = packing.map {|str| Segment.parse(str) }
12
+ new segments
13
+ end
14
+ end
15
+
16
+ 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