本示例涉及到单个MSP对象同时使用Signal类型、Message类型的入口;代理入口的使用。
注意:MSP对象的入口默认为代理入口,因此Signal类型、Message类型的数据都可接收;
cpp
#include "ext.h"
#include "ext_obex.h"
#include "z_dsp.h"
typedef struct _butterFilterTest {
t_pxobject ob; // the object itself (t_pxobject in MSP instead of t_object)
long iirOrder; // 滤波器阶数 n
t_atom* iirState; // 存储滤波器状态 n
int fltStateParaNum; // 滤波器状态参数个数 n
t_atom* a; // 滤波器参数a (n+1)
t_atom* b; // 滤波器参数b
int fltParaNum; // 滤波器参数个数 (n+1)
int sampleframes; // 帧大小
long lastVectorSize; // 用以判定signal vector size是否有变
//void* outLet;
/*** 用以测试 ***/
t_atom* sigList; // 存储滤波后的单帧信号
t_atom* tmpList; // 暂存到来的单帧信号
/***************/
} t_butterFilterTest;
void* butterFilterTest_new(t_symbol* s, long argc, t_atom* argv);
void butterFilterTest_free(t_butterFilterTest* x);
void butterFilterTest_assist(t_butterFilterTest* x, void* b, long m, long a, char* s);
void butterFilterTest_dsp64(t_butterFilterTest* x, t_object* dsp64, short* count, double samplerate, long maxvectorsize, long flags);
void butterFilterTest_perform64(t_butterFilterTest* x, t_object* dsp64, double** ins, long numins, double** outs, long numouts, long sampleframes, long flags, void* userparam);
void butterFilterTest_perform64_list(t_butterFilterTest* x, t_object* dsp64, double** ins, long numins, double** outs, long numouts, long sampleframes, long flags, void* userparam);
void butterFilterTest_feed(t_butterFilterTest* x, t_double* inSig, int sampleframes);
void butterFilterTest_recvList(t_butterFilterTest* x, t_symbol* s, long argc, t_atom* argv);
void butterFilterTest_feed_test(t_butterFilterTest* x, long sampleframes);
static t_class* butterFilterTest_class = NULL;
void ext_main(void* r) {
t_class* c = class_new("butterFilterTest~", (method)butterFilterTest_new, (method)butterFilterTest_free, (long)sizeof(t_butterFilterTest), 0L, A_GIMME, 0);
class_addmethod(c, (method)butterFilterTest_dsp64, "dsp64", A_CANT, 0);
class_addmethod(c, (method)butterFilterTest_assist, "assist", A_CANT, 0);
class_addmethod(c, (method)butterFilterTest_recvList, "list", A_GIMME, 0);
class_dspinit(c); // 初始化 & 加入通用处理方法
class_register(CLASS_BOX, c);
butterFilterTest_class = c;
}
void* butterFilterTest_new(t_symbol* s, long argc, t_atom* argv) {
t_butterFilterTest* x = (t_butterFilterTest*)object_alloc(butterFilterTest_class);
dsp_setup((t_pxobject*)x, 3); // MSP inlets: arg is # of inlets and is REQUIRED! 信号入口数为1,3则信号入口数为3
// use 0 if you don't need inlets
outlet_new(x, "signal"); // signal outlet (note "signal" rather than NULL) 信号出口
//x->outLet = listout(x);
x->a = NULL;
x->b = NULL;
x->fltParaNum = 0;
x->iirState = NULL;
x->fltStateParaNum = 0;
x->sigList = NULL;
x->tmpList = NULL;
x->lastVectorSize = 0;
return (x);
}
void butterFilterTest_free(t_butterFilterTest* x) {
dsp_free((t_pxobject*)x);
sysmem_freeptr(x->a);
sysmem_freeptr(x->b);
sysmem_freeptr(x->iirState);
sysmem_freeptr(x->sigList);
sysmem_freeptr(x->tmpList);
}
void butterFilterTest_assist(t_butterFilterTest* x, void* b, long m, long a, char* s) {
if (m == ASSIST_INLET) { //inlet
sprintf(s, "I am inlet %ld", a);
} else { // outlet
sprintf(s, "I am outlet %ld", a);
}
}
void butterFilterTest_recvList(t_butterFilterTest* x, t_symbol* s, long argc, t_atom* argv) {
long inNum = proxy_getinlet((t_object*)x);
post("inNum: %d. list recv.", inNum);
x->iirOrder = argc - 1; // 滤波器阶数
x->fltStateParaNum = argc - 1; // 滤波器状态参数个数
if (x->a == NULL || x->fltParaNum != argc) {
if (x->a != NULL) {
sysmem_freeptr(x->a);
sysmem_freeptr(x->iirState);
}
x->a = (t_atom*)sysmem_newptr(sizeof(t_atom) * argc);
x->iirState = (t_atom*)sysmem_newptr(sizeof(t_atom) * x->fltStateParaNum);
if (x->a == NULL || x->iirState == NULL) {
return;
}
}
if (x->b == NULL || x->fltParaNum != argc) {
if (x->b != NULL) {
sysmem_freeptr(x->b);
}
x->b = (t_atom*)sysmem_newptr(sizeof(t_atom) * argc);
if (x->b == NULL) {
return;
}
}
x->fltParaNum = argc; // 更新滤波器参数个数
switch (inNum) {
case 0:
post("List size: %d", argc);
for (int i = 0; i < argc; i++) {
atom_setfloat(&(x->tmpList[i]), atom_getfloat(&(argv[i])));
}
break;
case 1:
post("List size: %d", argc);
for (int i = 0; i < argc; i++) {
atom_setfloat(&(x->a[i]), atom_getfloat(&(argv[i])));
}
post("AAAA");
for (int i = 0; i < argc; i++) {
post("%lf", atom_getfloat(&(x->a[i])));
}
break;
case 2:
post("List size: %d", argc);
for (int i = 0; i < argc; i++) {
atom_setfloat(&(x->b[i]), atom_getfloat(&(argv[i])));
}
post("AAAA");
for (int i = 0; i < argc; i++) {
post("%lf", atom_getfloat(&(x->a[i])));
}
post("BBB");
for (int i = 0; i < argc; i++) {
post("%lf", atom_getfloat(&(x->b[i])));
}
post("recv iirState:");
for (int i = 0; i < x->fltStateParaNum; i++) {
post("%lf", atom_getfloat(&(x->iirState[i])));
}
break;
}
}
// registers a function for the signal chain in Max
void butterFilterTest_dsp64(t_butterFilterTest* x, t_object* dsp64, short* count, double samplerate, long maxvectorsize, long flags) {
post("my sample rate is: %f,vector size is: %ld", samplerate, maxvectorsize); // 和Audio status中设置相同
x->sampleframes = maxvectorsize;
/* 滤波器状态初始化*/
for (int i = 0; i < x->fltStateParaNum; i++) {
atom_setfloat(&(x->iirState[i]), 0);
}
post("dsp64 iirstate:");
for (int i = 0; i < x->fltStateParaNum; i++) {
post("%lf", atom_getfloat(&(x->iirState[i])));
}
if (x->sigList == NULL || x->lastVectorSize != maxvectorsize) {
if (x->sigList != NULL) {
sysmem_freeptr(x->sigList);
}
x->sigList = (t_atom*)sysmem_newptr(sizeof(t_atom) * maxvectorsize);
if (x->sigList == NULL) {
return;
}
}
if (x->tmpList == NULL || x->lastVectorSize != maxvectorsize) {
if (x->tmpList != NULL) {
sysmem_freeptr(x->tmpList);
}
x->tmpList = (t_atom*)sysmem_newptr(sizeof(t_atom) * maxvectorsize);
if (x->tmpList == NULL) {
return;
}
}
x->lastVectorSize = maxvectorsize;
post("%d", count[0]);
post("%d", count[1]);
if (count[0]) {
post("Signal come.");
object_method(dsp64, gensym("dsp_add64"), x, butterFilterTest_perform64, 0, NULL);
} else {
//post("List come.");
//object_method(dsp64, gensym("dsp_add64"), x, butterFilterTest_perform64_list, 0, NULL);
}
if (count[1]) {}
if (count[2]) {}
}
/*******************************************************逐帧验证**********************************************************/
void butterFilterTest_perform64_list(t_butterFilterTest* x, t_object* dsp64, double** ins, long numins, double** outs, long numouts,
long sampleframes, long flags, void* userparam) {
butterFilterTest_feed_test(x, sampleframes);
//outlet_anything(x->outLet, gensym("list"), x->sampleframes, x->sigList);
//post("%lf, %lf", x->iirState[0], x->iirState[1]);
}
void butterFilterTest_feed_test(t_butterFilterTest* x, long sampleframes) {
//post("%lf, %lf", x->iirState[0], x->iirState[1]);
for (int k = 0; k < x->fltParaNum; k++) { //归一化
atom_setfloat(&(x->b[k]), atom_getfloat(&(x->b[k])) / atom_getfloat(&(x->a[0])));
atom_setfloat(&(x->a[k]), atom_getfloat(&(x->a[k])) / atom_getfloat(&(x->a[0])));
}
//Sleep(2000);
for (int i = 0; i < sampleframes; i++) {
atom_setfloat(&(x->sigList[i]), (atom_getfloat(&(x->b[0])) * atom_getfloat(&(x->tmpList[i])) + atom_getfloat(&(x->iirState[0]))));
//post("sampleframs:%d, x->sigList[%d]: %lf, x->tmpList[%d]: %lf, x->iirState[0]: %lf", sampleframes, i, atom_getfloat(&(x->sigList[i])), i, atom_getfloat(&(x->tmpList[i])), x->iirState[0]);
for (int j = 1; j < x->fltParaNum - 1; j++) { // j = 1
atom_setfloat(&(x->iirState[j - 1]), (atom_getfloat(&(x->iirState[j])) + atom_getfloat(&(x->b[j])) * atom_getfloat(&(x->tmpList[i])) - atom_getfloat(&(x->a[j])) * atom_getfloat(&(x->sigList[i]))));
//x->iirState[j - 1] = x->iirState[j] + x->b[j] * atom_getfloat(&(x->tmpList[i])) - x->a[j] * atom_getfloat(&(x->sigList[i]));
}
atom_setfloat(&(x->iirState[x->fltParaNum - 2]), (atom_getfloat(&(x->b[x->fltParaNum - 1])) * atom_getfloat(&(x->tmpList[i])) - atom_getfloat(&(x->a[x->fltParaNum - 1])) * atom_getfloat(&(x->sigList[i]))));
//x->iirState[x->fltParaNum - 2] = x->b[x->fltParaNum - 1] * atom_getfloat(&(x->tmpList[i])) - x->a[x->fltParaNum - 1] * atom_getfloat(&(x->sigList[i]));
}
}
/*************************************************************************************************************************/
void butterFilterTest_perform64(t_butterFilterTest* x, t_object* dsp64, double** ins, long numins, double** outs, long numouts,
long sampleframes, long flags, void* userparam) { // this is the 64-bit perform method audio vectors
t_double* inL = ins[0]; // we get audio for each inlet of the object from the **ins argument
t_double* outL = outs[0]; // we get audio for each outlet of the object from the **outs argument
int n = sampleframes; // vector size
butterFilterTest_feed(x, inL, sampleframes);
post("perform64 iirstate:");
for (int i = 0; i < x->fltStateParaNum; i++) {
post("%lf", atom_getfloat(&(x->iirState[i])));
}
while (n--) {
*outL++ = *inL++;
}
}
void butterFilterTest_feed(t_butterFilterTest* x, t_double* inSig, int sampleframes) {
for (int k = 0; k < x->fltParaNum; k++) { // 归一化
atom_setfloat(&(x->b[k]), atom_getfloat(&(x->b[k])) / atom_getfloat(&(x->a[0])));
atom_setfloat(&(x->a[k]), atom_getfloat(&(x->a[k])) / atom_getfloat(&(x->a[0])));
}
for (int i = 0; i < sampleframes; i++) {
t_double tmp = inSig[i];
inSig[i] = atom_getfloat(&(x->b[0])) * tmp + atom_getfloat(&(x->iirState[0]));
for (int j = 1; j < x->fltParaNum - 1; j++) {
atom_setfloat(&(x->iirState[j - 1]), atom_getfloat(&(x->iirState[j])) + atom_getfloat(&(x->b[j])) * tmp - atom_getfloat(&(x->a[j])) * inSig[i]);
//x->iirState[j - 1] = atom_getfloat(&(x->iirState[j])) + atom_getfloat(&(x->b[j])) * tmp - atom_getfloat(&(x->a[j])) * inSig[i];
}
atom_setfloat(&(x->iirState[x->fltParaNum - 2]), atom_getfloat(&(x->b[x->fltParaNum - 1])) * tmp - atom_getfloat(&(x->a[x->fltParaNum - 1])) * inSig[i]);
//x->iirState[x->fltParaNum - 2] = x->b[x->fltParaNum - 1] * tmp - x->a[x->fltParaNum - 1] * inSig[i];
}
}