music-transcription 0.15.0 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
data/examples/song1.yml CHANGED
@@ -21,6 +21,8 @@ parts:
21
21
  - !ruby/object:Music::Transcription::Pitch
22
22
  octave: 2
23
23
  semitone: 0
24
+ cent: 0
25
+ total_cents: 2400
24
26
  articulation: :normal
25
27
  accented: false
26
28
  links: {}
@@ -32,6 +34,8 @@ parts:
32
34
  - !ruby/object:Music::Transcription::Pitch
33
35
  octave: 2
34
36
  semitone: 3
37
+ cent: 0
38
+ total_cents: 2700
35
39
  articulation: :normal
36
40
  accented: false
37
41
  links: {}
@@ -43,6 +47,8 @@ parts:
43
47
  - !ruby/object:Music::Transcription::Pitch
44
48
  octave: 2
45
49
  semitone: 5
50
+ cent: 0
51
+ total_cents: 2900
46
52
  articulation: :normal
47
53
  accented: false
48
54
  links: {}
@@ -54,6 +60,8 @@ parts:
54
60
  - !ruby/object:Music::Transcription::Pitch
55
61
  octave: 2
56
62
  semitone: 3
63
+ cent: 0
64
+ total_cents: 2700
57
65
  articulation: :normal
58
66
  accented: false
59
67
  links: {}
@@ -73,6 +81,8 @@ parts:
73
81
  - !ruby/object:Music::Transcription::Pitch
74
82
  octave: 2
75
83
  semitone: 0
84
+ cent: 0
85
+ total_cents: 2400
76
86
  articulation: :normal
77
87
  accented: false
78
88
  links: {}
@@ -84,6 +94,8 @@ parts:
84
94
  - !ruby/object:Music::Transcription::Pitch
85
95
  octave: 2
86
96
  semitone: 3
97
+ cent: 0
98
+ total_cents: 2700
87
99
  articulation: :normal
88
100
  accented: false
89
101
  links: {}
@@ -103,6 +115,8 @@ parts:
103
115
  - !ruby/object:Music::Transcription::Pitch
104
116
  octave: 2
105
117
  semitone: 0
118
+ cent: 0
119
+ total_cents: 2400
106
120
  articulation: :normal
107
121
  accented: false
108
122
  links: {}
@@ -114,6 +128,8 @@ parts:
114
128
  - !ruby/object:Music::Transcription::Pitch
115
129
  octave: 2
116
130
  semitone: 3
131
+ cent: 0
132
+ total_cents: 2700
117
133
  articulation: :normal
118
134
  accented: false
119
135
  links: {}
@@ -125,6 +141,8 @@ parts:
125
141
  - !ruby/object:Music::Transcription::Pitch
126
142
  octave: 2
127
143
  semitone: 5
144
+ cent: 0
145
+ total_cents: 2900
128
146
  articulation: :normal
129
147
  accented: false
130
148
  links: {}
@@ -136,6 +154,8 @@ parts:
136
154
  - !ruby/object:Music::Transcription::Pitch
137
155
  octave: 2
138
156
  semitone: 3
157
+ cent: 0
158
+ total_cents: 2700
139
159
  articulation: :normal
140
160
  accented: false
141
161
  links: {}
@@ -155,6 +175,8 @@ parts:
155
175
  - !ruby/object:Music::Transcription::Pitch
156
176
  octave: 2
157
177
  semitone: 0
178
+ cent: 0
179
+ total_cents: 2400
158
180
  articulation: :normal
159
181
  accented: false
160
182
  links: {}
@@ -166,6 +188,8 @@ parts:
166
188
  - !ruby/object:Music::Transcription::Pitch
167
189
  octave: 2
168
190
  semitone: 3
191
+ cent: 0
192
+ total_cents: 2700
169
193
  articulation: :normal
170
194
  accented: false
171
195
  links: {}
@@ -189,6 +213,8 @@ parts:
189
213
  - !ruby/object:Music::Transcription::Pitch
