aboutsummaryrefslogtreecommitdiffhomepage
path: root/applause.lua
diff options
context:
space:
mode:
Diffstat (limited to 'applause.lua')
-rw-r--r--applause.lua68
1 files changed, 53 insertions, 15 deletions
diff --git a/applause.lua b/applause.lua
index abb17f3..f43c0d3 100644
--- a/applause.lua
+++ b/applause.lua
@@ -1553,7 +1553,8 @@ end
MIDIVelocityStream = DeriveClass(Stream)
function MIDIVelocityStream:ctor(note, channel)
- self.note = note
+ -- `note` may be a note name like "A4"
+ self.note = type(note) == "string" and ntom(note) or note
assert(0 <= self.note and self.note <= 127,
"MIDI note out of range (0 <= x <= 127)")
@@ -1565,6 +1566,8 @@ end
-- This is for calling from external code (e.g. from
-- streams supporting MIDI natively)
function MIDIVelocityStream.getValue(note, channel)
+ -- `note` may be a note name like "A4"
+ note = type(note) == "string" and ntom(note) or note
-- NOTE: The native function assert() for invalid
-- notes or channels to avoid segfaults
assert(0 <= note and note <= 127,
@@ -1652,23 +1655,58 @@ end
-- MIDI primitives
--- There are only 128 possible MIDI notes,
--- so their frequencies can and should be cached.
--- We do this once instead of on-demand, so the lookup
--- table consists of consecutive numbers.
-local mtof_cache = table.new(128, 0)
-for note = 0, 127 do
- -- MIDI NOTE 69 corresponds to 440 Hz
- mtof_cache[note] = 440*math.pow(2, (note - 69)/12)
-end
+do
+ local note_names = {
+ "C", "C#", "D", "D#", "E", "F",
+ "F#", "G", "G#", "A", "A#", "B"
+ }
+
+ -- MIDI note number to name
+ -- NOTE: mton() can handle the words as generated by MIDINoteStream
+ function mton(note)
+ note = bit.band(note, 0xFF)
+ local octave = math.floor(note / 12)-1
+ return note_names[(note % 12)+1]..octave
+ end
+
+ function Stream:mton() return self:map(mton) end
--- Convert from MIDI note to frequency
--- NOTE: mtof() can handle the words as generated by MIDINoteStream
-function mtof(note)
- return mtof_cache[bit.band(note, 0xFF)]
+ local ntom_offsets = {}
+ for i, name in ipairs(note_names) do
+ ntom_offsets[name] = i-1
+ -- Saving the offsets for the lower-cased note names
+ -- avoids a string.upper() call in ntom()
+ ntom_offsets[name:lower()] = i-1
+ end
+
+ -- Note name to MIDI note number
+ function ntom(name)
+ local octave = name:byte(-1) - 48 + 1
+ return octave*12 + ntom_offsets[name:sub(1, -2)]
+ end
+
+ function Stream:ntom() return self:map(ntom) end
end
-function Stream:mtof() return self:map(mtof) end
+do
+ -- There are only 128 possible MIDI notes,
+ -- so their frequencies can and should be cached.
+ -- We do this once instead of on-demand, so the lookup
+ -- table consists of consecutive numbers.
+ local mtof_cache = table.new(128, 0)
+ for note = 0, 127 do
+ -- MIDI NOTE 69 corresponds to 440 Hz
+ mtof_cache[note] = 440*math.pow(2, (note - 69)/12)
+ end
+
+ -- Convert from MIDI note to frequency
+ -- NOTE: mtof() can handle the words as generated by MIDINoteStream
+ function mtof(note)
+ return mtof_cache[bit.band(note, 0xFF)]
+ end
+
+ function Stream:mtof() return self:map(mtof) end
+end
-- Convert from frequency to closest MIDI note
function ftom(freq)