diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-01-03 21:56:31 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2016-01-03 22:28:06 +0100 |
commit | cdbb6c0ac72817cd5f1eff16c1be944386a3773c (patch) | |
tree | e826192fb70b8ea6527ee158ef18d18a29821a41 /applause.c | |
parent | f8318d9d52dc136eecbae52d047f9ad9325dce76 (diff) | |
download | applause2-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.c | 31 |
1 files changed, 26 insertions, 5 deletions
@@ -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); |