190
214
  octave: 3
191
215
  semitone: 10
216
+ cent: 0
217
+ total_cents: 4600
192
218
  articulation: :normal
193
219
  accented: false
194
220
  links: {}
@@ -200,6 +226,8 @@ parts:
200
226
  - !ruby/object:Music::Transcription::Pitch
201
227
  octave: 3
202
228
  semitone: 10
229
+ cent: 0
230
+ total_cents: 4600
203
231
  articulation: :normal
204
232
  accented: false
205
233
  links: {}
@@ -211,6 +239,8 @@ parts:
211
239
  - !ruby/object:Music::Transcription::Pitch
212
240
  octave: 3
213
241
  semitone: 10
242
+ cent: 0
243
+ total_cents: 4600
214
244
  articulation: :normal
215
245
  accented: false
216
246
  links: {}
@@ -222,6 +252,8 @@ parts:
222
252
  - !ruby/object:Music::Transcription::Pitch
223
253
  octave: 3
224
254
  semitone: 10
255
+ cent: 0
256
+ total_cents: 4600
225
257
  articulation: :normal
226
258
  accented: false
227
259
  links: {}
@@ -233,6 +265,8 @@ parts:
233
265
  - !ruby/object:Music::Transcription::Pitch
234
266
  octave: 4
235
267
  semitone: 0
268
+ cent: 0
269
+ total_cents: 4800
236
270
  articulation: :normal
237
271
  accented: false
238
272
  links: {}
@@ -244,6 +278,8 @@ parts:
244
278
  - !ruby/object:Music::Transcription::Pitch
245
279
  octave: 3
246
280
  semitone: 9
281
+ cent: 0
282
+ total_cents: 4500
247
283
  articulation: :normal
248
284
  accented: false
249
285
  links: {}
@@ -255,6 +291,8 @@ parts:
255
291
  - !ruby/object:Music::Transcription::Pitch
256
292
  octave: 3
257
293
  semitone: 7
294
+ cent: 0
295
+ total_cents: 4300
258
296
  articulation: :normal
259
297
  accented: false
260
298
  links: {}
@@ -266,6 +304,8 @@ parts:
266
304
  - !ruby/object:Music::Transcription::Pitch
267
305
  octave: 3
268
306
  semitone: 5
307
+ cent: 0
308
+ total_cents: 4100
269
309
  articulation: :normal
270
310
  accented: false
271
311
  links: {}
@@ -277,6 +317,8 @@ parts:
277
317
  - !ruby/object:Music::Transcription::Pitch
278
318
  octave: 3
279
319
  semitone: 7
320
+ cent: 0
321
+ total_cents: 4300
280
322
  articulation: :slur
281
323
  accented: false
282
324
  links: {}
@@ -288,6 +330,8 @@ parts:
288
330
  - !ruby/object:Music::Transcription::Pitch
289
331
  octave: 3
290
332
  semitone: 5
333
+ cent: 0
334
+ total_cents: 4100
291
335
  articulation: :slur
292
336
  accented: false
293
337
  links: {}
@@ -299,6 +343,8 @@ parts:
299
343
  - !ruby/object:Music::Transcription::Pitch
300
344
  octave: 3
301
345
  semitone: 4
346
+ cent: 0
347
+ total_cents: 4000
302
348
  articulation: :normal
303
349
  accented: false
304
350
  links: {}
@@ -326,6 +372,8 @@ parts:
326
372
  - !ruby/object:Music::Transcription::Pitch
327
373
  octave: 3
328
374
  semitone: 10
375
+ cent: 0
376
+ total_cents: 4600
329
377
  articulation: :normal
330
378
  accented: false
331
379
  links: {}
@@ -337,6 +385,8 @@ parts:
337
385
  - !ruby/object:Music::Transcription::Pitch
338
386
  octave: 3
339
387
  semitone: 10
388
+ cent: 0
389
+ total_cents: 4600
340
390
  articulation: :normal
