aboutsummaryrefslogtreecommitdiffhomepage
path: root/applause.lua
diff options
context:
space:
mode:
Diffstat (limited to 'applause.lua')
-rw-r--r--applause.lua94
1 files changed, 92 insertions, 2 deletions
diff --git a/applause.lua b/applause.lua
index e5a9b42..a76fb41 100644
--- a/applause.lua
+++ b/applause.lua
@@ -1,5 +1,9 @@
local sndfile = require "sndfile"
local ffi = require "ffi"
+local bit = require "bit"
+
+-- Make table.new() available
+require "table.new"
--
-- Define C functions for benchmarking (POSIX libc)
@@ -123,6 +127,21 @@ for _, fnc in pairs{"abs", "acos", "asin", "atan",
end
end
+function Stream:bnot()
+ return self:map(bit.bnot)
+end
+
+-- Register all binary operators of the "bit" module
+for _, name in pairs{"bor", "band", "bxor",
+ "lshift", "rshift", "arshift",
+ "rol", "ror"} do
+ local fnc = bit[name]
+
+ Stream[name] = function(self, v)
+ return self:map(function(x) return fnc(x, v) end)
+ end
+end
+
-- Scalar operations
-- In contrast to stream operations (based on ZipStream),
-- these work only with scalars and do not
@@ -384,7 +403,7 @@ function Stream:__tostring()
t = self:sub(1, 1024):totable()
table.insert(t, "...")
else
- t = self()
+ t = self:totable()
end
for i = 1, #t do t[i] = tostring(t[i]) end
@@ -884,6 +903,50 @@ function NoiseStream:tick()
end
end
+-- Velocity of NOTE ON for a specific note on a channel
+MIDIVelocityStream = DeriveClass(Stream, function(self, note, channel)
+ self.note = note
+ self.channel = channel or 0
+end)
+
+-- implemented in applause.c, private!
+function MIDIVelocityStream.getValue(note, channel)
+ error("C function not registered!")
+end
+
+function MIDIVelocityStream:tick()
+ local note = self.note
+ local channel = self.channel
+ local getValue = self.getValue
+
+ return function()
+ return getValue(note, channel)
+ end
+end
+
+-- Stream of integer words representing the last MIDI note
+-- triggered on a channel with its corresponding velocity
+-- (of the NOTE ON message).
+-- The MIDI note is the lower byte and the velocity the
+-- upper byte of the word.
+MIDINoteStream = DeriveClass(Stream, function(self, channel)
+ self.channel = channel or 0
+end)
+
+-- implemented in applause.c, private!
+function MIDINoteStream.getValue(channel)
+ error("C function not registered!")
+end
+
+function MIDINoteStream:tick()
+ local channel = self.channel
+ local getValue = self.getValue
+
+ return function()
+ return getValue(channel)
+ end
+end
+
MIDICCStream = DeriveClass(Stream, function(self, control, channel)
self.control = control
self.channel = channel or 0
@@ -894,7 +957,6 @@ function MIDICCStream.getValue(control, channel)
error("C function not registered!")
end
--- FIXME: Perhaps implement tick() directly in C?
function MIDICCStream:tick()
local control = self.control
local channel = self.channel
@@ -905,6 +967,34 @@ function MIDICCStream:tick()
end
end
+-- MIDI primitives
+
+-- There are only 120 different 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(120, 0)
+for note = 0, 119 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
+
+-- Convert from frequency to closest MIDI note
+function ftom(freq)
+ -- NOTE: math.log/2 is a LuaJIT extension
+ return math.floor(12*math.log(freq/440, 2) + 0.5)+69
+end
+
+function Stream:ftom() return self:map(ftom) end
+
-- primitives
function tostream(v)