Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp')
-rw-r--r--TamTamSynthLab.activity/common/Util/Clooper/aclient.cpp1101
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, &param[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);
-}
-
-