341
391
  accented: false
342
392
  links: {}
@@ -348,6 +398,8 @@ parts:
348
398
  - !ruby/object:Music::Transcription::Pitch
349
399
  octave: 3
350
400
  semitone: 10
401
+ cent: 0
402
+ total_cents: 4600
351
403
  articulation: :normal
352
404
  accented: false
353
405
  links: {}
@@ -359,6 +411,8 @@ parts:
359
411
  - !ruby/object:Music::Transcription::Pitch
360
412
  octave: 3
361
413
  semitone: 10
414
+ cent: 0
415
+ total_cents: 4600
362
416
  articulation: :normal
363
417
  accented: false
364
418
  links: {}
@@ -370,6 +424,8 @@ parts:
370
424
  - !ruby/object:Music::Transcription::Pitch
371
425
  octave: 4
372
426
  semitone: 0
427
+ cent: 0
428
+ total_cents: 4800
373
429
  articulation: :normal
374
430
  accented: false
375
431
  links: {}
@@ -381,6 +437,8 @@ parts:
381
437
  - !ruby/object:Music::Transcription::Pitch
382
438
  octave: 3
383
439
  semitone: 9
440
+ cent: 0
441
+ total_cents: 4500
384
442
  articulation: :normal
385
443
  accented: false
386
444
  links: {}
@@ -392,6 +450,8 @@ parts:
392
450
  - !ruby/object:Music::Transcription::Pitch
393
451
  octave: 4
394
452
  semitone: 4
453
+ cent: 0
454
+ total_cents: 5200
395
455
  articulation: :normal
396
456
  accented: false
397
457
  links: {}
@@ -403,6 +463,8 @@ parts:
403
463
  - !ruby/object:Music::Transcription::Pitch
404
464
  octave: 4
405
465
  semitone: 4
466
+ cent: 0
467
+ total_cents: 5200
406
468
  articulation: :slur
407
469
  accented: false
408
470
  links: {}
@@ -414,6 +476,8 @@ parts:
414
476
  - !ruby/object:Music::Transcription::Pitch
415
477
  octave: 4
416
478
  semitone: 2
479
+ cent: 0
480
+ total_cents: 5000
417
481
  articulation: :slur
418
482
  accented: false
419
483
  links: {}
@@ -425,6 +489,8 @@ parts:
425
489
  - !ruby/object:Music::Transcription::Pitch
426
490
  octave: 4
427
491
  semitone: 0
492
+ cent: 0
493
+ total_cents: 4800
428
494
  articulation: :normal
429
495
  accented: false
430
496
  links: {}
data/examples/song2.yml CHANGED
@@ -21,6 +21,8 @@ parts:
21
21
  - !ruby/object:Music::Transcription::Pitch
22
22
  octave: 4
23
23
  semitone: 0
24
+ cent: 0
25
+ total_cents: 4800
24
26
  articulation: :normal
25
27
  accented: false
26
28
  links: {}
@@ -32,6 +34,8 @@ parts:
32
34
  - !ruby/object:Music::Transcription::Pitch
33
35
  octave: 3
34
36
  semitone: 10
37
+ cent: 0
38
+ total_cents: 4600
35
39
  articulation: :normal
36
40
  accented: false
37
41
  links: {}
@@ -43,6 +47,8 @@ parts:
43
47
  - !ruby/object:Music::Transcription::Pitch
44
48
  octave: 3
45
49
  semitone: 8
50
+ cent: 0
51
+ total_cents: 4400
46
52
  articulation: :normal
47
53
  accented: false
48
54
  links: {}
@@ -54,6 +60,8 @@ parts:
54
60
  - !ruby/object:Music::Transcription::Pitch
55
61
  octave: 3
56
62
  semitone: 7
63
+ cent: 0
64
+ total_cents: 4300
57
65
  articulation: :normal
58
66
  accented: false
59
67
  links: {}
