diff options
18 files changed, 1893 insertions, 462 deletions
diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.cpp b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.cpp index 346b653..36034b2 100644 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.cpp +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.cpp @@ -120,8 +120,8 @@ float maxiFFT::spectralCentroid() { maxiFFT::~maxiFFT() { delete _fft; - delete[] buffer,magnitudes,phases,window; - delete avgPower; + if (buffer) + delete[] buffer,magnitudes,phases,window, avgPower; } diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.h b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.h index 6c07089..d099e84 100644 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.h +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiFFT.h @@ -37,12 +37,14 @@ #include "fft.h" +#include "stddef.h" class maxiFFT { public: maxiFFT(){ - _fft = 0; + _fft = NULL; + buffer = magnitudes = phases = window = avgPower = NULL; }; ~maxiFFT(); void setup(int fftSize, int windowSize, int hopSize); diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.cpp b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.cpp index befa5f4..e72fd75 100644 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.cpp +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.cpp @@ -8,51 +8,53 @@ */ #include "maxiMFCC.h" -#include <math.h> -#include <iostream> -#ifdef __APPLE_CC__ -#include <Accelerate/Accelerate.h> -#endif -using namespace std; -void maxiMFCC::setup(unsigned int numBins, unsigned int numFilters, unsigned int numCoeffs, double minFreq, double maxFreq, unsigned int sampleRate) -{ - this->numFilters = numFilters; - this->numCoeffs = numCoeffs; - this->minFreq = minFreq; - this->maxFreq = maxFreq; - this->sampleRate = sampleRate; - this->numBins = numBins; - melFilters = NULL; - melBands = (double*) malloc(sizeof(double) * numFilters); -#ifdef __APPLE_CC__ - doubleSpec = (double*)malloc(sizeof(double) * numBins); -#endif - //create new matrix - dctMatrix = (double*)malloc(sizeof(double) * numCoeffs * numFilters); - calcMelFilterBank(sampleRate, numBins); - createDCTCoeffs(); -} -void maxiMFCC::mfcc(float* powerSpectrum, double *mfccs) { - melFilterAndLogSquare(powerSpectrum); - dct(mfccs); +template <> +void maxiMFCCAnalyser<double>::dct(double *mfccs) { + vDSP_mmulD(melBands, 1, dctMatrix, 1, mfccs, 1, 1, numCoeffs, numFilters); + double n = (double) numCoeffs; + vDSP_vsdivD(mfccs, 1, &n, mfccs, 1, numCoeffs); } +template <> +void maxiMFCCAnalyser<float>::dct(float *mfccs) { + vDSP_mmul(melBands, 1, dctMatrix, 1, mfccs, 1, 1, numCoeffs, numFilters); + float n = (float) numCoeffs; + vDSP_vsdiv(mfccs, 1, &n, mfccs, 1, numCoeffs); +} -void maxiMFCC::melFilterAndLogSquare(float* powerSpectrum){ +template <> +void maxiMFCCAnalyser<double>::melFilterAndLogSquare(float* powerSpectrum) { #ifdef __APPLE_CC__ //conv to double vDSP_vspdp(powerSpectrum, 1, doubleSpec, 1, numBins); - vDSP_mmulD(doubleSpec, 1, melFilters, 1, melBands, 1, 1, 42, 512); + // vDSP_mmulD(doubleSpec, 1, melFilters, 1, melBands, 1, 1, 42, 512); + vDSP_mmulD(doubleSpec, 1, melFilters, 1, melBands, 1, 1, numFilters, numBins); +#endif + melFilterAndLogSq_Part2(); +} + + +template <> +void maxiMFCCAnalyser<float>::melFilterAndLogSquare(float* powerSpectrum) { +#ifdef __APPLE_CC__ + vDSP_mmul(powerSpectrum, 1, melFilters, 1, melBands, 1, 1, numFilters, numBins); +#endif + melFilterAndLogSq_Part2(); +} + +template <class T> +void maxiMFCCAnalyser<T>::melFilterAndLogSq_Part2() { +#ifdef __APPLE_CC__ #else for (int filter = 0;filter < numFilters;filter++) { melBands[filter] = 0.0; for (int bin=0;bin<numBins;bin++) { -// int idx = (numBins * filter) + bin; + // int idx = (numBins * filter) + bin; int idx = filter + (bin * numFilters); -// melBands[filter] += (melFilters[filter][bin] * powerSpectrum[bin]); + // melBands[filter] += (melFilters[filter][bin] * powerSpectrum[bin]); melBands[filter] += (melFilters[idx] * powerSpectrum[bin]); } } @@ -63,143 +65,14 @@ void maxiMFCC::melFilterAndLogSquare(float* powerSpectrum){ } } -void maxiMFCC::dct(double *mfccs){ -#ifdef __APPLE_CC__ - vDSP_mmulD(melBands, 1, dctMatrix, 1, mfccs, 1, 1, numCoeffs, numFilters); - double n = (double) numCoeffs; - vDSP_vsdivD(mfccs, 1, &n, mfccs, 1, numCoeffs); -#else - for(int i=0; i < numCoeffs; i++) { - mfccs[i] = 0.0; - } - for(int i=0; i < numCoeffs; i++ ) { - for(int j=0; j < numFilters; j++) { - int idx = i + (j * numCoeffs); -// mfccs[i] += (dctMatrix[i][j] * melBands[j]); - mfccs[i] += (dctMatrix[idx] * melBands[j]); - } - } - for(int i=0; i < numCoeffs; i++) { - mfccs[i] /= numCoeffs; - } -#endif -} - -void maxiMFCC::createDCTCoeffs() { - double k = 3.14159265358979323846/numFilters; - double w1 = 1.0/(sqrt(numFilters)); - double w2 = sqrt(2.0/numFilters); - - - //generate dct matrix - for(int i = 0; i < numCoeffs; i++) - { - for(int j = 0; j < numFilters; j++) - { - int idx = i + (j * numCoeffs); - // if(i == 0) - // dctMatrix[i][j]= w1 * cos(k * (i+1) * (j + 0.5)); - // else - // dctMatrix[i][j] = w2 * cos(k * (i+1) * (j + 0.5)); - if(i == 0) - dctMatrix[idx]= w1 * cos(k * (i+1) * (j + 0.5)); - else - dctMatrix[idx] = w2 * cos(k * (i+1) * (j + 0.5)); - } - } - - -} -// implements this formula: -// mel = 2595 log10(Hz/700 + 1) -inline double hzToMel(double hz){ - return 2595.0 * (log10(hz/700.0 + 1.0)); -} -// implements this formula -// Hz = 700 (10^(mel/2595) - 1) -inline double melToHz(double mel){ - return 700.0 * (pow(10, mel/2595.0) - 1.0); -} -void maxiMFCC::calcMelFilterBank(double sampleRate, int numBins){ - double mel, dMel, maxMel, minMel, nyquist, binFreq, start, end, thisF, nextF, prevF; - int numValidBins; - - // ignore bins over nyquist - numValidBins = numBins; - - nyquist = sampleRate/2; - if (maxFreq > nyquist) { - maxFreq = nyquist; - } - - maxMel = hzToMel(maxFreq); - minMel = hzToMel(minFreq); - - dMel = (maxMel - minMel) / (numFilters + 2 - 1); - - double *filtPos = (double*) malloc(sizeof(double) * (numFilters + 2)); - - // first generate an array of start and end freqs for each triangle - mel = minMel; - for (int i=0;i<numFilters + 2;i++) { - // start of the triangle - filtPos[i] = melToHz(mel); -// std::cout << "[" << i << "] MFCC: centre is at " <<filtPos[i]<<"hz "<<mel<<" mels" << endl; - mel += dMel; - } - // now generate the coefficients for the mag spectrum - melFilters = (double*) malloc(sizeof(double) * numFilters * numValidBins); - - for (int filter = 1; filter < numFilters; filter++) { - for (int bin=0;bin<numValidBins;bin++) { - // frequency this bin represents - binFreq = (double) sampleRate / (double) numValidBins * (double) bin; - thisF = filtPos[filter]; - nextF = filtPos[filter+1]; - prevF = filtPos[filter-1]; - int idx = filter + (bin * numFilters); - if (binFreq > nextF || binFreq < prevF) { - // outside this filter - melFilters[idx] = 0; - //cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[filter][bin] << endl; - } - else { - double height = 2.0 / (nextF - prevF); - if (binFreq < thisF) { - // up - start = prevF; - end = thisF; - melFilters[idx] = (binFreq - start) * (height / (thisF - start)); - } - else { - // down - start = thisF; - end = nextF; - melFilters[idx] = height + ((binFreq - thisF) * (-height /(nextF - thisF))); - } -// cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[filter][bin] << endl; - //cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[idx] << endl; - } - } - } -} -maxiMFCC::~maxiMFCC() { - delete[] melFilters; - delete[] melBands; - delete[] dctMatrix; -#ifdef __APPLE_CC__ - delete doubleSpec; -#endif - -} diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.h b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.h index 1a2b3a3..60bfe04 100644 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.h +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maxiMFCC.h @@ -13,33 +13,192 @@ #pragma pack(16) #include "maxiFFT.h" +#include <math.h> +#include <iostream> +#ifdef __APPLE_CC__ +#include <Accelerate/Accelerate.h> +#endif -class maxiMFCC { -public: - maxiMFCC(){}; - ~maxiMFCC(); - void setup(unsigned int numBins, unsigned int numFilters, unsigned int numCoeffs, double minFreq, double maxFreq, unsigned int sampleRate); - void mfcc(float* powerSpectrum, double *mfccs); - double *melBands; +using namespace std; + + +// implements this formula: +// mel = 2595 log10(Hz/700 + 1) +inline double hzToMel(double hz){ + return 2595.0 * (log10(hz/700.0 + 1.0)); +} + +// implements this formula +// Hz = 700 (10^(mel/2595) - 1) +inline double melToHz(double mel){ + return 700.0 * (pow(10, mel/2595.0) - 1.0); +} +template <class T> +class maxiMFCCAnalyser { +public: + T *melBands; + maxiMFCCAnalyser():melFilters(NULL),dctMatrix(NULL), melBands(NULL){}; + ~maxiMFCCAnalyser() { + if (melFilters) { + delete[] melFilters; + delete[] melBands; + delete[] dctMatrix; +#ifdef __APPLE_CC__ + delete doubleSpec; +#endif + } + } + + void setup(unsigned int numBins, unsigned int numFilters, unsigned int numCoeffs, double minFreq, double maxFreq, unsigned int sampleRate) + { + this->numFilters = numFilters; + this->numCoeffs = numCoeffs; + this->minFreq = minFreq; + this->maxFreq = maxFreq; + this->sampleRate = sampleRate; + this->numBins = numBins; + melFilters = NULL; + melBands = (T*) malloc(sizeof(T) * numFilters); +#ifdef __APPLE_CC__ + doubleSpec = (T*)malloc(sizeof(T) * numBins); +#endif + //create new matrix + dctMatrix = (T*)malloc(sizeof(T) * numCoeffs * numFilters); + calcMelFilterBank(sampleRate, numBins); + createDCTCoeffs(); + } + void mfcc(float* powerSpectrum, T *mfccs) { + melFilterAndLogSquare(powerSpectrum); + dct(mfccs); + } + private: unsigned int numFilters, numCoeffs; double minFreq, maxFreq; unsigned int sampleRate; -// double **melFilters; - double *melFilters; + T *melFilters; unsigned int numBins; -// double **dctMatrix; - double *dctMatrix; + T *dctMatrix; +#ifdef __APPLE_CC__ + T *doubleSpec; +#endif + #ifdef __APPLE_CC__ - double *doubleSpec; + void dct(T *mfccs); //define later +#else + void dct(T *mfccs) { + for(int i=0; i < numCoeffs; i++) { + mfccs[i] = 0.0; + } + for(int i=0; i < numCoeffs; i++ ) { + for(int j=0; j < numFilters; j++) { + int idx = i + (j * numCoeffs); + mfccs[i] += (dctMatrix[idx] * melBands[j]); + } + } + for(int i=0; i < numCoeffs; i++) { + mfccs[i] /= numCoeffs; + } + } #endif void melFilterAndLogSquare(float* powerSpectrum); - void dct(double *mfccs); - void calcMelFilterBank(double sampleRate, int numBins); - void createDCTCoeffs(); + void melFilterAndLogSq_Part2(); + void calcMelFilterBank(double sampleRate, int numBins) { + + double mel, dMel, maxMel, minMel, nyquist, binFreq, start, end, thisF, nextF, prevF; + int numValidBins; + + // ignore bins over nyquist + numValidBins = numBins; + + nyquist = sampleRate/2; + if (maxFreq > nyquist) { + maxFreq = nyquist; + } + + maxMel = hzToMel(maxFreq); + minMel = hzToMel(minFreq); + + dMel = (maxMel - minMel) / (numFilters + 2 - 1); + + T *filtPos = (T*) malloc(sizeof(double) * (numFilters + 2)); + + // first generate an array of start and end freqs for each triangle + mel = minMel; + for (int i=0;i<numFilters + 2;i++) { + // start of the triangle + filtPos[i] = melToHz(mel); + // std::cout << "[" << i << "] MFCC: centre is at " <<filtPos[i]<<"hz "<<mel<<" mels" << endl; + mel += dMel; + } + // now generate the coefficients for the mag spectrum + melFilters = (T*) malloc(sizeof(T) * numFilters * numValidBins); + + for (int filter = 1; filter < numFilters; filter++) { + for (int bin=0;bin<numValidBins;bin++) { + // frequency this bin represents + binFreq = (T) sampleRate / (T) numValidBins * (T) bin; + thisF = filtPos[filter]; + nextF = filtPos[filter+1]; + prevF = filtPos[filter-1]; + int idx = filter + (bin * numFilters); + if (binFreq > nextF || binFreq < prevF) { + // outside this filter + melFilters[idx] = 0; + //cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[filter][bin] << endl; + } + else { + T height = 2.0 / (nextF - prevF); + + if (binFreq < thisF) { + // up + start = prevF; + end = thisF; + melFilters[idx] = (binFreq - start) * (height / (thisF - start)); + } + else { + // down + start = thisF; + end = nextF; + melFilters[idx] = height + ((binFreq - thisF) * (-height /(nextF - thisF))); + } + // cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[filter][bin] << endl; + //cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[idx] << endl; + } + } + } + } + void createDCTCoeffs() { + T k = 3.14159265358979323846/numFilters; + T w1 = 1.0/(sqrt(numFilters)); + T w2 = sqrt(2.0/numFilters); + + + //generate dct matrix + for(int i = 0; i < numCoeffs; i++) + { + for(int j = 0; j < numFilters; j++) + { + int idx = i + (j * numCoeffs); + if(i == 0) + dctMatrix[idx]= w1 * cos(k * (i+1) * (j + 0.5)); + else + dctMatrix[idx] = w2 * cos(k * (i+1) * (j + 0.5)); + } + } + + + } + + -};
\ No newline at end of file +}; + + + +typedef maxiMFCCAnalyser<double> maxiMFCC; +//typedef maxiMFCCAnalyser<float> maxiFloatMFCC; diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.cpp b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.cpp index 7c61174..3741173 100644 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.cpp +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.cpp @@ -47,14 +47,16 @@ int maxiSettings::bufferSize = 1024; double sineBuffer[514]={0,0.012268,0.024536,0.036804,0.049042,0.06131,0.073547,0.085785,0.097992,0.1102,0.12241,0.13455,0.1467,0.15884,0.17093,0.18301,0.19507,0.20709,0.21909,0.23105,0.24295,0.25485,0.26669,0.2785,0.29025,0.30197,0.31366,0.32529,0.33685,0.34839,0.35986,0.37128,0.38266,0.39395,0.40521,0.41641,0.42752,0.4386,0.44958,0.46051,0.47137,0.48215,0.49286,0.50351,0.51407,0.52457,0.53497,0.54529,0.55554,0.5657,0.57578,0.58575,0.59567,0.60547,0.6152,0.62482,0.63437,0.6438,0.65314,0.66238,0.67151,0.68057,0.68951,0.69833,0.70706,0.7157,0.72421,0.7326,0.74091,0.74908,0.75717,0.76514,0.77298,0.7807,0.7883,0.79581,0.80316,0.81042,0.81754,0.82455,0.83142,0.8382,0.84482,0.85132,0.8577,0.86392,0.87006,0.87604,0.88187,0.8876,0.89319,0.89862,0.90396,0.90912,0.91415,0.91907,0.92383,0.92847,0.93295,0.93729,0.9415,0.94556,0.94949,0.95325,0.95691,0.96039,0.96375,0.96692,0.97,0.9729,0.97565,0.97827,0.98074,0.98306,0.98523,0.98724,0.98914,0.99084,0.99243,0.99387,0.99515,0.99628,0.99725,0.99808,0.99875,0.99927,0.99966,0.99988,0.99997,0.99988,0.99966,0.99927,0.99875,0.99808,0.99725,0.99628,0.99515,0.99387,0.99243,0.99084,0.98914,0.98724,0.98523,0.98306,0.98074,0.97827,0.97565,0.9729,0.97,0.96692,0.96375,0.96039,0.95691,0.95325,0.94949,0.94556,0.9415,0.93729,0.93295,0.92847,0.92383,0.91907,0.91415,0.90912,0.90396,0.89862,0.89319,0.8876,0.88187,0.87604,0.87006,0.86392,0.8577,0.85132,0.84482,0.8382,0.83142,0.82455,0.81754,0.81042,0.80316,0.79581,0.7883,0.7807,0.77298,0.76514,0.75717,0.74908,0.74091,0.7326,0.72421,0.7157,0.70706,0.69833,0.68951,0.68057,0.67151,0.66238,0.65314,0.6438,0.63437,0.62482,0.6152,0.60547,0.59567,0.58575,0.57578,0.5657,0.55554,0.54529,0.53497,0.52457,0.51407,0.50351,0.49286,0.48215,0.47137,0.46051,0.44958,0.4386,0.42752,0.41641,0.40521,0.39395,0.38266,0.37128,0.35986,0.34839,0.33685,0.32529,0.31366,0.30197,0.29025,0.2785,0.26669,0.25485,0.24295,0.23105,0.21909,0.20709,0.19507,0.18301,0.17093,0.15884,0.1467,0.13455,0.12241,0.1102,0.097992,0.085785,0.073547,0.06131,0.049042,0.036804,0.024536,0.012268,0,-0.012268,-0.024536,-0.036804,-0.049042,-0.06131,-0.073547,-0.085785,-0.097992,-0.1102,-0.12241,-0.13455,-0.1467,-0.15884,-0.17093,-0.18301,-0.19507,-0.20709,-0.21909,-0.23105,-0.24295,-0.25485,-0.26669,-0.2785,-0.29025,-0.30197,-0.31366,-0.32529,-0.33685,-0.34839,-0.35986,-0.37128,-0.38266,-0.39395,-0.40521,-0.41641,-0.42752,-0.4386,-0.44958,-0.46051,-0.47137,-0.48215,-0.49286,-0.50351,-0.51407,-0.52457,-0.53497,-0.54529,-0.55554,-0.5657,-0.57578,-0.58575,-0.59567,-0.60547,-0.6152,-0.62482,-0.63437,-0.6438,-0.65314,-0.66238,-0.67151,-0.68057,-0.68951,-0.69833,-0.70706,-0.7157,-0.72421,-0.7326,-0.74091,-0.74908,-0.75717,-0.76514,-0.77298,-0.7807,-0.7883,-0.79581,-0.80316,-0.81042,-0.81754,-0.82455,-0.83142,-0.8382,-0.84482,-0.85132,-0.8577,-0.86392,-0.87006,-0.87604,-0.88187,-0.8876,-0.89319,-0.89862,-0.90396,-0.90912,-0.91415,-0.91907,-0.92383,-0.92847,-0.93295,-0.93729,-0.9415,-0.94556,-0.94949,-0.95325,-0.95691,-0.96039,-0.96375,-0.96692,-0.97,-0.9729,-0.97565,-0.97827,-0.98074,-0.98306,-0.98523,-0.98724,-0.98914,-0.99084,-0.99243,-0.99387,-0.99515,-0.99628,-0.99725,-0.99808,-0.99875,-0.99927,-0.99966,-0.99988,-0.99997,-0.99988,-0.99966,-0.99927,-0.99875,-0.99808,-0.99725,-0.99628,-0.99515,-0.99387,-0.99243,-0.99084,-0.98914,-0.98724,-0.98523,-0.98306,-0.98074,-0.97827,-0.97565,-0.9729,-0.97,-0.96692,-0.96375,-0.96039,-0.95691,-0.95325,-0.94949,-0.94556,-0.9415,-0.93729,-0.93295,-0.92847,-0.92383,-0.91907,-0.91415,-0.90912,-0.90396,-0.89862,-0.89319,-0.8876,-0.88187,-0.87604,-0.87006,-0.86392,-0.8577,-0.85132,-0.84482,-0.8382,-0.83142,-0.82455,-0.81754,-0.81042,-0.80316,-0.79581,-0.7883,-0.7807,-0.77298,-0.76514,-0.75717,-0.74908,-0.74091,-0.7326,-0.72421,-0.7157,-0.70706,-0.69833,-0.68951,-0.68057,-0.67151,-0.66238,-0.65314,-0.6438,-0.63437,-0.62482,-0.6152,-0.60547,-0.59567,-0.58575,-0.57578,-0.5657,-0.55554,-0.54529,-0.53497,-0.52457,-0.51407,-0.50351,-0.49286,-0.48215,-0.47137,-0.46051,-0.44958,-0.4386,-0.42752,-0.41641,-0.40521,-0.39395,-0.38266,-0.37128,-0.35986,-0.34839,-0.33685,-0.32529,-0.31366,-0.30197,-0.29025,-0.2785,-0.26669,-0.25485,-0.24295,-0.23105,-0.21909,-0.20709,-0.19507,-0.18301,-0.17093,-0.15884,-0.1467,-0.13455,-0.12241,-0.1102,-0.097992,-0.085785,-0.073547,-0.06131,-0.049042,-0.036804,-0.024536,-0.012268,0,0.012268 }; +int mtofarray[129]={0, 8.661957, 9.177024, 9.722718, 10.3, 10.913383, 11.562325, 12.25, 12.978271, 13.75, 14.567617, 15.433853, 16.351599, 17.323914, 18.354048, 19.445436, 20.601723, 21.826765, 23.124651, 24.5, 25.956543, 27.5, 29.135235, 30.867706, 32.703197, 34.647827, 36.708096, 38.890873, 41.203445, 43.65353, 46.249302, 49., 51.913086, 55., 58.27047, 61.735413, 65.406395, 69.295654, 73.416191, 77.781746, 82.406891, 87.30706, 92.498604, 97.998856, 103.826172, 110., 116.540939, 123.470825, 130.81279, 138.591309, 146.832382, 155.563492, 164.813782, 174.61412, 184.997208, 195.997711, 207.652344, 220., 233.081879, 246.94165, 261.62558, 277.182617,293.664764, 311.126984, 329.627563, 349.228241, 369.994415, 391.995422, 415.304688, 440., 466.163757, 493.883301, 523.25116, 554.365234, 587.329529, 622.253967, 659.255127, 698.456482, 739.988831, 783.990845, 830.609375, 880., 932.327515, 987.766602, 1046.502319, 1108.730469, 1174.659058, 1244.507935, 1318.510254, 1396.912964, 1479.977661, 1567.981689, 1661.21875, 1760., 1864.655029, 1975.533203, 2093.004639, 2217.460938, 2349.318115, 2489.015869, 2637.020508, 2793.825928, 2959.955322, 3135.963379, 3322.4375, 3520., 3729.31, 3951.066406, 4186.009277, 4434.921875, 4698.63623, 4978.031738, 5274.041016, 5587.651855, 5919.910645, 6271.926758, 6644.875, 7040., 7458.620117, 7902.132812, 8372.018555, 8869.84375, 9397.272461, 9956.063477, 10548.082031, 11175.303711, 11839.821289, 12543.853516, 13289.75}; + void setup();//use this to do any initialisation if you want. void play(double *channels);//run dac! maxiOsc::maxiOsc(){ phase = 0.0; -// memset(phases,0,500); -// memset(freqs,0,500); + // memset(phases,0,500); + // memset(freqs,0,500); } double maxiOsc::noise() { @@ -64,6 +66,11 @@ double maxiOsc::noise() { return(output); } +void maxiOsc::phaseReset(double phaseIn) { + phase=phaseIn; + +} + double maxiOsc::sinewave(double frequency) { output=sin (phase*(TWOPI)); if ( phase >= 1.0 ) phase -= 1.0; @@ -162,14 +169,13 @@ double maxiOsc::saw(double frequency) { } -double maxiOsc::triangle(double frequency, double phase) { - output=tri*2; +double maxiOsc::triangle(double frequency) { if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency*chandiv))); + phase += (1./(maxiSettings::sampleRate/(frequency))); if (phase <= 0.5 ) { - tri = phase; - } else { - tri =(1-phase); + output =((phase)*4)-1; + } else { + output =((0.5-phase)*4)-1; } return(output); @@ -177,36 +183,54 @@ double maxiOsc::triangle(double frequency, double phase) { //I like this. double maxiEnvelope::line(int numberofsegments,double segments[1000]) { - period=2./(segments[valindex+1]*0.004); - nextval=segments[valindex+2]; - currentval=segments[valindex]; - if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) { - amplitude += ((currentval-startval)/(maxiSettings::sampleRate/period)); - } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) { - amplitude -= (((currentval-startval)*(-1))/(maxiSettings::sampleRate/period)); - } else if (valindex >numberofsegments-1) { - valindex=numberofsegments-2; - } else { - valindex=valindex+2; - startval=currentval; + if (isPlaying==1) {//only make a sound once you've been triggered + + period=2./(segments[valindex+1]*0.004); + nextval=segments[valindex+2]; + currentval=segments[valindex]; + if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) { + amplitude += ((currentval-startval)/(maxiSettings::sampleRate/period)); + } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) { + amplitude -= (((currentval-startval)*(-1))/(maxiSettings::sampleRate/period)); + } else if (valindex >numberofsegments-1) { + valindex=numberofsegments-2; + } else { + valindex=valindex+2; + startval=currentval; + } + output=amplitude; + + } + else { + output=0; + } - output=amplitude; - return(output); + return(output); } //and this void maxiEnvelope::trigger(int index, double amp) { + isPlaying=1;//ok the envelope is being used now. valindex=index; amplitude=amp; } //and this + +maxiDelayline::maxiDelayline() { + memory[88200]=NULL; + +} + + double maxiDelayline::dl(double input, int size, double feedback) { - if ( phase >=size ) phase = 0; + if ( phase >=size ) { + phase = 0; + } memory[phase]=(memory[phase]*feedback)+(input*feedback)*0.5; phase+=1; - output=memory[phase+1]; + output=memory[phase]; return(output); } @@ -237,7 +261,7 @@ double maxiFilter::hipass(double input, double cutoff) { double maxiFilter::lores(double input,double cutoff1, double resonance) { cutoff=cutoff1*0.5; if (cutoff<10) cutoff=10; - if (cutoff>(maxiSettings::sampleRate*0.25)) cutoff=(maxiSettings::sampleRate*0.25); + if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); if (resonance<1.) resonance = 1.; z=cos(TWOPI*cutoff/maxiSettings::sampleRate); c=2-2*z; @@ -253,7 +277,7 @@ double maxiFilter::lores(double input,double cutoff1, double resonance) { double maxiFilter::hires(double input,double cutoff1, double resonance) { cutoff=cutoff1*0.5; if (cutoff<10) cutoff=10; - if (cutoff>(maxiSettings::sampleRate*0.25)) cutoff=(maxiSettings::sampleRate*0.25); + if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); if (resonance<1.) resonance = 1.; z=cos(TWOPI*cutoff/maxiSettings::sampleRate); c=2-2*z; @@ -323,8 +347,9 @@ double *maxiMix::ambisonic(double input,double eight[8],double x,double y,double } -bool maxiSample::load(string fileName) { +bool maxiSample::load(string fileName, int channel) { myPath = fileName; + readChannel=channel; return read(); } @@ -337,10 +362,8 @@ bool maxiSample::read() bool result; ifstream inFile( myPath.c_str(), ios::in | ios::binary); result = inFile; - if (inFile) { bool datafound = false; - inFile.seekg(4, ios::beg); inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize @@ -389,6 +412,16 @@ bool maxiSample::read() length=myDataSize*(0.5/myChannels); inFile.close(); // close the input file + if (myChannels>1) { + int position=0; + int channel=readChannel*2; + for (int i=channel;i<myDataSize+6;i+=(myChannels*2)) { + myData[position]=myData[i]; + myData[position+1]=myData[i+1]; + position+=2; + } + } + }else { cout << "ERROR: Could not load sample: " <<myPath << endl; } @@ -399,18 +432,19 @@ bool maxiSample::read() double maxiSample::play() { - long length=myDataSize*(1./myChannels); + // long length=myDataSize*(1./myChannels); double remainder; short* buffer = (short *)myData; position=(position+1); remainder = position - (long) position; if ((long) position>length) position=0; - output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + output = + (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation return(output); } double maxiSample::playOnce() { -// long length=myDataSize*(0.5/myChannels); + // long length=myDataSize*(0.5/myChannels); double remainder; short* buffer = (short *)myData; position=(position+1); @@ -419,14 +453,27 @@ double maxiSample::playOnce() { output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation else output=0; + + return(output); +} +double maxiSample::playOnce(double speed) { + double remainder; + //long a,b; + // long length=myDataSize*0.5; + short* buffer = (short *)myData; + position=position+((speed*chandiv*myChannels)/(maxiSettings::sampleRate/mySampleRate)); + if ((long) position<length) + output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + else + output=0; return(output); } double maxiSample::play(double speed) { double remainder; long a,b; -// long length=myDataSize*0.5; + // long length=myDataSize*0.5; short* buffer = (short *)myData; position=position+((speed*chandiv*myChannels)/(maxiSettings::sampleRate/mySampleRate)); if (speed >=0) { @@ -442,29 +489,29 @@ double maxiSample::play(double speed) { } if (position+2<length) { - b=position+2; + b=position+2; } else { - b=length-1; + b=length-1; } output = (double) ((1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation -} else { + } else { if ((long) position<0) position=length; remainder = position - floor(position); if (position-1>=0) { a=position-1; - - } - else { - a=0; - } - if (position-2>=0) { - b=position-2; - } - else { - b=0; - } + + } + else { + a=0; + } + if (position-2>=0) { + b=position-2; + } + else { + b=0; + } output = (double) ((-1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation } return(output); @@ -477,7 +524,7 @@ double maxiSample::play(double frequency, double start, double end) { double maxiSample::play(double frequency, double start, double end, double &pos) { double remainder; // long length=myDataSize; - + if (end>=length) end=length-1; long a,b; short* buffer = (short *)myData; @@ -503,7 +550,7 @@ double maxiSample::play(double frequency, double start, double end, double &pos) else { b=length-1; } - + output = (double) ((1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation } else { @@ -547,7 +594,7 @@ double maxiSample::play4(double frequency, double start, double end) { remainder = position - floor(position); if (position>0) { a=buffer[(int)(floor(position))-1]; - + } else { a=buffer[0]; @@ -556,14 +603,14 @@ double maxiSample::play4(double frequency, double start, double end) { b=buffer[(long) position]; if (position<end-2) { c=buffer[(long) position+1]; - + } else { c=buffer[0]; - + } if (position<end-3) { d=buffer[(long) position+2]; - + } else { d=buffer[0]; } @@ -803,3 +850,178 @@ void maxiSample::getLength() { } +/* OK this compressor and gate are now ready to use. The envelopes, like all the envelopes in this recent update, use stupid algorithms for + incrementing - consequently a long attack is something like 0.0001 and a long release is like 0.9999. + Annoyingly, a short attack is 0.1, and a short release is 0.99. I'll sort this out laters */ + +double maxiDyn::gate(double input, double threshold, long holdtime, double attack, double release) { + + if (fabs(input)>threshold && attackphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + if(amplitude==0) amplitude=0.01; + } + + if (attackphase==1 && amplitude<1) { + amplitude*=(1+attack); + output=input*amplitude; + } + + if (amplitude>=1) { + attackphase=0; + holdphase=1; + } + + if (holdcount<holdtime && holdphase==1) { + output=input; + holdcount++; + } + + if (holdcount==holdtime) { + holdphase=0; + releasephase=1; + } + + if (releasephase==1 && amplitude>0.) { + output=input*(amplitude*=release); + + } + + return output; +} + + +double maxiDyn::compressor(double input, double ratio, double threshold, double attack, double release) { + + if (fabs(input)>threshold && attackphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + if(currentRatio==0) currentRatio=ratio; + } + + if (attackphase==1 && currentRatio<ratio-1) { + currentRatio*=(1+attack); + } + + if (currentRatio>=ratio-1) { + attackphase=0; + releasephase=1; + } + + if (releasephase==1 && currentRatio>0.) { + currentRatio*=release; + } + + if (input>0.) { + output = input/(1.+currentRatio); + } else { + output = input/(1.+currentRatio); + } + + return output*(1+log(ratio)); +} + + +/* Lots of people struggle with the envelope generators so here's a new easy one. + It takes mental numbers for attack and release tho. Basically, they're exponentials. + I'll map them out later so that it's a bit more intuitive */ +double maxiEnv::ar(double input, double attack, double release, long holdtime, int trigger) { + + if (trigger==1 && attackphase!=1 && holdphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + } + + if (attackphase==1) { + amplitude+=(1*attack); + output=input*amplitude; + } + + if (amplitude>=1) { + amplitude=1; + attackphase=0; + holdphase=1; + } + + if (holdcount<holdtime && holdphase==1) { + output=input; + holdcount++; + } + + if (holdcount==holdtime && trigger==1) { + output=input; + } + + if (holdcount==holdtime && trigger!=1) { + holdphase=0; + releasephase=1; + } + + if (releasephase==1 && amplitude>0.) { + output=input*(amplitude*=release); + + } + + return output; +} + +/* and here's a new adsr. It's not bad, very simple to use*/ + +double maxiEnv::adsr(double input, double attack, double decay, double sustain, double release, long holdtime, int trigger) { + + if (trigger==1 && attackphase!=1 && holdphase!=1 && decayphase!=1){ + holdcount=0; + decayphase=0; + sustainphase=0; + releasephase=0; + attackphase=1; + } + + if (attackphase==1) { + amplitude+=(1*attack); + output=input*amplitude; + } + + if (amplitude>=1) { + amplitude=1; + attackphase=0; + decayphase=1; + } + + if (decayphase==1) { + output=input*(amplitude*=decay); + if (amplitude<=sustain) { + decayphase=0; + holdphase=1; + } + } + + if (holdcount<holdtime && holdphase==1) { + output=input*amplitude; + holdcount++; + } + + if (holdcount==holdtime && trigger==1) { + output=input*amplitude; + } + + if (holdcount==holdtime && trigger!=1) { + holdphase=0; + releasephase=1; + } + + if (releasephase==1 && amplitude>0.) { + output=input*(amplitude*=release); + + } + + return output; +} + +double convert::mtof(int midinote) { + + return mtofarray[midinote]; +}
\ No newline at end of file diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.h b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.h index 3304bac..102d552 100755 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.h +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/libs/maximilian.h @@ -70,7 +70,7 @@ class maxiOsc { double endphase; double output; double tri; - + public: maxiOsc(); @@ -79,12 +79,13 @@ public: double phasor(double frequency); double phasor(double frequency, double startphase, double endphase); double saw(double frequency); - double triangle(double frequency,double phase); + double triangle(double frequency); double square(double frequency); double pulse(double frequency, double duty); double noise(); double sinebuf(double frequency); double sinebuf4(double frequency); + void phaseReset(double phaseIn); }; @@ -96,6 +97,7 @@ class maxiEnvelope { double startval; double currentval; double nextval; + int isPlaying; public: double line(int numberofsegments,double segments[100]); @@ -115,9 +117,10 @@ class maxiDelayline { double memory[88200]; public: + maxiDelayline(); double dl(double input, int size, double feedback); double dl(double input, int size, double feedback, int position); - + }; @@ -134,6 +137,7 @@ class maxiFilter { double z;//pole double c;//filter coefficient public: + maxiFilter():x(0.0), y(0.0), z(0.0), c(0.0){}; double cutoff; double resonance; double lores(double input,double cutoff1, double resonance); @@ -159,35 +163,36 @@ public: }; - class maxiSample { private: string myPath; int myChunkSize; int mySubChunk1Size; + int readChannel; short myFormat; int myByteRate; short myBlockAlign; short myBitsPerSample; - int myDataSize; double position; double speed; double output; public: + int myDataSize; short myChannels; int mySampleRate; long length; void getLength(); - + + char* myData; // get/set for the Path property - + ~maxiSample() { - delete myData; + if (myData) delete[] myData; myChunkSize = NULL; mySubChunk1Size = NULL; myFormat = NULL; @@ -199,9 +204,9 @@ public: myDataSize = NULL; } -// maxiSample(); - - bool load(string fileName); + maxiSample():myData(NULL){}; + + bool load(string fileName, int channel=0); void trigger(); @@ -212,12 +217,14 @@ public: double playOnce(); + double playOnce(double speed); + double play(double speed); double play(double frequency, double start, double end, double &pos); double play(double frequency, double start, double end); - + double play4(double frequency, double start, double end); double bufferPlay(unsigned char &bufferin,long length); @@ -303,7 +310,7 @@ public: val = max(min(val, inMax), inMin); return pow((outMax / outMin), (val - inMin) / (inMax - inMin)) * outMin; } - + static double inline explin(double val, double inMin, double inMax, double outMin, double outMax) { //clipping val = max(min(val, inMax), inMin); @@ -313,4 +320,47 @@ public: }; +class maxiDyn { + + +public: + double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995); + double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995); + double input; + double ratio; + double currentRatio; + double threshold; + double output; + double attack; + double release; + double amplitude; + long holdtime; + long holdcount; + int attackphase,holdphase,releasephase; +}; + +class maxiEnv { + + +public: + double ar(double input, double attack=1, double release=0.9, long holdtime=1, int trigger=0); + double adsr(double input, double attack=1, double decay=0.99, double sustain=0.125, double release=0.9, long holdtime=1, int trigger=0); + double input; + double output; + double attack; + double decay; + double sustain; + double release; + double amplitude; + int trigger; + long holdtime; + long holdcount; + int attackphase,decayphase,sustainphase,holdphase,releasephase; +}; + +class convert { +public: + double mtof(int midinote); +}; + #endif diff --git a/ofxMaxim/ofMaxim007Example/ofxMaxim/src/ofxMaxim.h b/ofxMaxim/ofMaxim007Example/ofxMaxim/src/ofxMaxim.h index 3b5e3c5..ec8c539 100644 --- a/ofxMaxim/ofMaxim007Example/ofxMaxim/src/ofxMaxim.h +++ b/ofxMaxim/ofMaxim007Example/ofxMaxim/src/ofxMaxim.h @@ -36,6 +36,7 @@ #include "maximilian.h" #include "maxiFFT.h" #include "maxiGrains.h" +#include "maxiMFCC.h" typedef maxiMix ofxMaxiMix; @@ -48,6 +49,7 @@ typedef maxiFFT ofxMaxiFFT; typedef maxiIFFT ofxMaxiIFFT; typedef maxiFFTOctaveAnalyzer ofxMaxiFFTOctaveAnalyzer; typedef maxiSettings ofxMaxiSettings; +typedef maxiMFCC ofxMaxiMFCC; #endif diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.cpp b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.cpp index e19498d..3f13bd2 100644 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.cpp +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.cpp @@ -469,10 +469,8 @@ fft::~fft() { } /* Calculate the power spectrum */ -void fft::powerSpectrum(int start, float *data, float *window, float *magnitude,float *phase, float *power, float *avg_power) { +void fft::powerSpectrum(int start, float *data, float *window, float *magnitude,float *phase) { int i; - float total_power = 0.0f; - //windowing for (i = 0; i < n; i++) { @@ -484,23 +482,31 @@ void fft::powerSpectrum(int start, float *data, float *window, float *magnitude, for (i = 0; i < half; i++) { /* compute power */ - power[i] = out_real[i]*out_real[i] + out_img[i]*out_img[i]; - total_power += power[i]; + float power = out_real[i]*out_real[i] + out_img[i]*out_img[i]; /* compute magnitude and phase */ - magnitude[i] = 2.0*sqrt(power[i]); - - if (magnitude[i] < 0.000001){ // less than 0.1 nV - magnitude[i] = 0; // out of range - } else { - magnitude[i] = 20.0*log10(magnitude[i] + 1); // get to to db scale - } + magnitude[i] = sqrt(power); phase[i] = atan2(out_img[i],out_real[i]); + +// if (magnitude[i] < 0.000001){ // less than 0.1 nV +// magnitude[i] = 0; // out of range +// } else { +// magnitude[i] = 20.0*log10(magnitude[i] + 1); // get to to db scale +// } } - /* calculate average power */ - *(avg_power) = total_power / (float) half; } +void fft::convToDB(float *in, float *out) { + for (int i = 0; i < half; i++) { + if (in[i] < 0.000001){ // less than 0.1 nV + out[i] = 0; // out of range + } else { + out[i] = 20.0*log10(in[i] + 1); // get to to db scale + } + } +} + + #ifdef __APPLE_CC__ /* Calculate the power spectrum */ @@ -519,7 +525,7 @@ void fft::powerSpectrum_vdsp(int start, float *data, float *window, float *magni vDSP_fft_zrip(setupReal, &A, 1, log2n, FFT_FORWARD); //scale by 2 (see vDSP docs) - static float scale=0.5; + static float scale=0.5 ; vDSP_vsmul(A.realp, 1, &scale, A.realp, 1, half); vDSP_vsmul(A.imagp, 1, &scale, A.imagp, 1, half); @@ -533,13 +539,20 @@ void fft::powerSpectrum_vdsp(int start, float *data, float *window, float *magni magnitude[i]=polar[2*i]+1.0; phase[i]=polar[2*i + 1]; } - float ref = 1.0; - vDSP_vdbcon(magnitude, 1, &ref, magnitude, 1, half, 1); } +void fft::convToDB_vdsp(float *in, float *out) { + float ref = 1.0; + vDSP_vdbcon(in, 1, &ref, out, 1, half, 1); + //get rid of any -infs + float vmin=0.0; + float vmax=9999999.0; + vDSP_vclip(out, 1, &vmin, &vmax, out, 1, half); +} + #endif void fft::inversePowerSpectrum(int start, float *finalOut, float *window, float *magnitude,float *phase) { @@ -547,9 +560,11 @@ void fft::inversePowerSpectrum(int start, float *finalOut, float *window, float /* get real and imag part */ for (i = 0; i < half; i++) { - float mag = pow(10.0, magnitude[i] / 20.0) - 1.0; - in_real[i] = mag *cos(phase[i]); - in_img[i] = mag *sin(phase[i]); +// float mag = pow(10.0, magnitude[i] / 20.0) - 1.0; +// in_real[i] = mag *cos(phase[i]); +// in_img[i] = mag *sin(phase[i]); + in_real[i] = magnitude[i] *cos(phase[i]); + in_img[i] = magnitude[i] *sin(phase[i]); } /* zero negative frequencies */ @@ -571,7 +586,8 @@ void fft::inversePowerSpectrum_vdsp(int start, float *finalOut, float *window, f uint32_t i; for (i = 0; i < half; i++) { - polar[2*i] = pow(10.0, magnitude[i] / 20.0) - 1.0; +// polar[2*i] = pow(10.0, magnitude[i] / 20.0) - 1.0; + polar[2*i] = magnitude[i] - 1.0; polar[2*i + 1] = phase[i]; } @@ -581,7 +597,7 @@ void fft::inversePowerSpectrum_vdsp(int start, float *finalOut, float *window, f vDSP_fft_zrip(setupReal, &A, 1, log2n, FFT_INVERSE); vDSP_ztoc(&A, 1, (COMPLEX*) out_real, 2, half); - static float scale = 1./(2. * n); + static float scale = 1./n; vDSP_vsmul(out_real, 1, &scale, out_real, 1, n); //multiply by window diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.h b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.h index 77aa777..f7e1947 100644 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.h +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/fft.h @@ -38,10 +38,12 @@ #endif #ifdef __APPLE_CC__ -#include <Accelerate/Accelerate.h> + #include <Accelerate/Accelerate.h> + #warning Please link against the Accelerate framework #endif + class fft { public: @@ -61,12 +63,14 @@ public: float *polar; void powerSpectrum_vdsp(int start, float *data, float *window, float *magnitude,float *phase); void inversePowerSpectrum_vdsp(int start, float *finalOut, float *window, float *magnitude,float *phase); + void convToDB_vdsp(float *in, float *out); #endif; /* Calculate the power spectrum */ - void powerSpectrum(int start, float *data, float *window, float *magnitude, float *phase, float *power, float *avg_power); + void powerSpectrum(int start, float *data, float *window, float *magnitude, float *phase); /* ... the inverse */ void inversePowerSpectrum(int start, float *finalOut, float *window, float *magnitude,float *phase); + void convToDB(float *in, float *out); static void genWindow(int whichFunction, int NumSamples, float *window); diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.cpp b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.cpp index eee8ee8..36034b2 100644 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.cpp +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.cpp @@ -31,6 +31,7 @@ */ #include "maxiFFT.h" +#include "maximilian.h" #include <iostream> #include "math.h" @@ -49,13 +50,13 @@ void maxiFFT::setup(int _fftSize, int _windowSize, int _hopSize) { hopSize = _hopSize; buffer = (float *) malloc(fftSize * sizeof(float)); magnitudes = (float *) malloc(bins * sizeof(float)); + magnitudesDB = (float *) malloc(bins * sizeof(float)); phases = (float *) malloc(bins * sizeof(float)); - powers = (float *) malloc(bins * sizeof(float)); avgPower = new float; memset(buffer, 0, fftSize * sizeof(float)); memset(magnitudes, 0, bins * sizeof(float)); + memset(magnitudesDB, 0, bins * sizeof(float)); memset(phases, 0, bins * sizeof(float)); - memset(powers, 0, bins * sizeof(float)); *avgPower = 0; pos =windowSize - hopSize; newFFT = 0; @@ -73,7 +74,7 @@ bool maxiFFT::process(float value) { #if defined(__APPLE_CC__) && !defined(_NO_VDSP) _fft->powerSpectrum_vdsp(0, buffer, window, magnitudes, phases); #else - _fft->powerSpectrum(0, buffer, window, magnitudes, phases, powers, avgPower); + _fft->powerSpectrum(0, buffer, window, magnitudes, phases); #endif //shift buffer back by one hop size memcpy(buffer, buffer + hopSize, (windowSize - hopSize) * sizeof(float)); @@ -85,10 +86,42 @@ bool maxiFFT::process(float value) { return newFFT; } +float* maxiFFT::magsToDB() { +#if defined(__APPLE_CC__) && !defined(_NO_VDSP) + _fft->convToDB_vdsp(magnitudes, magnitudesDB); +#else + _fft->convToDB(magnitudes, magnitudesDB); +#endif + return magnitudesDB; +} + +float maxiFFT::spectralFlatness() { + float geometricMean=0, arithmaticMean=0; + for(int i=0; i < bins; i++) { + if (magnitudes[i] != 0) + geometricMean += log(magnitudes[i]); + arithmaticMean += magnitudes[i]; + } + geometricMean = exp(geometricMean / (float)bins); + arithmaticMean /= (float)bins; + return arithmaticMean !=0 ? geometricMean / arithmaticMean : 0; +} + +float maxiFFT::spectralCentroid() { + float x=0, y=0; + for(int i=0; i < bins; i++) { + x += fabs(magnitudes[i]) * (i+1); + y += fabs(magnitudes[i]); + } + return y != 0 ? x / y * ((float) maxiSettings::sampleRate / fftSize) : 0; +} + + + maxiFFT::~maxiFFT() { delete _fft; - delete[] buffer,magnitudes,phases,powers, window; - delete avgPower; + if (buffer) + delete[] buffer,magnitudes,phases,window, avgPower; } diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.h b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.h index 4d73441..d099e84 100644 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.h +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiFFT.h @@ -37,29 +37,37 @@ #include "fft.h" +#include "stddef.h" class maxiFFT { public: maxiFFT(){ - _fft = 0; + _fft = NULL; + buffer = magnitudes = phases = window = avgPower = NULL; }; ~maxiFFT(); void setup(int fftSize, int windowSize, int hopSize); bool process(float value); - float *magnitudes, *phases, *powers; + float* magsToDB(); + float *magnitudes, *phases, *magnitudesDB; float *avgPower; int windowSize; int hopSize; + int bins; + + //features + float spectralFlatness(); + float spectralCentroid(); private: float *buffer, *window; - int bins; int pos; float nextValue; int fftSize; fft *_fft; bool newFFT; + }; class maxiIFFT { diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiGrains.cpp b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiGrains.cpp new file mode 100644 index 0000000..951f3b5 --- /dev/null +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiGrains.cpp @@ -0,0 +1,6 @@ +#include "maxiGrains.h" + + + + + diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiGrains.h b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiGrains.h new file mode 100644 index 0000000..d17ffc9 --- /dev/null +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiGrains.h @@ -0,0 +1,443 @@ + + +#ifndef _MAXI_GRAINS_H +#define _MAXI_GRAINS_H +#include "maximilian.h" + +#if defined(__APPLE_CC__) +#include "accelerate/accelerate.h"; +//Mac users can uncommment the line below to use Apple's accelerate framework for calculating grains. This gives ~300% speed improvement and better sound quality, but doesn't work well on all machines. +//#define MAXIGRAINFAST +#endif + +#define PI 3.1415926535897932384626433832795028841968 + +#include <list> + +typedef unsigned long ulong; + +//window functions from http://en.wikipedia.org/wiki/Window_function#High-_and_moderate-resolution_windows + +struct hannWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return 0.5 * (1.0 - cos((2.0 * PI * windowPos) / (windowLength - 1))); + } +}; + +//this window can produce clicks +struct hammingWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return 0.54 - (0.46 * cos((2.0 * PI * windowPos) / (windowLength - 1))); + } +}; + + +struct cosineWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return sin((PI * windowPos) / (windowLength - 1)); + } +}; + +struct rectWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return 1; + } +}; + +struct triangleWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return (2.0 / (windowLength-1.0)) * (((windowLength-1.0)/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0))); + } +}; + +struct triangleNZWinFunctor { + //non zero end points + inline double operator()(ulong windowLength, ulong windowPos) { + return (2.0 / windowLength) * ((windowLength/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0))); + } +}; + +struct blackmanHarrisWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return 0.35875 - + (0.48829 * cos((2 * PI * windowPos) / (windowLength-1))) + + (0.14128 * cos((4 * PI * windowPos) / (windowLength-1))) + + (0.01168 * cos((6 * PI * windowPos) / (windowLength-1))); + } +}; + +struct blackmanNutallWinFunctor { + inline double operator()(ulong windowLength, ulong windowPos) { + return 0.3635819 - + (0.4891775 * cos((2 * PI * windowPos) / (windowLength-1))) + + (0.1365995 * cos((4 * PI * windowPos) / (windowLength-1))) + + (0.0106411 * cos((6 * PI * windowPos) / (windowLength-1))); + } +}; + +template<typename F> +class maxiGrainWindowCache { +public: + unsigned int cacheSize; + + maxiGrainWindowCache() { + cacheSize = maxiSettings::sampleRate / 2.0; //allocate mem for up to 500ms grains + cache = (double**)malloc(cacheSize * sizeof(double*)); + for(int i=0; i < cacheSize; i++) { + cache[i] = NULL; + } + } + + ~maxiGrainWindowCache() { + for(int i=0; i < cacheSize; i++) { + if(NULL != cache[i]) { + delete[] cache[i]; + } + } + } + + double* getWindow(const unsigned int length) { + if (NULL == cache[length]) { + cache[length] = (double*)malloc(length * sizeof(double)); + for(int i=0; i < length; i++) { + cache[length][i] = F()(length, i); + } + } + return cache[length]; + } + +private: + double** cache; + +}; + +class maxiGrainBase { +public: + virtual double play() = 0; + bool finished; +}; + +template<typename F> +class maxiGrain : public maxiGrainBase { +public: + maxiSample *sample; + double pos; + double dur; + ulong sampleStartPos; + ulong sampleIdx; + ulong sampleDur; + ulong sampleEndPos; + double freq; + double speed; + // F winFunc; + double inc; + double frequency; + double* window; +#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST) + double* grainSamples; +#endif + /* + position between 0.0 and 1.0 + duration in seconds + */ + maxiGrain(maxiSample *sample, const double position, const double duration, const double speed, maxiGrainWindowCache<F> *windowCache) :sample(sample), pos(position), dur(duration), speed(speed) + { + sampleStartPos = sample->length * pos; + sampleDur = dur * (double)sample->mySampleRate; + sampleDurMinusOne = sampleDur - 1; + sampleIdx = 0; + finished = 0; + freq = 1.0 / dur; + sampleEndPos = sampleStartPos + sampleDur; + frequency = freq * speed; + if (frequency > 0) { + pos = sampleStartPos; + }else{ + pos = sampleEndPos; + } + inc = sampleDur/(maxiSettings::sampleRate/frequency); + window = windowCache->getWindow(sampleDur); + +#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST) + //premake the grain using fast vector functions, and quadratic interpolation + double *sourceData = (double*)malloc(sampleDur * sizeof(double)); + short* buffer = (short *)sample->myData; + //convert sample to double data + vDSP_vflt16D(buffer + sampleStartPos, 1, sourceData, 1, min(sampleDur, sample->length - sampleStartPos)); + //todo: wraping code + + grainSamples = (double*)malloc(sampleDur * sizeof(double)); + //make list of interpolation indexes + double* interpIndexes = (double*)malloc(sampleDur * sizeof(double)); + double interpPos = sampleStartPos; + for(int i=0; i < sampleDur; i++) { + interpIndexes[i] = interpPos - sampleStartPos; + interpPos += fabs(inc); + } + vDSP_vqintD(sourceData, interpIndexes, 1, grainSamples, 1, sampleDur, sampleDur); + if (frequency < 0) { + vDSP_vrvrsD(grainSamples,1, sampleDur); + } + static double divFactor = 32767.0; + vDSP_vsdivD(grainSamples, 1, &divFactor, grainSamples, 1, sampleDur); + vDSP_vmulD(grainSamples, 1, window, 1, grainSamples, 1, sampleDur); + delete sourceData, interpIndexes; +#endif + } + + ~maxiGrain() { +#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST) + delete[] grainSamples; +#endif + } + + double play() { + double output = 0.0; + if (!finished) { +#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST) + output = grainSamples[sampleIdx]; +#else + envValue = window[sampleIdx]; + double remainder; + long a,b; + short* buffer = (short *)sample->myData; + if (frequency >0.) { + pos += inc; + long posl = static_cast<long>(pos); + remainder = pos - posl; + a=posl++; + if (a>=sample->length) { + a=posl-1; + } + b = posl+2; + if (b>=sample->length) { + b=sample->length-1; + } + output = (double) ((1-remainder) * buffer[a] + + remainder * buffer[b])/32767;//linear interpolation + } else { + frequency=frequency-(frequency+frequency); + pos += inc; + long posl = static_cast<long>(pos); + remainder = pos - posl; + if (posl-1>=0) { + a=posl-1; + } + else { + a=0; + } + if (posl-2>=0) { + b=posl-2; + } + else { + b=0; + } + output = (double) ((-1-remainder) * buffer[a] + + remainder * buffer[b])/32767;//linear interpolation + } + output *= envValue; +#endif + } + sampleIdx++; + if (sampleIdx >= sampleDur) finished = 1; + return output; + } + +private: + maxiGrain(); + double envValue; + ulong sampleDurMinusOne; +}; + + +typedef list<maxiGrainBase*> grainList; + +class maxiGrainPlayer { +public: + grainList grains; + maxiSample *sample; + + maxiGrainPlayer(maxiSample *sample) : sample(sample) { + } + + void addGrain(maxiGrainBase *g) { + grains.push_back(g); + } + + double play() { + double total = 0.0; + for(grainList::iterator it = grains.begin(); it != grains.end(); ++it) { + total += (*it)->play(); + if ((*it)->finished) { + delete(*it); + grains.erase(it); + } + } + return total; + } +}; + +template<typename F> +class maxiTimestretch { +public: + double position; + long cycles; + maxiSample *sample; + maxiGrainPlayer *grainPlayer; + maxiGrainWindowCache<F> windowCache; + double randomOffset; + + maxiTimestretch(maxiSample *sample) : sample(sample) { + position=0; + cycles=0; + grainPlayer = new maxiGrainPlayer(sample); + randomOffset=0; + } + + ~maxiTimestretch() { + delete grainPlayer; + } + + double play(double speed, double grainLength, int overlaps, double posMod=0.0) { + position = position + (1 * speed); + cycles++; + if (position > sample->length) position=0; + if (position < 0) position = sample->length; + double cycleLength = grainLength * maxiSettings::sampleRate / overlaps; + double cycleMod = fmod(cycles, cycleLength + randomOffset); + if (0 == floor(cycleMod)) { + // cout << cycleMod << endl; + speed = (speed > 0 ? 1 : -1); + // speed = speed - ((cycleMod / cycleLength) * 0.1); + maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache); + grainPlayer->addGrain(g); + // cout << grainPlayer->grains.size() << endl; + // randomOffset = rand() % 10; + // randomOffset = rand() % 10; + } + return grainPlayer->play(); + } + + double play2(double pos, double grainLength, int overlaps) { + cycles++; + pos *= sample->length; + if (0 == floor(fmod(cycles, grainLength * maxiSettings::sampleRate / overlaps))) { + maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(pos / sample->length)),0.0), grainLength, 1, &windowCache); + grainPlayer->addGrain(g); + } + return grainPlayer->play(); + } +}; + +//in maxiTimeStretch, the speed is either 1 or -1, and the actual speed value only affects the grain position +//in maxiPitchShift, speed is uncoupled from position and allowed to set it's value incrementally, resulting in pitchshift. +//with both high speed values and negative speed values there are some terrific artefacts! + +template<typename F> +class maxiPitchShift { +public: + double position; + long cycles; + maxiSample *sample; + maxiGrainPlayer *grainPlayer; + maxiGrainWindowCache<F> windowCache; + double randomOffset; + + maxiPitchShift(maxiSample *sample) : sample(sample) { + position=0; + cycles=0; + grainPlayer = new maxiGrainPlayer(sample); + randomOffset=0; + } + + ~maxiPitchShift() { + delete grainPlayer; + } + + double play(double speed, double grainLength, int overlaps, double posMod=0.0) { + position = position + 1; + cycles++; + if (position > sample->length) position=0; + if (position < 0) position = sample->length; + double cycleLength = grainLength * maxiSettings::sampleRate / overlaps; + double cycleMod = fmod(cycles, cycleLength + randomOffset); + if (0 == floor(cycleMod)) { + // cout << cycleMod << endl; + //speed = (speed > 0 ? 1 : -1); + speed = speed - ((cycleMod / cycleLength) * 0.1); + maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache); + grainPlayer->addGrain(g); + // cout << grainPlayer->grains.size() << endl; + // randomOffset = rand() % 10; + // randomOffset = rand() % 10; + } + return grainPlayer->play(); + } + + double play2(double pos, double grainLength, int overlaps) { + cycles++; + pos *= sample->length; + if (0 == floor(fmod(cycles, grainLength * maxiSettings::sampleRate / overlaps))) { + maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(pos / sample->length)),0.0), grainLength, 1, &windowCache); + grainPlayer->addGrain(g); + } + return grainPlayer->play(); + } +}; + +//and here's maxiPitchStretch. Args to the play function are basically speed for 'pitch' and rate for playback rate. +//the rest is the same. + +template<typename F> +class maxiPitchStretch { +public: + double position; + long cycles; + maxiSample *sample; + maxiGrainPlayer *grainPlayer; + maxiGrainWindowCache<F> windowCache; + double randomOffset; + + maxiPitchStretch(maxiSample *sample) : sample(sample) { + position=0; + cycles=0; + grainPlayer = new maxiGrainPlayer(sample); + randomOffset=0; + } + + ~maxiPitchStretch() { + delete grainPlayer; + } + + double play(double speed, double rate, double grainLength, int overlaps, double posMod=0.0) { + position = position + (1 * rate); + cycles++; + if (position > sample->length) position=0; + if (position < 0) position = sample->length; + double cycleLength = grainLength * maxiSettings::sampleRate / overlaps; + double cycleMod = fmod(cycles, cycleLength + randomOffset); + if (0 == floor(cycleMod)) { + // cout << cycleMod << endl; + //speed = (speed > 0 ? 1 : -1); + speed = speed - ((cycleMod / cycleLength) * 0.1); + maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache); + grainPlayer->addGrain(g); + // cout << grainPlayer->grains.size() << endl; + // randomOffset = rand() % 10; + // randomOffset = rand() % 10; + } + return grainPlayer->play(); + } + + double play2(double pos, double grainLength, int overlaps) { + cycles++; + pos *= sample->length; + if (0 == floor(fmod(cycles, grainLength * maxiSettings::sampleRate / overlaps))) { + maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(pos / sample->length)),0.0), grainLength, 1, &windowCache); + grainPlayer->addGrain(g); + } + return grainPlayer->play(); + } +}; + +#endif
\ No newline at end of file diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiMFCC.cpp b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiMFCC.cpp new file mode 100644 index 0000000..e72fd75 --- /dev/null +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiMFCC.cpp @@ -0,0 +1,78 @@ +/* + * maxiMFCC.cpp + * mfccs + * + * Created by Chris on 08/03/2011. + * Copyright 2011 Goldsmiths Creative Computing. All rights reserved. + * + */ + +#include "maxiMFCC.h" + + + +template <> +void maxiMFCCAnalyser<double>::dct(double *mfccs) { + vDSP_mmulD(melBands, 1, dctMatrix, 1, mfccs, 1, 1, numCoeffs, numFilters); + double n = (double) numCoeffs; + vDSP_vsdivD(mfccs, 1, &n, mfccs, 1, numCoeffs); +} + +template <> +void maxiMFCCAnalyser<float>::dct(float *mfccs) { + vDSP_mmul(melBands, 1, dctMatrix, 1, mfccs, 1, 1, numCoeffs, numFilters); + float n = (float) numCoeffs; + vDSP_vsdiv(mfccs, 1, &n, mfccs, 1, numCoeffs); +} + +template <> +void maxiMFCCAnalyser<double>::melFilterAndLogSquare(float* powerSpectrum) { +#ifdef __APPLE_CC__ + //conv to double + vDSP_vspdp(powerSpectrum, 1, doubleSpec, 1, numBins); + // vDSP_mmulD(doubleSpec, 1, melFilters, 1, melBands, 1, 1, 42, 512); + vDSP_mmulD(doubleSpec, 1, melFilters, 1, melBands, 1, 1, numFilters, numBins); +#endif + melFilterAndLogSq_Part2(); +} + + +template <> +void maxiMFCCAnalyser<float>::melFilterAndLogSquare(float* powerSpectrum) { +#ifdef __APPLE_CC__ + vDSP_mmul(powerSpectrum, 1, melFilters, 1, melBands, 1, 1, numFilters, numBins); +#endif + melFilterAndLogSq_Part2(); +} + +template <class T> +void maxiMFCCAnalyser<T>::melFilterAndLogSq_Part2() { +#ifdef __APPLE_CC__ +#else + for (int filter = 0;filter < numFilters;filter++) { + melBands[filter] = 0.0; + for (int bin=0;bin<numBins;bin++) { + // int idx = (numBins * filter) + bin; + int idx = filter + (bin * numFilters); + // melBands[filter] += (melFilters[filter][bin] * powerSpectrum[bin]); + melBands[filter] += (melFilters[idx] * powerSpectrum[bin]); + } + } +#endif + for(int filter=0; filter < numFilters; filter++) { + // log the square + melBands[filter] = melBands[filter] > 0.000001 ? log(melBands[filter] * melBands[filter]) : 0.0; + } +} + + + + + + + + + + + + diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiMFCC.h b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiMFCC.h new file mode 100644 index 0000000..60bfe04 --- /dev/null +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maxiMFCC.h @@ -0,0 +1,204 @@ +/* + * maxiMFCC.h + * mfccs + * + * Created by Chris on 08/03/2011. + * Copyright 2011 Goldsmiths Creative Computing. All rights reserved. + * + + Based on Matthew Yee-King's MFCCMYK java class + */ + +#pragma once +#pragma pack(16) + +#include "maxiFFT.h" +#include <math.h> +#include <iostream> +#ifdef __APPLE_CC__ +#include <Accelerate/Accelerate.h> +#endif + +using namespace std; + + +// implements this formula: +// mel = 2595 log10(Hz/700 + 1) +inline double hzToMel(double hz){ + return 2595.0 * (log10(hz/700.0 + 1.0)); +} + +// implements this formula +// Hz = 700 (10^(mel/2595) - 1) +inline double melToHz(double mel){ + return 700.0 * (pow(10, mel/2595.0) - 1.0); +} + +template <class T> +class maxiMFCCAnalyser { +public: + T *melBands; + maxiMFCCAnalyser():melFilters(NULL),dctMatrix(NULL), melBands(NULL){}; + ~maxiMFCCAnalyser() { + if (melFilters) { + delete[] melFilters; + delete[] melBands; + delete[] dctMatrix; +#ifdef __APPLE_CC__ + delete doubleSpec; +#endif + } + } + + void setup(unsigned int numBins, unsigned int numFilters, unsigned int numCoeffs, double minFreq, double maxFreq, unsigned int sampleRate) + { + this->numFilters = numFilters; + this->numCoeffs = numCoeffs; + this->minFreq = minFreq; + this->maxFreq = maxFreq; + this->sampleRate = sampleRate; + this->numBins = numBins; + melFilters = NULL; + melBands = (T*) malloc(sizeof(T) * numFilters); +#ifdef __APPLE_CC__ + doubleSpec = (T*)malloc(sizeof(T) * numBins); +#endif + //create new matrix + dctMatrix = (T*)malloc(sizeof(T) * numCoeffs * numFilters); + calcMelFilterBank(sampleRate, numBins); + createDCTCoeffs(); + } + void mfcc(float* powerSpectrum, T *mfccs) { + melFilterAndLogSquare(powerSpectrum); + dct(mfccs); + } + +private: + unsigned int numFilters, numCoeffs; + double minFreq, maxFreq; + unsigned int sampleRate; + T *melFilters; + unsigned int numBins; + T *dctMatrix; +#ifdef __APPLE_CC__ + T *doubleSpec; +#endif + +#ifdef __APPLE_CC__ + void dct(T *mfccs); //define later +#else + void dct(T *mfccs) { + for(int i=0; i < numCoeffs; i++) { + mfccs[i] = 0.0; + } + for(int i=0; i < numCoeffs; i++ ) { + for(int j=0; j < numFilters; j++) { + int idx = i + (j * numCoeffs); + mfccs[i] += (dctMatrix[idx] * melBands[j]); + } + } + for(int i=0; i < numCoeffs; i++) { + mfccs[i] /= numCoeffs; + } + } +#endif + + void melFilterAndLogSquare(float* powerSpectrum); + void melFilterAndLogSq_Part2(); + + + void calcMelFilterBank(double sampleRate, int numBins) { + + double mel, dMel, maxMel, minMel, nyquist, binFreq, start, end, thisF, nextF, prevF; + int numValidBins; + + // ignore bins over nyquist + numValidBins = numBins; + + nyquist = sampleRate/2; + if (maxFreq > nyquist) { + maxFreq = nyquist; + } + + maxMel = hzToMel(maxFreq); + minMel = hzToMel(minFreq); + + dMel = (maxMel - minMel) / (numFilters + 2 - 1); + + T *filtPos = (T*) malloc(sizeof(double) * (numFilters + 2)); + + // first generate an array of start and end freqs for each triangle + mel = minMel; + for (int i=0;i<numFilters + 2;i++) { + // start of the triangle + filtPos[i] = melToHz(mel); + // std::cout << "[" << i << "] MFCC: centre is at " <<filtPos[i]<<"hz "<<mel<<" mels" << endl; + mel += dMel; + } + // now generate the coefficients for the mag spectrum + melFilters = (T*) malloc(sizeof(T) * numFilters * numValidBins); + + for (int filter = 1; filter < numFilters; filter++) { + for (int bin=0;bin<numValidBins;bin++) { + // frequency this bin represents + binFreq = (T) sampleRate / (T) numValidBins * (T) bin; + thisF = filtPos[filter]; + nextF = filtPos[filter+1]; + prevF = filtPos[filter-1]; + int idx = filter + (bin * numFilters); + if (binFreq > nextF || binFreq < prevF) { + // outside this filter + melFilters[idx] = 0; + //cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[filter][bin] << endl; + } + else { + T height = 2.0 / (nextF - prevF); + + if (binFreq < thisF) { + // up + start = prevF; + end = thisF; + melFilters[idx] = (binFreq - start) * (height / (thisF - start)); + } + else { + // down + start = thisF; + end = nextF; + melFilters[idx] = height + ((binFreq - thisF) * (-height /(nextF - thisF))); + } + // cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[filter][bin] << endl; + //cout << "MFCCMYK: filter at " <<thisF << " bin at " <<binFreq <<" coeff " <<melFilters[idx] << endl; + } + } + } + } + void createDCTCoeffs() { + T k = 3.14159265358979323846/numFilters; + T w1 = 1.0/(sqrt(numFilters)); + T w2 = sqrt(2.0/numFilters); + + + //generate dct matrix + for(int i = 0; i < numCoeffs; i++) + { + for(int j = 0; j < numFilters; j++) + { + int idx = i + (j * numCoeffs); + if(i == 0) + dctMatrix[idx]= w1 * cos(k * (i+1) * (j + 0.5)); + else + dctMatrix[idx] = w2 * cos(k * (i+1) * (j + 0.5)); + } + } + + + } + + + +}; + + + +typedef maxiMFCCAnalyser<double> maxiMFCC; +//typedef maxiMFCCAnalyser<float> maxiFloatMFCC; diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.cpp b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.cpp index efd6d28..3741173 100644 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.cpp +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.cpp @@ -34,22 +34,29 @@ #include "maximilian.h" #include "math.h" -int channels=2; -int samplerate=44100; -int buffersize=1024; + +//int channels=2; +//int samplerate=44100; +//int buffersize=1024; float chandiv= 1; +int maxiSettings::sampleRate = 44100; +int maxiSettings::channels = 2; +int maxiSettings::bufferSize = 1024; + double sineBuffer[514]={0,0.012268,0.024536,0.036804,0.049042,0.06131,0.073547,0.085785,0.097992,0.1102,0.12241,0.13455,0.1467,0.15884,0.17093,0.18301,0.19507,0.20709,0.21909,0.23105,0.24295,0.25485,0.26669,0.2785,0.29025,0.30197,0.31366,0.32529,0.33685,0.34839,0.35986,0.37128,0.38266,0.39395,0.40521,0.41641,0.42752,0.4386,0.44958,0.46051,0.47137,0.48215,0.49286,0.50351,0.51407,0.52457,0.53497,0.54529,0.55554,0.5657,0.57578,0.58575,0.59567,0.60547,0.6152,0.62482,0.63437,0.6438,0.65314,0.66238,0.67151,0.68057,0.68951,0.69833,0.70706,0.7157,0.72421,0.7326,0.74091,0.74908,0.75717,0.76514,0.77298,0.7807,0.7883,0.79581,0.80316,0.81042,0.81754,0.82455,0.83142,0.8382,0.84482,0.85132,0.8577,0.86392,0.87006,0.87604,0.88187,0.8876,0.89319,0.89862,0.90396,0.90912,0.91415,0.91907,0.92383,0.92847,0.93295,0.93729,0.9415,0.94556,0.94949,0.95325,0.95691,0.96039,0.96375,0.96692,0.97,0.9729,0.97565,0.97827,0.98074,0.98306,0.98523,0.98724,0.98914,0.99084,0.99243,0.99387,0.99515,0.99628,0.99725,0.99808,0.99875,0.99927,0.99966,0.99988,0.99997,0.99988,0.99966,0.99927,0.99875,0.99808,0.99725,0.99628,0.99515,0.99387,0.99243,0.99084,0.98914,0.98724,0.98523,0.98306,0.98074,0.97827,0.97565,0.9729,0.97,0.96692,0.96375,0.96039,0.95691,0.95325,0.94949,0.94556,0.9415,0.93729,0.93295,0.92847,0.92383,0.91907,0.91415,0.90912,0.90396,0.89862,0.89319,0.8876,0.88187,0.87604,0.87006,0.86392,0.8577,0.85132,0.84482,0.8382,0.83142,0.82455,0.81754,0.81042,0.80316,0.79581,0.7883,0.7807,0.77298,0.76514,0.75717,0.74908,0.74091,0.7326,0.72421,0.7157,0.70706,0.69833,0.68951,0.68057,0.67151,0.66238,0.65314,0.6438,0.63437,0.62482,0.6152,0.60547,0.59567,0.58575,0.57578,0.5657,0.55554,0.54529,0.53497,0.52457,0.51407,0.50351,0.49286,0.48215,0.47137,0.46051,0.44958,0.4386,0.42752,0.41641,0.40521,0.39395,0.38266,0.37128,0.35986,0.34839,0.33685,0.32529,0.31366,0.30197,0.29025,0.2785,0.26669,0.25485,0.24295,0.23105,0.21909,0.20709,0.19507,0.18301,0.17093,0.15884,0.1467,0.13455,0.12241,0.1102,0.097992,0.085785,0.073547,0.06131,0.049042,0.036804,0.024536,0.012268,0,-0.012268,-0.024536,-0.036804,-0.049042,-0.06131,-0.073547,-0.085785,-0.097992,-0.1102,-0.12241,-0.13455,-0.1467,-0.15884,-0.17093,-0.18301,-0.19507,-0.20709,-0.21909,-0.23105,-0.24295,-0.25485,-0.26669,-0.2785,-0.29025,-0.30197,-0.31366,-0.32529,-0.33685,-0.34839,-0.35986,-0.37128,-0.38266,-0.39395,-0.40521,-0.41641,-0.42752,-0.4386,-0.44958,-0.46051,-0.47137,-0.48215,-0.49286,-0.50351,-0.51407,-0.52457,-0.53497,-0.54529,-0.55554,-0.5657,-0.57578,-0.58575,-0.59567,-0.60547,-0.6152,-0.62482,-0.63437,-0.6438,-0.65314,-0.66238,-0.67151,-0.68057,-0.68951,-0.69833,-0.70706,-0.7157,-0.72421,-0.7326,-0.74091,-0.74908,-0.75717,-0.76514,-0.77298,-0.7807,-0.7883,-0.79581,-0.80316,-0.81042,-0.81754,-0.82455,-0.83142,-0.8382,-0.84482,-0.85132,-0.8577,-0.86392,-0.87006,-0.87604,-0.88187,-0.8876,-0.89319,-0.89862,-0.90396,-0.90912,-0.91415,-0.91907,-0.92383,-0.92847,-0.93295,-0.93729,-0.9415,-0.94556,-0.94949,-0.95325,-0.95691,-0.96039,-0.96375,-0.96692,-0.97,-0.9729,-0.97565,-0.97827,-0.98074,-0.98306,-0.98523,-0.98724,-0.98914,-0.99084,-0.99243,-0.99387,-0.99515,-0.99628,-0.99725,-0.99808,-0.99875,-0.99927,-0.99966,-0.99988,-0.99997,-0.99988,-0.99966,-0.99927,-0.99875,-0.99808,-0.99725,-0.99628,-0.99515,-0.99387,-0.99243,-0.99084,-0.98914,-0.98724,-0.98523,-0.98306,-0.98074,-0.97827,-0.97565,-0.9729,-0.97,-0.96692,-0.96375,-0.96039,-0.95691,-0.95325,-0.94949,-0.94556,-0.9415,-0.93729,-0.93295,-0.92847,-0.92383,-0.91907,-0.91415,-0.90912,-0.90396,-0.89862,-0.89319,-0.8876,-0.88187,-0.87604,-0.87006,-0.86392,-0.8577,-0.85132,-0.84482,-0.8382,-0.83142,-0.82455,-0.81754,-0.81042,-0.80316,-0.79581,-0.7883,-0.7807,-0.77298,-0.76514,-0.75717,-0.74908,-0.74091,-0.7326,-0.72421,-0.7157,-0.70706,-0.69833,-0.68951,-0.68057,-0.67151,-0.66238,-0.65314,-0.6438,-0.63437,-0.62482,-0.6152,-0.60547,-0.59567,-0.58575,-0.57578,-0.5657,-0.55554,-0.54529,-0.53497,-0.52457,-0.51407,-0.50351,-0.49286,-0.48215,-0.47137,-0.46051,-0.44958,-0.4386,-0.42752,-0.41641,-0.40521,-0.39395,-0.38266,-0.37128,-0.35986,-0.34839,-0.33685,-0.32529,-0.31366,-0.30197,-0.29025,-0.2785,-0.26669,-0.25485,-0.24295,-0.23105,-0.21909,-0.20709,-0.19507,-0.18301,-0.17093,-0.15884,-0.1467,-0.13455,-0.12241,-0.1102,-0.097992,-0.085785,-0.073547,-0.06131,-0.049042,-0.036804,-0.024536,-0.012268,0,0.012268 }; +int mtofarray[129]={0, 8.661957, 9.177024, 9.722718, 10.3, 10.913383, 11.562325, 12.25, 12.978271, 13.75, 14.567617, 15.433853, 16.351599, 17.323914, 18.354048, 19.445436, 20.601723, 21.826765, 23.124651, 24.5, 25.956543, 27.5, 29.135235, 30.867706, 32.703197, 34.647827, 36.708096, 38.890873, 41.203445, 43.65353, 46.249302, 49., 51.913086, 55., 58.27047, 61.735413, 65.406395, 69.295654, 73.416191, 77.781746, 82.406891, 87.30706, 92.498604, 97.998856, 103.826172, 110., 116.540939, 123.470825, 130.81279, 138.591309, 146.832382, 155.563492, 164.813782, 174.61412, 184.997208, 195.997711, 207.652344, 220., 233.081879, 246.94165, 261.62558, 277.182617,293.664764, 311.126984, 329.627563, 349.228241, 369.994415, 391.995422, 415.304688, 440., 466.163757, 493.883301, 523.25116, 554.365234, 587.329529, 622.253967, 659.255127, 698.456482, 739.988831, 783.990845, 830.609375, 880., 932.327515, 987.766602, 1046.502319, 1108.730469, 1174.659058, 1244.507935, 1318.510254, 1396.912964, 1479.977661, 1567.981689, 1661.21875, 1760., 1864.655029, 1975.533203, 2093.004639, 2217.460938, 2349.318115, 2489.015869, 2637.020508, 2793.825928, 2959.955322, 3135.963379, 3322.4375, 3520., 3729.31, 3951.066406, 4186.009277, 4434.921875, 4698.63623, 4978.031738, 5274.041016, 5587.651855, 5919.910645, 6271.926758, 6644.875, 7040., 7458.620117, 7902.132812, 8372.018555, 8869.84375, 9397.272461, 9956.063477, 10548.082031, 11175.303711, 11839.821289, 12543.853516, 13289.75}; + void setup();//use this to do any initialisation if you want. void play(double *channels);//run dac! maxiOsc::maxiOsc(){ phase = 0.0; -// memset(phases,0,500); -// memset(freqs,0,500); + // memset(phases,0,500); + // memset(freqs,0,500); } double maxiOsc::noise() { @@ -59,10 +66,15 @@ double maxiOsc::noise() { return(output); } +void maxiOsc::phaseReset(double phaseIn) { + phase=phaseIn; + +} + double maxiOsc::sinewave(double frequency) { output=sin (phase*(TWOPI)); if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(samplerate/(frequency))); + phase += (1./(maxiSettings::sampleRate/(frequency))); return(output); } @@ -70,7 +82,7 @@ double maxiOsc::sinewave(double frequency) { double maxiOsc::sinebuf4(double frequency) { double remainder; double a,b,c,d,a1,a2,a3; - phase += 512./(samplerate/(frequency)); + phase += 512./(maxiSettings::sampleRate/(frequency)); if ( phase >= 511 ) phase -=512; remainder = phase - floor(phase); @@ -97,7 +109,7 @@ double maxiOsc::sinebuf4(double frequency) { double maxiOsc::sinebuf(double frequency) { double remainder; - phase += 512./(samplerate/(frequency*chandiv)); + phase += 512./(maxiSettings::sampleRate/(frequency*chandiv)); if ( phase >= 511 ) phase -=512; remainder = phase - floor(phase); output = (double) ((1-remainder) * sineBuffer[1+ (long) phase] + remainder * sineBuffer[2+(long) phase]); @@ -107,7 +119,7 @@ double maxiOsc::sinebuf(double frequency) { double maxiOsc::coswave(double frequency) { output=cos (phase*(TWOPI)); if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(samplerate/(frequency))); + phase += (1./(maxiSettings::sampleRate/(frequency))); return(output); } @@ -115,7 +127,7 @@ double maxiOsc::coswave(double frequency) { double maxiOsc::phasor(double frequency) { output=phase; if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(samplerate/(frequency))); + phase += (1./(maxiSettings::sampleRate/(frequency))); return(output); } @@ -123,7 +135,7 @@ double maxiOsc::square(double frequency) { if (phase<0.5) output=-1; if (phase>0.5) output=1; if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(samplerate/(frequency))); + phase += (1./(maxiSettings::sampleRate/(frequency))); return(output); } @@ -131,7 +143,7 @@ double maxiOsc::pulse(double frequency, double duty) { if (duty<0.) duty=0; if (duty>1.) duty=1; if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(samplerate/(frequency))); + phase += (1./(maxiSettings::sampleRate/(frequency))); if (phase<duty) output=-1.; if (phase>duty) output=1.; return(output); @@ -143,7 +155,7 @@ double maxiOsc::phasor(double frequency, double startphase, double endphase) { phase=startphase; } if ( phase >= endphase ) phase = startphase; - phase += ((endphase-startphase)/(samplerate/(frequency))); + phase += ((endphase-startphase)/(maxiSettings::sampleRate/(frequency))); return(output); } @@ -152,19 +164,18 @@ double maxiOsc::saw(double frequency) { output=phase; if ( phase >= 1.0 ) phase -= 2.0; - phase += (1./(samplerate/(frequency))); + phase += (1./(maxiSettings::sampleRate/(frequency))); return(output); } -double maxiOsc::triangle(double frequency, double phase) { - output=tri*2; +double maxiOsc::triangle(double frequency) { if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(samplerate/(frequency*chandiv))); + phase += (1./(maxiSettings::sampleRate/(frequency))); if (phase <= 0.5 ) { - tri = phase; - } else { - tri =(1-phase); + output =((phase)*4)-1; + } else { + output =((0.5-phase)*4)-1; } return(output); @@ -172,36 +183,54 @@ double maxiOsc::triangle(double frequency, double phase) { //I like this. double maxiEnvelope::line(int numberofsegments,double segments[1000]) { - period=2./(segments[valindex+1]*0.004); - nextval=segments[valindex+2]; - currentval=segments[valindex]; - if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) { - amplitude += ((currentval-startval)/(samplerate/period)); - } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) { - amplitude -= (((currentval-startval)*(-1))/(samplerate/period)); - } else if (valindex >numberofsegments-1) { - valindex=numberofsegments-2; - } else { - valindex=valindex+2; - startval=currentval; + if (isPlaying==1) {//only make a sound once you've been triggered + + period=2./(segments[valindex+1]*0.004); + nextval=segments[valindex+2]; + currentval=segments[valindex]; + if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) { + amplitude += ((currentval-startval)/(maxiSettings::sampleRate/period)); + } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) { + amplitude -= (((currentval-startval)*(-1))/(maxiSettings::sampleRate/period)); + } else if (valindex >numberofsegments-1) { + valindex=numberofsegments-2; + } else { + valindex=valindex+2; + startval=currentval; + } + output=amplitude; + } - output=amplitude; - return(output); + else { + output=0; + + } + return(output); } //and this -void maxiEnvelope::trigger(int index,double amp) { +void maxiEnvelope::trigger(int index, double amp) { + isPlaying=1;//ok the envelope is being used now. valindex=index; amplitude=amp; } //and this + +maxiDelayline::maxiDelayline() { + memory[88200]=NULL; + +} + + double maxiDelayline::dl(double input, int size, double feedback) { - if ( phase >=size ) phase = 0; + if ( phase >=size ) { + phase = 0; + } memory[phase]=(memory[phase]*feedback)+(input*feedback)*0.5; phase+=1; - output=memory[phase+1]; + output=memory[phase]; return(output); } @@ -231,9 +260,10 @@ double maxiFilter::hipass(double input, double cutoff) { //awesome. cuttof is freq in hz. res is between 1 and whatever. Watch out! double maxiFilter::lores(double input,double cutoff1, double resonance) { cutoff=cutoff1*0.5; - if (cutoff>(samplerate*0.25)) cutoff=(samplerate*0.25); + if (cutoff<10) cutoff=10; + if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); if (resonance<1.) resonance = 1.; - z=cos(TWOPI*cutoff/samplerate); + z=cos(TWOPI*cutoff/maxiSettings::sampleRate); c=2-2*z; double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1)); x=x+(input-y)*c; @@ -243,12 +273,13 @@ double maxiFilter::lores(double input,double cutoff1, double resonance) { return(output); } -//this is just stupid. Kindof works. +//working hires filter double maxiFilter::hires(double input,double cutoff1, double resonance) { cutoff=cutoff1*0.5; - if (cutoff>(samplerate*0.25)) cutoff=(samplerate*0.25); + if (cutoff<10) cutoff=10; + if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); if (resonance<1.) resonance = 1.; - z=cos(TWOPI*cutoff/samplerate); + z=cos(TWOPI*cutoff/maxiSettings::sampleRate); c=2-2*z; double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1)); x=x+(input-y)*c; @@ -261,9 +292,9 @@ double maxiFilter::hires(double input,double cutoff1, double resonance) { //This works a bit. Needs attention. double maxiFilter::bandpass(double input,double cutoff1, double resonance) { cutoff=cutoff1; - if (cutoff>(samplerate*0.5)) cutoff=(samplerate*0.5); + if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); if (resonance>=1.) resonance=0.999999; - z=cos(TWOPI*cutoff/samplerate); + z=cos(TWOPI*cutoff/maxiSettings::sampleRate); inputs[0] = (1-resonance)*(sqrt(resonance*(resonance-4.0*pow(z,2.0)+2.0)+1)); inputs[1] = 2*z*resonance; inputs[2] = pow((resonance*-1),2); @@ -316,8 +347,9 @@ double *maxiMix::ambisonic(double input,double eight[8],double x,double y,double } -bool maxiSample::load(string fileName) { +bool maxiSample::load(string fileName, int channel) { myPath = fileName; + readChannel=channel; return read(); } @@ -325,23 +357,125 @@ void maxiSample::trigger() { position = 0; } +bool maxiSample::read() +{ + bool result; + ifstream inFile( myPath.c_str(), ios::in | ios::binary); + result = inFile; + if (inFile) { + bool datafound = false; + inFile.seekg(4, ios::beg); + inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize + + inFile.seekg(16, ios::beg); + inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size + + //inFile.seekg(20, ios::beg); + inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM + + //inFile.seekg(22, ios::beg); + inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2) + + //inFile.seekg(24, ios::beg); + inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate + + //inFile.seekg(28, ios::beg); + inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate + + //inFile.seekg(32, ios::beg); + inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign + + //inFile.seekg(34, ios::beg); + inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample + + //ignore any extra chunks + char chunkID[5]=""; + chunkID[4] = 0; + int filePos = 36; + while(!datafound && !inFile.eof()) { + inFile.seekg(filePos, ios::beg); + inFile.read((char*) &chunkID, sizeof(char) * 4); + inFile.seekg(filePos + 4, ios::beg); + inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data + filePos += 8; + if (strcmp(chunkID,"data") == 0) { + datafound = true; + }else{ + filePos += myDataSize; + } + } + + // read the data chunk + myData = (char*) malloc(myDataSize * sizeof(char)); + inFile.seekg(filePos, ios::beg); + inFile.read(myData, myDataSize); + length=myDataSize*(0.5/myChannels); + inFile.close(); // close the input file + + if (myChannels>1) { + int position=0; + int channel=readChannel*2; + for (int i=channel;i<myDataSize+6;i+=(myChannels*2)) { + myData[position]=myData[i]; + myData[position+1]=myData[i+1]; + position+=2; + } + } + + }else { + cout << "ERROR: Could not load sample: " <<myPath << endl; + } + + + return result; // this should probably be something more descriptive +} + + double maxiSample::play() { - long length=myDataSize*(1./myChannels); + // long length=myDataSize*(1./myChannels); double remainder; short* buffer = (short *)myData; position=(position+1); remainder = position - (long) position; if ((long) position>length) position=0; - output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + output = + (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + return(output); +} + +double maxiSample::playOnce() { + // long length=myDataSize*(0.5/myChannels); + double remainder; + short* buffer = (short *)myData; + position=(position+1); + remainder = position - (long) position; + if ((long) position<length) + output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + else + output=0; + + return(output); +} + +double maxiSample::playOnce(double speed) { + double remainder; + //long a,b; + // long length=myDataSize*0.5; + short* buffer = (short *)myData; + position=position+((speed*chandiv*myChannels)/(maxiSettings::sampleRate/mySampleRate)); + if ((long) position<length) + output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + else + output=0; return(output); } double maxiSample::play(double speed) { double remainder; long a,b; -// long length=myDataSize*0.5; + // long length=myDataSize*0.5; short* buffer = (short *)myData; - position=position+((speed*chandiv*myChannels)/(samplerate/mySampleRate)); + position=position+((speed*chandiv*myChannels)/(maxiSettings::sampleRate/mySampleRate)); if (speed >=0) { if ((long) position>=length-1) position=1; @@ -355,79 +489,84 @@ double maxiSample::play(double speed) { } if (position+2<length) { - b=position+2; + b=position+2; } else { - b=length-1; + b=length-1; } output = (double) ((1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation -} else { + } else { if ((long) position<0) position=length; remainder = position - floor(position); if (position-1>=0) { a=position-1; - - } - else { - a=0; - } - if (position-2>=0) { - b=position-2; - } - else { - b=0; - } + + } + else { + a=0; + } + if (position-2>=0) { + b=position-2; + } + else { + b=0; + } output = (double) ((-1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation } return(output); } double maxiSample::play(double frequency, double start, double end) { + return play(frequency, start, end, position); +} + +double maxiSample::play(double frequency, double start, double end, double &pos) { double remainder; -// long length=myDataSize; + // long length=myDataSize; + if (end>=length) end=length-1; long a,b; short* buffer = (short *)myData; if (frequency >0.) { - if (position<start) { - position=start; + if (pos<start) { + pos=start; } - if ( position >= end ) position = start; - position += ((end-start)/(samplerate/(frequency*chandiv))); - remainder = position - floor(position); - long pos = floor(position); - if (pos+1<length) { - a=pos+1; - + if ( pos >= end ) pos = start; + pos += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = pos - floor(pos); + long posl = floor(pos); + if (posl+1<length) { + a=posl+1; + } else { - a=pos-1; + a=posl-1; } - if (pos+2<length) { - b=pos+2; + if (posl+2<length) { + b=posl+2; } else { b=length-1; } - + output = (double) ((1-remainder) * buffer[a] + - remainder * buffer[b])/32767;//linear interpolation + remainder * buffer[b])/32767;//linear interpolation } else { frequency=frequency-(frequency+frequency); - if ( position <= start ) position = end; - position -= ((end-start)/(samplerate/(frequency*chandiv))); - remainder = position - floor(position); - long pos = floor(position); - if (pos-1>=0) { - a=pos-1; - } - else { - a=0; - } - if (pos-2>=0) { - b=pos-2; + if ( pos <= start ) pos = end; + pos -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = pos - floor(pos); + long posl = floor(pos); + if (posl-1>=0) { + a=posl-1; + } + else { + a=0; + } + if (posl-2>=0) { + b=posl-2; } else { b=0; @@ -440,6 +579,7 @@ double maxiSample::play(double frequency, double start, double end) { return(output); } + //better cubic inerpolation. Cobbled together from various (pd externals, yehar, other places). double maxiSample::play4(double frequency, double start, double end) { double remainder; @@ -450,11 +590,11 @@ double maxiSample::play4(double frequency, double start, double end) { position=start; } if ( position >= end ) position = start; - position += ((end-start)/(samplerate/(frequency*chandiv))); + position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); remainder = position - floor(position); if (position>0) { a=buffer[(int)(floor(position))-1]; - + } else { a=buffer[0]; @@ -463,14 +603,14 @@ double maxiSample::play4(double frequency, double start, double end) { b=buffer[(long) position]; if (position<end-2) { c=buffer[(long) position+1]; - + } else { c=buffer[0]; - + } if (position<end-3) { d=buffer[(long) position+2]; - + } else { d=buffer[0]; } @@ -482,7 +622,7 @@ double maxiSample::play4(double frequency, double start, double end) { } else { frequency=frequency-(frequency+frequency); if ( position <= start ) position = end; - position -= ((end-start)/(samplerate/(frequency*chandiv))); + position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); remainder = position - floor(position); if (position>start && position < end-1) { a=buffer[(long) position+1]; @@ -530,7 +670,7 @@ double maxiSample::bufferPlay(unsigned char &bufferin,double speed,long length) double remainder; long a,b; short* buffer = (short *)bufferin; - position=position+((speed*chandiv*myChannels)/(samplerate/mySampleRate)); + position=position+((speed*chandiv*myChannels)/(maxiSettings::sampleRate/mySampleRate)); if (speed >=0) { if ((long) position>=length-1) position=1; @@ -583,7 +723,7 @@ double maxiSample::bufferPlay(unsigned char &bufferin,double frequency, double s } if ( position >= end ) position = start; - position += ((end-start)/(samplerate/(frequency*chandiv))); + position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); remainder = position - floor(position); long pos = floor(position); if (pos+1<length) { @@ -605,7 +745,7 @@ double maxiSample::bufferPlay(unsigned char &bufferin,double frequency, double s } else { frequency=frequency-(frequency+frequency); if ( position <= start ) position = end; - position -= ((end-start)/(samplerate/(frequency*chandiv))); + position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); remainder = position - floor(position); long pos = floor(position); if (pos-1>=0) { @@ -638,7 +778,7 @@ double maxiSample::bufferPlay4(unsigned char &bufferin,double frequency, double position=start; } if ( position >= end ) position = start; - position += ((end-start)/(samplerate/(frequency*chandiv))); + position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); remainder = position - floor(position); if (position>0) { a=buffer[(int)(floor(position))-1]; @@ -670,7 +810,7 @@ double maxiSample::bufferPlay4(unsigned char &bufferin,double frequency, double } else { frequency=frequency-(frequency+frequency); if ( position <= start ) position = end; - position -= ((end-start)/(samplerate/(frequency*chandiv))); + position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); remainder = position - floor(position); if (position>start && position < end-1) { a=buffer[(long) position+1]; @@ -710,3 +850,178 @@ void maxiSample::getLength() { } +/* OK this compressor and gate are now ready to use. The envelopes, like all the envelopes in this recent update, use stupid algorithms for + incrementing - consequently a long attack is something like 0.0001 and a long release is like 0.9999. + Annoyingly, a short attack is 0.1, and a short release is 0.99. I'll sort this out laters */ + +double maxiDyn::gate(double input, double threshold, long holdtime, double attack, double release) { + + if (fabs(input)>threshold && attackphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + if(amplitude==0) amplitude=0.01; + } + + if (attackphase==1 && amplitude<1) { + amplitude*=(1+attack); + output=input*amplitude; + } + + if (amplitude>=1) { + attackphase=0; + holdphase=1; + } + + if (holdcount<holdtime && holdphase==1) { + output=input; + holdcount++; + } + + if (holdcount==holdtime) { + holdphase=0; + releasephase=1; + } + + if (releasephase==1 && amplitude>0.) { + output=input*(amplitude*=release); + + } + + return output; +} + + +double maxiDyn::compressor(double input, double ratio, double threshold, double attack, double release) { + + if (fabs(input)>threshold && attackphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + if(currentRatio==0) currentRatio=ratio; + } + + if (attackphase==1 && currentRatio<ratio-1) { + currentRatio*=(1+attack); + } + + if (currentRatio>=ratio-1) { + attackphase=0; + releasephase=1; + } + + if (releasephase==1 && currentRatio>0.) { + currentRatio*=release; + } + + if (input>0.) { + output = input/(1.+currentRatio); + } else { + output = input/(1.+currentRatio); + } + + return output*(1+log(ratio)); +} + + +/* Lots of people struggle with the envelope generators so here's a new easy one. + It takes mental numbers for attack and release tho. Basically, they're exponentials. + I'll map them out later so that it's a bit more intuitive */ +double maxiEnv::ar(double input, double attack, double release, long holdtime, int trigger) { + + if (trigger==1 && attackphase!=1 && holdphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + } + + if (attackphase==1) { + amplitude+=(1*attack); + output=input*amplitude; + } + + if (amplitude>=1) { + amplitude=1; + attackphase=0; + holdphase=1; + } + + if (holdcount<holdtime && holdphase==1) { + output=input; + holdcount++; + } + + if (holdcount==holdtime && trigger==1) { + output=input; + } + + if (holdcount==holdtime && trigger!=1) { + holdphase=0; + releasephase=1; + } + + if (releasephase==1 && amplitude>0.) { + output=input*(amplitude*=release); + + } + + return output; +} + +/* and here's a new adsr. It's not bad, very simple to use*/ + +double maxiEnv::adsr(double input, double attack, double decay, double sustain, double release, long holdtime, int trigger) { + + if (trigger==1 && attackphase!=1 && holdphase!=1 && decayphase!=1){ + holdcount=0; + decayphase=0; + sustainphase=0; + releasephase=0; + attackphase=1; + } + + if (attackphase==1) { + amplitude+=(1*attack); + output=input*amplitude; + } + + if (amplitude>=1) { + amplitude=1; + attackphase=0; + decayphase=1; + } + + if (decayphase==1) { + output=input*(amplitude*=decay); + if (amplitude<=sustain) { + decayphase=0; + holdphase=1; + } + } + + if (holdcount<holdtime && holdphase==1) { + output=input*amplitude; + holdcount++; + } + + if (holdcount==holdtime && trigger==1) { + output=input*amplitude; + } + + if (holdcount==holdtime && trigger!=1) { + holdphase=0; + releasephase=1; + } + + if (releasephase==1 && amplitude>0.) { + output=input*(amplitude*=release); + + } + + return output; +} + +double convert::mtof(int midinote) { + + return mtofarray[midinote]; +}
\ No newline at end of file diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.h b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.h index 86fcef4..102d552 100755 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.h +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/libs/maximilian.h @@ -36,17 +36,31 @@ //#define MAXIMILIAN_PORTAUDIO #define MAXIMILIAN_RT_AUDIO -#include "ofMain.h" -#include "ofUtils.h" +//#include "ofMain.h" +//#include "ofUtils.h" #include <iostream> #include <fstream> #include <string> #include <cstdlib> +#include "math.h" using namespace std; -#define TWOPI 3.14159*2 +#define TWOPI (3.14159*2) + +class maxiSettings { +public: + static int sampleRate; + static int channels; + static int bufferSize; + static void setup(int initSampleRate, int initChannels, int initBufferSize) { + maxiSettings::sampleRate = initSampleRate; + maxiSettings::channels = initChannels; + maxiSettings::bufferSize = initBufferSize; + } +}; + class maxiOsc { @@ -56,7 +70,7 @@ class maxiOsc { double endphase; double output; double tri; - + public: maxiOsc(); @@ -65,12 +79,13 @@ public: double phasor(double frequency); double phasor(double frequency, double startphase, double endphase); double saw(double frequency); - double triangle(double frequency,double phase); + double triangle(double frequency); double square(double frequency); double pulse(double frequency, double duty); double noise(); double sinebuf(double frequency); double sinebuf4(double frequency); + void phaseReset(double phaseIn); }; @@ -82,6 +97,7 @@ class maxiEnvelope { double startval; double currentval; double nextval; + int isPlaying; public: double line(int numberofsegments,double segments[100]); @@ -101,9 +117,10 @@ class maxiDelayline { double memory[88200]; public: + maxiDelayline(); double dl(double input, int size, double feedback); double dl(double input, int size, double feedback, int position); - + }; @@ -120,6 +137,7 @@ class maxiFilter { double z;//pole double c;//filter coefficient public: + maxiFilter():x(0.0), y(0.0), z(0.0), c(0.0){}; double cutoff; double resonance; double lores(double input,double cutoff1, double resonance); @@ -145,35 +163,36 @@ public: }; - class maxiSample { private: string myPath; int myChunkSize; int mySubChunk1Size; + int readChannel; short myFormat; int myByteRate; short myBlockAlign; short myBitsPerSample; - int myDataSize; double position; double speed; double output; public: + int myDataSize; short myChannels; int mySampleRate; long length; void getLength(); - + + char* myData; // get/set for the Path property - + ~maxiSample() { - delete myData; + if (myData) delete[] myData; myChunkSize = NULL; mySubChunk1Size = NULL; myFormat = NULL; @@ -185,85 +204,27 @@ public: myDataSize = NULL; } -// maxiSample(); - - bool load(string fileName); + maxiSample():myData(NULL){}; + + bool load(string fileName, int channel=0); void trigger(); // read a wav file into this class - bool read() - { - bool result; - ifstream inFile( myPath.c_str(), ios::in | ios::binary); - result = inFile; - - if (inFile) { - //printf("Reading wav file...\n"); // for debugging only - - inFile.seekg(4, ios::beg); - inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize - - inFile.seekg(16, ios::beg); - inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size - - //inFile.seekg(20, ios::beg); - inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM - - //inFile.seekg(22, ios::beg); - inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2) - - //inFile.seekg(24, ios::beg); - inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate - - //inFile.seekg(28, ios::beg); - inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate - - //inFile.seekg(32, ios::beg); - inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign - - //inFile.seekg(34, ios::beg); - inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample - - //ignore any extra chunks - char chunkID[4]=""; - int filePos = 36; - bool found = false; - while(!found && !inFile.eof()) { - inFile.seekg(filePos, ios::beg); - inFile.read((char*) &chunkID, sizeof(char) * 4); - inFile.seekg(filePos + 4, ios::beg); - inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data - filePos += 8; - if (strcmp(chunkID,"data") == 0) { - found = true; - }else{ - filePos += myDataSize; - } - } - - - - // read the data chunk - myData = (char*) malloc(myDataSize * sizeof(char)); - inFile.seekg(filePos, ios::beg); - inFile.read(myData, myDataSize); - length=myDataSize*(0.5/myChannels); - - inFile.close(); // close the input file - } - - - return result; // this should probably be something more descriptive - } - + bool read(); double play(); + double playOnce(); + + double playOnce(double speed); + double play(double speed); + double play(double frequency, double start, double end, double &pos); + double play(double frequency, double start, double end); - + double play4(double frequency, double start, double end); double bufferPlay(unsigned char &bufferin,long length); @@ -349,7 +310,57 @@ public: val = max(min(val, inMax), inMin); return pow((outMax / outMin), (val - inMin) / (inMax - inMin)) * outMin; } + + static double inline explin(double val, double inMin, double inMax, double outMin, double outMax) { + //clipping + val = max(min(val, inMax), inMin); + return (log(val/inMin) / log(inMax/inMin) * (outMax - outMin)) + outMin; + } + }; +class maxiDyn { + + +public: + double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995); + double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995); + double input; + double ratio; + double currentRatio; + double threshold; + double output; + double attack; + double release; + double amplitude; + long holdtime; + long holdcount; + int attackphase,holdphase,releasephase; +}; + +class maxiEnv { + + +public: + double ar(double input, double attack=1, double release=0.9, long holdtime=1, int trigger=0); + double adsr(double input, double attack=1, double decay=0.99, double sustain=0.125, double release=0.9, long holdtime=1, int trigger=0); + double input; + double output; + double attack; + double decay; + double sustain; + double release; + double amplitude; + int trigger; + long holdtime; + long holdcount; + int attackphase,decayphase,sustainphase,holdphase,releasephase; +}; + +class convert { +public: + double mtof(int midinote); +}; + #endif diff --git a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/src/ofxMaxim.h b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/src/ofxMaxim.h index 317ba34..ec8c539 100644 --- a/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/src/ofxMaxim.h +++ b/ofxMaxim/ofxMaximiPhoneExample/ofxMaxim/src/ofxMaxim.h @@ -34,7 +34,9 @@ #define _OFMAXIM_H #include "maximilian.h" -//#include "maxiFFT.h" +#include "maxiFFT.h" +#include "maxiGrains.h" +#include "maxiMFCC.h" typedef maxiMix ofxMaxiMix; @@ -43,8 +45,11 @@ typedef maxiEnvelope ofxMaxiEnvelope; typedef maxiDelayline ofxMaxiDelayline; typedef maxiFilter ofxMaxiFilter; typedef maxiSample ofxMaxiSample; -//typedef maxiFFT ofxMaxiFFT; -//typedef maxiIFFT ofxMaxiIFFT; -//typedef maxiFFTOctaveAnalyzer ofxMaxiFFTOctaveAnalyzer; +typedef maxiFFT ofxMaxiFFT; +typedef maxiIFFT ofxMaxiIFFT; +typedef maxiFFTOctaveAnalyzer ofxMaxiFFTOctaveAnalyzer; +typedef maxiSettings ofxMaxiSettings; +typedef maxiMFCC ofxMaxiMFCC; + #endif |
