@@ -1,5 +1,5 @@
/*
* Copyright 2009,2010,2011 Reality Jockey, Ltd.
* Copyright 2009,2010,2011,2012 Reality Jockey, Ltd.
* info@rjdj.me
* http://rjdj.me/
*
@@ -20,21 +20,16 @@
*
*/

#include <float.h>
#include "ArrayArithmetic.h"
#include "DspHighpassFilter.h"
#include "PdGraph.h"

MessageObject *DspHighpassFilter::newObject(PdMessage *initMessage, PdGraph *graph) {
return new DspHighpassFilter(initMessage, graph);
}

DspHighpassFilter::DspHighpassFilter(PdMessage *initMessage, PdGraph *graph) : DspObject(2, 1, 0, 1, graph) {
sampleRate = graph->getSampleRate();
tapIn = 0.0f;
tapOut = 0.0f;
DspHighpassFilter::DspHighpassFilter(PdMessage *initMessage, PdGraph *graph) : DspFilter(2, graph) {
// by default, the filter is initialised completely open
calculateFilterCoefficients(initMessage->isFloat(0) ? initMessage->getFloat(0) : 0.0f);
calcFiltCoeff(initMessage->isFloat(0) ? initMessage->getFloat(0) : 0.0f);
}

DspHighpassFilter::~DspHighpassFilter() {
@@ -45,60 +40,44 @@ const char *DspHighpassFilter::getObjectLabel() {
return "hip~";
}

void DspHighpassFilter::calculateFilterCoefficients(float cutoffFrequency) {
if (cutoffFrequency <= 0.0f) {
cutoffFrequency = FLT_MIN;
} else if (cutoffFrequency > sampleRate/2.0f) {
cutoffFrequency = sampleRate/2.0f;
}
float rc = 1.0f / (2.0f * M_PI * cutoffFrequency);
alpha = rc / (rc + (1.0f/sampleRate));
coefficients[0] = alpha;
coefficients[1] = -1.0f * alpha;
coefficients[3] = -1.0f * alpha;
// http://en.wikipedia.org/wiki/High-pass_filter
void DspHighpassFilter::calcFiltCoeff(float fc) {
if (fc > 0.5f*graph->getSampleRate()) fc = 0.5f * graph->getSampleRate();
else if (fc < 0.0f) fc = 10.0f;

float alpha = graph->getSampleRate() / ((2.0f*M_PI*fc) + graph->getSampleRate());
b[0] = alpha;
b[1] = -alpha;
b[2] = 0.0f;
b[3] = -alpha;
b[4] = 0.0f;
}

void DspHighpassFilter::processMessage(int inletIndex, PdMessage *message) {
switch (inletIndex) {
case 0: {
if (message->isSymbol(0, "clear")) {
tapIn = 0.0f;
tapOut = 0.0f;
switch (message->getType(0)) {
case FLOAT: {
// signalConstant = message->getFloat(0);
break;
}
case SYMBOL: {
if (message->isSymbol(0, "clear")) {
x1 = x2 = 0.0f;
dspBufferAtOutlet0[0] = dspBufferAtOutlet0[1] = 0.0f;
}
break;
}
default: break;
}
break;
}
case 1: {
if (message->isFloat(0)) {
calculateFilterCoefficients(message->getFloat(0));
calcFiltCoeff(message->getFloat(0));
}
break;
}
default: {
break;
}
}
}

// http://en.wikipedia.org/wiki/High-pass_filter
void DspHighpassFilter::processDspWithIndex(int fromIndex, int toIndex) {
#if __APPLE__
const int duration = toIndex - fromIndex;
const int durationBytes = duration * sizeof(float);
float filterInputBuffer[duration+2];
memcpy(filterInputBuffer+2, dspBufferAtInlet0+fromIndex, durationBytes);
filterInputBuffer[0] = 0.0f; filterInputBuffer[1] = tapIn;
float filterOutputBuffer[duration+2];
filterOutputBuffer[0] = 0.0f; filterOutputBuffer[1] = tapOut;
vDSP_deq22(filterInputBuffer, 1, coefficients, filterOutputBuffer, 1, duration);
memcpy(dspBufferAtOutlet0+fromIndex, filterOutputBuffer+2, durationBytes);
tapIn = dspBufferAtInlet0[toIndex-1];
tapOut = dspBufferAtOutlet0[toIndex-1];
#else
dspBufferAtOutlet0[fromIndex] = alpha * (tapOut + dspBufferAtInlet0[fromIndex] - tapIn);
for (int i = fromIndex+1; i < toIndex; i++) {
dspBufferAtOutlet0[i] = alpha * (dspBufferAtOutlet0[i-1] + dspBufferAtInlet0[i] - dspBufferAtInlet0[i-1]);
default: break;
}
tapIn = dspBufferAtInlet0[toIndex-1];
tapOut = dspBufferAtOutlet0[toIndex-1];
#endif
}
@@ -1,5 +1,5 @@
/*
* Copyright 2009,2010,2011 Reality Jockey, Ltd.
* Copyright 2009,2010,2011,2012 Reality Jockey, Ltd.
* info@rjdj.me
* http://rjdj.me/
*
@@ -23,13 +23,13 @@
#ifndef _DSP_HIGH_PASS_FILTER_H_
#define _DSP_HIGH_PASS_FILTER_H_

#include "DspObject.h"
#include "DspFilter.h"

/**
* [hip~], [hip~ float]
* Specficially implement a one-tap IIR filter: y = x_0 - (alpha * x_0 + (1-alpha) * y_-1)
* A one-tap IIR filter: y[i] = a * (y[i-1] + x[i] - x[i-1])
*/
class DspHighpassFilter : public DspObject {
class DspHighpassFilter : public DspFilter {

public:
static MessageObject *newObject(PdMessage *initMessage, PdGraph *graph);
@@ -40,14 +40,7 @@ class DspHighpassFilter : public DspObject {

private:
void processMessage(int inletIndex, PdMessage *message);
void processDspWithIndex(int fromIndex, int toIndex);
void calculateFilterCoefficients(float cutoffFrequency);

float sampleRate;
float tapIn;
float tapOut;
float alpha;
float coefficients[5];
void calcFiltCoeff(float cutoffFrequency);
};

#endif // _DSP_HIGH_PASS_FILTER_H_
@@ -1,5 +1,5 @@
/*
* Copyright 2009,2010 Reality Jockey, Ltd.
* Copyright 2009,2010,2011,2012 Reality Jockey, Ltd.
* info@rjdj.me
* http://rjdj.me/
*
@@ -20,27 +20,15 @@
*
*/

#include "ArrayArithmetic.h"
#include "DspLowpassFilter.h"
#include "PdGraph.h"

MessageObject *DspLowpassFilter::newObject(PdMessage *initMessage, PdGraph *graph) {
return new DspLowpassFilter(initMessage, graph);
}

DspLowpassFilter::DspLowpassFilter(PdMessage *initMessage, PdGraph *graph) : DspObject(2, 1, 0, 1, graph) {
calculateFilterCoefficients(initMessage->isFloat(0) ? initMessage->getFloat(0) : graph->getSampleRate()/2.0f);
signalConstant = 0.0f;

// resize the output buffer to be 2 samples larger
float *buffer = (float *) realloc(dspBufferAtOutlet0, (blockSizeInt+2)*sizeof(float));
if (buffer != NULL) {
dspBufferAtOutlet0 = buffer;
} else {
free(dspBufferAtOutlet0);
dspBufferAtOutlet0 = (float *) malloc((blockSizeInt+2)*sizeof(float));
}
memset(dspBufferAtOutlet0, 0, (blockSizeInt+2)*sizeof(float)); // clear the buffer
DspLowpassFilter::DspLowpassFilter(PdMessage *initMessage, PdGraph *graph) : DspFilter(2, graph) {
calcFiltCoeff(initMessage->isFloat(0) ? initMessage->getFloat(0) : graph->getSampleRate()/2.0f);
}

DspLowpassFilter::~DspLowpassFilter() {
@@ -51,105 +39,44 @@ const char *DspLowpassFilter::getObjectLabel() {
return "lop~";
}

float *DspLowpassFilter::getDspBufferRefAtOutlet(int outletIndex) {
return dspBufferAtOutlet0+2;
}

void DspLowpassFilter::onInletConnectionUpdate() {
if (incomingMessageConnections[1].size() == 0) {
if (incomingDspConnections[0].size() < 2) {
codePath = DSP_LOP_DSP1_MESSAGE0;
} else {
codePath = DSP_LOP_DSPX_MESSAGE0;
}
} else {
codePath = DSP_LOP_DEFAULT;
}
}

void DspLowpassFilter::calculateFilterCoefficients(float cutoffFrequency) {
float alpha = cutoffFrequency * 2.0f * M_PI / graph->getSampleRate();
if (alpha < 0.0f) {
alpha = 0.0f;
} else if (alpha > 1.0f) {
alpha = 1.0f;
}
coefficients[0] = alpha;
coefficients[1] = 0.0f;
coefficients[2] = 0.0f;
coefficients[3] = -(1.0f-alpha);
coefficients[4] = 0.0f;
// http://en.wikipedia.org/wiki/Low_pass_filter
void DspLowpassFilter::calcFiltCoeff(float fc) {
if (fc > 0.5f * graph->getSampleRate()) fc = 0.5f * graph->getSampleRate();
else if (fc < 0.0f) fc = 0.0f;

float wc = 2.0f*M_PI*fc;
float alpha = wc / (wc + graph->getSampleRate());
b[0] = alpha;
b[1] = 0.0f;
b[2] = 0.0f;
b[3] = -(1.0f-alpha);
b[4] = 0.0f;
}

void DspLowpassFilter::processMessage(int inletIndex, PdMessage *message) {
switch (inletIndex) {
case 0: {
switch (message->getType(0)) {
case FLOAT: {
signalConstant = message->getFloat(0);
// signalConstant = message->getFloat(0);
break;
}
case SYMBOL: {
if (message->isSymbol(0, "clear")) {
dspBufferAtOutlet0[0] = dspBufferAtOutlet0[1] = 0.0f;
x1 = x2 = dspBufferAtOutlet0[0] = dspBufferAtOutlet0[1] = 0.0f;
}
break;
}
default: {
break;
}
default: break;
}
break;
}
case 1: {
if (message->isFloat(0)) {
calculateFilterCoefficients(message->getFloat(0));
calcFiltCoeff(message->getFloat(0));
}
break;
}
default: {
break;
}
}
}

void DspLowpassFilter::processDsp() {
switch (codePath) {
case DSP_LOP_DSPX_MESSAGE0: {
float buffer[blockSizeInt+2];
buffer[0] = 0.0f; buffer[1] = 0.0f;
resolveInputBuffers(0, buffer+2);
processLop(buffer, 0, blockSizeInt);
break;
}
case DSP_LOP_DSP1_MESSAGE0: {
float buffer[blockSizeInt+2];
buffer[0] = 0.0f; buffer[1] = 0.0f;
memcpy(buffer+2, dspBufferAtInlet0, numBytesInBlock);
processLop(buffer, 0, blockSizeInt);
break;
}
default: {
DspObject::processDsp();
break;
}
}
}

void DspLowpassFilter::processDspWithIndex(int fromIndex, int toIndex) {
switch (codePath) {
case DSP_LOP_MESSAGE_MESSAGE: {
float buffer[blockSizeInt+2];
ArrayArithmetic::fill(buffer, signalConstant, 0, blockSizeInt+2);
processLop(buffer, fromIndex, toIndex);
break;
}
default: {
float buffer[blockSizeInt+2];
buffer[0] = buffer[1] = 0.0f;
memcpy(buffer+2, dspBufferAtInlet0, numBytesInBlock);
processLop(buffer, fromIndex, toIndex);
break;
}
default: break;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2009,2010 Reality Jockey, Ltd.
* Copyright 2009,2010,2011,2012 Reality Jockey, Ltd.
* info@rjdj.me
* http://rjdj.me/
*
@@ -23,20 +23,13 @@
#ifndef _DSP_LOW_PASS_FILTER_H_
#define _DSP_LOW_PASS_FILTER_H_

#include "DspObject.h"

enum DspLopCodePath {
DSP_LOP_DSPX_MESSAGE0,
DSP_LOP_DSP1_MESSAGE0,
DSP_LOP_MESSAGE_MESSAGE,
DSP_LOP_DEFAULT
};
#include "DspFilter.h"

/**
* [lop~]
* Specficially implement a one-tap IIR filter: y = alpha * x_0 + (1-alpha) * y_-1
*/
class DspLowpassFilter : public DspObject {
class DspLowpassFilter : public DspFilter {

public:
static MessageObject *newObject(PdMessage *initMessage, PdGraph *graph);
@@ -45,38 +38,10 @@ class DspLowpassFilter : public DspObject {

static const char *getObjectLabel();

float *getDspBufferRefAtOutlet(int outletIndex);

void processDsp();

private:
void processMessage(int inletIndex, PdMessage *message);
void processDspWithIndex(int fromIndex, int toIndex);
void calculateFilterCoefficients(float cutoffFrequency);

inline void processLop(float *buffer, int fromIndex, int toIndex) {
#if __APPLE__
// vDSP_deq22 =
// out[i] = coeff[0]*in[i] + coeff[1]*in[i-1] + coeff[2]*in[i-2] - coeff[3]*out[i-1] - coeff[4]*out[i-2]
vDSP_deq22(buffer+fromIndex, 1, coefficients, dspBufferAtOutlet0+fromIndex, 1, toIndex - fromIndex);
#else
int _toIndex = toIndex + 2;
for (int i = fromIndex+2; i < _toIndex; i++) {
dspBufferAtOutlet0[i] = coefficients[0]*buffer[i] - coefficients[3]*dspBufferAtOutlet0[i-1];
}
#endif

// retain last output
dspBufferAtOutlet0[0] = dspBufferAtOutlet0[toIndex];
dspBufferAtOutlet0[1] = dspBufferAtOutlet0[toIndex+1];
}

void onInletConnectionUpdate();

DspLopCodePath codePath;

float coefficients[5];
float signalConstant;
private:
void calcFiltCoeff(float cutoffFrequency);
};

#endif // _DSP_LOW_PASS_FILTER_H_
@@ -13,6 +13,7 @@ LOCAL_SRC_FILES := \
./DspDelayWrite.cpp \
./DspDivide.cpp \
./DspEnvelope.cpp \
./DspFilter.cpp \
./DspHighpassFilter.cpp \
./DspInlet.cpp \
./DspLine.cpp \