@@ -65,6 +73,8 @@ parts:
65
73
  - !ruby/object:Music::Transcription::Pitch
66
74
  octave: 3
67
75
  semitone: 10
76
+ cent: 0
77
+ total_cents: 4600
68
78
  articulation: :normal
69
79
  accented: false
70
80
  links: {}
@@ -80,6 +90,8 @@ parts:
80
90
  - !ruby/object:Music::Transcription::Pitch
81
91
  octave: 5
82
92
  semitone: 4
93
+ cent: 0
94
+ total_cents: 6400
83
95
  articulation: :normal
84
96
  accented: false
85
97
  links: {}
@@ -91,6 +103,8 @@ parts:
91
103
  - !ruby/object:Music::Transcription::Pitch
92
104
  octave: 5
93
105
  semitone: 2
106
+ cent: 0
107
+ total_cents: 6200
94
108
  articulation: :normal
95
109
  accented: false
96
110
  links: {}
@@ -102,6 +116,8 @@ parts:
102
116
  - !ruby/object:Music::Transcription::Pitch
103
117
  octave: 5
104
118
  semitone: 0
119
+ cent: 0
120
+ total_cents: 6000
105
121
  articulation: :normal
106
122
  accented: false
107
123
  links: {}
@@ -113,6 +129,8 @@ parts:
113
129
  - !ruby/object:Music::Transcription::Pitch
114
130
  octave: 5
115
131
  semitone: 0
132
+ cent: 0
133
+ total_cents: 6000
116
134
  articulation: :normal
117
135
  accented: false
118
136
  links: {}
@@ -124,6 +142,8 @@ parts:
124
142
  - !ruby/object:Music::Transcription::Pitch
125
143
  octave: 5
126
144
  semitone: 0
145
+ cent: 0
146
+ total_cents: 6000
127
147
  articulation: :normal
128
148
  accented: false
129
149
  links: {}
@@ -135,6 +155,8 @@ parts:
135
155
  - !ruby/object:Music::Transcription::Pitch
136
156
  octave: 5
137
157
  semitone: 2
158
+ cent: 0
159
+ total_cents: 6200
138
160
  articulation: :normal
139
161
  accented: false
140
162
  links: {}
@@ -30,11 +30,10 @@ class Link
30
30
  end
31
31
 
32
32
  class TargetedLink < Link
33
- attr_accessor :target_pitch, :link_char
33
+ attr_accessor :target_pitch
34
34
 
35
- def initialize target_pitch, link_char
35
+ def initialize target_pitch
36
36
  @target_pitch = target_pitch
37
- @link_char = link_char
38
37
  end
39
38
 
40
39
  def ==(other)
@@ -47,27 +46,28 @@ class Link
47
46
 
48
47
  def transpose! diff
49
48
  @target_pitch = @target_pitch.transpose(diff)
49
+ return self
50
50
  end
51
51
 
52
52
  def to_s
53
- @link_char + @target_pitch.to_s
53
+ link_char + @target_pitch.to_s
54
54
  end
55
55
  end
56
56
 
57
57
  class Glissando < TargetedLink
58
- def initialize(target_pitch); super(target_pitch,"~"); end
58
+ def link_char; "~"; end
59
59
  end
60
60
 
61
61
  class Portamento < TargetedLink
62
- def initialize(target_pitch); super(target_pitch,"/"); end
62
+ def link_char; "/"; end
63
63
  end
64
64
 
65
65
  class Slur < TargetedLink
66
- def initialize(target_pitch); super(target_pitch,"="); end
66
+ def link_char; "="; end
67
67
  end
68
68
 
69
69
  class Legato < TargetedLink
70
- def initialize(target_pitch); super(target_pitch,"-"); end
70
+ def link_char; "|"; end
71
71
  end
72
72
  end
73
73
 
@@ -71,7 +71,7 @@ class Note
71
71
 
72
72
  art_str = case @articulation
73
73
  when Articulations::SLUR then "="
