#include "ext.h"
#include "z_dsp.h"
#include <cmath>
typedef struct {
t_pxobject msp_data;
float *window, *windowb, *buffer;
long winsize, bufsize, index, recordQ, loopQ, endQ, bufallocsize;
float alpha;
} MyObject;
void* object_data;
void main (void);
void* create_object (float maxsize);
void destroy_object (MyObject* mo);
void InputBang (MyObject* mo);
void InputLoopTime (MyObject* mo, float value);
void InputWindowSize (MyObject* mo, int value);
void InputAlpha (MyObject* mo, float value);
void MessageDSP (MyObject* mo, t_signal** signal, short* count);
void MessageClear (MyObject* mo);
void MessageStart (MyObject* mo);
void MessageStop (MyObject* mo);
t_int* Perform (t_int *parameters);
double BesselI0 (double x);
void MakeKaiserWindow (float* window, int size, float alpha);
void main(void) {
setup((t_messlist**)&object_data, (method)create_object,
(method)destroy_object, (short)sizeof(MyObject),
NULL, A_FLOAT, A_NOTHING);
addftx ((method)InputAlpha, 1);
addinx ((method)InputWindowSize, 2);
addftx ((method)InputLoopTime, 3);
addbang((method)InputBang);
addmess((method)MessageDSP, "dsp", A_CANT, A_NOTHING);
addmess((method)MessageClear, "clear", A_NOTHING);
addmess((method)MessageStart, "start", A_NOTHING);
addmess((method)MessageStop, "stop", A_NOTHING);
dsp_initclass();
}
void* create_object(float maxsize) {
long maxsamples;
MyObject *mo = (MyObject*)newobject(object_data);
dsp_setup((t_pxobject*)mo, 1);
outlet_new((t_pxobject*)mo, "signal");
floatin(mo, 1); intin(mo, 2); floatin(mo, 3);
if (maxsize < 1) {
post("Error: buffer size too small, setting it to 1000 milliseconds.");
maxsize = 1000.0;
}
maxsamples = (long)(maxsize/1000.0 * 44100.0 + 0.5);
mo->buffer = (float*)malloc(maxsamples * sizeof(float));
mo->bufallocsize = mo->bufsize = maxsamples;
mo->alpha = 1.25;
mo->window = NULL;
InputWindowSize(mo, 1024);
MessageClear(mo);
return mo;
}
void destroy_object(MyObject* mo) {
dsp_free(&(mo->msp_data));
free(mo->buffer); free(mo->window);
mo->buffer = mo->window = mo->windowb = NULL;
mo->bufallocsize = mo->bufsize = 0;
}
void InputBang(MyObject* mo) {
if (mo->loopQ) MessageStop(mo);
else MessageStart(mo);
}
void MessageStart(MyObject* mo) {
mo->loopQ = mo->recordQ = 1;
mo->index = 0;
post("kola~ start");
}
void MessageStop(MyObject* mo) {
mo->endQ = 1;
post("kola~ stop");
}
void MessageClear(MyObject* mo) {
int i;
for (i=0; i<mo->bufallocsize; i++) mo->buffer[i] = 0.0;
mo->index = 0;
}
void InputAlpha(MyObject* mo, float value) {
MakeKaiserWindow(mo->window, mo->winsize, value);
mo->alpha = value;
}
void InputWindowSize (MyObject* mo, int value) {
if (value < 2) value = 2;
value = value + (2 - value%2); value = value * 2;
if (mo->window != NULL) free(mo->window);
mo->window = (float*)malloc(value * sizeof(float));
mo->winsize = value;
mo->windowb = mo->window + value/2;
InputAlpha(mo, mo->alpha);
}
void InputLoopTime(MyObject* mo, float value) {
long samples = (long)(value / 1000.0 * 44100 + 0.5);
if (samples >= mo->bufallocsize) {
samples = mo->bufallocsize;
post("kola~: cannot set loop buffer that big!");
}
if (samples < 4) {
samples = 4;
post("kola~: setting minimum audio delay buffer sample size to 4.");
}
mo->bufsize = samples;
mo->index = 0;
}
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[1]->s_vec, signal[0]->s_n);
}
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;
long tindex;
for (i=0; i<count; i++) {
if (mo->recordQ) {
mo->buffer[mo->index] = input[i];
if (mo->index < mo->winsize/2) {
output[i] = mo->buffer[mo->index] * mo->window[mo->index];
} else if (mo->index >= mo->bufsize - mo->winsize/2) {
tindex = mo->winsize/2 - (mo->bufsize - mo->index);
output[i] = mo->buffer[mo->index] * mo->windowb[tindex]
+ mo->buffer[tindex] * mo->window[tindex];
} else {
output[i] = mo->buffer[mo->index];
}
} else if (mo->loopQ) {
if (mo->index < mo->winsize/2) {
tindex = mo->bufsize - mo->winsize/2 + mo->index;
output[i] = mo->buffer[mo->index] * mo->window[mo->index] +
mo->buffer[tindex] * mo->windowb[mo->index];
} else if (mo->index >= mo->bufsize - mo->winsize/2) {
if (mo->index == mo->bufsize - mo->winsize/2) {
post("kola~ ending");
}
tindex = mo->winsize/2 - (mo->bufsize - mo->index);
output[i] = mo->buffer[mo->index] * mo->windowb[tindex];
} else {
output[i] = mo->buffer[mo->index];
}
} else {
output[i] = 0.0;
}
mo->index++;
if (mo->recordQ && (mo->index >= mo->bufsize)) {
mo->index = mo->winsize/2;
mo->recordQ = 0;
} else if ((!mo->recordQ) && (!mo->endQ) && mo->loopQ &&
(mo->index >= mo->bufsize - mo->winsize/2)) {
mo->index = 0;
} else if (mo->index >= mo->bufsize) {
mo->endQ = mo->loopQ = mo->recordQ = mo->index = 0;
}
}
return parameters+paramcount+1;
}
#ifndef PI
#define PI 3.14159265358979323846264338328
#endif
void MakeKaiserWindow(float* window, int size, float alpha) {
double sumvalue = 0.0;
int i;
for (i=0; i<size/2; i++) {
sumvalue += BesselI0(PI * alpha * sqrt(1.0 - pow(4.0*i/size - 1.0, 2)));
window[i] = sumvalue;
}
sumvalue += BesselI0(PI * alpha * sqrt(1.0 - pow(4.0*(size/2)/size-1.0, 2)));
for (i=0; i<size/2; i++) {
window[i] = window[i]/sumvalue;
window[size-1-i] = window[i];
}
}
double BesselI0(double x) {
double denominator, numerator, z;
if (x == 0.0) return 1.0;
else {
z = x * x;
numerator = (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z* (z*
(z* 0.210580722890567e-22 + 0.380715242345326e-19 ) +
0.479440257548300e-16) + 0.435125971262668e-13 ) +
0.300931127112960e-10) + 0.160224679395361e-7 ) +
0.654858370096785e-5) + 0.202591084143397e-2 ) +
0.463076284721000e0) + 0.754337328948189e2 ) +
0.830792541809429e4) + 0.571661130563785e6 ) +
0.216415572361227e8) + 0.356644482244025e9 ) +
0.144048298227235e10);
denominator = (z*(z*(z-0.307646912682801e4)+
0.347626332405882e7)-0.144048298227235e10);
}
return -numerator/denominator;
}
|