-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathnote.ts
97 lines (85 loc) · 1.84 KB
/
note.ts
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
export const noteNames = [
'C',
'Db',
'D',
'Eb',
'E',
'F',
'Gb',
'G',
'Ab',
'A',
'Bb',
'B',
]
export const noteNamesWithSharps = [
'C',
'C#',
'D',
'D#',
'E',
'F',
'F#',
'G',
'G#',
'A',
'A#',
'B',
]
export const noteValues = { C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11 }
/**
* Note number (0~127) to name + octave (like "C4")
*
* Middle C is 60 = C4
*/
export function noteNumberToName(
note,
options: {
asObject?: boolean
octaveOffset?: number
sharp?: boolean
} = {}
) {
const data = noteNumberToNameAndOctave(note, options)
if (options.asObject) return data
return data.noteName + data.octave
}
/**
* Note number (0~127) to object { noteName, octave }
*/
export function noteNumberToNameAndOctave(
note,
options: {
octaveOffset?: number
sharp?: boolean
} = {}
) {
const { octaveOffset = 0, sharp = false } = options
const noteName = sharp ? noteNamesWithSharps[note % 12] : noteNames[note % 12]
const octave = Math.floor(Math.floor(note) / 12 - 1) + octaveOffset
return {
noteName,
octave,
}
}
/**
* Note name with octave (like "C4") to number (0~127)
*/
export function noteNameToNumber(name) {
if (typeof name !== 'string') name = ''
const matches = name.match(/([CDEFGAB])(#{0,2}|b{0,2})(-?\d+)/i)
if (!matches) return -1 // throw new RangeError('Invalid note name.')
const semitones = noteValues[matches[1].toUpperCase()]
const octave = parseInt(matches[3])
const octaveOffset = 0
let result = (octave + 1 - Math.floor(octaveOffset)) * 12 + semitones
if (matches[2].indexOf('b') > -1) {
result -= matches[2].length
} else if (matches[2].indexOf('#') > -1) {
result += matches[2].length
}
if (result < 0 || result > 127) {
// throw new RangeError('Invalid note name or note outside valid range.')
}
return result
}