74
- when Articulations::LEGATO then "-"
74
+ when Articulations::LEGATO then "|"
75
75
  when Articulations::TENUTO then "_"
76
76
  when Articulations::PORTATO then "%"
77
77
  when Articulations::STACCATO then "."
@@ -3,8 +3,8 @@ module Transcription
3
3
 
4
4
  # Abstraction of a musical pitch. Contains values for octave and semitone.
5
5
  #
6
- # Octaves represent the largest means of differing two pitches. Each
7
- # octave added will double the ratio. At zero octaves, the ratio is
6
+ # Octaves represent the largest means of differing two pitches. Each
7
+ # octave added will double the ratio. At zero octaves, the ratio is
8
8
  # 1.0. At one octave, the ratio will be 2.0. Each semitone is an increment
9
9
  # of less-than-power-of-two.
10
10
  #
@@ -12,7 +12,7 @@ module Transcription
12
12
  # semitones per octave is 12.
13
13
 
14
14
  # @author James Tunnell
15
- #
15
+ #
16
16
  # @!attribute [r] octave
17
17
  # @return [Fixnum] The pitch octave.
18
18
  # @!attribute [r] semitone
@@ -20,71 +20,87 @@ module Transcription
20
20
  #
21
21
  class Pitch
22
22
  include Comparable
23
- attr_reader :octave, :semitone, :total_semitone
23
+ attr_reader :octave, :semitone, :cent, :total_cents
24
24
 
25
- #The default number of semitones per octave is 12, corresponding to
25
+ #The default number of semitones per octave is 12, corresponding to
26
26
  # the twelve-tone equal temperment tuning system.
27
27
  SEMITONES_PER_OCTAVE = 12
28
+ CENTS_PER_SEMITONE = 100
29
+ CENTS_PER_OCTAVE = SEMITONES_PER_OCTAVE * CENTS_PER_SEMITONE
28
30
 
29
31
  # The base ferquency is C0
30
32
  BASE_FREQ = 16.351597831287414
31
-
32
- def initialize octave:0, semitone:0
33
+
34
+ def initialize octave:0, semitone:0, cent: 0
35
+ raise NonIntegerError, "octave #{octave} is not an integer" unless octave.is_a?(Integer)
36
+ raise NonIntegerError, "semitone #{semitone} is not an integer" unless semitone.is_a?(Integer)
37
+ raise NonIntegerError, "cent #{cent} is not an integer" unless cent.is_a?(Integer)
38
+
33
39
  @octave = octave
34
40
  @semitone = semitone
41
+ @cent = cent
42
+ @total_cents = (@octave*SEMITONES_PER_OCTAVE + @semitone)*CENTS_PER_SEMITONE + @cent
35
43
  normalize!
36
- @total_semitone = @octave*SEMITONES_PER_OCTAVE + @semitone
37
44
  end
38
45
 
39
- # Return the pitch's frequency, which is determined by multiplying the base
46
+ # Return the pitch's frequency, which is determined by multiplying the base
40
47
  # frequency and the pitch ratio. Base frequency defaults to DEFAULT_BASE_FREQ,
41
- # but can be set during initialization to something else by specifying the
48
+ # but can be set during initialization to something else by specifying the
42
49
  # :base_freq key.
43
50
  def freq
44
51
  return self.ratio() * BASE_FREQ
45
52
  end
46
-
47
- # Calculate the pitch ratio. Raises 2 to the power of the total semitone
48
- # count divided by semitones-per-octave.
53
+
54
+ # Calculate the pitch ratio. Raises 2 to the power of the total cent
55
+ # count divided by cents-per-octave.
49
56
  # @return [Float] ratio
50
57
  def ratio
51
- 2.0**(@total_semitone.to_f / SEMITONES_PER_OCTAVE)
58
+ 2.0**(@total_cents.to_f / CENTS_PER_OCTAVE)
52
59
  end
53
-
60
+
54
61
  # Override default hash method.
