diff options
Diffstat (limited to 'TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp')
-rw-r--r-- | TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp | 1101 |
1 files changed, 0 insertions, 1101 deletions
diff --git a/TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp b/TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp deleted file mode 100644 index 1a8e81b..0000000 --- a/TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp +++ /dev/null @@ -1,1101 +0,0 @@ -#include <Python.h> - -#include <pthread.h> -#include <stdio.h> -#include <time.h> -#include <unistd.h> -#include <sys/time.h> -#include <sched.h> - -#include <vector> -#include <map> -#include <cmath> - -#include <csound/csound.h> -#include <alsa/asoundlib.h> - -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; -} -#include "log.cpp" -#include "audio.cpp" - -#define FLOAT_TO_SHORT(in,out) __asm__ __volatile__ ("fistps %0" : "=m" (out) : "t" (in) : "st") ; - -int VERBOSE = 3; -FILE * _debug = NULL; -struct TamTamSound; -struct Music; -TamTamSound * g_tt = NULL; -Music * g_music = NULL; -static log_t * g_log = NULL; -const int STEP_eventMax = 16; //this is the most events that will be queued by a loop per step() - -/** - * Event is the type of event that Clooper puts in the loop buffer. - * It corresponds to a line of csound that starts with an 'i' - */ -struct Event -{ - char type; ///< if this event were listed in a csound file, the line would begin with this letter - int onset; ///< the onset time of this event (its temporal position) - bool time_in_ticks; ///< if true, then some parameters will be updated according to the tempo - bool active; ///< if true, then event() will actually do something - MYFLT prev_secs_per_tick; ///< normally used for ____, sometimes set to -1 to force recalculation of param[] entries - MYFLT duration, attack, decay;///< canonical values of some tempo-dependent parameters - std::vector<MYFLT> param; ///< parameter buffer for csound - - Event(char type, MYFLT * p, int param_count, bool in_ticks, bool active) - : type(type), onset(0), time_in_ticks(in_ticks), active(active), param(param_count) - { - assert(param_count >= 4); - onset = (int) p[1]; - duration = p[2]; - attack = param_count > 8 ? p[8]: 0.0; //attack - decay = param_count > 9 ? p[9]: 0.0; //decay - prev_secs_per_tick = -1.0; - for (int i = 0; i < param_count; ++i) param[i] = p[i]; - - param[1] = 0.0; //onset - } - /* - bool operator<(const Event &e) const - { - return onset < e.onset; - } - */ - void ev_print(FILE *f) - { - fprintf(f, "INFO: scoreEvent %c ", type); - for (size_t i = 0; i < param.size(); ++i) fprintf(f, "%lf ", param[i]); - fprintf(f, "[%s]\n", active ? "active": "inactive"); - } - /** - * Update the idx'th param value to have a certain value. - * - * Certain of the parameters are linked in strange hack-y ways, as defined by - * the constructor, and update() (which should be consistent with one another!) - * - * These events are for use with the file: TamTam/Resources/univorc.csd. - * So that file defines how the parameters will be interpreted by csound. - */ - void update(int idx, MYFLT val) - { - if ( (unsigned)idx >= param.size()) - { - if (_debug && (VERBOSE > 0)) fprintf(_debug, "ERROR: updateEvent request for too-high parameter %i\n", idx); - return; - } - if (time_in_ticks) - { - switch(idx) - { - case 1: onset = (int) val; break; - case 2: duration = val; break; - case 8: attack = val; break; - case 9: decay = val; break; - default: param[idx] = val; break; - } - prev_secs_per_tick = -1.0; //force recalculation - } - else - { - param[idx] = val; - } - } - /** - * An Event instance can be in an active or inactive state. If an Event instance - * is active, then event() will call a corresponding csoundScoreEvent(). If an - * Event instance is inactive, then event() is a noop. - */ - void activate_cmd(int cmd) - { - switch(cmd) - { - case 0: active = false; break; - case 1: active = true; break; - case 2: active = !active; break; - } - } - - /** - * Iff this instance is active, this call generates a csound event. - * Parameters are passed directly as a buffer of floats. If secs_per_tick - * != prev_secs_per_tick (possibly because prev_secs_per_tick was set to -1 - * by update() ) then this call will do some floating point ops to - * recalculate the parameter buffer. - */ - void event(CSOUND * csound, MYFLT secs_per_tick) - { - if (!active) return; - - if (time_in_ticks && (secs_per_tick != prev_secs_per_tick)) - { - param[2] = duration * secs_per_tick; - if (param.size() > 8) param[8] = std::max(0.002f, attack * param[2]); - if (param.size() > 9) param[9] = std::max(0.002f, decay * param[2]); - prev_secs_per_tick = secs_per_tick; - if (_debug && (VERBOSE > 2)) fprintf(_debug, "setting duration to %f\n", param[5]); - } - csoundScoreEvent(csound, type, ¶m[0], param.size()); - } -}; - -/** - * - * Loop is a repeat-able loop of Event instances. - * */ -struct Loop -{ - typedef int onset_t; - typedef int id_t; - typedef std::pair<onset_t, Event *> pair_t; - typedef std::multimap<onset_t, Event *>::iterator iter_t; - typedef std::map<id_t, iter_t>::iterator idmap_t; - - int tick_prev; - int tickMax; - MYFLT rtick; - - // a container of all events, sorted by onset time - // used for efficient playback - std::multimap<onset_t, Event *> ev; - // the playback head - std::multimap<onset_t, Event *>::iterator ev_pos; - // a container of pointers into ev, indexed by note id - // used for deleting, updating notes - std::map<id_t, iter_t> idmap; - int steps; - int playing; //true means that step() works, else step() is no-op - - Loop() : tick_prev(0), tickMax(1), rtick(0.0), ev(), ev_pos(ev.end()), steps(0), playing(0) - { - } - ~Loop() - { - //TODO: send these events to a recycling queue, don't erase them - for (iter_t i = ev.begin(); i != ev.end(); ++i) - { - delete i->second; - } - } - void deactivateAll() - { - for (iter_t i = ev.begin(); i != ev.end(); ++i) - { - i->second->activate_cmd(0); - } - } - MYFLT getTickf() - { - return fmod(rtick, (MYFLT)tickMax); - } - void setNumTicks(int nticks) - { - tickMax = nticks; - MYFLT fnticks = nticks; - if (rtick > fnticks) - { - rtick = fmodf(rtick, fnticks); - } - } - void setTickf(float t) - { - rtick = fmodf(t, (MYFLT) tickMax); - ev_pos = ev.lower_bound( (int) rtick ); - } - /** advance in play loop by rtick_inc ticks, possibly generate some - * csoundScoreEvent calls. - */ - void step(MYFLT rtick_inc, MYFLT secs_per_tick , CSOUND * csound) - { - if (!playing) return; - rtick += rtick_inc; - int tick = (int)rtick % tickMax; - if (tick == tick_prev) return; - - int events = 0; - int loop0 = 0; - int loop1 = 0; - 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 < STEP_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 < STEP_eventMax) ev_pos->second->event(csound, secs_per_tick); - ++ev_pos; - ++events; - ++loop1; - } - } - tick_prev = tick; - if (_debug && (VERBOSE>1) && (events >= STEP_eventMax)) fprintf(_debug, "WARNING: %i/%i events at once (%i, %i)\n", events, (int)ev.size(),loop0,loop1); - ++steps; - } - void addEvent(int id, char type, MYFLT * p, int np, bool in_ticks, bool active) - { - Event * e = new Event(type, p, np, in_ticks, active); - - idmap_t id_iter = idmap.find(id); - if (id_iter == idmap.end()) - { - //this is a new id - iter_t 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; - } - else - { - g_log->printf(1, "%s duplicate note %i\n", __FUNCTION__, id); - } - } - void delEvent(int id) - { - idmap_t id_iter = idmap.find(id); - if (id_iter != idmap.end()) - { - 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); - } - else - { - g_log->printf( 1, "%s unknown note %i\n", __FUNCTION__, id); - } - } - void updateEvent(int id, int idx, float val, int activate_cmd) - { - idmap_t id_iter = idmap.find(id); - if (id_iter != idmap.end()) - { - //this is a new id - iter_t e_iter = id_iter->second; - Event * 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); - - 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; - } - } - else - { - g_log->printf(1, "%s unknown note %i\n", __FUNCTION__, id); - } - } - void reset() - { - steps = 0; - } - void setPlaying(int tf) - { - playing = tf; - } -}; - -/** management of loops */ -struct Music -{ - typedef int loopIdx_t; - typedef std::map<int, Loop * > eventMap_t; - - eventMap_t loop; - int loop_nextIdx; - void * mutex; //modification and playing of loops cannot be interwoven - - Music() : - loop(), - loop_nextIdx(0), - mutex(csoundCreateMutex(0)) - { - } - ~Music() - { - for (eventMap_t::iterator i = loop.begin(); i != loop.end(); ++i) - { - delete i->second; - } - csoundDestroyMutex(mutex); - } - - void step(MYFLT amt, MYFLT secs_per_tick, CSOUND * csound) - { - csoundLockMutex(mutex); - for (eventMap_t::iterator i = loop.begin(); i != loop.end(); ++i) - { - i->second->step(amt, secs_per_tick, csound); - } - csoundUnlockMutex(mutex); - } - - /** allocate a new loop, and return its index */ - loopIdx_t alloc() - { - csoundLockMutex(mutex); - //find a loop_nextIdx that isn't in loop map already - while ( loop.find( loop_nextIdx) != loop.end()) ++loop_nextIdx; - loop[loop_nextIdx] = new Loop(); - csoundUnlockMutex(mutex); - return loop_nextIdx; - } - /** de-allocate a loop */ - void destroy(loopIdx_t loopIdx) - { - if (loop.find(loopIdx) != loop.end()) - { - csoundLockMutex(mutex); - //TODO: save the note events to a cache for recycling - delete loop[loopIdx]; - loop.erase(loopIdx); - csoundUnlockMutex(mutex); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - /** set the playing flag of the given loop */ - void playing(loopIdx_t loopIdx, int tf) - { - if (loop.find(loopIdx) != loop.end()) - { - csoundLockMutex(mutex); - loop[loopIdx]->setPlaying(tf); - csoundUnlockMutex(mutex); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - /** set the playing flag of the given loop */ - void addEvent(loopIdx_t loopIdx, int eventId, char type, MYFLT * p, int np, bool in_ticks, bool active) - { - if (loop.find(loopIdx) != loop.end()) - { - csoundLockMutex(mutex); - loop[loopIdx]->addEvent(eventId, type, p, np, in_ticks, active); - csoundUnlockMutex(mutex); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - void delEvent(loopIdx_t loopIdx, int eventId) - { - if (loop.find(loopIdx) != loop.end()) - { - csoundLockMutex(mutex); - loop[loopIdx]->delEvent(eventId); - csoundUnlockMutex(mutex); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - void updateEvent(loopIdx_t loopIdx, int eventId, int pIdx, float pVal, int activate_cmd) - { - if (loop.find(loopIdx) != loop.end()) - { - csoundLockMutex(mutex); - loop[loopIdx]->updateEvent(eventId, pIdx, pVal, activate_cmd); - csoundUnlockMutex(mutex); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - MYFLT getTickf(loopIdx_t loopIdx) - { - if (loop.find(loopIdx) != loop.end()) - { - return loop[loopIdx]->getTickf(); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - return 0.0; - } - } - void setTickf(loopIdx_t loopIdx, MYFLT tickf) - { - if (loop.find(loopIdx) != loop.end()) - { - loop[loopIdx]->setTickf(tickf); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - void setNumTicks(loopIdx_t loopIdx, int numTicks) - { - if (loop.find(loopIdx) != loop.end()) - { - loop[loopIdx]->setNumTicks(numTicks); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - void deactivateAll(loopIdx_t loopIdx) - { - if (loop.find(loopIdx) != loop.end()) - { - loop[loopIdx]->deactivateAll(); - } - else - { - g_log->printf(1, "%s() called on non-existant loop %i\n", __FUNCTION__ , loopIdx); - } - } - -}; - -/** - * The main object of control in the Clooper plugin. - * - * This guy controls the sound rendering thread, loads and unloads ALSA, - * maintains a csound instance, and maintains a subset of notes from the - * currently-loaded TamTam. - */ -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; - /** our note sources */ - Music music; - - MYFLT secs_per_tick; - MYFLT ticks_per_period; - MYFLT tick_adjustment; //the default time increment in thread_fn - MYFLT tick_total; - - /** 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; //should be 2 - int up_ratio; //if the hardware only supports a small integer multiple of our effective samplerate, do a real-time conversion - - log_t * ll; - SystemStuff * sys_stuff; - - TamTamSound(log_t * ll, char * orc, snd_pcm_uframes_t period0, unsigned int ppb, int ksmps, int framerate ) - : ThreadID(NULL), PERF_STATUS(STOP), csound(NULL), - music(), - ticks_per_period(0.0), - tick_adjustment(0.0), - tick_total(0.0), - csound_ksmps(ksmps), //must agree with the orchestra file - csound_frame_rate(framerate), //must agree with the orchestra file - period0(period0), - period_per_buffer(ppb), - up_ratio(1), - ll( ll ), - sys_stuff(NULL) - { - sys_stuff = new SystemStuff(ll); - if (0 > sys_stuff->open(csound_frame_rate, 4, period0, period_per_buffer)) - { - return; - } - sys_stuff->close(0); - up_ratio = sys_stuff->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; - const char **argv = (const char**)malloc(argc*sizeof(char*)); - argv[0] = "csound"; - argv[1] = "-m0"; - argv[2] = orc; - - ll->printf(1, "loading csound orchestra file %s\n", orc); - //csoundInitialize(&argc, &argv, 0); - csoundPreCompile(csound); - csoundSetHostImplementedAudioIO(csound, 1, csound_period_size); - int result = csoundCompile(csound, argc, (char**)argv); - if (result) - { - csound = NULL; - ll->printf( "ERROR: csoundCompile of orchestra %s failed with code %i\n", orc, result); - } - free(argv); - setTickDuration(0.05); - } - ~TamTamSound() - { - if (csound) - { - stop(); - ll->printf(2, "Going for csoundDestroy\n"); - csoundDestroy(csound); - } - ll->printf(2, "TamTamSound destroyed\n"); - if (sys_stuff) delete sys_stuff; - delete ll; - } - bool good() - { - return csound != NULL; - } - - uintptr_t thread_fn() - { - assert(csound); - - const int nchannels = 2; - int nloops = 0; - long int csound_nsamples = csoundGetOutputBufferSize(csound); - long int csound_nframes = csound_nsamples / nchannels; - - ll->printf(2, "INFO: nsamples = %li nframes = %li\n", csound_nsamples, csound_nframes); - - if (0 > sys_stuff->open(csound_frame_rate, 4, period0, period_per_buffer)) - { - ll->printf( "ERROR: failed to open alsa device, thread abort\n"); - return 1; - } - - assert(up_ratio == (signed)(sys_stuff->rate / csound_frame_rate)); - - bool do_upsample = (signed)sys_stuff->period_size != csound_nframes; - short *upbuf = new short[ sys_stuff->period_size * nchannels ]; - int cbuf_pos = csound_nframes; // trigger a call to csoundPerformBuffer immediately - float *cbuf = NULL; - int up_pos = 0; - int ratio_pos = 0; - - tick_total = 0.0f; - - while (PERF_STATUS == CONTINUE) - { - if ( do_upsample ) //fill one period of audio buffer data by 0 or more calls to csound - { - up_pos = 0; - int messed = 0; - short cursample[2]={0,0}; - while(!messed) - { - if (cbuf_pos == csound_nframes) - { - cbuf_pos = 0; - if (csoundPerformBuffer(csound)) { messed = 1;break;} - cbuf = csoundGetOutputBuffer(csound); - cursample[0] = (signed short int) (cbuf[cbuf_pos*2+0] * (1<<15)); - cursample[1] = (signed short int) (cbuf[cbuf_pos*2+1] * (1<<15)); - -/* - cbuf[cbuf_pos*2+0] *= (float) ((1<<14)); - cbuf[cbuf_pos*2+1] *= (float) ((1<<14)); - FLOAT_TO_SHORT( cbuf[cbuf_pos*2+0], cursample[0]); - FLOAT_TO_SHORT( cbuf[cbuf_pos*2+1], cursample[1]); -*/ - } - upbuf[2*up_pos+0] = cursample[0]; - upbuf[2*up_pos+1] = cursample[1]; - if (++ratio_pos == up_ratio) - { - ratio_pos = 0; - ++cbuf_pos; - cursample[0] = (signed short int) (cbuf[cbuf_pos*2+0] * (1<<15)); - cursample[1] = (signed short int) (cbuf[cbuf_pos*2+1] * (1<<15)); - /*cbuf[cbuf_pos*2+0] *= (float) ((1<<14)); - cbuf[cbuf_pos*2+1] *= (float) ((1<<14)); - FLOAT_TO_SHORT( cbuf[cbuf_pos*2+0], cursample[0]); - FLOAT_TO_SHORT( cbuf[cbuf_pos*2+1], cursample[1]); -*/ - } - - if (++up_pos == (signed)sys_stuff->period_size) break; - } - if (messed || (up_pos != (signed)sys_stuff->period_size)) break; - - if (0 > sys_stuff->writebuf(sys_stuff->period_size, upbuf)) break; - } - else //fill one period of audio directly from csound - { - if (csoundPerformBuffer(csound)) break; - cbuf = csoundGetOutputBuffer(csound); - for (int i = 0; i < csound_nframes * nchannels; ++i) - { - cbuf[i] *= (float) ((1<<15)-100.0f); - FLOAT_TO_SHORT( cbuf[i], upbuf[i]); - } - if (0 > sys_stuff->writebuf(csound_nframes,upbuf)) break; - } - - if (tick_adjustment > - ticks_per_period) - { - MYFLT tick_inc = ticks_per_period + tick_adjustment; - music.step( tick_inc, secs_per_tick, csound); - tick_adjustment = 0.0; - tick_total += tick_inc; - } - else - { - tick_adjustment += ticks_per_period; - } - ++nloops; - } - - sys_stuff->close(1); - delete [] upbuf; - ll->printf(2, "INFO: performance thread returning 0\n"); - return 0; - } - static uintptr_t csThread(void *clientData) - { - return ((TamTamSound*)clientData)->thread_fn(); - } - int start(int ) - { - if (!csound) { - ll->printf(1, "skipping %s, csound==NULL\n", __FUNCTION__); - return 1; - } - if (!ThreadID) - { - PERF_STATUS = CONTINUE; - ThreadID = csoundCreateThread(csThread, (void*)this); - ll->printf( "INFO(%s:%i) aclient launching performance thread (%p)\n", __FILE__, __LINE__, ThreadID ); - return 0; - } - ll->printf( "INFO(%s:%i) skipping duplicate request to launch a thread\n", __FILE__, __LINE__ ); - return 1; - } - int stop() - { - if (!csound) { - ll->printf(1, "skipping %s, csound==NULL\n", __FUNCTION__); - return 1; - } - if (ThreadID) - { - PERF_STATUS = STOP; - ll->printf( "INFO(%s:%i) aclient joining performance thread\n", __FILE__, __LINE__ ); - uintptr_t rval = csoundJoinThread(ThreadID); - ll->printf( "INFO(%s:%i) ... joined\n", __FILE__, __LINE__ ); - if (rval) ll->printf( "WARNING: thread returned %zu\n", rval); - ThreadID = NULL; - return 0; - } - return 1; - } - - /** pass an array event straight through to csound. only works if perf. thread is running */ - void scoreEvent(char type, MYFLT * p, int np) - { - if (!csound) { - ll->printf(1, "skipping %s, csound==NULL\n", __FUNCTION__); - return; - } - if (!ThreadID) - { - if (_debug && (VERBOSE > 1)) fprintf(_debug, "skipping %s, ThreadID==NULL\n", __FUNCTION__); - return ; - } - if (_debug && (VERBOSE > 2)) - { - fprintf(_debug, "INFO: scoreEvent %c ", type); - for (int i = 0; i < np; ++i) fprintf(_debug, "%lf ", p[i]); - fprintf(_debug, "\n"); - } - csoundScoreEvent(csound, type, p, np); - } - /** pass a string event straight through to csound. only works if perf. thread is running */ - void inputMessage(const char * msg) - { - if (!csound) { - ll->printf(1, "skipping %s, csound==NULL\n", __FUNCTION__); - return; - } - if (!ThreadID) - { - if (_debug && (VERBOSE > 1)) fprintf(_debug, "skipping %s, ThreadID==NULL\n", __FUNCTION__); - return ; - } - if (_debug &&(VERBOSE > 3)) fprintf(_debug, "%s\n", msg); - csoundInputMessage(csound, msg); - } - /** pass a setChannel command through to csound. only works if perf. thread is running */ - void setChannel(const char * name, MYFLT vol) - { - if (!csound) { - ll->printf(1, "skipping %s, csound==NULL\n", __FUNCTION__); - return; - } - if (!ThreadID) - { - if (_debug && (VERBOSE > 1)) fprintf(_debug, "skipping %s, ThreadID==NULL\n", __FUNCTION__); - return ; - } - MYFLT *p; - if (!(csoundGetChannelPtr(csound, &p, name, CSOUND_CONTROL_CHANNEL | CSOUND_INPUT_CHANNEL))) - *p = (MYFLT) vol; - else - { - if (_debug && (VERBOSE >0)) fprintf(_debug, "ERROR: failed to set channel: %s\n", name); - } - } - - /** adjust the global tick value by this much */ - void adjustTick(MYFLT dtick) - { - tick_adjustment += dtick; - } - void setTickDuration(MYFLT d ) - { - secs_per_tick = d; - ticks_per_period = csound_period_size / ( secs_per_tick * csound_frame_rate); - ll->printf( 3, "INFO: duration %lf := ticks_per_period %lf\n", secs_per_tick , ticks_per_period); - } - MYFLT getTickf() - { - return tick_total + tick_adjustment; - } -}; - - -static void cleanup(void) -{ - if (g_tt) - { - delete g_tt; - g_tt = NULL; - } -} - -#define DECL(s) static PyObject * s(PyObject * self, PyObject *args) -#define RetNone Py_INCREF(Py_None); return Py_None; - -//call once at end -DECL(sc_destroy) -{ - if (!PyArg_ParseTuple(args, "")) - { - return NULL; - } - if (g_tt) - { - delete g_tt; - g_tt = NULL; - if (_debug) fclose(_debug); - } - RetNone; -} -//call once at startup, should return 0 -DECL(sc_initialize) //(char * csd) -{ - char * str; - char * log_file; - int period, ppb, ksmps, framerate; - if (!PyArg_ParseTuple(args, "ssiiiii", &str, &log_file, &period, &ppb, &VERBOSE, &ksmps, &framerate )) - { - return NULL; - } - if ( log_file[0] ) - { - _debug = fopen(log_file,"w"); - if (_debug==NULL) - { - fprintf(stderr, "WARNING: fopen(%s) failed, logging to stderr\n", log_file); - _debug = stderr; - } - } - else - { - _debug = NULL; - fprintf(stderr, "Logging disabled on purpose\n"); - } - g_log = new log_t(_debug, VERBOSE); - g_tt = new TamTamSound(g_log, str, period, ppb, ksmps, framerate); - g_music = & g_tt->music; - atexit(&cleanup); - if (g_tt->good()) - return Py_BuildValue("i", 0); - else - return Py_BuildValue("i", -1); -} -//compile the score, connect to device, start a sound rendering thread -DECL(sc_start) -{ - int ppb; - if (!PyArg_ParseTuple(args, "i", &ppb )) - { - return NULL; - } - return Py_BuildValue("i", g_tt->start(ppb)); -} -//stop csound rendering thread, disconnect from sound device, clear tables. -DECL(sc_stop) -{ - if (!PyArg_ParseTuple(args, "" )) - { - return NULL; - } - return Py_BuildValue("i", g_tt->stop()); -} -DECL(sc_scoreEvent) //(char type, farray param) -{ - char ev_type; - PyObject *o; - if (!PyArg_ParseTuple(args, "cO", &ev_type, &o )) - { - return NULL; - } - if (o->ob_type - && o->ob_type->tp_as_buffer - && (1 == o->ob_type->tp_as_buffer->bf_getsegcount(o, NULL))) - { - if (o->ob_type->tp_as_buffer->bf_getreadbuffer) - { - void * ptr; - size_t len; - len = o->ob_type->tp_as_buffer->bf_getreadbuffer(o, 0, &ptr); - float * fptr = (float*)ptr; - size_t flen = len / sizeof(float); - g_tt->scoreEvent(ev_type, fptr, flen); - - Py_INCREF(Py_None); - return Py_None; - } - else - { - assert(!"asdf"); - } - } - assert(!"not reached"); - return NULL; -} -DECL (sc_inputMessage) //(const char *msg) -{ - char * msg; - if (!PyArg_ParseTuple(args, "s", &msg )) - { - return NULL; - } - g_tt->inputMessage(msg); - RetNone; -} -DECL(sc_setChannel) //(string name, float value) -{ - const char * str; - float v; - if (!PyArg_ParseTuple(args, "sf", &str,&v)) - { - return NULL; - } - g_tt->setChannel(str,v); - Py_INCREF(Py_None); - return Py_None; -} -DECL(sc_getTickf) // () -> float -{ - if (!PyArg_ParseTuple(args, "")) - { - return NULL; - } - return Py_BuildValue("f", g_tt->getTickf()); -} -DECL(sc_adjustTick) // (MYFLT ntick) -{ - float spt; - if (!PyArg_ParseTuple(args, "f", &spt )) - { - return NULL; - } - g_tt->adjustTick(spt); - RetNone; -} -DECL(sc_setTickDuration) // (MYFLT secs_per_tick) -{ - float spt; - if (!PyArg_ParseTuple(args, "f", &spt )) - { - return NULL; - } - g_tt->setTickDuration(spt); - RetNone; -} -DECL(sc_loop_new) // () -> int -{ - if (!PyArg_ParseTuple(args, "" )) return NULL; - return Py_BuildValue("i", g_music->alloc()); -} -DECL(sc_loop_delete) // (int loopIdx) -{ - int loopIdx; - if (!PyArg_ParseTuple(args, "i", &loopIdx )) return NULL; - g_music->destroy(loopIdx); - RetNone; -} -DECL(sc_loop_getTickf) // (int loopIdx) -> float -{ - int idx; - if (!PyArg_ParseTuple(args, "i", &idx )) - { - return NULL; - } - return Py_BuildValue("f", g_music->getTickf(idx)); -} -DECL(sc_loop_setNumTicks) //(int loopIdx, int nticks) -{ - int loopIdx; - int nticks; - if (!PyArg_ParseTuple(args, "ii", &loopIdx, &nticks )) return NULL; - g_music->setNumTicks(loopIdx, nticks); - RetNone; -} -DECL(sc_loop_setTickf) // (int loopIdx, float pos) -{ - int loopIdx; - MYFLT pos; - if (!PyArg_ParseTuple(args, "if", &loopIdx, &pos )) return NULL; - g_music->setTickf(loopIdx, pos); - RetNone; -} -DECL(sc_loop_addScoreEvent) // (int loopIdx, int id, int duration_in_ticks, char type, farray param) -{ - int loopIdx, qid, inticks, active; - char ev_type; - PyObject *o; - if (!PyArg_ParseTuple(args, "iiiicO", &loopIdx, &qid, &inticks, &active, &ev_type, &o )) return NULL; - - if (o->ob_type - && o->ob_type->tp_as_buffer - && (1 == o->ob_type->tp_as_buffer->bf_getsegcount(o, NULL))) - { - if (o->ob_type->tp_as_buffer->bf_getreadbuffer) - { - void * ptr; - size_t len; - len = o->ob_type->tp_as_buffer->bf_getreadbuffer(o, 0, &ptr); - float * fptr = (float*)ptr; - size_t flen = len / sizeof(float); - - g_music->addEvent(loopIdx, qid, ev_type, fptr, flen, inticks, active); - - RetNone; - } - else - { - assert(!"asdf"); - } - } - assert(!"not reached"); - return NULL; -} -DECL(sc_loop_delScoreEvent) // (int loopIdx, int id) -{ - int loopIdx, id; - if (!PyArg_ParseTuple(args, "ii", &loopIdx, &id )) - { - return NULL; - } - g_music->delEvent(loopIdx, id); - RetNone; -} -DECL(sc_loop_updateEvent) // (int loopIdx, int id, int paramIdx, float paramVal, int activate_cmd)) -{ - int loopIdx, eventId; - int idx; - float val; - int cmd; - if (!PyArg_ParseTuple(args, "iiifi", &loopIdx, &eventId, &idx, &val, &cmd)) return NULL; - g_music->updateEvent(loopIdx, eventId, idx, val, cmd); - RetNone; -} -DECL(sc_loop_deactivate_all) // (int id) -{ - int loopIdx; - if (!PyArg_ParseTuple(args, "i", &loopIdx)) return NULL; - g_music->deactivateAll(loopIdx); - RetNone; -} -DECL(sc_loop_playing) // (int loopIdx, int tf) -{ - int loopIdx, tf; - if (!PyArg_ParseTuple(args, "ii", &loopIdx, &tf )) return NULL; - g_music->playing(loopIdx, tf); - RetNone; -} - -#define MDECL(s) {""#s, s, METH_VARARGS, "documentation of "#s"... nothing!"} -static PyMethodDef SpamMethods[] = { - MDECL(sc_destroy), - MDECL(sc_initialize), - MDECL(sc_start), - MDECL(sc_stop), - - MDECL(sc_setChannel), - MDECL(sc_inputMessage), - MDECL(sc_scoreEvent), - - MDECL(sc_getTickf), - MDECL(sc_adjustTick), - MDECL(sc_setTickDuration), - - MDECL(sc_loop_new), - MDECL(sc_loop_delete), - MDECL(sc_loop_getTickf), - MDECL(sc_loop_setTickf), - MDECL(sc_loop_setNumTicks), - MDECL(sc_loop_delScoreEvent), - MDECL(sc_loop_addScoreEvent), - MDECL(sc_loop_updateEvent), - MDECL(sc_loop_deactivate_all), - MDECL(sc_loop_playing), - {NULL, NULL, 0, NULL} /*end of list */ -}; - -PyMODINIT_FUNC -initaclient(void) -{ - (void) Py_InitModule("aclient", SpamMethods); -} - - |