aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2016-01-07 00:36:41 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2016-01-07 00:36:41 +0100
commitdf719c87e3a48903805c5f63c7e0cb5ed361104d (patch)
treee0b543a77fa5d4e5a0317d6f490d9c447cb2a28f
parentddd66308d67ae29b59b81bd83fe0506e4a11d08b (diff)
downloadapplause2-df719c87e3a48903805c5f63c7e0cb5ed361104d.tar.gz
use the LuaJIT FFI interface for the MIDI streams
* should speed up things since the C function calls can be inlined * the C function does only rudimentary argument checking using assert() since they are only called internally. This means, calling it with wrong arguments can result in controlled crashes. This will point to programming errors since the real argument checking is done in Lua code at stream construction. * The MIDI*Stream.getValue() functions have been kept as wrappers around the native functions, to ease using them in other stream implementations that want to support MIDI natively.
-rw-r--r--applause.c108
-rw-r--r--applause.lua59
2 files changed, 104 insertions, 63 deletions
diff --git a/applause.c b/applause.c
index 6c3a2a3..f0e5034 100644
--- a/applause.c
+++ b/applause.c
@@ -394,23 +394,25 @@ init_audio(int buffer_size)
return 0;
}
-/* FIXME: Rewrite as an exported FFI-callable function */
-static int
-l_MIDIVelocityStream_getValue(lua_State *L)
+/**
+ * Get the MIDI velocity of the `note` last
+ * triggered on `channel` due to a NOTE ON message.
+ * This function is meant to be called using LuaJIT's
+ * FFI interface.
+ */
+int
+applause_midi_velocity_getvalue(int note, int channel)
{
- int top = lua_gettop(L);
- lua_Integer channel, note, value;
-
- luaL_argcheck(L, top == 2, top, "Note and channel number expected");
- luaL_checktype(L, 1, LUA_TNUMBER);
- luaL_checktype(L, 2, LUA_TNUMBER);
-
- note = lua_tointeger(L, 1);
- luaL_argcheck(L, 0 <= note && note <= 127, note,
- "Invalid note number range (0 <= x <= 127)");
- channel = lua_tointeger(L, 2);
- luaL_argcheck(L, 1 <= channel && channel <= 16, channel,
- "Invalid channel range (1 <= x <= 16)");
+ int value;
+
+ /*
+ * It's enough to assert() here since this
+ * function should only be called by the
+ * MIDIVelocityStream generator.
+ */
+ assert(0 <= note && note <= 127);
+ assert(1 <= channel && channel <= 16);
+
/* The NOTE arrays are 0-based */
channel--;
@@ -426,23 +428,30 @@ l_MIDIVelocityStream_getValue(lua_State *L)
value = midi_notes[channel][note];
pthread_mutex_unlock(&midi_mutex);
- lua_pushinteger(L, value);
- return 1;
+ return value;
}
-/* FIXME: Rewrite as an exported FFI-callable function */
-static int
-l_MIDINoteStream_getValue(lua_State *L)
+/**
+ * Get the MIDI note and velocity of the note last
+ * triggered on `channel`.
+ * This function is meant to be called using LuaJIT's
+ * FFI interface.
+ *
+ * @return A MIDI note number (least significant byte) and
+ * velocity (second least significant byte).
+ */
+int
+applause_midi_note_getvalue(int channel)
{
- int top = lua_gettop(L);
- lua_Integer channel, value;
+ int value;
- luaL_argcheck(L, top == 1, top, "Channel number expected");
- luaL_checktype(L, 1, LUA_TNUMBER);
+ /*
+ * It's enough to assert() here since this
+ * function should only be called by the
+ * MIDINoteStream generator.
+ */
+ assert(1 <= channel && channel <= 16);
- channel = lua_tointeger(L, 1);
- luaL_argcheck(L, 1 <= channel && channel <= 16, channel,
- "Invalid channel range (1 <= x <= 16)");
/* The NOTE arrays are 0-based */
channel--;
@@ -459,27 +468,28 @@ l_MIDINoteStream_getValue(lua_State *L)
(midi_notes[channel][midi_notes_last[channel]] << 8);
pthread_mutex_unlock(&midi_mutex);
- lua_pushinteger(L, value);
- return 1;
+ return value;
}
-/* FIXME: Rewrite as an exported FFI-callable function */
-static int
-l_MIDICCStream_getValue(lua_State *L)
+/**
+ * Get the last value of the MIDI control `control`
+ * on `channel`.
+ * This function is meant to be called using LuaJIT's
+ * FFI interface.
+ */
+int
+applause_midi_cc_getvalue(int control, int channel)
{
- int top = lua_gettop(L);
- lua_Integer channel, control, value;
-
- luaL_argcheck(L, top == 2, top, "Control and channel number expected");
- luaL_checktype(L, 1, LUA_TNUMBER);
- luaL_checktype(L, 2, LUA_TNUMBER);
-
- control = lua_tointeger(L, 1);
- luaL_argcheck(L, 0 <= control && control <= 127, control,
- "Invalid control number range (0 <= x <= 127)");
- channel = lua_tointeger(L, 2);
- luaL_argcheck(L, 1 <= channel && channel <= 16, channel,
- "Invalid channel range (1 <= x <= 16)");
+ int value;
+
+ /*
+ * It's enough to assert() here since this
+ * function should only be called by the
+ * MIDICCStream generator.
+ */
+ assert(0 <= control && control <= 127);
+ assert(1 <= channel && channel <= 16);
+
/* The NOTE arrays are 0-based */
channel--;
@@ -495,8 +505,7 @@ l_MIDICCStream_getValue(lua_State *L)
value = midi_controls[channel][control];
pthread_mutex_unlock(&midi_mutex);
- lua_pushinteger(L, value);
- return 1;
+ return value;
}
enum applause_audio_state {
@@ -834,9 +843,6 @@ typedef struct NativeMethod {
static const NativeMethod native_methods[] = {
{"Stream", "fork", l_Stream_fork},
- {"MIDIVelocityStream", "getValue", l_MIDIVelocityStream_getValue},
- {"MIDINoteStream", "getValue", l_MIDINoteStream_getValue},
- {"MIDICCStream", "getValue", l_MIDICCStream_getValue},
{NULL, NULL, NULL}
};
diff --git a/applause.lua b/applause.lua
index dd1d78f..0f8e357 100644
--- a/applause.lua
+++ b/applause.lua
@@ -60,6 +60,10 @@ enum applause_audio_state {
};
enum applause_audio_state applause_push_sample(double sample_double);
+
+int applause_midi_velocity_getvalue(int note, int channel);
+int applause_midi_note_getvalue(int channel);
+int applause_midi_cc_getvalue(int control, int channel);
]]
-- Sample rate
@@ -1140,21 +1144,33 @@ MIDIVelocityStream = DeriveClass(Stream)
function MIDIVelocityStream:ctor(note, channel)
self.note = note
+ assert(0 <= self.note and self.note <= 127,
+ "MIDI note out of range (0 <= x <= 127)")
+
self.channel = channel or 1
+ assert(1 <= self.channel and self.channel <= 16,
+ "MIDI channel out of range (1 <= x <= 16)")
end
--- implemented in applause.c, private!
+-- This is for calling from external code (e.g. from
+-- streams supporting MIDI natively)
function MIDIVelocityStream.getValue(note, channel)
- error("C function not registered!")
+ -- NOTE: The native function assert() for invalid
+ -- notes or channels to avoid segfaults
+ assert(0 <= note and note <= 127,
+ "MIDI note out of range (0 <= x <= 127)")
+ assert(1 <= channel and channel <= 16,
+ "MIDI channel out of range (1 <= x <= 16)")
+
+ return C.applause_midi_velocity_getvalue(note, channel)
end
function MIDIVelocityStream:tick()
local note = self.note
local channel = self.channel
- local getValue = self.getValue
return function()
- return getValue(note, channel)
+ return C.applause_midi_velocity_getvalue(note, channel)
end
end
@@ -1167,19 +1183,26 @@ MIDINoteStream = DeriveClass(Stream)
function MIDINoteStream:ctor(channel)
self.channel = channel or 1
+ assert(1 <= self.channel and self.channel <= 16,
+ "MIDI channel out of range (1 <= x <= 16)")
end
--- implemented in applause.c, private!
+-- This is for calling from external code (e.g. from
+-- streams supporting MIDI natively)
function MIDINoteStream.getValue(channel)
- error("C function not registered!")
+ -- NOTE: The native function assert() for invalid
+ -- notes or channels to avoid segfaults
+ assert(1 <= channel and channel <= 16,
+ "MIDI channel out of range (1 <= x <= 16)")
+
+ return C.applause_midi_note_getvalue(channel)
end
function MIDINoteStream:tick()
local channel = self.channel
- local getValue = self.getValue
return function()
- return getValue(channel)
+ return C.applause_midi_note_getvalue(channel)
end
end
@@ -1188,20 +1211,32 @@ MIDICCStream = DeriveClass(Stream)
function MIDICCStream:ctor(control, channel)
self.control = control
self.channel = channel or 1
+
+ assert(0 <= self.control and self.control <= 127,
+ "MIDI control number out of range (0 <= x <= 127)")
+ assert(1 <= self.channel and self.channel <= 16,
+ "MIDI channel out of range (1 <= x <= 16)")
end
--- implemented in applause.c, private!
+-- This is for calling from external code (e.g. from
+-- streams supporting MIDI natively)
function MIDICCStream.getValue(control, channel)
- error("C function not registered!")
+ -- NOTE: The native function assert() for invalid
+ -- notes or channels to avoid segfaults
+ assert(0 <= control and control <= 127,
+ "MIDI control number out of range (0 <= x <= 127)")
+ assert(1 <= channel and channel <= 16,
+ "MIDI channel out of range (1 <= x <= 16)")
+
+ return C.applause_midi_cc_getvalue(control, channel)
end
function MIDICCStream:tick()
local control = self.control
local channel = self.channel
- local getValue = self.getValue
return function()
- return getValue(control, channel)
+ return C.applause_midi_cc_getvalue(control, channel)
end
end