#include "chuck_dl.h" #include "chuck_def.h" #include #include #include CK_DLL_CTOR(TDFeatures_ctor); CK_DLL_DTOR(TDFeatures_dtor); CK_DLL_MFUN(TDFeatures_setFrame); // set frame, allocate memory (default 4410) CK_DLL_MFUN(TDFeatures_getFrame); // query frame size, in samples CK_DLL_MFUN(TDFeatures_setSrate); // set sample rate CK_DLL_MFUN(TDFeatures_getSrate); // query sample rate CK_DLL_MFUN(TDFeatures_getPower); // get power for most recent frame CK_DLL_MFUN(TDFeatures_getRMS); // get RMS for most recent frame CK_DLL_MFUN(TDFeatures_getPeak); // get abs peak for most ... CK_DLL_MFUN(TDFeatures_getPeakp); // get pos peak for most ... CK_DLL_MFUN(TDFeatures_getPeakn); // get neg peak for most ... CK_DLL_MFUN(TDFeatures_getZCs); // get all zero crossings in frame / 2 CK_DLL_MFUN(TDFeatures_getZCsp); // get positive-going zero crossings CK_DLL_MFUN(TDFeatures_getZCsn); // get negative-going zero crossings CK_DLL_MFUN(TDFeatures_setHyst); // set Hysteresis fraction (of peaks, 0.0-1.0) CK_DLL_MFUN(TDFeatures_getPitch); // get pitch estimate CK_DLL_TICK(TDFeatures_tick); t_CKINT TDFeatures_data_offset = 0; struct TDFeaturesData { int frame; // frame, size of buffer, update rate int count; // where are we in frame, circular buffer pointer int srate; float power; // sum of squares / frame size float powerTemp; // running calculation of above float peak; // max absolute value in frame float ppeak; // max signed value in frame float npeak; // min signed value in frame float ppeakTemp; // max signed value in frame float npeakTemp; // min signed value in frame int zcs; // number of pos+neg zero crossings / 2 int zcsp; // number of pos going zero crossings int zcsn; // number of neg going zero crossings int zcspTemp; // these are the variables for int zcsnTemp; // calculating running counts of zcs float hyst; // hysteresis fraction (of peaks, 0.0-1.0), default 0.0 // float *buffer; // holds our buffer of samples float lastIn; // last input sample }; CK_DLL_QUERY(TDFeatures) { QUERY->setname(QUERY, "TDFeatures"); QUERY->begin_class(QUERY, "TDFeatures", "UGen"); QUERY->add_ctor(QUERY, TDFeatures_ctor); QUERY->add_dtor(QUERY, TDFeatures_dtor); QUERY->add_ugen_func(QUERY, TDFeatures_tick, NULL, 1, 1); QUERY->add_mfun(QUERY, TDFeatures_setFrame, "int", "frame"); QUERY->add_arg(QUERY, "int", "arg"); QUERY->add_mfun(QUERY, TDFeatures_getFrame, "int", "frame"); QUERY->add_mfun(QUERY, TDFeatures_setSrate, "int", "srate"); QUERY->add_arg(QUERY, "int", "arg"); QUERY->add_mfun(QUERY, TDFeatures_getSrate, "int", "srate"); QUERY->add_mfun(QUERY, TDFeatures_setHyst, "float", "hyst"); QUERY->add_arg(QUERY, "float", "arg"); QUERY->add_mfun(QUERY, TDFeatures_getPower, "float", "power"); QUERY->add_mfun(QUERY, TDFeatures_getRMS, "float", "RMS"); QUERY->add_mfun(QUERY, TDFeatures_getPeak, "float", "peak"); QUERY->add_mfun(QUERY, TDFeatures_getPeakp, "float", "peakp"); QUERY->add_mfun(QUERY, TDFeatures_getPeakn, "float", "peakn"); QUERY->add_mfun(QUERY, TDFeatures_getZCs, "int", "ZCs"); QUERY->add_mfun(QUERY, TDFeatures_getZCsp, "int", "ZCsp"); QUERY->add_mfun(QUERY, TDFeatures_getZCsn, "int", "ZCsn"); QUERY->add_mfun(QUERY, TDFeatures_getPitch, "int", "pitch"); TDFeatures_data_offset = QUERY->add_mvar(QUERY, "int", "@lpc_data", false); QUERY->end_class(QUERY); return TRUE; } CK_DLL_CTOR(TDFeatures_ctor) { OBJ_MEMBER_INT(SELF, TDFeatures_data_offset) = 0; TDFeaturesData * tdfdata = new TDFeaturesData; tdfdata->frame = 4410; // default, can reset after construct tdfdata->count = 0; tdfdata->srate = 44100; // default, can reset after construct tdfdata->hyst = 0.0; tdfdata->power = 0.0; tdfdata->powerTemp = 0.0; tdfdata->peak = 0.0; tdfdata->ppeak = 0.0; tdfdata->npeak = 0.0; tdfdata->ppeakTemp = -1000.0; tdfdata->npeakTemp = 1000.0; tdfdata->zcs = 0; tdfdata->zcsp = 0; tdfdata->zcsn = 0; tdfdata->zcspTemp = 0; tdfdata->zcsnTemp = 0; // tdfdata->buffer = (float *) malloc(sizeof(float) * tdfdata->frame); // for (int i = 0; i < tdfdata->frame; i++) { // tdfdata->buffer[i] = 0.0; // } tdfdata->lastIn = 0.0; OBJ_MEMBER_INT(SELF, TDFeatures_data_offset) = (t_CKINT) tdfdata; } CK_DLL_DTOR(TDFeatures_dtor) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); if(tdfdata) { // free(tdfdata->buffer); delete tdfdata; OBJ_MEMBER_INT(SELF, TDFeatures_data_offset) = 0; tdfdata = NULL; } } CK_DLL_TICK(TDFeatures_tick) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); *out = in; // first things first; tdfdata->powerTemp += in*in; // count positive-going zero crossings float temp = tdfdata->ppeak * tdfdata->hyst; if (in > temp && tdfdata->lastIn <= temp) { tdfdata->zcspTemp++; } // count negative-going zero crossings temp = tdfdata->npeak * tdfdata->hyst; if (in < temp && tdfdata->lastIn >= temp) { tdfdata->zcsnTemp++; } // track our peaks if (in > tdfdata->ppeakTemp) tdfdata->ppeakTemp = in; if (in < tdfdata->npeakTemp) tdfdata->npeakTemp = in; // not sure we actually need buffer at all, but in caseā€¦ // tdfdata->buffer[tdfdata->count] = in; tdfdata->count++; // we definitely have to do this if (tdfdata->count >= tdfdata->frame) { tdfdata->power = tdfdata->powerTemp; tdfdata->powerTemp = 0.0; tdfdata->zcsn = tdfdata->zcsnTemp; tdfdata->zcsp = tdfdata->zcspTemp; tdfdata->zcspTemp = 0; tdfdata->zcsnTemp = 0; tdfdata->npeak = tdfdata->npeakTemp; tdfdata->ppeak = tdfdata->ppeakTemp; tdfdata->peak = fabs(tdfdata->npeakTemp); if (fabs(tdfdata->ppeakTemp) > tdfdata->peak) { tdfdata->peak = fabs(tdfdata->ppeakTemp); } tdfdata->npeakTemp = 1000.0; // in case there's lots of DC tdfdata->ppeakTemp = -1000.0; // we still get peaks tdfdata->count = 0; } tdfdata->lastIn = in; return TRUE; } CK_DLL_MFUN(TDFeatures_setFrame) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); // TODO: sanity check tdfdata->frame = GET_NEXT_INT(ARGS); // free(tdfdata->buffer); // int i; // tdfdata->buffer = (float *) malloc(sizeof(float) * tdfdata->frame); // for (i = 0; i < tdfdata->frame; i++) { // tdfdata->buffer[i] = 0.0; // } RETURN->v_int = tdfdata->frame; } CK_DLL_MFUN(TDFeatures_getFrame) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_int = tdfdata->frame; } CK_DLL_MFUN(TDFeatures_setSrate) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); // TODO: sanity check tdfdata->frame = GET_NEXT_INT(ARGS); RETURN->v_int = tdfdata->srate; } CK_DLL_MFUN(TDFeatures_getSrate) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_int = tdfdata->srate; } CK_DLL_MFUN(TDFeatures_getPower) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_float = tdfdata->power/tdfdata->frame; } CK_DLL_MFUN(TDFeatures_getRMS) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_float = sqrt(tdfdata->power/tdfdata->frame); } CK_DLL_MFUN(TDFeatures_getPeak) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_float = tdfdata->peak; } CK_DLL_MFUN(TDFeatures_getPeakp) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_float = tdfdata->ppeak; } CK_DLL_MFUN(TDFeatures_getPeakn) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_float = tdfdata->npeak; } CK_DLL_MFUN(TDFeatures_getZCs) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_int = (tdfdata->zcsp + tdfdata->zcsn) / 2; } CK_DLL_MFUN(TDFeatures_getPitch) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_int = tdfdata->srate*(tdfdata->zcsp + tdfdata->zcsn)/tdfdata->frame/2; } CK_DLL_MFUN(TDFeatures_getZCsp) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_int = tdfdata->zcsp; } CK_DLL_MFUN(TDFeatures_getZCsn) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); RETURN->v_int = tdfdata->zcsn; } CK_DLL_MFUN(TDFeatures_setHyst) { TDFeaturesData * tdfdata = (TDFeaturesData *) OBJ_MEMBER_INT(SELF, TDFeatures_data_offset); tdfdata->hyst = GET_NEXT_FLOAT(ARGS); RETURN->v_float = tdfdata->hyst; }