music-transcription 0.17.1 → 0.19.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/examples/hip.rb +4 -4
  3. data/examples/missed_connection.rb +3 -3
  4. data/examples/song1.rb +6 -6
  5. data/examples/song2.rb +3 -3
  6. data/lib/music-transcription.rb +8 -2
  7. data/lib/music-transcription/model/change.rb +9 -3
  8. data/lib/music-transcription/model/measure_score.rb +62 -0
  9. data/lib/music-transcription/model/meter.rb +5 -1
  10. data/lib/music-transcription/model/note.rb +4 -1
  11. data/lib/music-transcription/model/note_score.rb +60 -0
  12. data/lib/music-transcription/model/part.rb +4 -1
  13. data/lib/music-transcription/model/program.rb +5 -2
  14. data/lib/music-transcription/model/tempo.rb +13 -23
  15. data/lib/music-transcription/packing/measure_score_packing.rb +34 -0
  16. data/lib/music-transcription/packing/{score_packing.rb → note_score_packing.rb} +12 -21
  17. data/lib/music-transcription/packing/part_packing.rb +1 -1
  18. data/lib/music-transcription/packing/program_packing.rb +1 -1
  19. data/lib/music-transcription/parsing/convenience_methods.rb +37 -58
  20. data/lib/music-transcription/parsing/numbers/nonnegative_float_parsing.rb +172 -59
  21. data/lib/music-transcription/parsing/numbers/nonnegative_float_parsing.treetop +13 -1
  22. data/lib/music-transcription/parsing/numbers/positive_float_parsing.rb +505 -0
  23. data/lib/music-transcription/parsing/numbers/positive_float_parsing.treetop +35 -0
  24. data/lib/music-transcription/parsing/numbers/positive_integer_parsing.rb +2 -0
  25. data/lib/music-transcription/parsing/numbers/positive_integer_parsing.treetop +2 -0
  26. data/lib/music-transcription/parsing/numbers/positive_rational_parsing.rb +86 -0
  27. data/lib/music-transcription/parsing/numbers/positive_rational_parsing.treetop +21 -0
  28. data/lib/music-transcription/parsing/parseable.rb +32 -0
  29. data/lib/music-transcription/parsing/tempo_parsing.rb +396 -0
  30. data/lib/music-transcription/parsing/tempo_parsing.treetop +49 -0
  31. data/lib/music-transcription/validatable.rb +5 -18
  32. data/lib/music-transcription/version.rb +1 -1
  33. data/spec/model/measure_score_spec.rb +85 -0
  34. data/spec/model/note_score_spec.rb +68 -0
  35. data/spec/model/tempo_spec.rb +15 -15
  36. data/spec/packing/{score_packing_spec.rb → measure_score_packing_spec.rb} +13 -7
  37. data/spec/packing/note_score_packing_spec.rb +100 -0
  38. data/spec/packing/part_packing_spec.rb +1 -1
  39. data/spec/parsing/convenience_methods_spec.rb +80 -81
  40. data/spec/parsing/numbers/nonnegative_float_spec.rb +19 -2
  41. data/spec/parsing/numbers/positive_float_spec.rb +28 -0
  42. data/spec/parsing/numbers/positive_integer_spec.rb +13 -2
  43. data/spec/parsing/numbers/positive_rational_spec.rb +28 -0
  44. data/spec/parsing/tempo_parsing_spec.rb +21 -0
  45. metadata +27 -8
  46. data/lib/music-transcription/model/score.rb +0 -68
  47. data/spec/model/score_spec.rb +0 -69
@@ -16,7 +16,7 @@ class Part
16
16
  end
17
17
 
18
18
  def self.unpack packing
19
- unpacked_notes = Parsing::notes(packing["notes"])
19
+ unpacked_notes = Note.split_parse(packing["notes"])
20
20
  unpacked_dcs = Hash[ packing["dynamic_changes"].map do |offset,change|
21
21
  [ offset,Change.unpack(change) ]
22
22
  end ]
@@ -9,7 +9,7 @@ class Program
9
9
  end
10
10
 
11
11
  def self.unpack packing
12
- segments = packing.map {|str| Parsing::segment(str) }
12
+ segments = packing.map {|str| Segment.parse(str) }
13
13
  new segments
