music-transcription 0.11.0 → 0.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +1 -1
  3. data/examples/{make_hip.rb → hip.rb} +8 -2
  4. data/examples/hip_packed.yml +22 -0
  5. data/examples/{make_missed_connection.rb → missed_connection.rb} +8 -2
  6. data/examples/missed_connection.yml +2 -2
  7. data/examples/missed_connection_packed.yml +14 -0
  8. data/examples/{make_song1.rb → song1.rb} +7 -1
  9. data/examples/song1_packed.yml +19 -0
  10. data/examples/{make_song2.rb → song2.rb} +6 -1
  11. data/examples/song2_packed.yml +21 -0
  12. data/lib/music-transcription.rb +11 -3
  13. data/lib/music-transcription/model/link.rb +24 -6
  14. data/lib/music-transcription/model/meter.rb +10 -0
  15. data/lib/music-transcription/model/meters.rb +1 -1
  16. data/lib/music-transcription/model/note.rb +32 -0
  17. data/lib/music-transcription/model/pitch.rb +19 -0
  18. data/lib/music-transcription/packing/change_packing.rb +27 -0
  19. data/lib/music-transcription/packing/part_packing.rb +33 -0
  20. data/lib/music-transcription/packing/program_packing.rb +18 -0
  21. data/lib/music-transcription/packing/score_packing.rb +59 -0
  22. data/lib/music-transcription/parsing/convenience_methods.rb +10 -0
  23. data/lib/music-transcription/parsing/meter_parsing.rb +117 -9
  24. data/lib/music-transcription/parsing/meter_parsing.treetop +12 -0
  25. data/lib/music-transcription/parsing/note_node.rb +42 -0
  26. data/lib/music-transcription/parsing/note_parsing.rb +57 -180
  27. data/lib/music-transcription/parsing/note_parsing.treetop +2 -19
  28. data/lib/music-transcription/parsing/numbers/nonnegative_float_parsing.rb +178 -0
  29. data/lib/music-transcription/parsing/numbers/nonnegative_float_parsing.treetop +19 -0
  30. data/lib/music-transcription/parsing/{nonnegative_integer_parsing.rb → numbers/nonnegative_integer_parsing.rb} +9 -0
  31. data/lib/music-transcription/parsing/{nonnegative_integer_parsing.treetop → numbers/nonnegative_integer_parsing.treetop} +7 -1
  32. data/lib/music-transcription/parsing/numbers/nonnegative_rational_parsing.rb +88 -0
  33. data/lib/music-transcription/parsing/numbers/nonnegative_rational_parsing.treetop +22 -0
  34. data/lib/music-transcription/parsing/{positive_integer_parsing.rb → numbers/positive_integer_parsing.rb} +0 -0
  35. data/lib/music-transcription/parsing/{positive_integer_parsing.treetop → numbers/positive_integer_parsing.treetop} +0 -0
  36. data/lib/music-transcription/parsing/segment_parsing.rb +143 -0
  37. data/lib/music-transcription/parsing/segment_parsing.treetop +25 -0
  38. data/lib/music-transcription/version.rb +1 -1
  39. data/spec/model/link_spec.rb +44 -60
  40. data/spec/model/meter_spec.rb +18 -0
  41. data/spec/model/note_spec.rb +39 -0
  42. data/spec/model/pitch_spec.rb +32 -0
  43. data/spec/packing/change_packing_spec.rb +91 -0
  44. data/spec/packing/part_packing_spec.rb +66 -0
  45. data/spec/packing/program_packing_spec.rb +33 -0
  46. data/spec/packing/score_packing_spec.rb +122 -0
  47. data/spec/parsing/meter_parsing_spec.rb +2 -2
  48. data/spec/parsing/note_node_spec.rb +87 -0
  49. data/spec/parsing/note_parsing_spec.rb +3 -0
  50. data/spec/parsing/numbers/nonnegative_float_spec.rb +11 -0
  51. data/spec/parsing/{nonnegative_integer_spec.rb → numbers/nonnegative_integer_spec.rb} +1 -1
  52. data/spec/parsing/numbers/nonnegative_rational_spec.rb +11 -0
  53. data/spec/parsing/{positive_integer_spec.rb → numbers/positive_integer_spec.rb} +1 -1
  54. data/spec/parsing/segment_parsing_spec.rb +27 -0
  55. metadata +45 -17
  56. data/lib/music-transcription/parsing/note_nodes.rb +0 -64
  57. data/spec/parsing/note_nodes_spec.rb +0 -84
