-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpitch.rb
67 lines (59 loc) · 1.72 KB
/
pitch.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Pitch
attr_accessor :note, :octave
def initialize(note, octave)
@note = prepare_note_for_offset_map(note)
@octave = octave
end
# Formula to derive note frequencies of the equal tempered scale
# http://www.phy.mtu.edu/~suits/NoteFreqCalcs.html
def frequency
growth_rate = 2 ** (1.0 / 12)
frequency = 440 * (growth_rate ** semitones_from_A4)
frequency.round(3)
end
def to_s
note = replace_sharp_or_flat(@note.to_s)
octave = @octave.to_s
return "#{note} #{octave}"
end
private
NOTE_TO_SEMITONE_OFFSET_MAP = {B: 2,
Bf: 1,
As: 1,
A: 0,
Af: -1,
Gs: -1,
G: -2,
Gf: -3,
Fs: -3,
F: -4,
E: -5,
Ef: -6,
Ds: -6,
D: -7,
Df: -8,
Cs: -8,
C: -9}
def semitones_from_A4
octave_diff = @octave - 4
(octave_diff * 12) + NOTE_TO_SEMITONE_OFFSET_MAP[@note]
end
def replace_sharp_or_flat(note)
if note[1] == "s"
note[0] + "#"
elsif note[1] == "f"
note[0] + "b"
else
note
end
end
def prepare_note_for_offset_map(note)
letter = note[0].upcase
accidental = if note[1] then
note[1].downcase
else
""
end
"#{letter}#{accidental}".to_sym
end
end