diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-01-07 00:36:41 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-01-07 00:36:41 +0100 |
commit | df719c87e3a48903805c5f63c7e0cb5ed361104d (patch) | |
tree | e0b543a77fa5d4e5a0317d6f490d9c447cb2a28f | |
parent | ddd66308d67ae29b59b81bd83fe0506e4a11d08b (diff) | |
download | applause2-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.c | 108 | ||||
-rw-r--r-- | applause.lua | 59 |
2 files changed, 104 insertions, 63 deletions
@@ -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 |