// // Copyright: Copyright 2003 Craig Stuart Sapp // Programmer: Craig Stuart Sapp // Creation Date: Wed Mar 12 07:54:55 PST 2003 // Last Modified: Wed Mar 12 09:54:51 PST 2003 // Filename: digitar.c // Web Address: http://peabody.sapp.org/class/dmp2/lab/digitar/digitar.c // Syntax: C; Max4/MSP2 External Object; CodeWarrior 6.0 // OS: Mac OS 9; PPC // // Description: Recursive averaging filter. The classical Karplus-Strong // string plucked string physical model discovered in 1979. // #include "ext.h" #include "z_dsp.h" typedef struct { t_pxobject msp_data; // must always be the first field; used by MSP. float* table; // storage for recursion memory. long allocsize; // sample size of table. long size; // current size of the recursion (<= allocsize). long tempsize; // size of table for next note. long read; // read index of the table. float save; // temporary sample value to use for averaging } MyObject; void* object_data; // pointer to data for object (created in setup()); // function declarations: void main (void); void* create_object (long tableAllocation); void destroy_object (MyObject* mo); void InputBang (MyObject* mo); void InputSize (MyObject* mo, long value); void MessageDSP (MyObject* mo, t_signal** signal, short* count); void MessageClear (MyObject* mo); t_int* Perform (t_int* parameters); float randsignal (void); ////////////////////////////////////////////////////////////////////////// // // Initialization functions: // void main(void) { setup((t_messlist**)&object_data, (method)create_object, (method)destroy_object, (short)sizeof(MyObject), NULL, A_LONG, A_NOTHING); addbang((method)InputBang); addint((method)InputSize); addmess((method)MessageDSP, "dsp", A_CANT, A_NOTHING); addmess((method)MessageClear, "clear", A_NOTHING); dsp_initclass(); } ////////////////////////////// // // create_object -- object initializing function. // void* create_object(long tableAllocation) { MyObject *mo = (MyObject*)newobject(object_data); // create data storage dsp_setup((t_pxobject*)mo, 0); // no input signals outlet_new((t_pxobject*)mo, "signal"); // output 1 for sound. if (tableAllocation < 1) { post("Warning: setting table memory to 10,000 samples."); tableAllocation = 10000; } mo->table = (float*)malloc(tableAllocation * sizeof(float)); mo->allocsize = tableAllocation; mo->tempsize = tableAllocation; mo->size = tableAllocation; mo->read = 0; MessageClear(mo); return mo; // return pointer to data storage } ////////////////////////////// // // destroy_object -- free the DSP stuff and free the recursion table memory. // void destroy_object(MyObject *mo) { dsp_free(&(mo->msp_data)); if (mo->table != NULL) { free(mo->table); mo->table = NULL; mo->allocsize = 0; mo->size = 0; mo->tempsize = 0; } } ////////////////////////////////////////////////////////////////////////// // // Behavior functions: // ////////////////////////////// // // InputBang -- fill the wavetable with whitenoise to generate another note. // void InputBang(MyObject *mo) { long i; mo->size = mo->tempsize; for (i=0; isize; i++) { mo->table[i] = randsignal(); } mo->read = 0; mo->save = mo->table[mo->read]; } ////////////////////////////// // // MessageClear -- erase the contents of the table. // void MessageClear(MyObject *mo) { long i; for (i=0; iallocsize; i++) { mo->table[i] = 0.0; } mo->save = 0.0; mo->read = 0; } ////////////////////////////// // // InputSize -- set the table size of the next note to be played // void InputSize(MyObject *mo, long value) { if (value > mo->allocsize || value <= 0) { post("Error: Maximum table size allowed is %ld.", mo->allocsize); } else { mo->tempsize = value; } } ////////////////////////////// // // MessageDSP -- What to do when a "dsp" message arrives into the object. // void MessageDSP(MyObject* mo, t_signal** signal, short* count) { #pragma unused(count) dsp_add(Perform, 4, 4, mo, signal[0]->s_vec, signal[0]->s_n); } ////////////////////////////// // // Perform -- do the calculations for one sample group. // t_int* Perform(t_int *parameters) { long pcount = (long) (parameters[1]); MyObject *mo = (MyObject*)(parameters[2]); t_float *output = (t_float*) (parameters[3]); long count = (long) (parameters[4]); long i; for (i=0; itable[mo->read]; mo->table[mo->read] = (mo->table[mo->read] + mo->save)/2.0; mo->save = output[i]; mo->read++; if (mo->read >= mo->size) { mo->read = 0; } } return parameters+pcount+1; } /////////////////////////////////////////////////////////////////////////// // // Helper Functions: // ////////////////////////////// // // randsignal -- return a random number between [-1.0 .. 1.0). // float randsignal(void) { return (float)rand()/RAND_MAX * 2.0 - 1.0; }