diff options
author | James <james@mackie.fourth> | 2007-03-17 18:37:52 (GMT) |
---|---|---|
committer | James <james@mackie.fourth> | 2007-03-17 18:37:52 (GMT) |
commit | fec8aed1a6d1b01d1314ab144bd5698c43266ed5 (patch) | |
tree | 8c11ac399c114901710cb713199d107a5a53d8c1 /Util/Clooper | |
parent | 6292d23393ae45731f2393cc6ed265a2252a653a (diff) |
new more robust alsa
Diffstat (limited to 'Util/Clooper')
-rw-r--r-- | Util/Clooper/Makefile | 9 | ||||
-rw-r--r-- | Util/Clooper/aclient.cpp | 762 |
2 files changed, 441 insertions, 330 deletions
diff --git a/Util/Clooper/Makefile b/Util/Clooper/Makefile index fafc0c5..85c439b 100644 --- a/Util/Clooper/Makefile +++ b/Util/Clooper/Makefile @@ -1,14 +1,13 @@ CC=gcc -CFLAGS+=-g -Wall -Werror -fPIC #-O3 -finline - -PYTHON=/usr/include/python2.4 +CXXFLAGS+=-g -Wall -Werror -fPIC -I/home/james/cvs/sugar-jhbuild/build/include #-O3 -finline +LDFLAGS+= -L/home/james/cvs/sugar-jhbuild/build/lib -L/usr/local/lib -lpython2.5 -lcsound -lasound all : aclient.so aclient.so : aclient.cpp - g++ $(CFLAGS) -shared -o $@ $< -lpython2.4 -lcsound -lasound + g++ $(CXXFLAGS) $(PYTHON) -shared -o $@ $< $(LDFLAGS) clean : - rm sclient.so + rm aclient.so diff --git a/Util/Clooper/aclient.cpp b/Util/Clooper/aclient.cpp index caafc0d..07186c4 100644 --- a/Util/Clooper/aclient.cpp +++ b/Util/Clooper/aclient.cpp @@ -1,4 +1,4 @@ -#include <python2.4/Python.h> +#include <python2.5/Python.h> #include <pthread.h> #include <stdio.h> @@ -14,70 +14,23 @@ #include <csound/csound.h> #include <alsa/asoundlib.h> -#define ACFG(cmd) {int err = 0; if ( (err = cmd) < 0) { if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: %s:%i (%s)\n", __FILE__, __LINE__, snd_strerror(err)); return err;} } -#define ERROR_HERE if (_debug) fprintf(_debug, "ERROR: %s:%i\n", __FILE__, __LINE__); +#define ERROR_HERE if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: %s:%i\n", __FILE__, __LINE__) + +#define IF_DEBUG(N) if (_debug && (VERBOSE > N)) int VERBOSE = 1; FILE * _debug = NULL; -unsigned int SAMPLE_RATE = 16000; -static int setparams (snd_pcm_t * phandle, int periods_per_buffer, snd_pcm_uframes_t period_size ) -{ - snd_pcm_hw_params_t *hw; - int srate_dir = 0; - snd_pcm_uframes_t buffer_size = period_size * periods_per_buffer, bsize, psize; - - ACFG(snd_pcm_hw_params_malloc(&hw)); - ACFG(snd_pcm_hw_params_any(phandle, hw)); - ACFG(snd_pcm_hw_params_set_access(phandle, hw, SND_PCM_ACCESS_RW_INTERLEAVED)); - ACFG(snd_pcm_hw_params_set_format(phandle, hw, SND_PCM_FORMAT_FLOAT)); - ACFG(snd_pcm_hw_params_set_rate_near(phandle, hw, &SAMPLE_RATE, &srate_dir)); - ACFG(snd_pcm_hw_params_set_channels(phandle, hw, 2)); - ACFG(snd_pcm_hw_params_set_buffer_size_near(phandle, hw, &buffer_size)); - ACFG(snd_pcm_hw_params_set_period_size_near(phandle, hw, &period_size, 0)); - ACFG(snd_pcm_hw_params_get_buffer_size(hw, &bsize)); - ACFG(snd_pcm_hw_params_get_period_size(hw, &psize, 0)); - - assert(bsize == buffer_size); - assert(psize == period_size); - - ACFG(snd_pcm_hw_params(phandle, hw)); - - snd_pcm_hw_params_free (hw); - return 0; -} -static int setswparams(snd_pcm_t *phandle) -{ - /* not sure what to do here */ - return 0; -} - -static void setscheduler(void) -{ - struct sched_param sched_param; - - if (sched_getparam(0, &sched_param) < 0) { - printf("Scheduler getparam failed...\n"); - return; - } - sched_param.sched_priority = sched_get_priority_max(SCHED_RR); - - if (sched_setscheduler(0, SCHED_RR, &sched_param)) - { - if (_debug && (VERBOSE > 2)) printf("WARNING: Scheduler set to Round Robin with priority %i failed!\n", sched_param.sched_priority); - } - else - { - if (_debug && (VERBOSE > 2)) printf("INFO: Scheduler set to Round Robin with priority %i.\n", sched_param.sched_priority); - } -} - -#if 0 static double pytime(const struct timeval * tv) { + struct timeval t; + if (!tv) + { + tv = &t; + gettimeofday(&t, NULL); + } return (double) tv->tv_sec + (double) tv->tv_usec / 1000000.0; } -#endif struct ev_t { @@ -163,252 +116,431 @@ struct ev_t csoundScoreEvent(csound, type, ¶m[0], param.size()); } }; -struct EvLoop +struct SystemStuff { - int tick_prev; - int tickMax; - MYFLT rtick; - MYFLT secs_per_tick; - MYFLT ticks_per_step; - typedef std::pair<int, ev_t *> pair_t; - typedef std::multimap<int, ev_t *>::iterator iter_t; - typedef std::map<int, iter_t>::iterator idmap_t; - - std::multimap<int, ev_t *> ev; - std::multimap<int, ev_t *>::iterator ev_pos; - std::map<int, iter_t> idmap; - CSOUND * csound; - void * mutex; - int steps; - - EvLoop(CSOUND * cs, snd_pcm_uframes_t period_size) : tick_prev(0), tickMax(1), rtick(0.0), ev(), ev_pos(ev.end()), csound(cs), mutex(NULL), steps(0) - { - setTickDuration(0.05, period_size); - mutex = csoundCreateMutex(0); - } - ~EvLoop() + static void setscheduler(void) { - csoundLockMutex(mutex); - for (iter_t i = ev.begin(); i != ev.end(); ++i) + struct sched_param sched_param; + + if (sched_getparam(0, &sched_param) < 0) { + printf("Scheduler getparam failed...\n"); + return; + } + sched_param.sched_priority = sched_get_priority_max(SCHED_RR); + + if (sched_setscheduler(0, SCHED_RR, &sched_param)) { - delete i->second; + if (_debug && (VERBOSE > 2)) printf("WARNING: Scheduler set to Round Robin with priority %i failed!\n", sched_param.sched_priority); } - csoundUnlockMutex(mutex); - csoundDestroyMutex(mutex); - } - void clear() - { - csoundLockMutex(mutex); - for (iter_t i = ev.begin(); i != ev.end(); ++i) + else { - delete i->second; + if (_debug && (VERBOSE > 2)) printf("INFO: Scheduler set to Round Robin with priority %i.\n", sched_param.sched_priority); } - ev.erase(ev.begin(), ev.end()); - ev_pos = ev.end(); - idmap.erase(idmap.begin(), idmap.end()); - csoundUnlockMutex(mutex); } - void deactivateAll() + + /** the currently opened pcm hande */ + snd_pcm_t * pcm; + snd_pcm_uframes_t period_size; + unsigned int frame_rate; + + SystemStuff() : pcm(NULL), period_size(0), frame_rate(0) { - csoundLockMutex(mutex); - for (iter_t i = ev.begin(); i != ev.end(); ++i) - { - i->second->activate_cmd(0); - } - csoundUnlockMutex(mutex); } - int getTick() + ~SystemStuff() { - return (int)rtick % tickMax; + if (pcm) close(0); } - void setNumTicks(int nticks) + + int open(unsigned int rate0, int upsample_max, snd_pcm_uframes_t period0, unsigned int p_per_buff) { - tickMax = nticks; - if ((int)rtick > nticks) + snd_pcm_hw_params_t *hw; + + if ( 0 > snd_pcm_open(&pcm, "default", SND_PCM_STREAM_PLAYBACK, 0)) { ERROR_HERE; return -1; } + if ( 0 > snd_pcm_hw_params_malloc(&hw)) { ERROR_HERE; snd_pcm_close(pcm); pcm = NULL; return -1; } + + //now we can be a bit flexible with the buffer size and the sample-rate... + + int upsample; + for (upsample = 1; upsample < upsample_max; ++upsample) { - int t = (int)rtick % nticks; - rtick = t; + frame_rate = rate0 * upsample; + + if ( 0 > snd_pcm_hw_params_any(pcm, hw)) { ERROR_HERE; goto open_error;} + + //first do the compulsory steps... interleaved float, 2 channel + if ( 0 > snd_pcm_hw_params_set_rate_resample(pcm, hw, 0)) { ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_test_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_set_access(pcm, hw, SND_PCM_ACCESS_RW_INTERLEAVED)){ ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_test_format(pcm, hw, SND_PCM_FORMAT_FLOAT)) { ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_set_format(pcm, hw, SND_PCM_FORMAT_FLOAT)) { ERROR_HERE; goto open_error;} + if ( 0 > snd_pcm_hw_params_set_channels(pcm, hw, 2)) { ERROR_HERE; goto open_error;} + + IF_DEBUG(1) fprintf(_debug, "testing rate : %i\t", frame_rate); + if ( snd_pcm_hw_params_test_rate(pcm, hw, frame_rate, 0)) + { + fprintf(_debug, "failed.\n"); + continue; + } + else + { + IF_DEBUG(1) fprintf(_debug, "success! setting rate : %i\n", frame_rate); + if (0 > snd_pcm_hw_params_set_rate(pcm, hw, frame_rate, 0)) { ERROR_HERE; goto open_error;} + + snd_pcm_uframes_t minb=0, maxb= 0; + int mind=0, maxd=0; + snd_pcm_hw_params_get_period_size_min(hw, &minb,&mind); + snd_pcm_hw_params_get_period_size_max(hw, &maxb,&maxd); + IF_DEBUG(1) fprintf(_debug, "FYI: period size range is [%li/%i,%li/%i]\n", minb,mind, maxb, maxd); + + assert(mind == 0); //rate_resample 0 makes this true right? + assert(maxd == 0); //rate_resample 0 makes this true right? + + if (period0 < minb) + { + IF_DEBUG(1) fprintf(_debug, "requested period size (%li) < min (%li), adjusting to min\n", period_size, minb); + period_size = minb; + } + else if (period0 > maxb) + { + IF_DEBUG(1) fprintf(_debug, "requested period size (%li) < max (%li), adjusting to min\n", period_size, maxb); + period_size = maxb; + } + else + { + period_size = period0; + } + + IF_DEBUG(1) fprintf(_debug, "testing period size : %li\n", period_size); + if ( 0 > snd_pcm_hw_params_test_period_size(pcm, hw, period_size, 0)){ ERROR_HERE; goto open_error;} + + + IF_DEBUG(1) fprintf(_debug, "setting period size : %li\n", period_size); + if ( 0 > snd_pcm_hw_params_set_period_size(pcm, hw, period_size, 0)){ ERROR_HERE; goto open_error;} + + IF_DEBUG(1) fprintf(_debug, "setting buffer size : %i * %li = %li\n", p_per_buff, period_size, p_per_buff * period_size); + if ( 0 > snd_pcm_hw_params_set_buffer_size(pcm, hw, p_per_buff*period_size)) { ERROR_HERE; goto open_error;} + + break; + } } + + if (upsample_max == upsample) { ERROR_HERE; goto open_error; } + + if (0 > snd_pcm_hw_params(pcm, hw)) { ERROR_HERE; goto open_error; } + + snd_pcm_hw_params_free (hw); + return 0; + +open_error: + snd_pcm_hw_params_free (hw); + snd_pcm_close(pcm); + pcm = NULL; + return -1; } - void setTick(int t) + void close(int drain = 0) { - t = t % tickMax; - rtick = (MYFLT)(t % tickMax); - //TODO: binary search would be faster - csoundLockMutex(mutex); - ev_pos = ev.lower_bound( t ); - csoundUnlockMutex(mutex); + if (drain) snd_pcm_drain(pcm); + snd_pcm_close(pcm); + pcm = NULL; } - void setTickDuration(MYFLT d, int period_size) + void prepare() { - if (!csound) { - if (_debug && (VERBOSE > 1)) fprintf(_debug, "skipping setTickDuration, csound==NULL\n"); - return; + if (0 > snd_pcm_prepare(pcm)) { ERROR_HERE; } + } + int write(snd_pcm_uframes_t frame_count, float * frame_data) + { + int err; + err = snd_pcm_writei (pcm, frame_data, frame_count ); + if (err == (signed)frame_count) return 0; //success + + assert(err < 0); + + const char * msg = NULL; + snd_pcm_state_t state = snd_pcm_state(pcm); + switch (state) + { + case SND_PCM_STATE_OPEN: msg = "open"; break; + case SND_PCM_STATE_SETUP: msg = "setup"; break; + case SND_PCM_STATE_PREPARED:msg = "prepared"; break; + case SND_PCM_STATE_RUNNING: msg = "running"; break; + case SND_PCM_STATE_XRUN: msg = "xrun"; break; + case SND_PCM_STATE_DRAINING: msg = "draining"; break; + case SND_PCM_STATE_PAUSED: msg = "paused"; break; + case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break; + case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break; } - secs_per_tick = d; - ticks_per_step = period_size / ( d * 16000); - if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: duration %lf := ticks_per_step %lf\n", d, ticks_per_step); + if (_debug && (VERBOSE > 0)) fprintf (_debug, "WARNING: write failed (%s)\tstate = %s\ttime=%lf\n", snd_strerror (err), msg, pytime(NULL)); + if (0 > snd_pcm_recover(pcm, err, 0)) { ERROR_HERE; return err;} + if (0 > snd_pcm_prepare(pcm)) { ERROR_HERE; return err;} + return 1; //warning } - void step() +}; +struct TamTamSound +{ + /** the id of an running sound-rendering thread, or NULL */ + void * ThreadID; + /** a flag to tell the thread to continue, or break */ + enum {CONTINUE, STOP} PERF_STATUS; + /** our csound object, NULL iff there was a problem creating it */ + CSOUND * csound; + + /** the event loop */ + struct EvLoop { - rtick += ticks_per_step; - int tick = (int)rtick % tickMax; - if (tick == tick_prev) return; + int tick_prev; + int tickMax; + MYFLT rtick; + MYFLT secs_per_tick; + MYFLT ticks_per_step; + typedef std::pair<int, ev_t *> pair_t; + typedef std::multimap<int, ev_t *>::iterator iter_t; + typedef std::map<int, iter_t>::iterator idmap_t; + + std::multimap<int, ev_t *> ev; + std::multimap<int, ev_t *>::iterator ev_pos; + std::map<int, iter_t> idmap; + CSOUND * csound; + void * mutex; + int steps; + TamTamSound * tt; - csoundLockMutex(mutex); - int events = 0; - int loop0 = 0; - int loop1 = 0; - const int eventMax = 8; //NOTE: events beyond this number will be ignored!!! - if (!ev.empty()) + EvLoop(CSOUND * cs, TamTamSound * tt) : tick_prev(0), tickMax(1), rtick(0.0), ev(), ev_pos(ev.end()), csound(cs), mutex(NULL), steps(0), tt(tt) + { + setTickDuration(0.05); + mutex = csoundCreateMutex(0); + } + ~EvLoop() + { + csoundLockMutex(mutex); + for (iter_t i = ev.begin(); i != ev.end(); ++i) + { + delete i->second; + } + csoundUnlockMutex(mutex); + csoundDestroyMutex(mutex); + } + void clear() + { + csoundLockMutex(mutex); + for (iter_t i = ev.begin(); i != ev.end(); ++i) + { + delete i->second; + } + ev.erase(ev.begin(), ev.end()); + ev_pos = ev.end(); + idmap.erase(idmap.begin(), idmap.end()); + csoundUnlockMutex(mutex); + } + void deactivateAll() { - if (steps && (tick < tick_prev)) // should be true only after the loop wraps (not after insert) + csoundLockMutex(mutex); + for (iter_t i = ev.begin(); i != ev.end(); ++i) { - while (ev_pos != ev.end()) + i->second->activate_cmd(0); + } + csoundUnlockMutex(mutex); + } + int getTick() + { + return (int)rtick % tickMax; + } + void setNumTicks(int nticks) + { + tickMax = nticks; + if ((int)rtick > nticks) + { + int t = (int)rtick % nticks; + rtick = t; + } + } + void setTick(int t) + { + t = t % tickMax; + rtick = (MYFLT)(t % tickMax); + //TODO: binary search would be faster + csoundLockMutex(mutex); + ev_pos = ev.lower_bound( t ); + csoundUnlockMutex(mutex); + } + void setTickDuration(MYFLT d) + { + if (!csound) { + if (_debug && (VERBOSE > 1)) fprintf(_debug, "skipping setTickDuration, csound==NULL\n"); + return; + } + secs_per_tick = d; + ticks_per_step = tt->csound_period_size / ( d * tt->csound_frame_rate); + if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: duration %lf := ticks_per_step %lf\n", d, ticks_per_step); + } + void step() + { + rtick += ticks_per_step; + int tick = (int)rtick % tickMax; + if (tick == tick_prev) return; + + csoundLockMutex(mutex); + int events = 0; + int loop0 = 0; + int loop1 = 0; + const int eventMax = 8; //NOTE: events beyond this number will be ignored!!! + if (!ev.empty()) + { + if (steps && (tick < tick_prev)) // should be true only after the loop wraps (not after insert) + { + while (ev_pos != ev.end()) + { + if (_debug && (VERBOSE > 3)) ev_pos->second->ev_print(_debug); + if (events < eventMax) ev_pos->second->event(csound, secs_per_tick); + ++ev_pos; + ++events; + ++loop0; + } + ev_pos = ev.begin(); + } + while ((ev_pos != ev.end()) && (tick >= ev_pos->first)) { if (_debug && (VERBOSE > 3)) ev_pos->second->ev_print(_debug); if (events < eventMax) ev_pos->second->event(csound, secs_per_tick); ++ev_pos; ++events; - ++loop0; + ++loop1; } - ev_pos = ev.begin(); - } - while ((ev_pos != ev.end()) && (tick >= ev_pos->first)) - { - if (_debug && (VERBOSE > 3)) ev_pos->second->ev_print(_debug); - if (events < eventMax) ev_pos->second->event(csound, secs_per_tick); - ++ev_pos; - ++events; - ++loop1; } + csoundUnlockMutex(mutex); + tick_prev = tick; + if (_debug && (VERBOSE>1) && (events >= eventMax)) fprintf(_debug, "WARNING: %i/%i events at once (%i, %i)\n", events,ev.size(),loop0,loop1); + ++steps; } - csoundUnlockMutex(mutex); - tick_prev = tick; - if (_debug && (VERBOSE>1) && (events >= eventMax)) fprintf(_debug, "WARNING: %i/%i events at once (%i, %i)\n", events,ev.size(),loop0,loop1); - ++steps; - } - void addEvent(int id, char type, MYFLT * p, int np, bool in_ticks, bool active) - { - ev_t * e = new ev_t(type, p, np, in_ticks, active); - - idmap_t id_iter = idmap.find(id); - if (id_iter == idmap.end()) + void addEvent(int id, char type, MYFLT * p, int np, bool in_ticks, bool active) { - //this is a new id - csoundLockMutex(mutex); + ev_t * e = new ev_t(type, p, np, in_ticks, active); - iter_t e_iter = ev.insert(pair_t(e->onset, e)); + idmap_t id_iter = idmap.find(id); + if (id_iter == idmap.end()) + { + //this is a new id + csoundLockMutex(mutex); - //TODO: optimize by thinking about whether to do ev_pos = e_iter - ev_pos = ev.upper_bound( tick_prev ); - idmap[id] = e_iter; + iter_t e_iter = ev.insert(pair_t(e->onset, e)); - csoundUnlockMutex(mutex); - } - else - { - if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: skipping request to add duplicate note %i\n", id); + //TODO: optimize by thinking about whether to do ev_pos = e_iter + ev_pos = ev.upper_bound( tick_prev ); + idmap[id] = e_iter; + + csoundUnlockMutex(mutex); + } + else + { + if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: skipping request to add duplicate note %i\n", id); + } } - } - void delEvent(int id) - { - idmap_t id_iter = idmap.find(id); - if (id_iter == idmap.end()) + void delEvent(int id) { - if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: delEvent request for unknown note %i\n", id); + idmap_t id_iter = idmap.find(id); + if (id_iter == idmap.end()) + { + if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: delEvent request for unknown note %i\n", id); + } + else + { + csoundLockMutex(mutex); + iter_t e_iter = id_iter->second;//idmap[id]; + if (e_iter == ev_pos) ++ev_pos; + + delete e_iter->second; + ev.erase(e_iter); + idmap.erase(id_iter); + + csoundUnlockMutex(mutex); + } } - else + void updateEvent(int id, int idx, float val, int activate_cmd) { + idmap_t id_iter = idmap.find(id); + if (id_iter == idmap.end()) + { + if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: updateEvent request for unknown note %i\n", id); + return; + } + + //this is a new id csoundLockMutex(mutex); - iter_t e_iter = id_iter->second;//idmap[id]; - if (e_iter == ev_pos) ++ev_pos; + iter_t e_iter = id_iter->second; + ev_t * e = e_iter->second; + int onset = e->onset; + e->update(idx, val); + e->activate_cmd(activate_cmd); + if (onset != e->onset) + { + ev.erase(e_iter); - delete e_iter->second; - ev.erase(e_iter); - idmap.erase(id_iter); + e_iter = ev.insert(pair_t(e->onset, e)); + //TODO: optimize by thinking about whether to do ev_pos = e_iter + ev_pos = ev.upper_bound( tick_prev ); + idmap[id] = e_iter; + } csoundUnlockMutex(mutex); } - } - void updateEvent(int id, int idx, float val, int activate_cmd) - { - idmap_t id_iter = idmap.find(id); - if (id_iter == idmap.end()) + void reset() { - if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: updateEvent request for unknown note %i\n", id); - return; + steps = 0; } + }; + EvLoop * loop; + /** a flag, true iff the thread should play&advance the loop */ + int thread_playloop; - //this is a new id - csoundLockMutex(mutex); - iter_t e_iter = id_iter->second; - ev_t * e = e_iter->second; - int onset = e->onset; - e->update(idx, val); - e->activate_cmd(activate_cmd); - if (onset != e->onset) - { - ev.erase(e_iter); + /** the upsampling ratio from csound */ + unsigned int csound_ksmps; + snd_pcm_uframes_t csound_frame_rate; + snd_pcm_uframes_t csound_period_size; + snd_pcm_uframes_t period0; + unsigned int period_per_buffer; + int up_ratio; - e_iter = ev.insert(pair_t(e->onset, e)); + SystemStuff sys_stuff; - //TODO: optimize by thinking about whether to do ev_pos = e_iter - ev_pos = ev.upper_bound( tick_prev ); - idmap[id] = e_iter; - } - csoundUnlockMutex(mutex); - } - void reset() + TamTamSound(char * orc, snd_pcm_uframes_t period0, unsigned int ppb) + : ThreadID(NULL), PERF_STATUS(STOP), csound(NULL), + loop(NULL), thread_playloop(0), + csound_ksmps(64), //MAGIC: must agree with the orchestra file + csound_frame_rate(16000), //MAGIC: must agree with the orchestra file + period0(period0), + period_per_buffer(ppb), + up_ratio(0), + sys_stuff() { - steps = 0; - } -}; -struct TamTamSound -{ - void * ThreadID; - CSOUND * csound; - enum {CONTINUE, STOP} PERF_STATUS; - FILE * _light; - int thread_playloop; - int thread_measurelag; - EvLoop * loop; - const snd_pcm_uframes_t period_size; - int periods_per_buffer; - - TamTamSound(char * orc) - : ThreadID(NULL), csound(NULL), PERF_STATUS(STOP), - _light(fopen("/sys/bus/platform/devices/leds-olpc/leds:olpc:keyboard/brightness", "w")), - thread_playloop(0), thread_measurelag(0), loop(NULL), - period_size(1<<8), periods_per_buffer(2) - { - if (1) - { - csound = csoundCreate(NULL); - int argc=3; - char **argv = (char**)malloc(argc*sizeof(char*)); - argv[0] = "csound"; - argv[1] ="-m0"; - argv[2] = orc; - if (_debug && (VERBOSE>1)) fprintf(_debug, "loading file %s\n", orc); - - //csoundInitialize(&argc, &argv, 0); - csoundPreCompile(csound); - csoundSetHostImplementedAudioIO(csound, 1, period_size); - int result = csoundCompile(csound, argc, &(argv[0])); - if (result) - { - csound = NULL; - if (_debug && (VERBOSE>0)) fprintf(_debug, "ERROR: csoundCompile of orchestra %s failed with code %i\n", - orc, result); - } - free(argv); + if (0 > sys_stuff.open(csound_frame_rate, 4, period0, period_per_buffer)) + { + return; } - else + sys_stuff.close(0); + up_ratio = sys_stuff.frame_rate / csound_frame_rate; + csound_period_size = (sys_stuff.period_size % up_ratio == 0) + ? sys_stuff.period_size / up_ratio + : csound_ksmps * 4; + + csound = csoundCreate(NULL); + int argc=3; + char **argv = (char**)malloc(argc*sizeof(char*)); + argv[0] = "csound"; + argv[1] ="-m0"; + argv[2] = orc; + if (_debug && (VERBOSE>1)) fprintf(_debug, "loading file %s\n", orc); + + //csoundInitialize(&argc, &argv, 0); + csoundPreCompile(csound); + csoundSetHostImplementedAudioIO(csound, 1, csound_period_size); + int result = csoundCompile(csound, argc, &(argv[0])); + if (result) { csound = NULL; + if (_debug && (VERBOSE>0)) fprintf(_debug, "ERROR: csoundCompile of orchestra %s failed with code %i\n", + orc, result); } - loop = new EvLoop(csound, period_size); + free(argv); + loop = new EvLoop(csound, this); } ~TamTamSound() { @@ -421,79 +553,65 @@ struct TamTamSound if (_debug && (VERBOSE > 2)) fprintf(_debug, "Going for csoundDestroy\n"); csoundDestroy(csound); } - if (_light) fclose(_light); - if (_debug && (VERBOSE > 2)) fprintf(_debug, "TamTam aclient destroyed\n"); } uintptr_t thread_fn() { - struct timeval tv0; + assert(csound); + const int nchannels = 2; int nloops = 0; - long int nsamples = csoundGetOutputBufferSize(csound); - long int nframes = nsamples/2; /* nchannels == 2 */ /* nframes per write */ - assert((unsigned)nframes == period_size); - float * buf = (float*)malloc(nsamples * sizeof(float)); - if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: nsamples = %li nframes = %li\n", nsamples, nframes); + long int csound_nsamples = csoundGetOutputBufferSize(csound); + long int csound_nframes = csound_nsamples / nchannels; - snd_pcm_t * phandle; - ACFG(snd_pcm_open(&phandle, "default", SND_PCM_STREAM_PLAYBACK,0)); - if (setparams(phandle, periods_per_buffer, period_size)) - { - goto thread_fn_cleanup; - } - if (setswparams(phandle)) - { - goto thread_fn_cleanup; - } - if (0 > snd_pcm_prepare(phandle)) - { - ERROR_HERE; - goto thread_fn_cleanup; - } - for (int i = 0; i < nframes; ++i) - { - buf[i*2] = buf[i*2+1] = 0.5 * sin( i / (float)nframes * 10.0 * M_PI); - } + if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: nsamples = %li nframes = %li\n", csound_nsamples, csound_nframes); - setscheduler(); + if (0 > sys_stuff.open(csound_frame_rate, 4, period0, period_per_buffer)) return 1; + + assert(up_ratio = sys_stuff.frame_rate / csound_frame_rate); + + float *upbuf = new float[ sys_stuff.period_size * nchannels ]; //2 channels + int cbuf_pos = csound_nframes; + float *cbuf = NULL; + unsigned up_pos = 0; + int ratio_pos = 0; + + sys_stuff.setscheduler(); //it might work... while (PERF_STATUS == CONTINUE) { - int err = 0; - float *cbuf = csoundGetOutputBuffer(csound); - gettimeofday(&tv0, 0); - if (1 && csoundPerformBuffer(csound)) break; - assert(sizeof (MYFLT) == 4); - - if ((err = snd_pcm_writei (phandle, cbuf, nframes)) != nframes) + if (sys_stuff.period_size == (unsigned)csound_nframes ) { - const char * msg = NULL; - snd_pcm_state_t state = snd_pcm_state(phandle); - switch (state) - { - case SND_PCM_STATE_OPEN: msg = "open"; break; - case SND_PCM_STATE_SETUP: msg = "setup"; break; - case SND_PCM_STATE_PREPARED:msg = "prepared"; break; - case SND_PCM_STATE_RUNNING: msg = "running"; break; - case SND_PCM_STATE_XRUN: msg = "xrun"; break; - case SND_PCM_STATE_DRAINING: msg = "draining"; break; - case SND_PCM_STATE_PAUSED: msg = "paused"; break; - case SND_PCM_STATE_SUSPENDED: msg = "suspended"; break; - case SND_PCM_STATE_DISCONNECTED: msg = "disconnected"; break; - } - //if (state != SND_PCM_STATE_XRUN) - if (_debug && (VERBOSE > 0)) fprintf (_debug, "WARNING: write to audio interface failed (%s)\tstate = %s\n", snd_strerror (err), msg); - ACFG(snd_pcm_recover(phandle, err, 0)); - if (0 > snd_pcm_prepare(phandle)) + if (csoundPerformBuffer(csound)) break; + if (0 > sys_stuff.write(sys_stuff.period_size, csoundGetOutputBuffer(csound))) break; + } + else + { + up_pos = 0; + for(;;) { - ERROR_HERE; - goto thread_fn_cleanup; + if (cbuf_pos == csound_nframes) + { + cbuf_pos = 0; + if (csoundPerformBuffer(csound)) break; + cbuf = csoundGetOutputBuffer(csound); + } + upbuf[2*up_pos+0] = cbuf[cbuf_pos*2+0]; + upbuf[2*up_pos+1] = cbuf[cbuf_pos*2+1]; + + if (++ratio_pos == up_ratio) + { + ratio_pos = 0; + ++cbuf_pos; + } + + if (++up_pos == sys_stuff.period_size) break; } - state = snd_pcm_state(phandle); + if (up_pos != sys_stuff.period_size) break; - assert(state == SND_PCM_STATE_PREPARED || state == SND_PCM_STATE_RUNNING); + if (0 > sys_stuff.write(sys_stuff.period_size, upbuf)) break; } + if (thread_playloop) { loop->step(); @@ -501,12 +619,6 @@ struct TamTamSound ++nloops; } -thread_fn_cleanup: - free(buf); - snd_pcm_drain(phandle); - - snd_pcm_close (phandle); - if (_debug && (VERBOSE > 2)) fprintf(_debug, "INFO: returning from performance thread\n"); return 0; } @@ -514,7 +626,7 @@ thread_fn_cleanup: { return ((TamTamSound*)clientData)->thread_fn(); } - int start(int p_per_b) + int start(int ) { if (!csound) { if (_debug && (VERBOSE > 1)) fprintf(_debug, "skipping %s, csound==NULL\n", __FUNCTION__); @@ -523,7 +635,6 @@ thread_fn_cleanup: if (!ThreadID) { PERF_STATUS = CONTINUE; - periods_per_buffer = p_per_b; ThreadID = csoundCreateThread(csThread, (void*)this); return 0; } @@ -709,7 +820,8 @@ DECL(sc_initialize) //(char * csd) { char * str; char * log_file; - if (!PyArg_ParseTuple(args, "ss", &str, &log_file )) + int period, ppb; + if (!PyArg_ParseTuple(args, "ssii", &str, &log_file, &period, &ppb )) { return NULL; } @@ -717,7 +829,7 @@ DECL(sc_initialize) //(char * csd) _debug = fopen(log_file,"w"); else _debug = NULL; - sc_tt = new TamTamSound(str); + sc_tt = new TamTamSound(str, period, ppb); atexit(&cleanup); if (sc_tt->good()) return Py_BuildValue("i", 0); @@ -826,7 +938,7 @@ DECL(sc_loop_getTick) // -> int { return NULL; } - return Py_BuildValue("i", sc_tt->loop->getTick()); + return Py_BuildValue("i", sc_tt->loop ? sc_tt->loop->getTick():-1); } DECL(sc_loop_setNumTicks) //(int nticks) { @@ -835,7 +947,7 @@ DECL(sc_loop_setNumTicks) //(int nticks) { return NULL; } - sc_tt->loop->setNumTicks(nticks); + if (sc_tt->loop) sc_tt->loop->setNumTicks(nticks); RetNone; } DECL(sc_loop_setTick) // (int ctick) @@ -845,7 +957,7 @@ DECL(sc_loop_setTick) // (int ctick) { return NULL; } - sc_tt->loop->setTick(ctick); + if (sc_tt->loop) sc_tt->loop->setTick(ctick); RetNone; } DECL(sc_loop_setTickDuration) // (MYFLT secs_per_tick) @@ -855,7 +967,7 @@ DECL(sc_loop_setTickDuration) // (MYFLT secs_per_tick) { return NULL; } - sc_tt->loop->setTickDuration(spt, sc_tt->period_size); + if (sc_tt->loop) sc_tt->loop->setTickDuration(spt); RetNone; } DECL(sc_loop_addScoreEvent) // (int id, int duration_in_ticks, char type, farray param) @@ -878,7 +990,7 @@ DECL(sc_loop_addScoreEvent) // (int id, int duration_in_ticks, char type, farray len = o->ob_type->tp_as_buffer->bf_getreadbuffer(o, 0, &ptr); float * fptr = (float*)ptr; size_t flen = len / sizeof(float); - sc_tt->loop->addEvent(qid, ev_type, fptr, flen, inticks, active); + if (sc_tt->loop) sc_tt->loop->addEvent(qid, ev_type, fptr, flen, inticks, active); Py_INCREF(Py_None); return Py_None; @@ -898,7 +1010,7 @@ DECL(sc_loop_delScoreEvent) // (int id) { return NULL; } - sc_tt->loop->delEvent(id); + if (sc_tt->loop) sc_tt->loop->delEvent(id); RetNone; } DECL(sc_loop_updateEvent) // (int id) @@ -911,7 +1023,7 @@ DECL(sc_loop_updateEvent) // (int id) { return NULL; } - sc_tt->loop->updateEvent(id, idx, val, cmd); + if (sc_tt->loop) sc_tt->loop->updateEvent(id, idx, val, cmd); RetNone; } DECL(sc_loop_deactivate_all) // (int id) @@ -920,7 +1032,7 @@ DECL(sc_loop_deactivate_all) // (int id) { return NULL; } - sc_tt->loop->deactivateAll(); + if (sc_tt->loop) sc_tt->loop->deactivateAll(); RetNone; } DECL(sc_loop_clear) @@ -929,7 +1041,7 @@ DECL(sc_loop_clear) { return NULL; } - sc_tt->loop->clear(); + if (sc_tt->loop) sc_tt->loop->clear(); RetNone; } DECL(sc_loop_playing) // (int tf) @@ -939,7 +1051,7 @@ DECL(sc_loop_playing) // (int tf) { return NULL; } - sc_tt->loopPlaying(i); + if (sc_tt->loop) sc_tt->loopPlaying(i); RetNone; } DECL (sc_inputMessage) //(const char *msg) |