// // Programmer: Craig Stuart Sapp // Creation Date: Thu Apr 17 18:24:33 PDT 2003 // Last Modified: Fri Apr 18 20:42:08 PDT 2003 // Filename: sndpower.c // Web Address: http://peabody.sapp.org/class/dmp2/lab/sndpower/sndpower.c // Syntax: C; Max4/MSP2 External Object; CodeWarrior 6.0 // OS: Mac OS 9; PPC // // Description: Monitors the audio signal power of a signal. // // Bug: Stack overflow occurs after a while. // #include "ext.h" #include "z_dsp.h" #include typedef struct { t_pxobject msp_data; // must always be the first field; used by MSP double sum; // used to sum the squares of the signal long count; // count to the chunk size long chunk; // number of samples in a chunk void* outputDb; // output RMS value void* outputRms; // output RMS value void* outputPeak; // output Peak amplitude based on RMS value } MyObject; void* object_data; // pointer to data for object (created in setup()); // function declarations: void main (void); void* create_object (long maxsize); void InputBang (MyObject* mo); void InputChunkSize (MyObject* mo, long value); void MessageDSP (MyObject* mo, t_signal** signal, short* count); void MessageClear (MyObject* mo); t_int* Perform (t_int *parameters); void outputAnalysis (MyObject* mo); ////////////////////////////////////////////////////////////////////////// // // Initialization functions: // ////////////////////////////// // // main -- called once when object is created in a Max/MSP patch window. // void main(void) { setup((t_messlist**)&object_data, (method)create_object, (method)dsp_free, (short)sizeof(MyObject), NULL, A_LONG, A_NOTHING); addinx((method)InputChunkSize, 1); // input 2: size of chunk addmess((method)MessageDSP, "dsp", A_CANT, A_NOTHING); addmess((method)MessageClear, "clear", A_NOTHING); addbang((method)InputBang); dsp_initclass(); } ////////////////////////////// // // create_object -- object initializing function. // void* create_object(long chunksize) { MyObject *mo = (MyObject*)newobject(object_data); // create data storage dsp_setup((t_pxobject*)mo, 1); // input 1 intin(mo, 1); // input 2: size of chunk mo->outputPeak = floatout(mo); // output 3 mo->outputRms = floatout(mo); // output 2 mo->outputDb = floatout(mo); // output 1 outlet_new((t_pxobject*)mo, "signal"); // signal output 1 mo->chunk = chunksize; MessageClear(mo); return mo; // return pointer to data storage } ////////////////////////////////////////////////////////////////////////// // // Behavior functions: // ////////////////////////////// // // InputBang -- send out the analysis when a bang is done. // void InputBang(MyObject* mo) { outputAnalysis(mo); MessageClear(mo); } ////////////////////////////// // // InputChunkSize -- Zero or negative values will prevent regular // outputing of analysis, and only a bang object will output the // power analysis. // void InputChunkSize(MyObject *mo, long value) { mo->chunk = 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) int paramcount = 5; dsp_add(Perform, paramcount, paramcount, mo, signal[0]->s_vec, signal[0]->s_vec, signal[0]->s_n); } ////////////////////////////// // // MessageClear -- empty the contents of the delayline. // void MessageClear(MyObject* mo) { mo->count = 0; mo->sum = 0.0; } ////////////////////////////// // // Perform -- do the action for one sample group (number of samples // specified by the value w[3], which is to copy the input data into // the output data. // t_int* Perform(t_int *parameters) { long paramcount = (long) (parameters[1]); MyObject *mo = (MyObject*)(parameters[2]); t_float *input = (t_float*) (parameters[3]); t_float *output = (t_float*) (parameters[4]); long count = (long) (parameters[5]); long i; for (i=0; isum += input[i] * input[i]; output[i] = input[i]; mo->count++; if ((mo->count >= mo->chunk) && (mo->chunk > 0)) { outputAnalysis(mo); MessageClear(mo); } } return parameters+paramcount+1; // return pointer to next item in DSP chain } ////////////////////////////////////////////////////////////////////////// // // Helper functions: // ////////////////////////////// // // outputAnalysis -- // void outputAnalysis(MyObject* mo) { float db; float rms; float peak; if (mo->sum <= 0.0) { db = -1000.0; } else { // energy measurement: already squared the amplitude, so using 10.0 db = (float)(10.0 * log10(mo->sum/mo->count)); } rms = (float)sqrt(mo->sum / mo->count); peak = (float)(sqrt(2) * rms); outlet_float(mo->outputPeak, peak); outlet_float(mo->outputRms, rms); outlet_float(mo->outputDb, db); }