@@ -0,0 +1,59 @@
1
+ module Music
2
+ module Transcription
3
+
4
+ class Score
5
+ def pack
6
+ packed_start_meter = start_meter.to_s
7
+ packed_mcs = Hash[ meter_changes.map do |offset,change|
8
+ a = change.pack
9
+ a[0] = a[0].to_s
10
+ [offset,a]
11
+ end ]
12
+
13
+ packed_tcs = Hash[ tempo_changes.map do |k,v|
14
+ [k,v.to_ary]
15
+ end ]
16
+
17
+ packed_parts = Hash[
18
+ @parts.map do |name,part|
19
+ [ name, part.pack ]
20
+ end
21
+ ]
22
+ packed_prog = program.pack
23
+
24
+ { "start_meter" => packed_start_meter,
25
+ "meter_changes" => packed_mcs,
26
+ "start_tempo" => start_tempo,
27
+ "tempo_changes" => packed_tcs,
28
+ "program" => packed_prog,
29
+ "parts" => packed_parts,
30
+ }
31
+ end
32
+
33
+ def self.unpack packing
34
+ unpacked_start_meter = Parsing::meter(packing["start_meter"])
35
+ unpacked_mcs = Hash[ packing["meter_changes"].map do |k,v|
36
+ v = v.clone
37
+ v[0] = Parsing::meter(v[0])
38
+ [k, Change.from_ary(v) ]
39
+ end ]
40
+
41
+ unpacked_tcs = Hash[ packing["tempo_changes"].map do |k,v|
42
+ [k, Change.from_ary(v)]
43
+ end ]
44
+
45
+ unpacked_parts = Hash[ packing["parts"].map do |name,packed|
46
+ [name, Part.unpack(packed)]
47
+ end ]
48
+
49
+ unpacked_prog = Program.unpack packing["program"]
50
+
51
+ new(unpacked_start_meter, packing["start_tempo"],
52
+ meter_changes: unpacked_mcs, tempo_changes: unpacked_tcs,
53
+ program: unpacked_prog, parts: unpacked_parts
54
+ )
55
+ end
56
+ end
57
+
58
+ end
59
+ end
@@ -5,6 +5,7 @@ module Parsing
5
5
  PITCH_PARSER = PitchParser.new
6
6
  NOTE_PARSER = NoteParser.new
7
7
  METER_PARSER = MeterParser.new
8
+ SEGMENT_PARSER = SegmentParser.new
8
9
 
9
10
  def duration dur_str
10
11
  DURATION_PARSER.parse(dur_str).to_r
@@ -50,6 +51,11 @@ module Parsing
50
51
  METER_PARSER.parse(meter_str).to_meter
51
52
  end
52
53
  module_function :meter
54
+
55
+ def segment seg_str
56
+ SEGMENT_PARSER.parse(seg_str).to_range
57
+ end
58
+ module_function :segment
53
59
  end
54
60
  end
55
61
  end
@@ -90,4 +96,8 @@ class String
90
96
  def to_meter
91
97
  Music::Transcription::Parsing::meter(self)
92
98
  end
99
+
100
+ def to_segment
101
+ Music::Transcription::Parsing::segment(self)
102
+ end
93
103
  end
@@ -14,7 +14,39 @@ module Meter
14
14
 
15
15
  include PositiveInteger
16
16
 