55
62
  def hash
56
- return @total_semitone
63
+ return @total_cents
57
64
  end
58
-
65
+
59
66
  # Compare pitch equality using total semitone
60
67
  def ==(other)
61
68
  return (self.class == other.class &&
62
- @total_semitone == other.total_semitone)
69
+ @total_cents == other.total_cents)
63
70
  end
64
-
71
+
65
72
  def eql?(other)
66
73
  self == other
67
74
  end
68
-
75
+
69
76
  # Compare pitches. A higher ratio or total semitone is considered larger.
70
77
  # @param [Pitch] other The pitch object to compare.
71
78
  def <=> (other)
72
- @total_semitone <=> other.total_semitone
79
+ @total_cents <=> other.total_cents
80
+ end
81
+
82
+ # rounds to the nearest semitone
83
+ def round
84
+ if @cent == 0
85
+ self.clone
86
+ else
87
+ Pitch.new(semitone: (@total_cents / CENTS_PER_SEMITONE.to_f).round)
88
+ end
73
89
  end
74
-
90
+
91
+ # diff in (rounded) semitones
75
92
  def diff other
76
- @total_semitone - other.total_semitone
93
+ Rational(@total_cents - other.total_cents, CENTS_PER_SEMITONE)
77
94
  end
78
-
79
- def transpose interval
80
- Pitch.from_semitones @total_semitone + interval
95
+
96
+ def transpose semitones
97
+ Pitch.new(cent: (@total_cents + semitones * CENTS_PER_SEMITONE).round)
81
98
  end
82
-
83
- # Produce an identical Pitch object.
99
+
84
100
  def clone
85
- Marshal.load(Marshal.dump(self)) # is this cheating?
101
+ Pitch.new(cent: @total_cents)
86
102
  end
87
-
103
+
88
104
  def to_s(sharpit = false)
89
105
  letter = case semitone
90
106
  when 0 then "C"
@@ -101,34 +117,38 @@ class Pitch
101
117
  when 11 then "B"
102
118
  end
103
119
 
104
- return letter + octave.to_s
120
+ if @cent == 0
121
+ return letter + octave.to_s
122
+ elsif @cent > 0
123
+ return letter + octave.to_s + "+" + @cent.to_s
124
+ else
125
+ return letter + octave.to_s + @cent.to_s
126
+ end
105
127
  end
106
-
128
+
107
129
  def self.from_ratio ratio
108
130
  raise NonPositiveError, "ratio #{ratio} is not > 0" unless ratio > 0
109
131
  x = Math.log2 ratio
110
- semitones = (x * SEMITONES_PER_OCTAVE).round
111
- from_semitones(semitones)
132
+ new(cent: (x * CENTS_PER_OCTAVE).round)
112
133
  end
113
-
134
+
114
135
  def self.from_freq freq
115
136
  from_ratio(freq / BASE_FREQ)
116
137
  end
117
-
118
- def self.from_semitones semitones
119
- Pitch.new(semitone: semitones)
120
- end
121
-
138
+
122
139
  private
123
-
124
- # Balance out the octave and semitone count.
140
+
141
+ # Balance out the octave and semitone count.
125
142
  def normalize!
126
- semitoneTotal = (@octave * SEMITONES_PER_OCTAVE) + @semitone
143
+ centsTotal = @total_cents
144
+
145
+ @octave = centsTotal / CENTS_PER_OCTAVE
146
+ centsTotal -= @octave * CENTS_PER_OCTAVE
127
147
 
128
- @octave = semitoneTotal / SEMITONES_PER_OCTAVE
129
- semitoneTotal -= @octave * SEMITONES_PER_OCTAVE
148
+ @semitone = centsTotal / CENTS_PER_SEMITONE
149
+ centsTotal -= @semitone * CENTS_PER_SEMITONE
130
150
 
131
- @semitone = semitoneTotal
151
+ @cent = centsTotal
132
152
  return self
133
153
  end
134
154
  end