14
14
  end
15
15
  end
@@ -1,103 +1,82 @@
1
1
  module Music
2
2
  module Transcription
3
- module Parsing
4
- DURATION_PARSER = DurationParser.new
5
- PITCH_PARSER = PitchParser.new
6
- NOTE_PARSER = NoteParser.new
7
- METER_PARSER = MeterParser.new
8
- SEGMENT_PARSER = SegmentParser.new
9
-
10
- def duration dur_str
11
- DURATION_PARSER.parse(dur_str).to_r
3
+
4
+ class Duration
5
+ PARSER = Parsing::DurationParser.new
6
+ CONVERSION_METHOD = :to_r
7
+ include Parseable
12
8
  end
13
- alias :dur :duration
14
- module_function :duration
15
- module_function :dur
16
9
 
17
- def durations durs_str
18
- durs_str.split.map do |dur_str|
19
- duration(dur_str)
20
- end
10
+ class Pitch
11
+ PARSER = Parsing::PitchParser.new
12
+ CONVERSION_METHOD = :to_pitch
13
+ include Parseable
21
14
  end
22
- alias :durs :durations
23
- module_function :durs
24
- module_function :durations
25
15
 
26
- def pitch p_str
27
- PITCH_PARSER.parse(p_str).to_pitch
16
+ class Note
17
+ PARSER = Parsing::NoteParser.new
18
+ CONVERSION_METHOD = :to_note
19
+ include Parseable
28
20
  end
29
- module_function :pitch
30
21
 
31
- def pitches ps_str
32
- ps_str.split.map do |p_str|
33
- pitch(p_str)
34
- end
35
- end
36
- module_function :pitches
37
-
38
- def note note_str
39
- NOTE_PARSER.parse(note_str).to_note
22
+ class Meter
23
+ PARSER = Parsing::MeterParser.new
24
+ CONVERSION_METHOD = :to_meter
25
+ include Parseable
40
26
  end
41
- module_function :note
42
27
 
43
- def notes notes_str
44
- notes_str.split.map do |note_str|
45
- note(note_str)
46
- end
28
+ class Segment
29
+ PARSER = Parsing::SegmentParser.new
30
+ CONVERSION_METHOD = :to_range
31
+ include Parseable
47
32
  end
48
- module_function :notes
49
33
 
50
- def meter meter_str
51
- METER_PARSER.parse(meter_str).to_meter
34
+ class Tempo
35
+ PARSER = Parsing::TempoParser.new
36
+ CONVERSION_METHOD = :to_tempo
37
+ include Parseable
52
38
  end
53
- module_function :meter
54
-
55
- def segment seg_str
56
- SEGMENT_PARSER.parse(seg_str).to_range
57
- end
58
- module_function :segment
59
- end
60
39
  end
61
40
  end
62
41
 
63
42
  class String
64
43
  def to_duration
65
- Music::Transcription::Parsing::duration(self)
44
+ Music::Transcription::Duration.parse(self)
66
45
  end
67
46
  alias :to_dur :to_duration
68
47
  alias :to_d :to_duration
69
48
 
70
- def to_durations
71
- Music::Transcription::Parsing::durations(self)
49
+ def to_durations pattern=" "
50
+ Music::Transcription::Duration.split_parse(self, pattern)
72
51
  end
73
52
  alias :to_durs :to_durations
74
53
  alias :to_ds :to_durations
75
54
 
76
- def to_pitch
77
- Music::Transcription::Parsing::pitch(self)
55
+ def to_pitch
56
+ Music::Transcription::Pitch.parse(self)
78
57
  end
79
58
  alias :to_p :to_pitch
80
59
 
81
- def to_pitches
82
- Music::Transcription::Parsing::pitches(self)
60
+ def to_pitches pattern=" "
61
+ Music::Transcription::Pitch.split_parse(self, pattern)
83
62
  end
84
63
  alias :to_ps :to_pitches
85
64
 
86
65
  def to_note
87
- Music::Transcription::Parsing::note(self)
66
+ Music::Transcription::Note.parse(self)
88
67
  end
89
68
  alias :to_n :to_note
90
69
 