17
- module Meter0
17
+ def _nt_meter
18
+ start_index = index
19
+ if node_cache[:meter].has_key?(index)
20
+ cached = node_cache[:meter][index]
21
+ if cached
22
+ node_cache[:meter][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
23
+ @index = cached.interval.end
24
+ end
25
+ return cached
26
+ end
27
+
28
+ i0 = index
29
+ r1 = _nt_meter1
30
+ if r1
31
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
32
+ r0 = r1
33
+ else
34
+ r2 = _nt_meter2
35
+ if r2
36
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
37
+ r0 = r2
38
+ else
39
+ @index = i0
40
+ r0 = nil
41
+ end
42
+ end
43
+
44
+ node_cache[:meter][start_index] = r0
45
+
46
+ r0
47
+ end
48
+
49
+ module Meter10
18
50
  def bpm
19
51
  elements[0]
20
52
  end
@@ -24,18 +56,18 @@ module Meter
24
56
  end
25
57
  end
26
58
 
27
- module Meter1
59
+ module Meter11
28
60
  def to_meter
29
61
  Music::Transcription::Meter.new(bpm.to_i, Rational(1,bd.to_i))
30
62
  end
31
63
  end
32
64
 
33
- def _nt_meter
65
+ def _nt_meter1
34
66
  start_index = index
35
- if node_cache[:meter].has_key?(index)
36
- cached = node_cache[:meter][index]
67
+ if node_cache[:meter1].has_key?(index)
68
+ cached = node_cache[:meter1][index]
37
69
  if cached
38
- node_cache[:meter][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
70
+ node_cache[:meter1][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
39
71
  @index = cached.interval.end
40
72
  end
41
73
  return cached
@@ -60,14 +92,90 @@ module Meter
60
92
  end
61
93
  if s0.last
62
94
  r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
63
- r0.extend(Meter0)
64
- r0.extend(Meter1)
95
+ r0.extend(Meter10)
96
+ r0.extend(Meter11)
65
97
  else
66
98
  @index = i0
67
99
  r0 = nil
68
100
  end
69
101
 
70
- node_cache[:meter][start_index] = r0
102
+ node_cache[:meter1][start_index] = r0
103
+
104
+ r0
105
+ end
106
+
107
+ module Meter20
108
+ def bpm
109
+ elements[0]
110
+ end
111
+
112
+ def num
113
+ elements[2]
114
+ end
115
+
116
+ def den
117
+ elements[4]
118
+ end
119
+ end
120
+
121
+ module Meter21
122
+ def to_meter
123
+ Music::Transcription::Meter.new(bpm.to_i, Rational(num.to_i,den.to_i))
124
+ end
125
+ end
126
+
127
+ def _nt_meter2
128
+ start_index = index
129
+ if node_cache[:meter2].has_key?(index)
130
+ cached = node_cache[:meter2][index]
131
+ if cached
132
+ node_cache[:meter2][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
133
+ @index = cached.interval.end
134
+ end
135
+ return cached
136
+ end
137
+
138
+ i0, s0 = index, []
139
+ r1 = _nt_positive_integer
140
+ s0 << r1
141
+ if r1
142
+ if (match_len = has_terminal?("*", false, index))
143
+ r2 = true
144
+ @index += match_len
145
+ else
146
+ terminal_parse_failure("*")
147
+ r2 = nil
148
+ end
149
+ s0 << r2
150
+ if r2
151
+ r3 = _nt_positive_integer
152
+ s0 << r3
153
+ if r3
154
+ if (match_len = has_terminal?("/", false, index))
155
+ r4 = true
156
+ @index += match_len
157
+ else
158
+ terminal_parse_failure("/")
159
+ r4 = nil
160
+ end
161
+ s0 << r4
162
+ if r4
163
+ r5 = _nt_positive_integer
164
+ s0 << r5
165
+ end
166
+ end
167
+ end
168
+ end
169
+ if s0.last
170
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
171
+ r0.extend(Meter20)
172
+ r0.extend(Meter21)
173
+ else
174
+ @index = i0
175
+ r0 = nil
176
+ end
177
+
178
+ node_cache[:meter2][start_index] = r0
71
179
 
72
180
  r0
73
181
  end
@@ -6,12 +6,24 @@ grammar Meter
6
6
  include PositiveInteger
7
7
 
8
8
  rule meter
9
+ meter1 / meter2
10
+ end
11
+
12
+ rule meter1
9
13
  bpm:positive_integer "/" bd:positive_integer {
10
14
  def to_meter
11
15
  Music::Transcription::Meter.new(bpm.to_i, Rational(1,bd.to_i))
12
16
  end
13
17
  }
14
18
  end
19
+
20
+ rule meter2
21
+ bpm:positive_integer "*" num:positive_integer "/" den:positive_integer {
22
+ def to_meter
23
+ Music::Transcription::Meter.new(bpm.to_i, Rational(num.to_i,den.to_i))
24
+ end
25
+ }
26
+ end
15
27
  end
16
28
 
17
29
  end
@@ -0,0 +1,42 @@
1
+ module Music
2
+ module Transcription
3
+ module Parsing
4
+ class NoteNode < Treetop::Runtime::SyntaxNode
5
+ def primitives env
6
+ [ self.to_note ]
7
+ end
8
+
9
+ def to_note
10
+ pitches = []
11
+ links = {}
12
+
13
+ unless pitch_links.empty?
14
+ first = pitch_links.first
15
+ more = pitch_links.more
16
+
17
+ pitches.push first.pitch.to_pitch
18
+ unless first.the_link.empty?
19
+ links[pitches[-1]] = first.the_link.to_link
20
+ end
21
+
22
+ more.elements.each do |x|
23
+ pitches.push x.pl.pitch.to_pitch
24
+ unless x.pl.the_link.empty?
25
+ links[pitches[-1]] = x.pl.the_link.to_link
26
+ end
27
+ end
28
+ end
29
+
30
+ artic = Music::Transcription::Articulations::NORMAL
31
+ unless art.empty?
32
+ artic = art.to_articulation
33
+ end
34
+
35
+ accent_flag = acc.empty? ? false : true
36
+ Music::Transcription::Note.new(duration.to_r,
37
+ pitches, links: links, articulation: artic, accented: accent_flag)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -20,151 +20,23 @@ module Note
20
20
 
21
21
  include Duration
22
22
 
23
- def _nt_note
24
- start_index = index
25
- if node_cache[:note].has_key?(index)
26
- cached = node_cache[:note][index]
27
- if cached
28
- node_cache[:note][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
29
- @index = cached.interval.end
30
- end
31
- return cached
32
- end
33
-
34
- i0 = index
35
- r1 = _nt_polyphonic_note
36
- if r1
37
- r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
38
- r0 = r1
39
- else
40
- r2 = _nt_monophonic_note
41
- if r2
42
- r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
43
- r0 = r2
44
- else
45
- r3 = _nt_rest_note
46
- if r3
47
- r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
48
- r0 = r3
49
- else
50
- @index = i0
51
- r0 = nil
52
- end
53
- end
54
- end
55
-
56
- node_cache[:note][start_index] = r0
57
-
58
- r0
59
- end
60
-
61
- module RestNote0
62
- def duration
63
- elements[0]
64
- end
65
- end
66
-
67
- def _nt_rest_note
68
- start_index = index
69
- if node_cache[:rest_note].has_key?(index)
70
- cached = node_cache[:rest_note][index]
71
- if cached
72
- node_cache[:rest_note][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
73
- @index = cached.interval.end
74
- end
75
- return cached
76
- end
77
-
78
- i0, s0 = index, []
79
- r1 = _nt_duration
80
- s0 << r1
81
- if s0.last
82
- r0 = instantiate_node(RestNoteNode,input, i0...index, s0)
83
- r0.extend(RestNote0)
84
- else
85
- @index = i0
86
- r0 = nil
87
- end
88
-
89
- node_cache[:rest_note][start_index] = r0
90
-
91
- r0
92
- end
93
-
94
- module MonophonicNote0
95
- def duration
96
- elements[0]
97
- end
98
-
99
- def art
100
- elements[1]
101
- end
102
-
23
+ module Note0
103
24
  def pl
104
- elements[2]
105
- end
106
-
107
- def acc
108
- elements[3]
25
+ elements[1]
109
26
  end
110
27
  end
111
28
 
112
- def _nt_monophonic_note
113
- start_index = index
114
- if node_cache[:monophonic_note].has_key?(index)
115
- cached = node_cache[:monophonic_note][index]
116
- if cached
117
- node_cache[:monophonic_note][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
118
- @index = cached.interval.end
119
- end
120
- return cached
121
- end
122
-
123
- i0, s0 = index, []
124
- r1 = _nt_duration
125
- s0 << r1
126
- if r1
127
- r3 = _nt_articulation
128
- if r3
129
- r2 = r3
130
- else
131
- r2 = instantiate_node(SyntaxNode,input, index...index)
132
- end
133
- s0 << r2
134
- if r2
135
- r4 = _nt_pitch_link
136
- s0 << r4
137
- if r4
138
- r6 = _nt_accent
139
- if r6
140
- r5 = r6
141
- else
142
- r5 = instantiate_node(SyntaxNode,input, index...index)
143
- end
144
- s0 << r5
145
- end
146
- end
147
- end
148
- if s0.last
149
- r0 = instantiate_node(MonophonicNoteNode,input, i0...index, s0)
150
- r0.extend(MonophonicNote0)
151
- else
152
- @index = i0
153
- r0 = nil
29
+ module Note1
30
+ def first
31
+ elements[0]
154
32
  end
155
33
 
156
- node_cache[:monophonic_note][start_index] = r0
157
-
158
- r0
159
- end
160
-
161
- module PolyphonicNote0
162
- def pl
34
+ def more
163
35
  elements[1]
164
36
  end
165
37
  end
166
38
 
167
- module PolyphonicNote1
39
+ module Note2
168
40
  def duration
169
41
  elements[0]
170
42
  end
@@ -173,25 +45,21 @@ module Note
173
45
  elements[1]
174
46
  end
175
47
 
176
- def pl
48
+ def pitch_links
177
49
  elements[2]
178
50
  end
179
51
 
180
- def more_pitches
181
- elements[3]
182
- end
183
-
184
52
  def acc
185
- elements[4]
53
+ elements[3]
186
54
  end
187
55
  end
188
56
 
189
- def _nt_polyphonic_note
57
+ def _nt_note
190
58
  start_index = index
191
- if node_cache[:polyphonic_note].has_key?(index)
192
- cached = node_cache[:polyphonic_note][index]
59
+ if node_cache[:note].has_key?(index)
60
+ cached = node_cache[:note][index]
193
61
  if cached
194
- node_cache[:polyphonic_note][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
62
+ node_cache[:note][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
195
63
  @index = cached.interval.end
196
64
  end
197
65
  return cached
@@ -209,65 +77,74 @@ module Note
209
77
  end
210
78
  s0 << r2
211
79
  if r2
212
- r4 = _nt_pitch_link
213
- s0 << r4
214
- if r4
215
- s5, i5 = [], index
80
+ i5, s5 = index, []
81
+ r6 = _nt_pitch_link
82
+ s5 << r6
83
+ if r6
84
+ s7, i7 = [], index
216
85
  loop do
217
- i6, s6 = index, []
86
+ i8, s8 = index, []
218
87
  if (match_len = has_terminal?(",", false, index))
219
- r7 = true
88
+ r9 = true
220
89
  @index += match_len
221
90
  else
222
91
  terminal_parse_failure(",")
223
- r7 = nil
92
+ r9 = nil
224
93
  end
225
- s6 << r7
226
- if r7
227
- r8 = _nt_pitch_link
228
- s6 << r8
94
+ s8 << r9
95
+ if r9
96
+ r10 = _nt_pitch_link
97
+ s8 << r10
229
98
  end
230
- if s6.last
231
- r6 = instantiate_node(SyntaxNode,input, i6...index, s6)
232
- r6.extend(PolyphonicNote0)
99
+ if s8.last
100
+ r8 = instantiate_node(SyntaxNode,input, i8...index, s8)
101
+ r8.extend(Note0)
233
102
  else
234
- @index = i6
235
- r6 = nil
103
+ @index = i8
104
+ r8 = nil
236
105
  end
237
- if r6
238
- s5 << r6
106
+ if r8
107
+ s7 << r8
239
108
  else
240
109
  break
241
110
  end
242
111
  end
243
- if s5.empty?
244
- @index = i5
245
- r5 = nil
112
+ r7 = instantiate_node(SyntaxNode,input, i7...index, s7)
113
+ s5 << r7
114
+ end
115
+ if s5.last
116
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
117
+ r5.extend(Note1)
118
+ else
119
+ @index = i5
120
+ r5 = nil
121
+ end
122
+ if r5
123
+ r4 = r5
124
+ else
125
+ r4 = instantiate_node(SyntaxNode,input, index...index)
126
+ end
127
+ s0 << r4
128
+ if r4
129
+ r12 = _nt_accent
130
+ if r12
131
+ r11 = r12
246
132
  else
247
- r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
248
- end
249
- s0 << r5
250
- if r5
251
- r10 = _nt_accent
252
- if r10
253
- r9 = r10
254
- else
255
- r9 = instantiate_node(SyntaxNode,input, index...index)
256
- end
257
- s0 << r9
133
+ r11 = instantiate_node(SyntaxNode,input, index...index)
258
134
  end
135
+ s0 << r11
259
136
  end
260
137
  end
261
138
  end
262
139
  if s0.last
263
- r0 = instantiate_node(PolyphonicNoteNode,input, i0...index, s0)
264
- r0.extend(PolyphonicNote1)
140
+ r0 = instantiate_node(NoteNode,input, i0...index, s0)
141
+ r0.extend(Note2)
265
142
  else
266
143
  @index = i0
267
144
  r0 = nil
268
145
  end
269
146
 
270
- node_cache[:polyphonic_note][start_index] = r0
147
+ node_cache[:note][start_index] = r0
271
148
 
272
149
  r0
273
150
  end