aboutsummaryrefslogtreecommitdiffhomepage
path: root/applause.c
diff options
context:
space:
mode:
authorRobin Haberkorn <robin.haberkorn@googlemail.com>2016-01-03 21:56:31 +0100
committerRobin Haberkorn <robin.haberkorn@googlemail.com>2016-01-03 22:28:06 +0100
commitcdbb6c0ac72817cd5f1eff16c1be944386a3773c (patch)
treee826192fb70b8ea6527ee158ef18d18a29821a41 /applause.c
parentf8318d9d52dc136eecbae52d047f9ad9325dce76 (diff)
downloadapplause2-cdbb6c0ac72817cd5f1eff16c1be944386a3773c.tar.gz
SyncedStream optimization: Allow streams to be reused within one stream graph without recomputation
* Since it comes with an overhead, it has to be enabled by constructing a SyncedStream or calling Stream:sync() * Reusing samples works by sharing generator functions and caching samples until a clock signal changes. The clock signal is currently a global variable "clock_signal" that oscillates between true and false. * This means that all sample generating methods like :play() or :totable() will have to advance the clock using the global clockCycle() function. It is a global function, so it can be invoked more or less efficiently by the :play() implementation (currently using the old-school Lua/C API). These restrictions might fall when using the LuaJIT way of interacting with native code. * Since playback must begin from the beginning for every :play(), an explicit reset() mechanism has been introduced which can usually be ignored in Stream implementations. It does however allow SyncedStream to reset the generator closure. * SndfileStream has been simplified since now it is possible to keep the file handle open. However as long as Stream synchronization is not automatic, SndfileStreams must be explicitly synced when using one stream multiple times. * Syncing is thought to be performed automatically by an optimizer when one object is used more than once e.g. in a :play() call. * Non-synced streams are currently slightly slower than before this commit, probably because of the additional clockCycle() call.
Diffstat (limited to 'applause.c')
-rw-r--r--applause.c31
1 files changed, 26 insertions, 5 deletions
diff --git a/applause.c b/applause.c
index 981b80d..ddf4993 100644
--- a/applause.c
+++ b/applause.c
@@ -496,12 +496,18 @@ l_Stream_play(lua_State *L)
luaL_argcheck(L, top == 1, top, "Stream object expected");
luaL_checktype(L, 1, LUA_TTABLE);
- /* get tick() method */
- lua_getfield(L, -1, "tick");
+ /* get reset() method */
+ lua_getfield(L, 1, "reset");
luaL_checktype(L, -1, LUA_TFUNCTION);
- /* move in front of stream table since it needs a `self' argument */
- lua_insert(L, 1);
+ /* duplicate object table since we have to call self.reset(self) */
+ lua_pushvalue(L, 1);
+ lua_call(L, 1, 0);
+ /* get tick() method */
+ lua_getfield(L, 1, "tick");
+ luaL_checktype(L, -1, LUA_TFUNCTION);
+ /* duplicate object table since we have to call self.tick(self) */
+ lua_pushvalue(L, 1);
lua_call(L, 1, 1);
/* the tick generator function should now be on top of the stack */
luaL_checktype(L, -1, LUA_TFUNCTION);
@@ -514,6 +520,14 @@ l_Stream_play(lua_State *L)
luaJIT_setmode(L, -1, LUAJIT_MODE_ALLFUNC | LUAJIT_MODE_ON);
/*
+ * Get global cycleClock() function. It exists so we can
+ * conveniently advance the clock from the native C method
+ * without calling lua_setfield() and access a class table
+ * from generator methods at sample rate.
+ */
+ lua_getglobal(L, "clockCycle");
+
+ /*
* Perform garbage collection cycle and turn it off
* temporarily. This improves the realtime properties
* of the sample generation loop below.
@@ -537,9 +551,16 @@ l_Stream_play(lua_State *L)
buffer_xrun = 0;
}
- /* duplicate generator function */
+ /*
+ * Duplicate and call clockCycle() function.
+ * This is more efficient than calling lua_getglobal()
+ * at sample rate.
+ */
lua_pushvalue(L, -1);
+ lua_call(L, 0, 0);
+ /* duplicate generator function */
+ lua_pushvalue(L, -2);
/* generate next sample */
lua_call(L, 0, 1);