Gamma  0.9.5
Generic Synthesis Library
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator
/Users/ljp/code/gamma/trunk/Gamma/Scheduler.h
00001 #ifndef INC_GAM_SCHEDULER_H
00002 #define INC_GAM_SCHEDULER_H
00003 
00004 #include "Gamma/Node.h"
00005 #include "Gamma/AudioIO.h"
00006 #include "Gamma/Thread.h"
00007 #include "Gamma/Timer.h"
00008 #include <queue>
00009 #include <list>
00010 
00011 namespace gam{
00012 
00013 class Scheduler;
00014 
00015 
00016 #ifndef FUNC_MAX_DATA_SIZE
00017 #define FUNC_MAX_DATA_SIZE 64
00018 #endif
00019 
00021 class Func{
00022 public:
00023     typedef void (* func_t)(void * data);
00024 
00025     template <class R>
00026     Func(R (*fnc)()){
00027         struct Data{
00028             R (*fnc)();
00029             static void call(void * data){
00030                 Data& d = *(Data *)data;
00031                 d.fnc();
00032             }
00033         } data = {fnc};
00034         set(Data::call, (void *)&data, sizeof(Data));
00035     }
00036 
00037     template <class R, class A, class L>
00038     Func(R (*fnc)(A), L l){
00039         struct Data{
00040             R (*fnc)(A);
00041             L l;
00042             static void call(void * data){
00043                 Data& d = *(Data *)data;
00044                 d.fnc(d.l);
00045             }
00046         } data = {fnc,l};
00047         set(Data::call, (void *)&data, sizeof(Data));
00048     }
00049 
00050     template <class R, class A, class B, class L, class M>
00051     Func(R (*fnc)(A,B), L l, M m){
00052         struct Data{
00053             R (*fnc)(A,B);
00054             L l; M m;
00055             static void call(void * data){
00056                 Data& d = *(Data *)data;
00057                 d.fnc(d.l,d.m);
00058             }
00059         } data = {fnc,l,m};
00060         set(Data::call, (void *)&data, sizeof(Data));
00061     }
00062 
00063     template <class R, class A, class B, class C, class L, class M, class N>
00064     Func(R (*fnc)(A,B,C), L l, M m, N n){
00065         struct Data{
00066             R (*fnc)(A,B,C);
00067             L l; M m; N n;
00068             static void call(void * data){
00069                 Data& d = *(Data *)data;
00070                 d.fnc(d.l,d.m,d.n);
00071             }
00072         } data = {fnc,l,m,n};
00073         set(Data::call, (void *)&data, sizeof(Data));
00074     }
00075 
00076     template <class R, class A, class B, class C, class D, class L, class M, class N, class O>
00077     Func(R (*fnc)(A,B,C,D), L l, M m, N n, O o){
00078         struct Data{
00079             R (*fnc)(A,B,C,D);
00080             L l; M m; N n; O o;
00081             static void call(void * data){
00082                 Data& d = *(Data *)data;
00083                 d.fnc(d.l,d.m,d.n,d.o);
00084             }
00085         } data = {fnc,l,m,n,o};
00086         set(Data::call, (void *)&data, sizeof(Data));
00087     }
00088 
00089 
00090     template <class Obj1, class Obj2, class R>
00091     Func(Obj1& obj, R (Obj2::*mth)()){
00092         struct Data{
00093             Obj1& obj;
00094             R (Obj2::*mth)();
00095             static void call(void * data){
00096                 Data& d = *(Data *)data;
00097                 (d.obj.*d.mth)();
00098             }
00099         } data = {obj,mth};
00100         set(Data::call, (void *)&data, sizeof(Data));
00101     }
00102 
00103     template <class Obj1, class Obj2, class R, class A, class L>
00104     Func(Obj1& obj, R (Obj2::*mth)(A), L l){
00105         struct Data{
00106             Obj1& obj;
00107             R (Obj2::*mth)(A);
00108             L l;
00109             static void call(void * data){
00110                 Data& d = *(Data *)data;
00111                 (d.obj.*d.mth)(d.l);
00112             }
00113         } data = {obj,mth,l};
00114         set(Data::call, (void *)&data, sizeof(Data));
00115     }
00116 
00117     template <class Obj1, class Obj2, class R, class A, class B, class L, class M>
00118     Func(Obj1& obj, R (Obj2::*mth)(A,B), L l, M m){
00119         struct Data{
00120             Obj1& obj;
00121             R (Obj2::*mth)(A,B);
00122             L l; M m;
00123             static void call(void * data){
00124                 Data& d = *(Data *)data;
00125                 (d.obj.*d.mth)(d.l,d.m);
00126             }
00127         } data = {obj,mth,l,m};
00128         set(Data::call, (void *)&data, sizeof(Data));
00129     }
00130 
00131     template <class Obj1, class Obj2, class R, class A, class B, class C, class L, class M, class N>
00132     Func(Obj1& obj, R (Obj2::*mth)(A,B,C), L l, M m, N n){
00133         struct Data{
00134             Obj1& obj;
00135             R (Obj2::*mth)(A,B,C);
00136             L l; M m; N n;
00137             static void call(void * data){
00138                 Data& d = *(Data *)data;
00139                 (d.obj.*d.mth)(d.l,d.m,d.n);
00140             }
00141         } data = {obj,mth,l,m,n};
00142         set(Data::call, (void *)&data, sizeof(Data));
00143     }
00144 
00145     template <class Obj1, class Obj2, class R, class A, class B, class C, class D, class L, class M, class N, class O>
00146     Func(Obj1& obj, R (Obj2::*mth)(A,B,C,D), L l, M m, N n, O o){
00147         struct Data{
00148             Obj1& obj;
00149             R (Obj2::*mth)(A,B,C,D);
00150             L l; M m; N n; O o;
00151             static void call(void * data){
00152                 Data& d = *(Data *)data;
00153                 (d.obj.*d.mth)(d.l,d.m,d.n,d.o);
00154             }
00155         } data = {obj,mth,l,m,n,o};
00156         set(Data::call, (void *)&data, sizeof(Data));
00157     }
00158 
00160     void operator()(){ mFunc(mData); }
00161 
00162     const char * data() const { return mData; }
00163     const void * obj() const { return mObj; }
00164 
00165 private:
00166     union{
00167         char mData[FUNC_MAX_DATA_SIZE];
00168         void * mObj;
00169     };
00170     func_t mFunc;
00171 
00172     void set(func_t f, void * data, int size){
00173         mFunc = f;
00174         #ifndef NDEBUG
00175         if(size > FUNC_MAX_DATA_SIZE){
00176             printf("Func maximum data size exceeded. "
00177                 "Attempt to use %d bytes with maximum size set to %d.\n",
00178                 size, FUNC_MAX_DATA_SIZE);
00179             exit(-1);
00180         }
00181         #endif
00182         memcpy(mData, data, size);
00183         //printf("Func::set() with %d bytes\n", size);      
00184     }
00185 };
00186 
00187 
00188 
00189 // This defines a block-rate processing node in the audio graph
00190 class Process : public Node3<Process>{
00191 public:
00192 
00193     Process(double delay=0.);
00194 
00195     virtual ~Process();
00196 
00198     Process& dt(double v){ mDelay=v; return *this; }
00199 
00201     Process& free();
00202     
00204     
00207     Process& active(bool v);
00208 
00209     Process& reset();
00210 
00212     Process * update(const Process * top, AudioIOData& io);
00213 
00214     bool deletable() const { return mDeletable; }
00215     bool done() const { return DONE==mStatus; }
00216     bool active() const { return ACTIVE==mStatus; }
00217     bool inactive() const { return INACTIVE==mStatus; }
00218 
00219     void print();
00220 
00221 protected:
00222     friend class Scheduler;
00223     
00224     enum{
00225         INACTIVE=0,     // node and descendents are not executed
00226         ACTIVE,         // node and descendents are executed
00227         DONE            // processing done, node and descendents can be removed
00228     };
00229     
00230     int mStatus;
00231     double mDelay;
00232     bool mDeletable;
00233 
00234     virtual void onProcess(AudioIOData& io){}
00235     virtual void onReset(){}
00236 
00237     Process * process(const Process * top, AudioIOData& io, int frameStart=0);
00238 };
00239 
00240 
00241 
00242 class ControlFunc{
00243 public:
00244     ControlFunc(const Func& f, double dt=0)
00245     :   mFunc(f), mDelay(dt), mPeriod(0), mObjDel(0)
00246     {}
00247     
00248     ControlFunc& dt(double v){ mDelay=v; return *this; }
00249     ControlFunc& period(double v){ mPeriod=v; return *this; }
00250 
00251     void operator()(){ mFunc(); }
00252 
00253 protected:
00254     friend class Scheduler;
00255     Func mFunc;
00256     double mDelay;
00257     double mPeriod;
00258     int mObjDel;
00259 };
00260 
00261 
00262 
00263 class Scheduler : public Process{
00264 public:
00265 
00266     typedef std::queue<Process *> FreeList;
00267     typedef std::list<ControlFunc> Funcs;
00268 
00269     Scheduler();
00270 
00271     ~Scheduler();
00272 
00274     bool empty() const;
00275     
00277     bool check();
00278     
00280     
00283     int reclaim();
00284     
00286     template <class AProcess>
00287     AProcess& add(){
00288         AProcess * v = new AProcess;
00289         cmdAdd(v); return *v;
00290     }
00291 
00292 //  template <class AProcess>
00293 //  AProcess& add(){
00294 //      Pool& pool = getPool<AProcess>();
00295 //      
00296 //      Process * proc = pool.create<AProcess>();
00297 //
00298 //      cmdAdd(proc); return *v;
00299 //  }
00300 
00301     template <class AProcess, class A>
00302     AProcess& add(const A& a){
00303         AProcess * v = new AProcess(a);
00304         cmdAdd(v); return *v;
00305     }
00306 
00307     template <class AProcess, class A, class B>
00308     AProcess& add(const A& a, const B& b){
00309         AProcess * v = new AProcess(a,b);
00310         cmdAdd(v); return *v;
00311     }
00312 
00313     template <class AProcess, class A, class B, class C>
00314     AProcess& add(const A& a, const B& b, const C& c){
00315         AProcess * v = new AProcess(a,b,c);
00316         cmdAdd(v); return *v;
00317     }
00318 
00319     template <class AProcess, class A, class B, class C, class D>
00320     AProcess& add(const A& a, const B& b, const C& c, const D& d){
00321         AProcess * v = new AProcess(a,b,c,d);
00322         cmdAdd(v); return *v;
00323     }
00324 
00325     template <class AProcess, class A, class B, class C, class D, class E>
00326     AProcess& add(const A& a, const B& b, const C& c, const D& d, const E& e){
00327         AProcess * v = new AProcess(a,b,c,d,e);
00328         cmdAdd(v); return *v;
00329     }
00330 
00331     template <class AProcess, class A, class B, class C, class D, class E, class F>
00332     AProcess& add(const A& a, const B& b, const C& c, const D& d, const E& e, const F& f){
00333         AProcess * v = new AProcess(a,b,c,d,e,f);
00334         cmdAdd(v); return *v;
00335     }
00336 
00337 
00339     template <class AProcess>
00340     AProcess& add(Process& parent){
00341         AProcess * v = new AProcess;
00342         pushCommand(Command::ADD_FIRST_CHILD, &parent, v);
00343         return *v;
00344     }
00345 
00346 
00347 
00348     ControlFunc& add(const Func& f){
00349         mFuncs.push_back(f);
00350         return mFuncs.back();
00351     }
00352     
00353     
00354 
00355 //  template <class AProcess>
00356 //  Pool& getPool(){
00357 //  
00358 //  }
00359 
00360 //  void print(){
00361 //      printf("%d events\n", (int)events().size());
00362 //      Events::iterator it = events().begin();
00363 //      for(; it!=events().end(); ++it){
00364 //          printf("\t"); (*it)->print();
00365 //      }
00366 //  }
00367 
00369 
00372     void update(AudioIOData& io);
00373 
00374     Scheduler& period(float v);
00375 
00376     void start();
00377 
00378     void stop();
00379 
00380     static void audioCB(AudioIOData& io){
00381         Scheduler& s = io.user<Scheduler>();
00382         s.update(io);
00383     }
00384 
00385 protected:
00386 
00387     struct Command{
00388         enum Type{
00389             ADD_FIRST_CHILD,
00390             ADD_LAST_CHILD,
00391             REMOVE_CHILD
00392         };
00393         
00394         Type type;
00395         Process * object;
00396         Process * other;
00397     };
00398 
00399     // LPT:  low-priority thread
00400     // HPT: high-priority thread
00401     std::queue<Command> mAddCommands;   // items newly allocated in LPT to be added to tree in HPT
00402     FreeList mFreeList; // items removed from tree in HPT to be deleted in LPT
00403     Funcs mFuncs;
00404     Thread mThread; // garbage collection thread
00405     float mPeriod;
00406     double mTime;
00407     bool mRunning;
00408     
00409     static void * cThreadFunc(void * user);
00410     
00411     void updateControlFuncs(double dt);
00412 
00413     void pushCommand(Command::Type c, Process * object, Process * other);
00414     void cmdAdd(Process * v);
00415 
00416     // Execute pending graph manipulation commands from HPT.
00417     // This is to be called from the same thread that is executing the
00418     // processing within nodes (i.e., from the audio thread).
00419     void updateTree();
00420     
00421     // Moves branches marked as being done to a free list for cleanup by a 
00422     // lower priority thread.
00423     void updateFreeList();
00424 };
00425 
00426 } //gam::
00427 
00428 #endif