91
- def to_notes
92
- Music::Transcription::Parsing::notes(self)
70
+ def to_notes pattern=" "
71
+ Music::Transcription::Note.split_parse(self, pattern)
93
72
  end
94
73
  alias :to_ns :to_notes
95
74
 
96
75
  def to_meter
97
- Music::Transcription::Parsing::meter(self)
76
+ Music::Transcription::Meter.parse(self)
98
77
  end
99
78
 
100
79
  def to_segment
101
- Music::Transcription::Parsing::segment(self)
80
+ Music::Transcription::Segment.parse(self)
102
81
  end
103
82
  end
@@ -13,12 +13,6 @@ module NonnegativeFloat
13
13
  end
14
14
 
15
15
  module NonnegativeFloat0
16
- end
17
-
18
- module NonnegativeFloat1
19
- end
20
-
21
- module NonnegativeFloat2
22
16
  def to_f
23
17
  text_value.to_f
24
18
  end
@@ -37,6 +31,100 @@ module NonnegativeFloat
37
31
  return cached
38
32
  end
39
33
 
34
+ i0 = index
35
+ r1 = _nt_float1
36
+ if r1
37
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
38
+ r0 = r1
39
+ r0.extend(NonnegativeFloat0)
40
+ else
41
+ r2 = _nt_float2
42
+ if r2
43
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
44
+ r0 = r2
45
+ r0.extend(NonnegativeFloat0)
46
+ else
47
+ @index = i0
48
+ r0 = nil
49
+ end
50
+ end
51
+
52
+ node_cache[:nonnegative_float][start_index] = r0
53
+
54
+ r0
55
+ end
56
+
57
+ module Float10
58
+ def exponent
59
+ elements[1]
60
+ end
61
+ end
62
+
63
+ def _nt_float1
64
+ start_index = index
65
+ if node_cache[:float1].has_key?(index)
66
+ cached = node_cache[:float1][index]
67
+ if cached
68
+ node_cache[:float1][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
69
+ @index = cached.interval.end
70
+ end
71
+ return cached
72
+ end
73
+
74
+ i0, s0 = index, []
75
+ s1, i1 = [], index
76
+ loop do
77
+ if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index)
78
+ r2 = true
79
+ @index += 1
80
+ else
81
+ terminal_parse_failure('[0-9]')
82
+ r2 = nil
83
+ end
84
+ if r2
85
+ s1 << r2
86
+ else
87
+ break
88
+ end
89
+ end
90
+ if s1.empty?
91
+ @index = i1
92
+ r1 = nil
93
+ else
94
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
95
+ end
96
+ s0 << r1
97
+ if r1
98
+ r3 = _nt_exponent
99
+ s0 << r3
100
+ end
101
+ if s0.last
102
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
103
+ r0.extend(Float10)
104
+ else
105
+ @index = i0
106
+ r0 = nil
107
+ end
108
+
109
+ node_cache[:float1][start_index] = r0
110
+
111
+ r0
112
+ end
113
+
114
+ module Float20
115
+ end
116
+
117
+ def _nt_float2
118
+ start_index = index
119
+ if node_cache[:float2].has_key?(index)
120
+ cached = node_cache[:float2][index]
121
+ if cached
122
+ node_cache[:float2][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
123
+ @index = cached.interval.end
124
+ end
125
+ return cached
126
+ end
127
+
40
128
  i0, s0 = index, []
41
129
  s1, i1 = [], index
42
130
  loop do
@@ -93,56 +181,7 @@ module NonnegativeFloat
93
181
  end
94
182
  s0 << r4
95
183
  if r4
96
- i7, s7 = index, []
97
- if (match_len = has_terminal?("e", false, index))
98
- r8 = true
99
- @index += match_len
100
- else
101
- terminal_parse_failure("e")
102
- r8 = nil
103
- end
104
- s7 << r8
105
- if r8
106
- if has_terminal?(@regexps[gr = '\A[+-]'] ||= Regexp.new(gr), :regexp, index)
107
- r9 = true
108
- @index += 1
109
- else
110
- terminal_parse_failure('[+-]')
111
- r9 = nil
112
- end
113
- s7 << r9
114
- if r9
115
- s10, i10 = [], index
116
- loop do
117
- if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index)
118
- r11 = true
119
- @index += 1
120
- else
121
- terminal_parse_failure('[0-9]')
122
- r11 = nil
123
- end
124
- if r11
125
- s10 << r11
126
- else
127
- break
128
- end
129
- end
130
- if s10.empty?
131
- @index = i10
132
- r10 = nil
133
- else
134
- r10 = instantiate_node(SyntaxNode,input, i10...index, s10)
135
- end
136
- s7 << r10
137
- end
138
- end
139
- if s7.last
140
- r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
141
- r7.extend(NonnegativeFloat0)
142
- else
143
- @index = i7
144
- r7 = nil
145
- end
184
+ r7 = _nt_exponent
146
185
  if r7
