music-transcription 0.5.6 → 0.5.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/music-transcription/note.rb +23 -15
- data/lib/music-transcription/part.rb +5 -5
- data/lib/music-transcription/pitch.rb +55 -119
- data/lib/music-transcription/version.rb +1 -1
- data/spec/note_spec.rb +39 -3
- data/spec/pitch_spec.rb +32 -33
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5041a24490fc0a9178e61905b5febb392d081428
|
4
|
+
data.tar.gz: 95223ce876d78e49ba61b232af70ef08805b20cf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba123f27fc90869a0741e6f7232b875ac7bf48df1757cf2409fedd91f8c79b5fcd516bf521888f361204e63aae6632c9e836096e2b591bd0cd34060086c8bfeb
|
7
|
+
data.tar.gz: 2b24520d8a6a7c9a5b6d8c210d30046e0159316ea92c45fcdb2c6e8139e437e5d9119988076122a51f3d6036704c66d9059190be702a4ea187fc4d57cdb4a472
|
@@ -56,30 +56,38 @@ class Note
|
|
56
56
|
Marshal.load(Marshal.dump(self))
|
57
57
|
end
|
58
58
|
|
59
|
-
def transpose_pitches_only
|
59
|
+
def transpose_pitches_only diff
|
60
60
|
self.clone.transpose_pitches! pitch_diff, transpose_link
|
61
61
|
end
|
62
62
|
|
63
|
-
def transpose_pitches_only!
|
64
|
-
|
65
|
-
new_links = {}
|
66
|
-
@links.each_pair do |k,v|
|
67
|
-
new_links[k + pitch_diff] = v
|
68
|
-
end
|
69
|
-
@links = new_links
|
70
|
-
return self
|
63
|
+
def transpose_pitches_only! diff
|
64
|
+
self.transpose! diff, false
|
71
65
|
end
|
72
66
|
|
73
|
-
def transpose_pitches_and_links
|
74
|
-
self.clone.transpose_pitches_and_links!
|
67
|
+
def transpose_pitches_and_links diff
|
68
|
+
self.clone.transpose_pitches_and_links! diff
|
75
69
|
end
|
76
70
|
|
77
|
-
def transpose_pitches_and_links!
|
78
|
-
|
71
|
+
def transpose_pitches_and_links! diff
|
72
|
+
self.transpose! diff, true
|
73
|
+
end
|
74
|
+
|
75
|
+
def transpose diff, transpose_links
|
76
|
+
self.clone.transpose! diff, transpose_links
|
77
|
+
end
|
78
|
+
|
79
|
+
def transpose! diff, transpose_link_targets
|
80
|
+
unless diff.is_a?(Pitch)
|
81
|
+
diff = Pitch.make_from_semitone(diff)
|
82
|
+
end
|
83
|
+
|
84
|
+
@pitches = @pitches.map {|pitch| pitch + diff}
|
79
85
|
new_links = {}
|
80
86
|
@links.each_pair do |k,v|
|
81
|
-
|
82
|
-
|
87
|
+
if transpose_link_targets
|
88
|
+
v.target_pitch += diff
|
89
|
+
end
|
90
|
+
new_links[k + diff] = v
|
83
91
|
end
|
84
92
|
@links = new_links
|
85
93
|
return self
|
@@ -46,15 +46,15 @@ class Part
|
|
46
46
|
return @notes.inject(0) { |sum, note| sum + note.duration }
|
47
47
|
end
|
48
48
|
|
49
|
-
def transpose
|
50
|
-
self.clone.transpose!
|
49
|
+
def transpose diff
|
50
|
+
self.clone.transpose! diff
|
51
51
|
end
|
52
52
|
|
53
|
-
def transpose!
|
53
|
+
def transpose! diff
|
54
54
|
@notes[0...-1].each do |note|
|
55
|
-
note.transpose_pitches_and_links!
|
55
|
+
note.transpose_pitches_and_links! diff
|
56
56
|
end
|
57
|
-
@notes[-1].transpose_pitches_only!
|
57
|
+
@notes[-1].transpose_pitches_only! diff
|
58
58
|
return self
|
59
59
|
end
|
60
60
|
|
@@ -1,134 +1,77 @@
|
|
1
1
|
module Music
|
2
2
|
module Transcription
|
3
3
|
|
4
|
-
# Abstraction of a musical pitch. Contains values for octave
|
5
|
-
# and cent. These values are useful because they allow simple mapping to
|
6
|
-
# both the abstract (musical scales) and concrete (audio data).
|
4
|
+
# Abstraction of a musical pitch. Contains values for octave and semitone.
|
7
5
|
#
|
8
|
-
# Fundamentally, pitch can be considered a ratio to some base number.
|
9
|
-
# For music, this is a base frequency. The pitch frequency can be
|
10
|
-
# determined by multiplying the base frequency by the pitch ratio. For
|
11
|
-
# the standard musical scale, the base frequency of C0 is 16.35 Hz.
|
12
|
-
#
|
13
6
|
# Octaves represent the largest means of differing two pitches. Each
|
14
7
|
# octave added will double the ratio. At zero octaves, the ratio is
|
15
|
-
# 1.0. At one octave, the ratio will be 2.0. Each semitone
|
16
|
-
#
|
17
|
-
#
|
18
|
-
# Semitones are the primary steps between octaves. By default, the
|
19
|
-
# number of semitones per octave is 12, corresponding to the twelve-tone equal
|
20
|
-
# temperment tuning system. The number of semitones per octave can be
|
21
|
-
# modified at runtime by overriding the Pitch::SEMITONES_PER_OCTAVE
|
22
|
-
# constant.
|
23
|
-
#
|
24
|
-
# Cents are the smallest means of differing two pitches. By default, the
|
25
|
-
# number of cents per semitone is 100 (hence the name cent, as in per-
|
26
|
-
# cent). This number can be modified at runtime by overriding the
|
27
|
-
# Pitch::CENTS_PER_SEMITONE constant.
|
8
|
+
# 1.0. At one octave, the ratio will be 2.0. Each semitone is an increment
|
9
|
+
# of less-than-power-of-two.
|
28
10
|
#
|
11
|
+
# Semitones are the primary steps between octaves. The number of
|
12
|
+
# semitones per octave is 12.
|
13
|
+
|
29
14
|
# @author James Tunnell
|
30
15
|
#
|
31
16
|
# @!attribute [r] octave
|
32
17
|
# @return [Fixnum] The pitch octave.
|
33
18
|
# @!attribute [r] semitone
|
34
19
|
# @return [Fixnum] The pitch semitone.
|
35
|
-
# @!attribute [r] cent
|
36
|
-
# @return [Fixnum] The pitch cent.
|
37
|
-
# @!attribute [r] cents_per_octave
|
38
|
-
# @return [Fixnum] The number of cents per octave. Default is 1200
|
39
|
-
# (12 x 100). If a different scale is required,
|
40
|
-
# modify CENTS_PER_SEMITONE (default 12) and/or
|
41
|
-
# SEMITONES_PER_OCTAVE (default 100).
|
42
|
-
# @!attribute [r] base_freq
|
43
|
-
# @return [Numeric] Multiplied with pitch ratio to determine the final frequency
|
44
|
-
# of the pitch. Defaults to DEFAULT_BASE_FREQ, but can be set
|
45
|
-
# during initialization to something else using the :base_freq key.
|
46
20
|
#
|
47
21
|
class Pitch
|
48
22
|
include Comparable
|
49
|
-
attr_reader :
|
23
|
+
attr_reader :octave, :semitone
|
50
24
|
|
51
25
|
#The default number of semitones per octave is 12, corresponding to
|
52
26
|
# the twelve-tone equal temperment tuning system.
|
53
27
|
SEMITONES_PER_OCTAVE = 12
|
54
28
|
|
55
|
-
#The
|
56
|
-
|
57
|
-
CENTS_PER_SEMITONE = 100
|
58
|
-
|
59
|
-
# The default base ferquency is C0
|
60
|
-
DEFAULT_BASE_FREQ = 16.351597831287414
|
29
|
+
# The base ferquency is C0
|
30
|
+
BASE_FREQ = 16.351597831287414
|
61
31
|
|
62
32
|
# A new instance of Pitch.
|
63
33
|
# @raise [NonPositiveFrequencyError] if base_freq is not > 0.
|
64
|
-
def initialize octave:0, semitone:0
|
65
|
-
@cents_per_octave = CENTS_PER_SEMITONE * SEMITONES_PER_OCTAVE
|
34
|
+
def initialize octave:0, semitone:0
|
66
35
|
@octave = octave
|
67
36
|
@semitone = semitone
|
68
|
-
@cent = cent
|
69
|
-
raise ValueNonPositiveError if base_freq <= 0
|
70
|
-
@base_freq = base_freq
|
71
37
|
normalize!
|
72
38
|
end
|
73
39
|
|
74
|
-
## Set @base_freq, which is used with the pitch ratio to produce the
|
75
|
-
## pitch frequency.
|
76
|
-
#def base_freq= base_freq
|
77
|
-
# raise NonPositiveFrequencyError if base_freq <= 0
|
78
|
-
# @base_freq = base_freq
|
79
|
-
#end
|
80
|
-
#
|
81
|
-
## Set @octave.
|
82
|
-
#def octave= octave
|
83
|
-
# @octave = octave
|
84
|
-
#end
|
85
|
-
#
|
86
|
-
## Set semitone.
|
87
|
-
#def semitone= semitone
|
88
|
-
# @semitone = semitone
|
89
|
-
#end
|
90
|
-
#
|
91
|
-
## Set @cent.
|
92
|
-
#def cent= cent
|
93
|
-
# @cent = cent
|
94
|
-
#end
|
95
|
-
|
96
40
|
# Return the pitch's frequency, which is determined by multiplying the base
|
97
41
|
# frequency and the pitch ratio. Base frequency defaults to DEFAULT_BASE_FREQ,
|
98
42
|
# but can be set during initialization to something else by specifying the
|
99
43
|
# :base_freq key.
|
100
44
|
def freq
|
101
|
-
return self.ratio() *
|
45
|
+
return self.ratio() * BASE_FREQ
|
102
46
|
end
|
103
47
|
|
104
48
|
# Set the pitch according to the given frequency. Uses the current base_freq
|
105
49
|
# to determine what the pitch ratio should be, and sets it accordingly.
|
106
50
|
def freq= freq
|
107
|
-
self.ratio = freq /
|
51
|
+
self.ratio = freq / BASE_FREQ
|
108
52
|
end
|
109
53
|
|
110
|
-
# Calculate the total
|
111
|
-
#
|
112
|
-
# @return [Fixnum] total
|
113
|
-
def
|
114
|
-
return (@octave *
|
115
|
-
(@semitone * CENTS_PER_SEMITONE) + @cent
|
54
|
+
# Calculate the total semitone count. Converts octave to semitone count
|
55
|
+
# before adding to existing semitone count.
|
56
|
+
# @return [Fixnum] total semitone count
|
57
|
+
def total_semitone
|
58
|
+
return (@octave * SEMITONES_PER_OCTAVE) + @semitone
|
116
59
|
end
|
117
60
|
|
118
|
-
# Set the Pitch ratio according to a total number of
|
119
|
-
# @param [Fixnum]
|
120
|
-
# @raise [ArgumentError] if
|
121
|
-
def
|
122
|
-
raise ArgumentError, "
|
123
|
-
@octave, @semitone
|
61
|
+
# Set the Pitch ratio according to a total number of semitones.
|
62
|
+
# @param [Fixnum] semitone The total number of semitones to use.
|
63
|
+
# @raise [ArgumentError] if semitone is not an Integer
|
64
|
+
def total_semitone= semitone
|
65
|
+
raise ArgumentError, "semitone is not a Integer" if !semitone.is_a?(Integer)
|
66
|
+
@octave, @semitone = 0, semitone
|
124
67
|
normalize!
|
125
68
|
end
|
126
69
|
|
127
|
-
# Calculate the pitch ratio. Raises 2 to the power of the total
|
128
|
-
# count divided by
|
70
|
+
# Calculate the pitch ratio. Raises 2 to the power of the total semitone
|
71
|
+
# count divided by semitones-per-octave.
|
129
72
|
# @return [Float] ratio
|
130
73
|
def ratio
|
131
|
-
2.0**(self.
|
74
|
+
2.0**(self.total_semitone.to_f / SEMITONES_PER_OCTAVE)
|
132
75
|
end
|
133
76
|
|
134
77
|
# Represent the Pitch ratio according to a ratio.
|
@@ -138,7 +81,7 @@ class Pitch
|
|
138
81
|
raise RangeError, "ratio #{ratio} is less than or equal to 0.0" if ratio <= 0.0
|
139
82
|
|
140
83
|
x = Math.log2 ratio
|
141
|
-
self.
|
84
|
+
self.total_semitone = (x * SEMITONES_PER_OCTAVE).round
|
142
85
|
end
|
143
86
|
|
144
87
|
# Round to the nearest semitone.
|
@@ -146,55 +89,47 @@ class Pitch
|
|
146
89
|
self.clone.round!
|
147
90
|
end
|
148
91
|
|
149
|
-
# Round to the nearest semitone.
|
150
|
-
def round!
|
151
|
-
if @cent >= (CENTS_PER_SEMITONE / 2)
|
152
|
-
@semitone += 1
|
153
|
-
end
|
154
|
-
@cent = 0
|
155
|
-
normalize!
|
156
|
-
return self
|
157
|
-
end
|
158
|
-
|
159
92
|
# Calculates the number of semitones which would represent the pitch's
|
160
|
-
# octave and semitone count
|
93
|
+
# octave and semitone count
|
161
94
|
def total_semitone
|
162
95
|
return (@octave * SEMITONES_PER_OCTAVE) + @semitone
|
163
96
|
end
|
164
97
|
|
165
98
|
# Override default hash method.
|
166
99
|
def hash
|
167
|
-
return self.
|
100
|
+
return self.total_semitone
|
168
101
|
end
|
169
102
|
|
170
|
-
# Compare pitch equality using total
|
103
|
+
# Compare pitch equality using total semitone
|
171
104
|
def ==(other)
|
172
|
-
self.
|
105
|
+
self.total_semitone == other.total_semitone
|
106
|
+
end
|
107
|
+
|
108
|
+
def eql?(other)
|
109
|
+
self == other
|
173
110
|
end
|
174
111
|
|
175
|
-
# Compare pitches. A higher ratio or total
|
112
|
+
# Compare pitches. A higher ratio or total semitone is considered larger.
|
176
113
|
# @param [Pitch] other The pitch object to compare.
|
177
114
|
def <=> (other)
|
178
|
-
self.
|
115
|
+
self.total_semitone <=> other.total_semitone
|
179
116
|
end
|
180
117
|
|
181
|
-
# Add pitches by adding the total
|
118
|
+
# Add pitches by adding the total semitone count of each.
|
182
119
|
# @param [Pitch] other The pitch object to add.
|
183
120
|
def + (other)
|
184
121
|
self.class.new(
|
185
122
|
octave: (@octave + other.octave),
|
186
|
-
semitone: (@semitone + other.semitone)
|
187
|
-
cent: (@cent + other.cent)
|
123
|
+
semitone: (@semitone + other.semitone)
|
188
124
|
)
|
189
125
|
end
|
190
126
|
|
191
|
-
# Add pitches by subtracting the total
|
127
|
+
# Add pitches by subtracting the total semitone count.
|
192
128
|
# @param [Pitch] other The pitch object to subtract.
|
193
129
|
def - (other)
|
194
130
|
self.class.new(
|
195
131
|
octave: (@octave - other.octave),
|
196
132
|
semitone: (@semitone - other.semitone),
|
197
|
-
cent: (@cent - other.cent)
|
198
133
|
)
|
199
134
|
end
|
200
135
|
|
@@ -203,26 +138,19 @@ class Pitch
|
|
203
138
|
Marshal.load(Marshal.dump(self)) # is this cheating?
|
204
139
|
end
|
205
140
|
|
206
|
-
# Balance out the octave
|
141
|
+
# Balance out the octave and semitone count.
|
207
142
|
def normalize!
|
208
|
-
|
209
|
-
|
210
|
-
@octave = centTotal / @cents_per_octave
|
211
|
-
centTotal -= @octave * @cents_per_octave
|
143
|
+
semitoneTotal = (@octave * SEMITONES_PER_OCTAVE) + @semitone
|
212
144
|
|
213
|
-
@
|
214
|
-
|
145
|
+
@octave = semitoneTotal / SEMITONES_PER_OCTAVE
|
146
|
+
semitoneTotal -= @octave * SEMITONES_PER_OCTAVE
|
215
147
|
|
216
|
-
@
|
148
|
+
@semitone = semitoneTotal
|
217
149
|
return self
|
218
150
|
end
|
219
151
|
|
220
152
|
# Produce a string representation of a pitch (e.g. "C2")
|
221
153
|
def to_s
|
222
|
-
if @cents_per_octave != 1200
|
223
|
-
raise "Don't know how to produce a string representation since cents_per_octave is not 1200."
|
224
|
-
end
|
225
|
-
|
226
154
|
semitone_str = case @semitone
|
227
155
|
when 0 then "C"
|
228
156
|
when 1 then "Db"
|
@@ -241,11 +169,19 @@ class Pitch
|
|
241
169
|
return semitone_str + @octave.to_s
|
242
170
|
end
|
243
171
|
|
244
|
-
def self.make_from_freq(freq
|
172
|
+
def self.make_from_freq(freq)
|
245
173
|
pitch = Pitch.new()
|
246
|
-
pitch.ratio = freq /
|
174
|
+
pitch.ratio = freq / BASE_FREQ
|
247
175
|
return pitch
|
248
176
|
end
|
177
|
+
|
178
|
+
def self.make_from_semitone semitones
|
179
|
+
if semitones.is_a?(Integer)
|
180
|
+
return Pitch.new(semitone: semitones)
|
181
|
+
else
|
182
|
+
raise ArgumentError, "Cannot make Pitch from #{semitones}"
|
183
|
+
end
|
184
|
+
end
|
249
185
|
end
|
250
186
|
|
251
187
|
end
|
data/spec/note_spec.rb
CHANGED
@@ -5,7 +5,7 @@ describe Note do
|
|
5
5
|
@pitch = C4
|
6
6
|
end
|
7
7
|
|
8
|
-
|
8
|
+
describe '.new' do
|
9
9
|
it 'should assign :duration that is given during construction' do
|
10
10
|
note = Note.new 2
|
11
11
|
note.duration.should eq(2)
|
@@ -28,11 +28,47 @@ describe Note do
|
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
31
|
+
describe '#duration=' do
|
32
32
|
it 'should assign duration' do
|
33
33
|
note = Note.new 2, [@pitch]
|
34
34
|
note.duration = 3
|
35
35
|
note.duration.should eq 3
|
36
36
|
end
|
37
|
-
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe '#transpose!' do
|
40
|
+
context 'transpose_link_targets set false' do
|
41
|
+
context 'given pitch diff' do
|
42
|
+
before(:all) do
|
43
|
+
@note = Note::Quarter.new([C2,F2], links:{C2=>Link::Slur.new(D2)})
|
44
|
+
@diff = Pitch.new(semitone: 4)
|
45
|
+
@note.transpose! @diff, false
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should modifiy pitches by adding pitch diff' do
|
49
|
+
@note.pitches[0].should eq E2
|
50
|
+
@note.pitches[1].should eq A2
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should not affect link targets' do
|
54
|
+
@note.links.should have_key(E2)
|
55
|
+
@note.links[E2].target_pitch.should eq(D2)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'given integer diff' do
|
60
|
+
it 'should transpose the given number of semitones' do
|
61
|
+
Note::Quarter.new([C2]).transpose!(4,false).pitches[0].should eq(E2)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'transpose_link_targets set true' do
|
68
|
+
it 'should also transpose link targets' do
|
69
|
+
note = Note::Quarter.new([C2,F2], links:{C2=>Link::Slur.new(D2)})
|
70
|
+
note.transpose!(2,true)
|
71
|
+
note.links[D2].target_pitch.should eq(E2)
|
72
|
+
end
|
73
|
+
end
|
38
74
|
end
|
data/spec/pitch_spec.rb
CHANGED
@@ -5,17 +5,15 @@ describe Pitch do
|
|
5
5
|
before :each do
|
6
6
|
@cases =
|
7
7
|
[
|
8
|
-
{ octave: 1, semitone: 0,
|
9
|
-
{ octave: 2, semitone: 0,
|
10
|
-
{ octave: 1, semitone: 6,
|
11
|
-
{ octave: 2, semitone: 6,
|
12
|
-
{ octave:
|
13
|
-
{ octave:
|
14
|
-
{ octave:
|
15
|
-
{ octave: -
|
16
|
-
{ octave: -
|
17
|
-
{ octave: -2, semitone: 7, cent: 55, :ratio => 0.3867, :total_cent => -1645 },
|
18
|
-
{ octave: -1, semitone: 9, cent: 23, :ratio => 0.8521, :total_cent => -277 },
|
8
|
+
{ octave: 1, semitone: 0, :ratio => 2.0, :total_semitone => 12 },
|
9
|
+
{ octave: 2, semitone: 0, :ratio => 4.0, :total_semitone => 24 },
|
10
|
+
{ octave: 1, semitone: 6, :ratio => 2.828, :total_semitone => 18 },
|
11
|
+
{ octave: 2, semitone: 6, :ratio => 5.657, :total_semitone => 30 },
|
12
|
+
{ octave: 3, semitone: 7, :ratio => 11.986, :total_semitone => 43 },
|
13
|
+
{ octave: -1, semitone: 0, :ratio => 0.5, :total_semitone => -12 },
|
14
|
+
{ octave: -2, semitone: 0, :ratio => 0.25, :total_semitone => -24 },
|
15
|
+
{ octave: -2, semitone: 7, :ratio => 0.375, :total_semitone => -17 },
|
16
|
+
{ octave: -1, semitone: 9, :ratio => 0.841, :total_semitone => -3 },
|
19
17
|
]
|
20
18
|
end
|
21
19
|
|
@@ -27,20 +25,19 @@ describe Pitch do
|
|
27
25
|
obj = Pitch.new octave: 4, semitone: 3
|
28
26
|
obj.octave.should eq(4)
|
29
27
|
obj.semitone.should eq(3)
|
30
|
-
obj.cent.should eq(0)
|
31
28
|
end
|
32
29
|
|
33
|
-
it "should use default octave
|
30
|
+
it "should use default octave and semitone if none is given" do
|
34
31
|
p = Pitch.new
|
35
32
|
p.ratio.should be_within(0.01).of(1.0)
|
36
|
-
p.
|
33
|
+
p.total_semitone.should eq(0)
|
37
34
|
end
|
38
35
|
|
39
|
-
it "should use the octave
|
36
|
+
it "should use the octave and semitone given during construction" do
|
40
37
|
@cases.each do |case_data|
|
41
|
-
p = Pitch.new octave: case_data[:octave], semitone: case_data[:semitone]
|
38
|
+
p = Pitch.new octave: case_data[:octave], semitone: case_data[:semitone]
|
42
39
|
p.ratio.should be_within(0.01).of case_data[:ratio]
|
43
|
-
p.
|
40
|
+
p.total_semitone.should be case_data[:total_semitone]
|
44
41
|
end
|
45
42
|
end
|
46
43
|
|
@@ -51,20 +48,18 @@ describe Pitch do
|
|
51
48
|
|
52
49
|
p.octave.should eq case_data[:octave]
|
53
50
|
p.semitone.should eq case_data[:semitone]
|
54
|
-
p.
|
55
|
-
p.total_cent.should eq case_data[:total_cent]
|
51
|
+
p.total_semitone.should eq case_data[:total_semitone]
|
56
52
|
end
|
57
53
|
end
|
58
54
|
|
59
|
-
it "should setting by
|
55
|
+
it "should setting by total_semitone" do
|
60
56
|
@cases.each do |case_data|
|
61
57
|
p = Pitch.new
|
62
|
-
p.
|
58
|
+
p.total_semitone = case_data[:total_semitone]
|
63
59
|
|
64
60
|
p.octave.should eq case_data[:octave]
|
65
61
|
p.semitone.should eq case_data[:semitone]
|
66
|
-
p.
|
67
|
-
p.total_cent.should eq case_data[:total_cent]
|
62
|
+
p.total_semitone.should eq case_data[:total_semitone]
|
68
63
|
end
|
69
64
|
end
|
70
65
|
|
@@ -106,7 +101,7 @@ describe Pitch do
|
|
106
101
|
a4.freq.should be_within(0.01).of(440.0)
|
107
102
|
end
|
108
103
|
|
109
|
-
|
104
|
+
describe 'String#to_pitch' do
|
110
105
|
it 'should create a Pitch object that matches the musical note' do
|
111
106
|
{
|
112
107
|
"Ab2" => Pitch.new(octave: 2, semitone: 8),
|
@@ -122,17 +117,21 @@ describe Pitch do
|
|
122
117
|
end
|
123
118
|
end
|
124
119
|
|
125
|
-
|
120
|
+
describe '.make_from_freq' do
|
126
121
|
it 'should make a pitch whose freq is approximately the given freq' do
|
127
|
-
|
128
|
-
[1.0, 25.0, 200.0, 3500.0].each do |given_freq|
|
122
|
+
[16.35, 440.0, 987.77].each do |given_freq|
|
129
123
|
pitch = Pitch.make_from_freq given_freq
|
130
|
-
freq
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
124
|
+
pitch.freq.should be_within(0.01).of(given_freq)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe '.make_from_semitone' do
|
130
|
+
context 'given an integer less than 12' do
|
131
|
+
before(:all) { @pitch = Pitch.make_from_semitone(11) }
|
132
|
+
|
133
|
+
it 'semitone should equal given integer' do
|
134
|
+
@pitch.semitone.should eq 11
|
136
135
|
end
|
137
136
|
end
|
138
137
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: music-transcription
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Tunnell
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-09-
|
11
|
+
date: 2014-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|