147
186
  r6 = r7
148
187
  else
@@ -154,14 +193,88 @@ module NonnegativeFloat
154
193
  end
155
194
  if s0.last
156
195
  r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
157
- r0.extend(NonnegativeFloat1)
158
- r0.extend(NonnegativeFloat2)
196
+ r0.extend(Float20)
159
197
  else
160
198
  @index = i0
161
199
  r0 = nil
162
200
  end
163
201
 
164
- node_cache[:nonnegative_float][start_index] = r0
202
+ node_cache[:float2][start_index] = r0
203
+
204
+ r0
205
+ end
206
+
207
+ module Exponent0
208
+ end
209
+
210
+ def _nt_exponent
211
+ start_index = index
212
+ if node_cache[:exponent].has_key?(index)
213
+ cached = node_cache[:exponent][index]
214
+ if cached
215
+ node_cache[:exponent][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
216
+ @index = cached.interval.end
217
+ end
218
+ return cached
219
+ end
220
+
221
+ i0, s0 = index, []
222
+ if (match_len = has_terminal?("e", false, index))
223
+ r1 = true
224
+ @index += match_len
225
+ else
226
+ terminal_parse_failure("e")
227
+ r1 = nil
228
+ end
229
+ s0 << r1
230
+ if r1
231
+ if has_terminal?(@regexps[gr = '\A[+-]'] ||= Regexp.new(gr), :regexp, index)
232
+ r3 = true
233
+ @index += 1
234
+ else
235
+ terminal_parse_failure('[+-]')
236
+ r3 = nil
237
+ end
238
+ if r3
239
+ r2 = r3
240
+ else
241
+ r2 = instantiate_node(SyntaxNode,input, index...index)
242
+ end
243
+ s0 << r2
244
+ if r2
245
+ s4, i4 = [], index
246
+ loop do
247
+ if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index)
248
+ r5 = true
249
+ @index += 1
250
+ else
251
+ terminal_parse_failure('[0-9]')
252
+ r5 = nil
253
+ end
254
+ if r5
255
+ s4 << r5
256
+ else
257
+ break
258
+ end
259
+ end
260
+ if s4.empty?
261
+ @index = i4
262
+ r4 = nil
263
+ else
264
+ r4 = instantiate_node(SyntaxNode,input, i4...index, s4)
265
+ end
266
+ s0 << r4
267
+ end
268
+ end
269
+ if s0.last
270
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
271
+ r0.extend(Exponent0)
272
+ else
273
+ @index = i0
274
+ r0 = nil
275
+ end
276
+
277
+ node_cache[:exponent][start_index] = r0
165
278
 
166
279
  r0
167
280
  end
@@ -4,7 +4,7 @@ module Parsing
4
4
 
5
5
  grammar NonnegativeFloat
6
6
  rule nonnegative_float
7
- [0-9]+ [.] [0-9]+ ("e" [+-] [0-9]+)? {
7
+ (float1 / float2) {
8
8
  def to_f
9
9
  text_value.to_f
10
10
  end
@@ -12,6 +12,18 @@ grammar NonnegativeFloat
12
12
  alias :to_num :to_f
13
13
  }
14
14
  end
15
+
16
+ rule float1
17
+ [0-9]+ exponent
18
+ end
19
+
20
+ rule float2
21
+ [0-9]+ [.] [0-9]+ exponent?
22
+ end
23
+
24
+ rule exponent
25
+ "e" [+-]? [0-9]+
26
+ end
15
27
  end
16
28
 
17
29
  end