Mercurial > hg > drum-timing-analyser
changeset 0:82352cfc0b23
Added files from ISMIR groove drum timing work
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/DevNotes.txt Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,12 @@ + + +load in + +kick +snare +room + +recordedFileClass + +holds the three audio files +loads each
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/chromagramm/ChordDetect.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,476 @@ +/* + * ChordDetect.cpp + * ChordDetect + * + * Created by Adam Stark on 28/04/2008. + * Copyright 2008 __MyCompanyName__. All rights reserved. + * + */ + +#include "ChordDetect.h" +#include <iostream> +#include <math.h> +using namespace std; + +ChordDetect :: ChordDetect() +{ + + bias = 1.06; + + makeprofiles(); + +} + +//-------------------------------------------------------------------------------------- +// destructor +ChordDetect :: ~ChordDetect() +{ + +} + + +//-------------------------------------------------------------------------------------- +// main function to be called with 8192 sample frame at 11025 Hz +void ChordDetect :: C_Detect(float c[],float c_low[]) +{ + for (int i = 0;i < 12;i++) + { + chroma[i] = c[i]; + chroma_low[i] = c_low[i]; + } + + calculateweightings(); + + classifychromagram(); + + //cout << root << " " << quality << " " << intervals << endl; +} + +//-------------------------------------------------------------------------------------- +// analyse the chromagram and assign it a root note, chord type and any features +void ChordDetect :: classifychromagram() +{ + int i; + int j; + int fifth; + int chordindex; + + // remove some of the 5th note energy from chromagram + for (i = 0;i < 12;i++) + { + fifth = (i+7) % 12; + chroma[fifth] = chroma[fifth] - (0.1*chroma[i]); + + if (chroma[fifth] < 0) + { + chroma[fifth] = 0; + } + + } + + + // major chords + for (j=0;j < 12;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + } + + // minor chords + for (j=12;j < 24;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + } + + // diminished 5th chords + for (j=24;j < 36;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + } + + // augmented 5th chords + for (j=36;j < 48;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,3); + + chord[j] = chord[j] / weight_aug[j-36]; + } + + // sus2 chords + for (j=48;j < 60;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],1,3); + + chord[j] = chord[j] / weight_sus[j-48]; + } + + // sus4 chords + for (j=60;j < 72;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],1,3); + + chord[j] = chord[j] / weight_sus[j-60]; + } + + // major 7th chords + for (j=72;j < 84;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],1,4); + } + + // minor 7th chords + for (j=84;j < 96;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,4); + } + + // dominant 7th chords + for (j=96;j < 108;j++) + { + chord[j] = calcchordvalue(chroma,profiles[j],bias,4); + } + + chordindex = minindex(chord,108); + + // major + if (chordindex < 12) + { + root = chordindex; + quality = 1; + intervals = 0; + } + + // minor + if ((chordindex >= 12) && (chordindex < 24)) + { + root = chordindex-12; + quality = 0; + intervals = 0; + } + + // diminished 5th + if ((chordindex >= 24) && (chordindex < 36)) + { + root = chordindex-24; + quality = 4; + intervals = 0; + } + + // augmented 5th + if ((chordindex >= 36) && (chordindex < 48)) + { + root = chordindex-36; + quality = 6; + intervals = 0; + } + + // sus2 + if ((chordindex >= 48) && (chordindex < 60)) + { + root = chordindex-48; + quality = 2; + intervals = 2; + } + + // sus4 + if ((chordindex >= 60) && (chordindex < 72)) + { + root = chordindex-60; + quality = 2; + intervals = 4; + } + + // major 7th + if ((chordindex >= 72) && (chordindex < 84)) + { + root = chordindex-72; + quality = 1; + intervals = 7; + } + + // minor 7th + if ((chordindex >= 84) && (chordindex < 96)) + { + root = chordindex-84; + quality = 0; + intervals = 7; + } + + // dominant 7th + if ((chordindex >= 96) && (chordindex < 108)) + { + root = chordindex-96; + quality = 2; + intervals = 7; + } +} + +//-------------------------------------------------------------------------------------- +// calculate weightings to help distinguish between sus2/sus4 and aug chords +void ChordDetect :: calculateweightings() +{ + int i; + float maxval = 0; + int fifth; + int augfifth; + + maxval = max(chroma_low,12); + + // normalise chroma low + for (i = 0;i < 12;i++) + { + chroma_low[i] = chroma_low[i] / maxval; + } + + // make weight for sus chords + for (i = 0;i < 12;i++) + { + fifth = i+7; + augfifth = i+8; + + if (fifth >= 12) + { + fifth = fifth-12; + } + + if (augfifth >= 12) + { + augfifth = augfifth-12; + } + + weight_sus[i] = chroma_low[i] + (chroma_low[fifth]/2); + weight_aug[i] = chroma_low[i] + (chroma_low[augfifth]/2); + } + + maxval = max(weight_sus,12); + // normalise weight_sus + for (i = 0;i < 12;i++) + { + weight_sus[i] = weight_sus[i] / maxval; + } + + maxval = max(weight_aug,12); + // normalise weight_aug + for (i = 0;i < 12;i++) + { + weight_aug[i] = weight_aug[i] / maxval; + } + + +} + + +//-------------------------------------------------------------------------------------- +// return delta value indicating how similar the chroma is to the chord template - lower value = more similar +float ChordDetect :: calcchordvalue(float c[],float T[],float biasval, float N) +{ + float sum = 0; + float delta; + + for (int i=0;i < 12;i++) + { + sum = sum + ((1-T[i])*(pow(c[i],2))); + } + + delta = sqrt(sum) / ((12 - N)*biasval); + + return delta; +} + + +//-------------------------------------------------------------------------------------- +// returns max value of an array +float ChordDetect :: max(float array[],int length) +{ + float max = 0; + + for (int i=0;i < length;i++) + { + if (array[i] > max) + { + max = array[i]; + } + } + + return max; +} + +//-------------------------------------------------------------------------------------- +// returns index of minimum value of array +int ChordDetect :: minindex(float array[],int length) +{ + float min = 10000; + int minindex = 0; + int i; + + for (i = 0;i < length;i++) + { + if (array[i] < min) + { + min = array[i]; + minindex = i; + } + } + + return minindex; +} + +//-------------------------------------------------------------------------------------- +// calculates bit mask chord profiles +void ChordDetect :: makeprofiles() +{ + int i; + int t; + int j = 0; + int root; + int third; + int fifth; + int seventh; + + float v1 = 1; + float v2 = 1; + float v3 = 1; + + // set profiles matrix to all zeros + for (j = 0;j < 108;j++) + { + for (t = 0;t < 12;t++) + { + profiles[j][t] = 0; + } + } + + // reset j to zero to begin creating profiles + j = 0; + + // major chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // minor chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+3) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // diminished chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+3) % 12; + fifth = (i+6) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // augmented chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+8) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // sus2 chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+2) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // sus4 chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+5) % 12; + fifth = (i+7) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + + j++; + } + + // major 7th chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+7) % 12; + seventh = (i+11) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + profiles[j][seventh] = v3; + + j++; + } + + // minor 7th chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+3) % 12; + fifth = (i+7) % 12; + seventh = (i+10) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + profiles[j][seventh] = v3; + + j++; + } + + // dominant 7th chords + for (i = 0;i < 12;i++) + { + root = i % 12; + third = (i+4) % 12; + fifth = (i+7) % 12; + seventh = (i+10) % 12; + + profiles[j][root] = v1; + profiles[j][third] = v2; + profiles[j][fifth] = v3; + profiles[j][seventh] = v3; + + j++; + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/chromagramm/ChordDetect.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,49 @@ +/* + * ChordDetect.h + * ChordDetect + * + * Created by Adam Stark on 28/04/2008. + * Copyright 2008 __MyCompanyName__. All rights reserved. + * + */ + +#ifndef CHORDDETECT_H +#define CHORDDETECT_H + +#include "fftw3.h" + +class ChordDetect +{ +public: + ChordDetect(); // constructor + ~ChordDetect(); // destructor + void C_Detect(float c[],float c_low[]); + + int root; + int quality; + int intervals; + +private: + void makeprofiles(); + void calculateweightings(); + void classifychromagram(); + + float calcchordvalue(float c[],float T[],float biasval, float N); + float max(float array[],int length); + int minindex(float array[],int length); + + float chroma[12]; + float chroma_low[12]; + float weight_sus[12]; + float weight_aug[12]; + float profiles[108][12]; + float w_profile[12]; + + float chord[108]; + + float bias; + + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/chromagramm/Chromagram.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,427 @@ + + +#include "Chromagram.h" +#include <iostream> +#include <math.h> +using namespace std; + +Chromagram :: Chromagram() +{ + pi = 3.14159265; + bsize = 8192; + + // array init + buffer = new float[8192]; // make audio buffer + wbuffer = new float[8192]; // to hold windowed audio buffer + win = new float[8192]; + d_frame = new float[128]; + hop = new float[1024]; + mag = new float[(bsize/2)+1]; + + maximumChromaValue = 1.0; + + float base = 130.81278265; + + for (int i = 0;i < 12;i++) + { + note[i] = base*pow(2,(((float) i)/12)); + } + + harmonics = 2; + octaves = 2; + search = 2; // p is number of bins either side of target to search for other peaks + + out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * bsize); // complex array to hold fft + p = fftwf_plan_dft_r2c_1d(bsize,wbuffer,out,FFTW_FORWARD*-1); // plan for executing fft of wbuffer + + chromaready = 0; +} + +//-------------------------------------------------------------------------------------- +// destructor +Chromagram :: ~Chromagram() +{ + // destroy fft plan + // fftwf_destroy_plan(p); - causes problem - why? (Andrew R) + + // deallocate memory + win = NULL; + delete [] win; + buffer = NULL; + delete [] buffer; + wbuffer = NULL; + delete [] wbuffer; + + //printf("delete chromogram\n"); +} + +//-------------------------------------------------------------------------------------- +// Initialises all framesize dependent variables. Should be called to properly initialise variables and anytime the frame size changes. +void Chromagram :: initialise(int framesize,int hsize) +{ + fsize = framesize; + hopsize = hsize; + + d_frame = new float[fsize/4]; + hop = new float[hopsize]; + + + calcrate = (hopsize*4)/fsize; + + count = 0; + + //fsize = framesize; // set frame size + + ratio = ((float) 11025) / ((float) 8192); + hamming(bsize); // define a hanning window offline +} + +//-------------------------------------------------------------------------------------- +// Processes a single frame +void Chromagram :: processframe(float frame[]) +{ + int i; + int j; + int c; + + chromaready = 0; // default case that chroma isn't ready + + // downsample frame + downsampleframe(frame); + + if (count < calcrate) + { + c = count*(fsize/4); + + j = 0; + for (i = c;i < c+(fsize/4);i++) + { + hop[i] = d_frame[j];//d_frame is downsampled + j++; + } + count++;// = count + 1; + } + + if (count == calcrate) + { + for (i=0;i < 8192-hopsize;i++) + { + buffer[i] = buffer[i+hopsize]; + } + + j = 0; + for (i=8192-hopsize;i < bsize;i++) + { + buffer[i] = hop[j]; + j++; + } + + chromacalc(buffer); + + count = 0; + } + +} +/* +// Processes a single frame +void Chromagram :: processFrame(float* frame, int length){ + if (length == 8192){ + + int i; + int j; + int c; + + chromaready = 0; // default case that chroma isn't ready + + // downsample frame + downsampleframe(frame); + + if (count < calcrate) + { + c = count*(fsize/4); + + j = 0; + for (i = c;i < c+(fsize/4);i++) + { + hop[i] = d_frame[j]; + j++; + } + count = count + 1; + } + + if (count == calcrate) + { + for (i=0;i < 8192-hopsize;i++) + { + buffer[i] = buffer[i+hopsize]; + } + + j = 0; + for (i=8192-hopsize;i < bsize;i++) + { + buffer[i] = hop[j]; + j++; + } + + chromacalc(buffer); + + count = 0; + } + } + +} +*/ + + +//-------------------------------------------------------------------------------------- +// Processes a single frame +void Chromagram :: downsampleframe(float frame[]) +{ + float filt_frame[fsize]; + + float b0,b1,b2,a1,a2; + float x_1,x_2,y_1,y_2; + + b0 = 0.2929; + b1 = 0.5858; + b2 = 0.2929; + a1 = -0.0000; + a2 = 0.1716; + + x_1 = 0; + x_2 = 0; + y_1 = 0; + y_2 = 0; + + for (int i=0;i < fsize;i++) + { + filt_frame[i] = frame[i]*b0 + x_1*b1 + x_2*b2 - y_1*a1 - y_2*a2; + + x_2 = x_1; + x_1 = frame[i]; + y_2 = y_1; + y_1 = filt_frame[i]; + } + + for (int i=0;i < (fsize/4);i++) + { + d_frame[i] = filt_frame[i*4]; + } + +} + +//-------------------------------------------------------------------------------------- +// main function to be called with 8192 sample frame at 11025 Hz +void Chromagram :: chromacalc(float frame[]) +{ + int i; + + // apply hanning window to buffer + for (i = 0; i < bsize;i++) + { + wbuffer[i] = frame[i] * win[i]; + } + + getmagspectrum(); + + generatechromagram(); + + chromaready = 1; + +// for (i = 0;i < 12;i++) +// { +// cout << chroma[i] << " "; +// } +// +// cout << endl; + + //cout << "root: " << root << " type: " << type << " features: " << features << endl; + + //cout << root << " " << quality << " " << intervals << endl; +} + +//-------------------------------------------------------------------------------------- +// creates a chromagram from the magnitude spectrum of the input signal +void Chromagram :: generatechromagram() +{ + int i; + float sum; + float notesum = 0; + float noteval; + int index; + float maxval = 0; + int searchlength; + + for (i = 0;i < 12;i++) + { + sum = 0; + + for (int oct = 1;oct <= octaves;oct++) + { + noteval = (note[i]/ratio)*((float) oct); + notesum = 0; + + for (int h = 1;h <= harmonics;h++) + { + index = round(noteval*((float) h)); + + searchlength = search*h; + + maxval = 0; + for (int n = (index-searchlength);n <= index+searchlength;n++) + { + if (mag[n] > maxval) + { + maxval = mag[n]; + } + } + + notesum = notesum+(maxval*(1/((float) h))); + } + sum = sum + notesum; + + if (oct == 1) + { + chroma_low[i] = notesum; + } + } + + chroma[i] = sum; + rawChroma[i] = sum; + + if (sum > maximumChromaValue) + maximumChromaValue = sum; + + } + + double L_One_Norm = 0; + for (i = 0;i < 12;i++){ + L_One_Norm += chroma[i]; + } + + if (L_One_Norm == 0) + L_One_Norm = 1; + + // normalise chromagram + maxval = max(chroma,12); + + maxval = L_One_Norm; + + for (i = 0;i < 12;i++) + { + chroma[i] = chroma[i] / maxval; + + } + + quantiseChromagram(); + + +} + + +void Chromagram :: quantiseChromagram(){ + for (int i = 0;i < 12;i++){ + + quantisedChromagram[i] = 0; + + if (chroma[i] > 0.05) + quantisedChromagram[i]++; + + if (chroma[i] > 0.1) + quantisedChromagram[i]++; + + if (chroma[i] > 0.2) + quantisedChromagram[i]++; + + if (chroma[i] > 0.4) + quantisedChromagram[i]++; + + } +} + +double Chromagram :: getQuantisedDistance(float secondQuantisedChroma[12]){ + double cosineDistance = 0; + double quantLengthOne = 0; + double quantLengthTwo = 0; + for (int i = 0;i < 12;i++){ + + cosineDistance += quantisedChromagram[i] * secondQuantisedChroma[i]; + + quantLengthOne += quantisedChromagram[i] *quantisedChromagram[i]; + quantLengthTwo += secondQuantisedChroma[i] * secondQuantisedChroma[i]; + + } + + cosineDistance /= sqrt(quantLengthOne * quantLengthTwo); + + return cosineDistance; + +} + + +//-------------------------------------------------------------------------------------- +// main function to be called with 8192 sample frame at 11025 Hz +void Chromagram :: hamming(int N) +{ + int n; + + // apply hanning window to buffer + for (n = 0; n < N;n++) + { + win[n] = 0.54 - 0.46*cos(2*pi*(((float) n)/((float) N))); + } +} + +//-------------------------------------------------------------------------------------- +// finds mag spectrum of input +void Chromagram :: getmagspectrum() +{ + int i = 0; + + // execute fft plan, i.e. compute fft of buffer + fftwf_execute(p); + + // compute first (N/2)+1 mag values + for (i = 0;i < (bsize/2)+1;i++) + { + mag[i] = sqrt(pow(out[i][0],2) + pow(out[i][1],2)); + mag[i] = sqrt(mag[i]); + } +} + +//-------------------------------------------------------------------------------------- +// returns max value of an array +float Chromagram :: max(float array[],int length) +{ + float max = 0; + + for (int i=0;i < length;i++) + { + if (array[i] > max) + { + max = array[i]; + } + } + + return max; +} + +//-------------------------------------------------------------------------------------- +// returns index of minimum value of array +int Chromagram :: minindex(float array[],int length) +{ + float min = 10000; + int minindex = 0; + int i; + + for (i = 0;i < length;i++) + { + if (array[i] < min) + { + min = array[i]; + minindex = i; + } + } + + return minindex; +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/chromagramm/Chromagram.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,70 @@ + + +#ifndef CHROMAGRAM_H +#define CHROMAGRAM_H + +#include "fftw3.h" + +class Chromagram +{ +public: + Chromagram(); // constructor + ~Chromagram(); // destructor + void chromacalc(float frame[]); + void initialise(int framesize,int hsize); + void processframe(float frame[]); +// void processFrame(float* frame, int length); + + float rawChroma[12]; + float chroma[12]; + float chroma_low[12]; + int chromaready; + + float maximumChromaValue; + + int quantisedChromagram[12]; + double getQuantisedDistance(float secondQuantisedChroma[12]); + +private: + void hamming(int N); + void makeprofiles(); + void getmagspectrum(); + void generatechromagram(); + + void quantiseChromagram();//follows muller's method for quantising + //taking L1 norm, normalising to that, then looking at the bins + + //float euclidean(float v1[],float v2[],int length); + float max(float array[],int length); + int minindex(float array[],int length); + void downsampleframe(float frame[]); + + int bsize; + int count; + int hopsize; + int fsize; + int calcrate; + float ratio; + + float *buffer; // audio buffer + float *wbuffer; // windowed audio buffer + float *win; // hanning window + float *mag; + float *d_frame; + float *hop; + + + float note[12]; + int harmonics; + int octaves; + int search; + + fftwf_plan p; // create fft plan + fftwf_complex *out; // to hold complex fft values + + float pi; + + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/fftw/fftw3.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,381 @@ +/* + * Copyright (c) 2003, 2007-8 Matteo Frigo + * Copyright (c) 2003, 2007-8 Massachusetts Institute of Technology + * + * The following statement of license applies *only* to this header file, + * and *not* to the other files distributed with FFTW or derived therefrom: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS + * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE + * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/***************************** NOTE TO USERS ********************************* + * + * THIS IS A HEADER FILE, NOT A MANUAL + * + * If you want to know how to use FFTW, please read the manual, + * online at http://www.fftw.org/doc/ and also included with FFTW. + * For a quick start, see the manual's tutorial section. + * + * (Reading header files to learn how to use a library is a habit + * stemming from code lacking a proper manual. Arguably, it's a + * *bad* habit in most cases, because header files can contain + * interfaces that are not part of the public, stable API.) + * + ****************************************************************************/ + +#ifndef FFTW3_H +#define FFTW3_H + +#include <stdio.h> + +#ifdef __cplusplus +extern "C" +{ +#endif /* __cplusplus */ + +/* If <complex.h> is included, use the C99 complex type. Otherwise + define a type bit-compatible with C99 complex */ +#if !defined(FFTW_NO_Complex) && defined(_Complex_I) && defined(complex) && defined(I) +# define FFTW_DEFINE_COMPLEX(R, C) typedef R _Complex C +#else +# define FFTW_DEFINE_COMPLEX(R, C) typedef R C[2] +#endif + +#define FFTW_CONCAT(prefix, name) prefix ## name +#define FFTW_MANGLE_DOUBLE(name) FFTW_CONCAT(fftw_, name) +#define FFTW_MANGLE_FLOAT(name) FFTW_CONCAT(fftwf_, name) +#define FFTW_MANGLE_LONG_DOUBLE(name) FFTW_CONCAT(fftwl_, name) + +/* IMPORTANT: for Windows compilers, you should add a line + #define FFTW_DLL + here and in kernel/ifftw.h if you are compiling/using FFTW as a + DLL, in order to do the proper importing/exporting, or + alternatively compile with -DFFTW_DLL or the equivalent + command-line flag. This is not necessary under MinGW/Cygwin, where + libtool does the imports/exports automatically. */ +#if defined(FFTW_DLL) && (defined(_WIN32) || defined(__WIN32__)) + /* annoying Windows syntax for shared-library declarations */ +# if defined(COMPILING_FFTW) /* defined in api.h when compiling FFTW */ +# define FFTW_EXTERN extern __declspec(dllexport) +# else /* user is calling FFTW; import symbol */ +# define FFTW_EXTERN extern __declspec(dllimport) +# endif +#else +# define FFTW_EXTERN extern +#endif + +enum fftw_r2r_kind_do_not_use_me { + FFTW_R2HC=0, FFTW_HC2R=1, FFTW_DHT=2, + FFTW_REDFT00=3, FFTW_REDFT01=4, FFTW_REDFT10=5, FFTW_REDFT11=6, + FFTW_RODFT00=7, FFTW_RODFT01=8, FFTW_RODFT10=9, FFTW_RODFT11=10 +}; + +struct fftw_iodim_do_not_use_me { + int n; /* dimension size */ + int is; /* input stride */ + int os; /* output stride */ +}; + +#include <stddef.h> /* for ptrdiff_t */ +struct fftw_iodim64_do_not_use_me { + ptrdiff_t n; /* dimension size */ + ptrdiff_t is; /* input stride */ + ptrdiff_t os; /* output stride */ +}; + +/* + huge second-order macro that defines prototypes for all API + functions. We expand this macro for each supported precision + + X: name-mangling macro + R: real data type + C: complex data type +*/ + +#define FFTW_DEFINE_API(X, R, C) \ + \ +FFTW_DEFINE_COMPLEX(R, C); \ + \ +typedef struct X(plan_s) *X(plan); \ + \ +typedef struct fftw_iodim_do_not_use_me X(iodim); \ +typedef struct fftw_iodim64_do_not_use_me X(iodim64); \ + \ +typedef enum fftw_r2r_kind_do_not_use_me X(r2r_kind); \ + \ +FFTW_EXTERN void X(execute)(const X(plan) p); \ + \ +FFTW_EXTERN X(plan) X(plan_dft)(int rank, const int *n, \ + C *in, C *out, int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_1d)(int n, C *in, C *out, int sign, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_2d)(int n0, int n1, \ + C *in, C *out, int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_3d)(int n0, int n1, int n2, \ + C *in, C *out, int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + int sign, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_dft)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + C *in, C *out, \ + int sign, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *ri, R *ii, R *ro, R *io, \ + unsigned flags); \ + \ +FFTW_EXTERN void X(execute_dft)(const X(plan) p, C *in, C *out); \ +FFTW_EXTERN void X(execute_split_dft)(const X(plan) p, R *ri, R *ii, \ + R *ro, R *io); \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft_r2c)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + C *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_r2c)(int rank, const int *n, \ + R *in, C *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_1d)(int n,R *in,C *out,unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_2d)(int n0, int n1, \ + R *in, C *out, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_r2c_3d)(int n0, int n1, \ + int n2, \ + R *in, C *out, unsigned flags); \ + \ + \ +FFTW_EXTERN X(plan) X(plan_many_dft_c2r)(int rank, const int *n, \ + int howmany, \ + C *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_c2r)(int rank, const int *n, \ + C *in, R *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_1d)(int n,C *in,R *out,unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_2d)(int n0, int n1, \ + C *in, R *out, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_dft_c2r_3d)(int n0, int n1, \ + int n2, \ + C *in, R *out, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_dft_r2c)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_dft_c2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft_r2c)( \ + int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru_split_dft_c2r)( \ + int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_dft_r2c)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, C *out, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_dft_c2r)(int rank, \ + const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + C *in, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft_r2c)( \ + int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, R *ro, R *io, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_guru64_split_dft_c2r)( \ + int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *ri, R *ii, R *out, \ + unsigned flags); \ + \ +FFTW_EXTERN void X(execute_dft_r2c)(const X(plan) p, R *in, C *out); \ +FFTW_EXTERN void X(execute_dft_c2r)(const X(plan) p, C *in, R *out); \ + \ +FFTW_EXTERN void X(execute_split_dft_r2c)(const X(plan) p, \ + R *in, R *ro, R *io); \ +FFTW_EXTERN void X(execute_split_dft_c2r)(const X(plan) p, \ + R *ri, R *ii, R *out); \ + \ +FFTW_EXTERN X(plan) X(plan_many_r2r)(int rank, const int *n, \ + int howmany, \ + R *in, const int *inembed, \ + int istride, int idist, \ + R *out, const int *onembed, \ + int ostride, int odist, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_r2r)(int rank, const int *n, R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_r2r_1d)(int n, R *in, R *out, \ + X(r2r_kind) kind, unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_r2r_2d)(int n0, int n1, R *in, R *out, \ + X(r2r_kind) kind0, X(r2r_kind) kind1, \ + unsigned flags); \ +FFTW_EXTERN X(plan) X(plan_r2r_3d)(int n0, int n1, int n2, \ + R *in, R *out, X(r2r_kind) kind0, \ + X(r2r_kind) kind1, X(r2r_kind) kind2, \ + unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru_r2r)(int rank, const X(iodim) *dims, \ + int howmany_rank, \ + const X(iodim) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN X(plan) X(plan_guru64_r2r)(int rank, const X(iodim64) *dims, \ + int howmany_rank, \ + const X(iodim64) *howmany_dims, \ + R *in, R *out, \ + const X(r2r_kind) *kind, unsigned flags); \ + \ +FFTW_EXTERN void X(execute_r2r)(const X(plan) p, R *in, R *out); \ + \ +FFTW_EXTERN void X(destroy_plan)(X(plan) p); \ +FFTW_EXTERN void X(forget_wisdom)(void); \ +FFTW_EXTERN void X(cleanup)(void); \ + \ +FFTW_EXTERN void X(set_timelimit)(double); \ + \ +FFTW_EXTERN void X(plan_with_nthreads)(int nthreads); \ +FFTW_EXTERN int X(init_threads)(void); \ +FFTW_EXTERN void X(cleanup_threads)(void); \ + \ +FFTW_EXTERN void X(export_wisdom_to_file)(FILE *output_file); \ +FFTW_EXTERN char *X(export_wisdom_to_string)(void); \ +FFTW_EXTERN void X(export_wisdom)(void (*write_char)(char c, void *), \ + void *data); \ +FFTW_EXTERN int X(import_system_wisdom)(void); \ +FFTW_EXTERN int X(import_wisdom_from_file)(FILE *input_file); \ +FFTW_EXTERN int X(import_wisdom_from_string)(const char *input_string); \ +FFTW_EXTERN int X(import_wisdom)(int (*read_char)(void *), void *data); \ + \ +FFTW_EXTERN void X(fprint_plan)(const X(plan) p, FILE *output_file); \ +FFTW_EXTERN void X(print_plan)(const X(plan) p); \ + \ +FFTW_EXTERN void *X(malloc)(size_t n); \ +FFTW_EXTERN void X(free)(void *p); \ + \ +FFTW_EXTERN void X(flops)(const X(plan) p, \ + double *add, double *mul, double *fmas); \ +FFTW_EXTERN double X(estimate_cost)(const X(plan) p); \ + \ +FFTW_EXTERN const char X(version)[]; \ +FFTW_EXTERN const char X(cc)[]; \ +FFTW_EXTERN const char X(codelet_optim)[]; + + +/* end of FFTW_DEFINE_API macro */ + +FFTW_DEFINE_API(FFTW_MANGLE_DOUBLE, double, fftw_complex) +FFTW_DEFINE_API(FFTW_MANGLE_FLOAT, float, fftwf_complex) +FFTW_DEFINE_API(FFTW_MANGLE_LONG_DOUBLE, long double, fftwl_complex) + +#define FFTW_FORWARD (-1) +#define FFTW_BACKWARD (+1) + +#define FFTW_NO_TIMELIMIT (-1.0) + +/* documented flags */ +#define FFTW_MEASURE (0U) +#define FFTW_DESTROY_INPUT (1U << 0) +#define FFTW_UNALIGNED (1U << 1) +#define FFTW_CONSERVE_MEMORY (1U << 2) +#define FFTW_EXHAUSTIVE (1U << 3) /* NO_EXHAUSTIVE is default */ +#define FFTW_PRESERVE_INPUT (1U << 4) /* cancels FFTW_DESTROY_INPUT */ +#define FFTW_PATIENT (1U << 5) /* IMPATIENT is default */ +#define FFTW_ESTIMATE (1U << 6) + +/* undocumented beyond-guru flags */ +#define FFTW_ESTIMATE_PATIENT (1U << 7) +#define FFTW_BELIEVE_PCOST (1U << 8) +#define FFTW_NO_DFT_R2HC (1U << 9) +#define FFTW_NO_NONTHREADED (1U << 10) +#define FFTW_NO_BUFFERING (1U << 11) +#define FFTW_NO_INDIRECT_OP (1U << 12) +#define FFTW_ALLOW_LARGE_GENERIC (1U << 13) /* NO_LARGE_GENERIC is default */ +#define FFTW_NO_RANK_SPLITS (1U << 14) +#define FFTW_NO_VRANK_SPLITS (1U << 15) +#define FFTW_NO_VRECURSE (1U << 16) +#define FFTW_NO_SIMD (1U << 17) +#define FFTW_NO_SLOW (1U << 18) +#define FFTW_NO_FIXED_RADIX_LARGE_N (1U << 19) +#define FFTW_ALLOW_PRUNING (1U << 20) +#define FFTW_WISDOM_ONLY (1U << 21) + +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + +#endif /* FFTW3_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/AubioOnsetDetector.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,410 @@ +/* + * AubioOnsetDetector.cpp + * aubioonset~ + * + * Created by Andrew Robertson on 13/08/2010. + * Copyright 2010 __MyCompanyName__. All rights reserved. + * + */ + +#include "AubioOnsetDetector.h" + +AubioOnsetDetector :: AubioOnsetDetector(){ + buffersize = 1024; + hopsize = 512; + //aubio related setup + o = new_aubio_onsetdetection(aubio_onset_complex, buffersize, 1);//initially in complex mode + pv = (aubio_pvoc_t *)new_aubio_pvoc(buffersize, hopsize, 1); + parms = new_aubio_peakpicker(threshold); + vec = (fvec_t *)new_fvec(hopsize,1); + + threshold = 1; + threshold2 = -70.; + + maximumDetectionValue = 10.0; + resetValues(); + thresholdRelativeToMedian = 1.1; + cutoffForRepeatOnsetsMillis = 100; + medianSpeed = 15; + pos = 0; + + detectionTriggerRatio = 0.5f; + detectionTriggerThreshold = 10; + + + +} + +AubioOnsetDetector :: ~AubioOnsetDetector(){ + aubio_onsetdetection_free (o); + del_aubio_pvoc(pv); + del_aubio_peakpicker(parms); + del_fvec(vec); + aubio_cleanup(); +} + +void AubioOnsetDetector :: resetValues(){ + printf("Aubio Onset RESET VALUES\n"); + + rawDetectionValue = 1; + peakPickedDetectionValue = 1; + medianDetectionValue = 10.; + lastMedianOnsetFrame = 0; + currentFrame = 0; + aubioLongTermAverage = 10.; + lastDfValue = 0; + bestSlopeValue = 0; + recentValueIndex = 0; + lastSlopeOnsetFrame = 0; + bestSlopeMedian = 10; + slopeFallenBelowMedian = true; + maximumDetectionValue = 10.0; + + for (int i = 0;i< numberOfDetectionValues;i++) + recentRawDetectionValues[i] = 1; +} + + +void AubioOnsetDetector :: initialise(){ + //reinitialises our object + o = new_aubio_onsetdetection(aubio_onset_complex, buffersize, 1);//initially in complex mode + pv = (aubio_pvoc_t *)new_aubio_pvoc(buffersize, hopsize, 1); + parms = new_aubio_peakpicker(threshold); + vec = (fvec_t *)new_fvec(hopsize,1); + pos = 0; + fvec_write_sample(vec, 0.234, 0, pos); + fftgrain = (cvec_t *)new_cvec(buffersize,1); + onset = (fvec_t *)new_fvec(1,1); + } + + + +bool AubioOnsetDetector :: processframe(double* frame, const int& n){ + bool newFrameResult = false; + //Paul Brossier's aubioonsetclass~ code ported from Pd + int j,isonset; + for (j=0;j<n;j++) { + + // write input to datanew + fvec_write_sample(vec, frame[j], 0, pos);//vec->data[0][pos] = frame[j] + //time for fft + + if (pos == hopsize-1) { //hopsize is 512 + newFrameResult = true; + aubioOnsetFound = false; + + // block loop + aubio_pvoc_do (pv,vec, fftgrain); + + fftgrain->norm[0][0] = fabs(fftgrain->norm[0][0]); + //added hack to solve bug that norm[0][0] is negative sometimes. + + aubio_onsetdetection(o, fftgrain, onset); + rawDetectionValue = onset->data[0][0]; + //Paul Brossier's method to return value of peak picking process + + + postProcessing(); + + // smpl_t my_sample_value; + peakPickedDetectionValue = aubio_peakpick_pimrt_getval(parms); + //peakPickedDetectionValue = my_sample_value; + + isonset = aubio_peakpick_pimrt(onset,parms); + if (isonset) { + // test for silence + if (aubio_silence_detection(vec, threshold2)==1){ + isonset=0; + } + else{ + // outlet_bang(x->bangoutlet); + aubioOnsetFound = true; + } + }//end if (isonset) + + + + // end of block loop + pos = -1; // so it will be zero next j loop + } + pos++; + + }//end for j +//end of Paul's code + +return newFrameResult; + +} + + +bool AubioOnsetDetector :: processframe(float* frame, const int& n){ + bool newFrameResult = false; + //Paul Brossier's aubioonsetclass~ code ported from Pd + int j,isonset; + for (j=0;j<n;j++) { + + // write input to datanew + fvec_write_sample(vec, frame[j], 0, pos);//vec->data[0][pos] = frame[j] + //time for fft + + if (pos == hopsize-1) { //hopsize is 512 + newFrameResult = true; + aubioOnsetFound = false; + + // block loop + aubio_pvoc_do (pv,vec, fftgrain); + + fftgrain->norm[0][0] = fabs(fftgrain->norm[0][0]); + //added hack to solve bug that norm[0][0] is negative sometimes. + + aubio_onsetdetection(o, fftgrain, onset); + rawDetectionValue = onset->data[0][0]; + //Paul Brossier's method to return value of peak picking process + + + postProcessing(); + + // smpl_t my_sample_value; + //peakPickedDetectionValue = aubio_peakpick_pimrt_getval(parms); + //peakPickedDetectionValue = my_sample_value; + + //Paul Brossier's onset detection method + isonset = aubio_peakpick_pimrt(onset,parms); + if (isonset) { + // test for silence + if (aubio_silence_detection(vec, threshold2)==1){ + isonset=0; + } + else{ + // outlet_bang(x->bangoutlet); + aubioOnsetFound = true; + } + }//end if (isonset) + + + + // end of block loop + pos = -1; // so it will be zero next j loop + } + pos++; + + }//end for j + //end of Paul's code + + return newFrameResult; + +} + + + + void AubioOnsetDetector :: postProcessing(){ + //anrMedia processed has conditions below + anrMedianProcessedOnsetFound = checkForMedianOnset(rawDetectionValue); + + //the slope idea is we need both a high rise and a high / steep slope and we + //look for both of these + bestSlopeValue = getBestSlopeValue(rawDetectionValue); + anrBestSlopeOnset = checkForSlopeOnset(bestSlopeValue); + } + +bool AubioOnsetDetector :: checkForMedianOnset(const float& dfvalue){ + bool onsetDetected = false; + //check for onset relative to our rising and falling median threshold + + if (dfvalue > medianDetectionValue * thresholdRelativeToMedian && + dfvalue > aubioLongTermAverage && + //lastDfValue < medianDetectionValue && + 1000*framesToSeconds(currentFrame - lastMedianOnsetFrame) > cutoffForRepeatOnsetsMillis){ + + onsetDetected = true; + lastMedianOnsetFrame = currentFrame; + //printf("frame diff between onsets %6.1f", (1000*framesToSeconds(currentFrame - lastMedianOnsetFrame)) ); + } + +// aubioLongTermAverage *= 0.995; + aubioLongTermAverage += 0.01*(dfvalue - aubioLongTermAverage); + + if (dfvalue > medianDetectionValue) + medianDetectionValue = dfvalue; + else + medianDetectionValue += 0.01*medianSpeed*(dfvalue - medianDetectionValue); + + if (dfvalue > maximumDetectionValue){ + maximumDetectionValue = dfvalue; + printf("DF value causes new max %f\n", maximumDetectionValue); + } + + + currentFrame++; + lastDfValue = dfvalue; + + +return onsetDetected; +} + + + + double AubioOnsetDetector::getBestSlopeValue(const float& dfvalue){ + //the idea is we want a high slope + recentRawDetectionValues[recentValueIndex] = dfvalue; + double bestValue = 0; + for (int i = 1;i < numberOfDetectionValues;i++){ + double angle = 0; + int otherIndex = (recentValueIndex - i + numberOfDetectionValues)%numberOfDetectionValues; + double testValue = 0; + if (otherIndex > 0 && recentRawDetectionValues[otherIndex] > 0){ + angle = atan((float)(i * dfvalue)/ (numberOfDetectionValues*(dfvalue-recentRawDetectionValues[otherIndex])) ); + testValue = (dfvalue - recentRawDetectionValues[otherIndex]) * cos(angle); + } + + if (testValue > bestValue) + bestValue = testValue; + } + + recentValueIndex++; + + if (recentValueIndex == numberOfDetectionValues) + recentValueIndex = 0; + + + return bestValue; + + } + + + + + bool AubioOnsetDetector :: checkForSlopeOnset(const float& bestValue){ + bool onsetDetected = false; + //check for onset relative to our processed slope function + //a mix between increase in value and the gradient of that increase + + if (bestValue > bestSlopeMedian * thresholdRelativeToMedian && //better than recent average + 1000*framesToSeconds(currentFrame - lastSlopeOnsetFrame) > cutoffForRepeatOnsetsMillis //after cutoff time + && slopeFallenBelowMedian // has had onset and fall away again + && bestValue > detectionTriggerThreshold * detectionTriggerRatio //longer term ratio of winning onsets + ){ + // printf("frame diff between onsets %6.1f", (1000*framesToSeconds(currentFrame - lastMedianOnsetFrame)) ); + onsetDetected = true; + lastSlopeOnsetFrame = currentFrame; + slopeFallenBelowMedian = false; + + updateDetectionTriggerThreshold(bestValue); + } + + + if (bestValue > bestSlopeMedian){ + bestSlopeMedian += (bestValue - bestSlopeMedian)*0.04;//was 1.1 + } + else{ + bestSlopeMedian *= 0.99; + slopeFallenBelowMedian = true;; + } + + //bestSlopeMedian += 0.02* (bestValue - bestSlopeMedian); + + + return onsetDetected; + } + + + void AubioOnsetDetector::updateDetectionTriggerThreshold(const float& val){ + float detectionAdaptSpeed = 0.05;//moving average, roughly last twenty onsets + detectionTriggerThreshold *= 1- detectionAdaptSpeed; + detectionTriggerThreshold += (val * detectionAdaptSpeed); + } + + +double AubioOnsetDetector::framesToSeconds(const float& frames){ + double seconds = frames * buffersize / 44100.; + return seconds; +} +/* +double AubioOnsetDetector::framesToMillis(const float& frames){ + double seconds = frames * buffersize * 1000.0 / 44100.; + return seconds; +} +*/ +float AubioOnsetDetector :: getRawDetectionFrame(){ +return rawDetectionValue; +} + +float AubioOnsetDetector :: getPeakPickedDetectionFrame(){ +return peakPickedDetectionValue; +} + + +void AubioOnsetDetector :: onsetclass_energy(){ + //aubio_onsetdetection_type + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_energy, buffersize, 1); +} + +void AubioOnsetDetector :: onsetclass_hfc(){ +/** High Frequency Content onset detection function + + This method computes the High Frequency Content (HFC) of the input spectral + frame. The resulting function is efficient at detecting percussive onsets. + + Paul Masri. Computer modeling of Sound for Transformation and Synthesis of + Musical Signal. PhD dissertation, University of Bristol, UK, 1996.*/ + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_hfc, buffersize, 1); +} + + +void AubioOnsetDetector :: onsetclass_complex(){ + //aubio_onsetdetection_type + //Complex Domain Method onset detection function + //Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain + //onset detection for musical signals. In Proceedings of the Digital Audio + //Effects Conference, DAFx-03, pages 90-93, London, UK, 2003. + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_complex, buffersize, 1); +} + +void AubioOnsetDetector :: onsetclass_phase(){ +/** Phase Based Method onset detection function + + Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset + detection for music signals. In Proceedings of the IEEE International + Conference on Acoustics Speech and Signal Processing, pages 441­444, + Hong-Kong, 2003.*/ + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_phase, buffersize, 1); + +} + +void AubioOnsetDetector :: onsetclass_specdiff(){ + /* Spectral difference method onset detection function + Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to + rhythm analysis. In IEEE International Conference on Multimedia and Expo + (ICME 2001), pages 881­884, Tokyo, Japan, August 2001. + */ + //aubio_onsetdetection_type + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_specdiff, buffersize, 1); +} + +void AubioOnsetDetector :: onsetclass_kl(){ + /** Kullback-Liebler onset detection function + + Stephen Hainsworth and Malcom Macleod. Onset detection in music audio + signals. In Proceedings of the International Computer Music Conference + (ICMC), Singapore, 2003. + */ + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_kl, buffersize, 1); +} + +void AubioOnsetDetector :: onsetclass_mkl(){ + + /** Modified Kullback-Liebler onset detection function + + Paul Brossier, ``Automatic annotation of musical audio for interactive + systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital + music, Queen Mary University of London, London, UK, 2003.*/ + aubio_onsetdetection_free (o); + o = new_aubio_onsetdetection(aubio_onset_hfc, buffersize, 1); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/AubioOnsetDetector.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,80 @@ + +#ifndef AUBIOONSETDETECTOR_H +#define AUBIOONSETDETECTOR_H + +#include "aubio.h" + +class AubioOnsetDetector +{ +public: + AubioOnsetDetector(); + ~AubioOnsetDetector(); + void initialise(); + void resetValues(); + + bool processframe(double* frame, const int& n); + bool processframe(float* frame, const int& n); + + void onsetclass_energy(); + void onsetclass_complex(); + void onsetclass_specdiff(); + void onsetclass_kl(); + void onsetclass_mkl(); + void onsetclass_hfc(); + void onsetclass_phase(); + + bool checkForMedianOnset(const float& dfvalue); + void postProcessing(); + + float getRawDetectionFrame(); + float getPeakPickedDetectionFrame(); + double framesToSeconds(const float& frames); +// double framesToMillis(const float& frames); +// boolean getIsOnset(); + + + aubio_onsetdetection_t *o; + aubio_pvoc_t *pv; + aubio_pickpeak_t *parms; + + + fvec_t *vec; + fvec_t *onset; + cvec_t *fftgrain;//complex vector of buffersize, 1 + + bool aubioOnsetFound;//method used by Paul Brossier + //see relevant papers - eg fast transients 2005 + int buffersize, hopsize, pos; + float threshold, threshold2; + float rawDetectionValue, peakPickedDetectionValue; + + static const int numberOfDetectionValues = 16; + float recentRawDetectionValues[numberOfDetectionValues]; + + int recentValueIndex; + + float medianDetectionValue, aubioLongTermAverage ; + bool anrMedianProcessedOnsetFound;//simple median method by Andrew Robertson + //requires a fast rise, slower fall + long lastMedianOnsetFrame, currentFrame; + float thresholdRelativeToMedian; + long cutoffForRepeatOnsetsMillis; + float medianSpeed; + float lastDfValue; + float bestSlopeValue; + double getBestSlopeValue(const float& dfvalue); + double bestSlopeMedian; + bool anrBestSlopeOnset; + long lastSlopeOnsetFrame; + bool slopeFallenBelowMedian; + bool checkForSlopeOnset(const float& bestValue); + + void updateDetectionTriggerThreshold(const float& val); + + float detectionTriggerThreshold, detectionTriggerRatio; + float maximumDetectionValue; + + +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/AubioPitch.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,154 @@ +/* + * AubioPitch.cpp + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 24/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "AubioPitch.h" + + + +//HERE I'm using doPitchDetection as it avoids the buffering problem +//I just fill the buffer with what samples I want and get pitch returned. + + +AubioPitch::AubioPitch(){ + bufsize = 4096; + hopsize = bufsize / 2; + pitch = 0.0; + + aubio_pitchdetection_type type_pitch = aubio_pitch_yinfft;// now changed + aubio_pitchdetection_mode mode_pitch = aubio_pitchm_freq; +// bufsize*4 below + pitchDetect = new_aubio_pitchdetection(bufsize, hopsize, 1, 44100., type_pitch, mode_pitch); + + aubio_pitchdetection_set_yinthresh(pitchDetect, 0.85); + + vec = (fvec_t *)new_fvec(hopsize,1);//anr changed from hopsize + + pos = 0; +} + +AubioPitch::~AubioPitch(){ + del_aubio_pitchdetection(pitchDetect); + del_fvec(vec); + aubio_cleanup(); + //delk fvec + +} + +bool AubioPitch::processFrame(float* frame, int size){// + //note this no longer called + int j; + bool pitchDetected = false; + //smpl_t pitch; + + for (j=0;j<size;j++) { + + fvec_write_sample(vec, frame[j], 0, pos); + + if (pos == hopsize-1) { //anr recent change from hopsize + // block loop / + + pitch = aubio_pitchdetection(pitchDetect, vec); + pitchDetected = true; + printf("PITCH IS %f\n", pitch); + + // printf("Pitch detected %f\n", pitch); +// outlet_float(x->pitchOutlet, pitch); + + // end of block loop + pos = -1; // so it will be zero next j loop // + } + pos++; + + } + return pitchDetected; + +} + +//anr idea of adding to buffer +void AubioPitch::addToBuffer(float* tmpFrame, const int& n){ + for (int j=0;j < n;j++) { + fvec_write_sample(vec, tmpFrame[j], 0, pos); + + if (pos == hopsize - 1){ + //pitch = aubio_pitchdetection(x->o,x->vec); + //outlet_float(x->pitchOutlet, pitch); + + pitch = aubio_pitchdetection(pitchDetect, vec); + pos = -1; + } + + pos++; + } +} + +float AubioPitch::getPitch(){ +//float newPitch = aubio_pitchdetection(pitchDetect, vec); +// return newPitch; + return pitch; +} + +//this function is more useful here +//can process a frame - by converting it into an fvec_t type used by aubio +//but since only do this once, better for our purposes than the more iterative method above +//we just store the float frames and when needed, call this for our pitch calculation on the whole +//buffer - checking that length below is in fact bufsize + +float AubioPitch::doPitchDetection(float* frame, const int& length){ + //fn to do pitch detection without all the buffering etc + float newPitch = -1.0; + if (length == bufsize){ + fvec_t* tmpVec; + tmpVec = new_fvec(bufsize,1); + for (int j =0;j < length;j++){ + fvec_write_sample(tmpVec, frame[j], 0, j); + // printf("vec[%i] = %.3f\n", j, frame[j]); + } + newPitch = aubio_pitchdetection(pitchDetect, tmpVec); + // printf("NEW PITCH FOUND %f\n", newPitch); + } + return newPitch; +} + + +//float AubioPitch::getPitchDetectedFromBuffer(float* frame, const int& length){ + +// smpl_t pitch = 0.; +/* fvec_t * buf; + for (int i = 0;i < length;i++){ + buf[i] = frame[i]; + } +*/ + +/* if (length == bufsize){ + pitch = aubio_pitchyinfft_detect(pitchDetect->yinfft, buf, pitchDetect->yinthres); + + if (pitch > 0){ + pitch = pitchDetect->srate/(pitch + 0.); + } else { + pitch = 0.; + } + + }//end if right size + */ +// return pitch; + +//} + + + + + + +/*This is the fvec_t defn from aubio: + AUBIO f_vec + struct _fvec_t { + ba_uint_t length; /**< length of buffer + ba_uint_t channels; /**< number of channels + smpl_t **data; /**< data array of size [length] * [channels] + */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/AubioPitch.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,46 @@ +/* + * AubioPitch.h + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 24/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + + +#ifndef AUBIO_PITCH_H +#define AUBIO_PITCH_H + +#include "ofMain.h" +#include "aubio.h" + +class AubioPitch { +public: + AubioPitch(); + ~AubioPitch(); + + bool processFrame(float* frame, int size); + + int bufsize, hopsize; + + aubio_pitchdetection_type type_pitch; + aubio_pitchdetection_mode mode_pitch; + + + float threshold; + + smpl_t pitch; + + aubio_pitchdetection_t *pitchDetect; + fvec_t *vec; + int pos; + + float doPitchDetection(float* frame, const int& length); + + float getPitch(); + void addToBuffer(float* tmpFrame, const int& n); + + //float getPitchDetectedFromBuffer(float* frame, const int& length); + +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/ChromaOnset.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,146 @@ +/* + * ChromaOnset.cpp + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 17/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "ChromaOnset.h" + +//stores the information about our onset event +//when it happened +//what the chromagram was immeditaely after +//what the pitch was using AubioPitch class + +//FrameHolder holds the audio samples needed to do the harmonic analysis after the fact + +ChromaOnset::ChromaOnset(){ + frameTime = 0; + millisTime = 0; + chromaCalculated = false; + chromaSize = 2048; + + cgramPtr = new Chromagram(); + cgramPtr->initialise(512, chromaSize); + + onsetIndex = 0; + + matched = false; + //we also store an aubio pitch result - using a Frameholder to hold the frames we need to calculate this on + aubioPitch = 0; + aubioPitchFound = false; + + pitchFrameCounter = 0;//counts til time to do pitch detection + + +// aubioPitchDetector = new AubioPitch(); + +} + +void ChromaOnset::deleteChromagram(){ + delete cgramPtr; + //printf("chromagram deleted\n"); +} + + +bool ChromaOnset::processFrame(float* frame, const int& length){ + bool newlyCalculated = false; + if (chromaCalculated == false){ + + cgramPtr->processframe(frame); + + if (cgramPtr->chromaready){ + + float tmpMax = max(cgramPtr->maximumChromaValue, 1.0f); + + for (int i = 0;i < 12;i++){ + chromaValues.push_back(cgramPtr->rawChroma[i]/tmpMax); + quantisedChromaValues.push_back(cgramPtr->quantisedChromagram[i]); + // printf("chroma [%i] %f max %f quantised %i\n", i, cgramPtr->rawChroma[i], cgramPtr->chroma[i], cgramPtr->quantisedChromagram[i] ); + } + chromaCalculated = true; + newlyCalculated = true; + //this would do chord detection + // chord.C_Detect(chromoGramm.chroma,chromoGramm.chroma_low); + // rootChord[chromaIndex] = chord.root; + + } + + } + + return newlyCalculated; +} + +double ChromaOnset::timeDistanceMillis(const ChromaOnset& secondChromaOnset){ + + return (abs(secondChromaOnset.millisTime - millisTime)); +} + +double ChromaOnset::pitchDistance(const ChromaOnset& secondChromaOnset){ + + return (abs(secondChromaOnset.aubioPitch - aubioPitch)); +} + +double ChromaOnset::getQuantisedDistance(ChromaOnset& secondChromaOnset){ + + return getChromaQuantisedDistance(&secondChromaOnset.quantisedChromaValues[0]); + +} + +double ChromaOnset::getChromaQuantisedDistance(float* quantisedChromagramTwo){ + + double cosineDistance = 0; + double quantLengthOne = 0; + double quantLengthTwo = 0; + for (int i = 0;i < 12;i++){ + + cosineDistance += quantisedChromaValues[i] * quantisedChromagramTwo[i]; + + quantLengthOne += quantisedChromaValues[i] * quantisedChromaValues[i]; + quantLengthTwo += quantisedChromagramTwo[i] * quantisedChromagramTwo[i]; + + } + + if (quantLengthOne > 0 && quantLengthTwo > 0) + cosineDistance /= sqrt(quantLengthOne * quantLengthTwo); + else + cosineDistance = 0; + + return cosineDistance; + + +} + +double ChromaOnset::chromaDotProductDistance(const ChromaOnset& secondChromaOnset){ + double dotProductSum = 0; + double chromaOneSum = 0; + double chromaTwoSum = 0; + if (chromaValues.size() == 12 && secondChromaOnset.chromaValues.size() == 12){ + for (int i = 0;i < 12;i++){ + dotProductSum += chromaValues[i]*secondChromaOnset.chromaValues[i]; + chromaOneSum += chromaValues[i]*chromaValues[i]; + chromaTwoSum += secondChromaOnset.chromaValues[i]*secondChromaOnset.chromaValues[i]; + } + chromaOneSum = sqrt(chromaOneSum); + chromaTwoSum = sqrt(chromaTwoSum); + if (chromaOneSum > 0 && chromaTwoSum > 0) + dotProductSum /= (chromaOneSum*chromaTwoSum); + else + dotProductSum = 0; + } + return (dotProductSum); +} + +void ChromaOnset::printInfo(){ + + printf("ONSET : frametime %i, millis %f pitch %f\n", frameTime, millisTime, aubioPitch); + printf("chroma: "); + + for(int i = 0;i < chromaValues.size();i++) + printf("[%i] %1.3f, ", i, chromaValues[i]); + + printf(".\n"); + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/ChromaOnset.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,77 @@ +/* + * ChromaOnset.h + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 17/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#ifndef CHROMA_ONSET_H +#define CHROMA_ONSET_H + +#include "ofMain.h" +#include "chromaGram.h" +//#include "AubioPitch.h" +#include "FrameHolder.h" + +/* +//could switch to a struct to hold this? + + struct OnsetEvent{ + double millisTime; + int frameTime; + + bool chromaCalculated; + float chromaValues[12]; + + bool aubioPitchFound; + float aubioPitch; +}; +*/ + +class ChromaOnset { + public: + ChromaOnset(); + + double millisTime; + int frameTime; + //chromagram chroma; + bool chromaCalculated; + int chromaSize; + int pitchFrameCounter; + + //move chromagram out of this class + //Chromagram cgram; + + typedef std::vector<float> FloatVector; + FloatVector chromaValues; + FloatVector quantisedChromaValues; + + double getQuantisedDistance(ChromaOnset& secondChromaOnset); + double getChromaQuantisedDistance(float* quantisedChromagramTwo); + //also do pitch detection using this class + //AubioPitch *aubioPitchDetector; + bool aubioPitchFound; + float aubioPitch; + + bool matched;//just for drawing + + + bool processFrame(float* frame, const int& length); +// void calculateChroma(float* frame, const int& length); + + double timeDistanceMillis(const ChromaOnset& secondChromaOnset); + double pitchDistance(const ChromaOnset& secondChromaOnset); + double chromaDotProductDistance(const ChromaOnset& secondChromaOnset); + + + Chromagram* cgramPtr; + void deleteChromagram(); + + FrameHolder onsetFrame; + + int onsetIndex;//in terms of our onset detection fn - ofxAubioOnsetDetector + void printInfo(); +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/FrameHolder.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,62 @@ +/* + * FrameHolder.cpp + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 25/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "FrameHolder.h" + +FrameHolder::FrameHolder(){ + sizeOfFrame = 0; + sizeOfFvec = 0; + frame.reserve(4096); +// buffersize = 8192; + frameCounter = 0; +// vec = (fvec_t *)new_fvec(buffersize,1); + //printf("initialise frameholder\n"); +} + + +void FrameHolder::deleteFrame(){ + frame.clear(); + //printf("clear frame\n"); +} + + +void FrameHolder::addToFrame(float* newAudio, const int& length){ + for (int i = 0;i < length;i++){ + // printf("new audio %i is %f\n", i, newAudio[i]); + frame.push_back(newAudio[i]); + } + + sizeOfFrame = frame.size(); + //printf("framesize %i\n", sizeOfFrame); +} + +bool FrameHolder::sizeEquals(const int& length){ + if (sizeOfFrame == length) + return true; + else + return false; +} +/* +void FrameHolder::addToFvec(float* newAudio, const int& length){ + //my way to write to fvec - hope it works! + for (int i =;i < length;i++) + vec->data[i+sizeOfFvec] = newAudio[i]; + + sizeOfFvec += length; + +// fvec_write_sample(vec, frame[j], 0, pos); +} + +void FrameHolder::addToFvec(float* newAudio, const int& length){ + for (int i = 0;i < length;i++) + frame.push_back(newAudio[i]); + + size = frame.size(); +} +*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/FrameHolder.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,44 @@ +/* + * FrameHolder.h + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 25/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + + +#ifndef FRAME_HOLDER_H +#define FRAME_HOLDER_H + +#include "ofMain.h" +//#include "chromaGram.h" +//#include "AubioPitch.h" +//#include "aubio.h" + +class FrameHolder { +public: + FrameHolder(); + + int sizeOfFrame, sizeOfFvec; + std::vector<float> frame; + + void deleteFrame(); + void addToFrame(float* newAudio, const int& length); + + bool sizeEquals(const int& length); + + int frameCounter; + //_fvec_t aubioFvec; +// fvec_t *vec; + + /* + struct _fvec_t { + ba_uint_t length; /**< length of buffer + ba_uint_t channels; /**< number of channels + smpl_t **data; /**< data array of size [length] * [channels] + */ + +}; +#endif + \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/PreciseOnsetLocator.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,145 @@ +/* + * PreciseOnsetLocator.cpp + * peakOnsetDetector + * + * Created by Andrew on 21/09/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "PreciseOnsetLocator.h" + +PreciseOnsetLocator::PreciseOnsetLocator(){ + setup(512); + +} + +PreciseOnsetLocator::~PreciseOnsetLocator(){ + onsetSamples.clear(); + recentBufferSamples.clear(); +} + + +void PreciseOnsetLocator::setup(const int& size){ + onsetSamples.clear(); + recentBufferSamples.clear(); + bufferSize = size; + onsetSamples.assign(bufferSize, 0.0); + recentBufferSamples.assign(bufferSize, 0.0); + printInfo = false; +} + +void PreciseOnsetLocator::storeSamples(double* newSamples){ + + for (int i = 0;i < bufferSize;i++) + recentBufferSamples[i] = newSamples[i]; + +} + + +void PreciseOnsetLocator::storeSamples(float* newSamples){ + + for (int i = 0;i < bufferSize;i++) + recentBufferSamples[i] = newSamples[i]; + +} + + +int PreciseOnsetLocator::findExactOnset(double* frame, const int& framesize){ + //store the samples - mainly for viewing actually + if (framesize == bufferSize){ + onsetSamples.clear(); + for (int i = 0; i < bufferSize;i++) { + onsetSamples.push_back(frame[i]); + } + + if (recentBufferSamples.size() == 0) + printf("Bad size onset vector\n"); + + double energySum = 0; + double lastEnergySum, hopsizeLastEnergySum; + double energyDifference; + int bestEnergyIndex = 0; + double bestEnergyDifference = 0; + int endIndex = bufferSize; + int hopSize; + + printInfo = false; + + for (int resolution = bufferSize/2;resolution > 1;resolution/=2){ + if (printInfo) + printf("resolution %i\n", resolution); + + bestEnergyDifference = 0; + // printf("previous energy %f", lastEnergySum); + //initialise last energySum + hopSize = resolution/2; + + + lastEnergySum = getLastEnergySum(bestEnergyIndex, resolution); + hopsizeLastEnergySum = getLastEnergySum(bestEnergyIndex + hopSize, resolution); + + for (int startIndex = bestEnergyIndex;startIndex + resolution <= endIndex;startIndex += hopSize){ + if (printInfo) + printf("index %i last energy %f hop energy %f ", startIndex, lastEnergySum, hopsizeLastEnergySum); + + //sum the energy for this new frame + energySum = 0; + for (int i = 0;i < resolution;i++){ + energySum += onsetSamples[startIndex + i] * onsetSamples[startIndex + i]; + } + if (printInfo) + printf("energysum %f\n", energySum); + //check if new max difference + energyDifference = energySum - lastEnergySum; + if (energyDifference > bestEnergyDifference){ + bestEnergyDifference = energyDifference; + bestEnergyIndex = startIndex; + } + + //store the values for checking in two loops time (because proceeding at resolution/2 each step) + //eg 0_to_128 compared to -128_to_0, 64_to_196 compared to -64_to_64, then 128_256 compared with 0_to_128, + lastEnergySum = hopsizeLastEnergySum;// energySum; + hopsizeLastEnergySum = energySum; + + } + if (printInfo) + printf("winning index is %i\n", bestEnergyIndex); + endIndex = bestEnergyIndex + resolution; + + } + if (printInfo) + printf("TOTAL WINNER %i\n", bestEnergyIndex); + return bestEnergyIndex; + }else{ + printf("NOt same buffersize!\n"); + return 0; + } + +} + + + +int PreciseOnsetLocator::findExactOnset(float* frame, const int& framesize){ + + double tempOnsetSamples[framesize]; + for (int i = 0;i < framesize;i++) + tempOnsetSamples[i] = frame[i]; + + return findExactOnset(&tempOnsetSamples[0], framesize); +} + + +double PreciseOnsetLocator::getLastEnergySum(const int& startIndex, const int& vectorSize){ + double lastEnergySum = 0; + + for (int i = startIndex - vectorSize;i < startIndex;i++){ + if (i > 0) + lastEnergySum += onsetSamples[i] * onsetSamples[i]; + else { + lastEnergySum += recentBufferSamples[bufferSize + i] * recentBufferSamples[bufferSize + i]; + } + } + return lastEnergySum; + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/PreciseOnsetLocator.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,41 @@ +/* + * PreciseOnsetLocator.h + * peakOnsetDetector + * + * Created by Andrew on 21/09/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + + +#ifndef PRECISE_ONSET_LOCATOR +#define PRECISE_ONSET_LOCATOR + +#include <vector.h> + +class PreciseOnsetLocator{ + public: + + PreciseOnsetLocator(); + ~PreciseOnsetLocator(); + + int bufferSize; + bool printInfo; + + vector <double> onsetSamples;//holds the audio samples when onset is found + vector <double> recentBufferSamples; + + double getLastEnergySum(const int& startIndex, const int& vectorSize); + int findExactOnset(double* frame, const int& framesize); + int findExactOnset(float* frame, const int& framesize); + + int exactOnsetIndex; + + void setup(const int& size); + + void storeSamples(double* newSamples); + void storeSamples(float* newSamples); + + +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/ofxAubioOnsetDetection.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,906 @@ +/* + * ofxAubioOnsetDetection.cpp + * ofxOnsetDetection + * + * Created by Andrew on 24/11/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "ofxAubioOnsetDetection.h" + + +//@ do: fix up reset - maybe think of using vectors + +//tracktypes: +//there are three types +//0 and 2 - the onset only type +//1 - bass - ie.e uses aubio pitch +//3 - harmonic - such as guitar represented by a chromagram following the onset + +//we calculate these by logging the time then filling up a window for the calculation. + + + +ofxAubioOnsetDetection::ofxAubioOnsetDetection(){ + //onsetDetector = new AubioOnsetDetector(); + onsetDetector.initialise(); + + initialiseValues(); + + printf("ofxAubioOnsetDetector made\n"); + + amplitudeNumber = 256;//number of amplitudes shown on screen + maximumAubioPitch = 220;//max pitch shown inside window + minimumAubioPitch = 55.0/2.0; + trackType = 0; + + + printf("max val on making is %f\n", onsetDetector.maximumDetectionValue); +} + + +ofxAubioOnsetDetection::~ofxAubioOnsetDetection(){ +// delete onsetDetector; + printf("DELETE ONSET CALLED\n"); +// delete qmOnsetDetector; +} + +void ofxAubioOnsetDetection::initialiseValues(){ + printf("ONSET DETECTOR INITIALISED\n"); + // useMedianOnsetDetection = true; + onsetIndex = 0; + frameCountIndex = 0; + playPositionFrames = 0; + playPosition = 0; + + screenWidth = ofGetWidth(); + screenHeight = ofGetHeight(); + + //each file has onset window to be displayed in + window.setToRelativeSize(0.1, 0.1, 0.8, 0.3); + //fullScreen.setToRelativeSize(0,0,1,1); + + drawParams.width = 5; + drawParams.maximumValue = 10; + drawParams.minimumValue = 0; + drawParams.difference = 10; + drawParams.scale_factor = 30; + + setDrawParams(); +} + +void ofxAubioOnsetDetection::reset(){ + onsetIndex = 0; + frameCountIndex = 0; + + for (int i = 0;i < NUM_DETECTION_SAMPLES;i++){ + onsetFunction[i] = 0; + medianOnsetFunction[i] = 0; + highSlopeOnsetFunction[i] = 0; + + } + + + highSlopeOnsetsFrames.clear(); + highSlopeOnsetsMillis.clear();//The high slope onsets are the ones stored as chromaOnsets + //(i.e. have associated chroma and pitch to them) + chromaOnsets.clear(); + + onsetDetector.resetValues(); + + printf("Resetting the ofxAubioOnsetDetector\n"); +} + + +void ofxAubioOnsetDetection::processFrame(double* frame, const int& n){ + //bool onsetFound = false; + // aubio onset detector then processes current frame - returns bool true when new detection is output + //if buffer full and new result is processed (buffer is 1024 with hopsize 512 - can be set to other values) + + //for other class OnsetDetectionFunction : dfSample = qmonsetDetector.getDFsample(frame); + + //printf("process using double\n"); - NOT USING + + if (onsetDetector.processframe(frame, n)){ + + rawOnsetFunction[onsetIndex] = onsetDetector.rawDetectionValue; + medianOnsetFunction[onsetIndex] = onsetDetector.medianDetectionValue; +// aubioOnsetFunction[onsetIndex] = ??; + highSlopeOnsetFunction[onsetIndex] = onsetDetector.bestSlopeValue; + aubioLongTermAverage[onsetIndex] = onsetDetector.aubioLongTermAverage; + + // outlet_float(x->detectionFunctionOutlet, x->onsetDetector.peakPickedDetectionValue); + + if (onsetDetector.aubioOnsetFound){ + aubioOnsetRecorded[onsetIndex] = true; + } + else{ + aubioOnsetRecorded[onsetIndex] = false;//anr chnage late on + } + + + if (onsetDetector.anrMedianProcessedOnsetFound){ + onsetFound = true; + medianOnsetRecorded[onsetIndex] = true; + }else{ + onsetFound = false; + medianOnsetRecorded[onsetIndex] = false; + } + + if (onsetDetector.anrBestSlopeOnset){ + highSlopeOnsetRecorded[onsetIndex] = true; + highSlopeOnsetsFrames.push_back(frameCountIndex); + highSlopeOnsetsMillis.push_back(framesToMillis(frameCountIndex)); + + printf("onset frame %i is time %f \n", frameCountIndex, framesToMillis(frameCountIndex)); + + + chromaOnsetPtr = new ChromaOnset(); + chromaOnsetPtr ->frameTime = frameCountIndex; + chromaOnsetPtr->millisTime = framesToMillis(frameCountIndex); + chromaOnsetPtr->onsetIndex = onsetIndex; + chromaOnsets.push_back(*chromaOnsetPtr); + + + } + else{ + highSlopeOnsetRecorded[onsetIndex] = false; + } + + frameCountIndex++;//this one never loops + onsetIndex++; + if (onsetIndex == NUM_DETECTION_SAMPLES) + onsetIndex = 0;//this loops round + + }//end if new aubio onset detection result + + printf("N is %i\n", n); + float* tmpFrame; + vector<float> tmpFloatvector; + for (int i = 0;i < n;i++){ + //tmpFrame[i] = frame[i]; + tmpFloatvector.push_back(frame[i]); + } + + checkChromaAndPitch(&tmpFloatvector[0], n); + + + } + +void ofxAubioOnsetDetection::checkChromaAndPitch(float* tmpFrame, const int& n){ + //new method for pitch + //calculate always + pitchDetector.addToBuffer(tmpFrame, n); + + //process frames into each onset's chromagram analyser + for (int i = 0;i < chromaOnsets.size();i++){ + + //aubio pitch using yin + if (trackType == 1 && !chromaOnsets[i].aubioPitchFound ){//not yet done + + + //dont actually need to add this to the frame anymore! + // chromaOnsets[i].onsetFrame.addToFrame(tmpFrame, n);//add to frame in the chromaOnset class + // chromaOnsets[i].onsetFrame.frameCounter += n; + chromaOnsets[i].pitchFrameCounter += n; + + //used to use chromaOnsets[i].pitchFrameCounter + // printf("adding to frame for onset %i at frametime %i\n", i, frameCountIndex); + if (chromaOnsets[i].pitchFrameCounter >= pitchDetector.bufsize){//enough to calculate yin with using aubio pitch detection + + printf("frame %i onset frame counter %i chromacounter %i\n", chromaOnsets[i].onsetFrame.sizeOfFrame, chromaOnsets[i].onsetFrame.frameCounter, chromaOnsets[i].pitchFrameCounter ); + + + //float originalPitchMethod = pitchDetector.doPitchDetection(&chromaOnsets[i].onsetFrame.frame[0], pitchDetector.bufsize); + chromaOnsets[i].aubioPitch = pitchDetector.getPitch();//used to be originalPitchMethod; + + chromaOnsets[i].aubioPitchFound = true; + chromaOnsets[i].onsetFrame.deleteFrame(); + // printf("Aubio Pitch recieved for onset %i is %f\n", i, chromaOnsets[i].aubioPitch); + + + + + } + + } + + + //chroma + if (chromaOnsets[i].processFrame(tmpFrame, n) && trackType == 1){ + //!= 3 : i.e. true when we dont need so we delete immediately + //printf("onset %i (frametime %i) chroma is newly calculated at frame %i\n", i, chromaOnsets[i].frameTime, frameCountIndex); + chromaOnsets[i].printInfo(); + chromaOnsets[i].deleteChromagram(); + } + + }//end for all onsets +} + +void ofxAubioOnsetDetection::processFrame(float* frame, const int& n){ + //bool onsetFound = false; + // aubio onset detector then processes current frame - returns bool true when new detection is output + //if buffer full and new result is processed (buffer is 1024 with hopsize 512 - can be set to other values) + + //for other class OnsetDetectionFunction : dfSample = qmonsetDetector.getDFsample(frame); + +// printf("process using float\n"); + //THIS ONE IS USED! + + if (onsetDetector.processframe(frame, n)){ + + rawOnsetFunction[onsetIndex] = onsetDetector.rawDetectionValue; + medianOnsetFunction[onsetIndex] = onsetDetector.medianDetectionValue; + // aubioOnsetFunction[onsetIndex] = ??; + highSlopeOnsetFunction[onsetIndex] = onsetDetector.bestSlopeValue; + aubioLongTermAverage[onsetIndex] = onsetDetector.aubioLongTermAverage; + + // outlet_float(x->detectionFunctionOutlet, x->onsetDetector.peakPickedDetectionValue); + + if (onsetDetector.aubioOnsetFound){ + aubioOnsetRecorded[onsetIndex] = true; + } + else{ + aubioOnsetRecorded[onsetIndex] = false; + } + + + if (onsetDetector.anrMedianProcessedOnsetFound){ + onsetFound = true; + medianOnsetRecorded[onsetIndex] = true; + }else{ + onsetFound = false; + medianOnsetRecorded[onsetIndex] = false; + } + + if (onsetDetector.anrBestSlopeOnset){ + //do + highSlopeOnsetRecorded[onsetIndex] = true; + + printf("Frame index %i", frameCountIndex); + int exactOnsetIndex = precisionLocator.findExactOnset(&frame[0], n);//divide by 512.0 or bufferSize to get [0,1] value + printf("Exact index %i ", exactOnsetIndex); + + highSlopeOnsetsFrames.push_back(frameCountIndex); + float exactOffset = -1.0*framesToMillis((float)(n - exactOnsetIndex)/512.0); + + float millistime = framesToMillis(frameCountIndex); + float finalPreciseTime = millistime + exactOffset;//i.e. with offset due to energy analysis of frame + printf("exact offset %f millis %f final time %f\n", exactOffset, millistime, finalPreciseTime); + highSlopeOnsetsMillis.push_back(finalPreciseTime); + + + //did use the above but all info held in ChromaOnset class + + /* + ChromaOnset c; + c.frameTime = frameCountIndex; + c.millisTime = framesToMillis(frameCountIndex); + c.onsetIndex = onsetIndex; + */ + chromaOnsetPtr = new ChromaOnset(); + chromaOnsetPtr->frameTime = frameCountIndex; + chromaOnsetPtr->onsetIndex = onsetIndex; + chromaOnsetPtr->millisTime = finalPreciseTime;//framesToMillis(frameCountIndex); + chromaOnsets.push_back(*chromaOnsetPtr); + + // printf("frame %i is time %f \n", frameCountIndex, framesToMillis(frameCountIndex)); + } + else{ + highSlopeOnsetRecorded[onsetIndex] = false; + } + + frameCountIndex++;//this one never loops + onsetIndex++; + if (onsetIndex == NUM_DETECTION_SAMPLES) + onsetIndex = 0;//this loops round + + }//end if new aubio onset detection result + + //need to store these continually to help in location process + precisionLocator.storeSamples(&frame[0]); + + checkChromaAndPitch(frame, n); + +} + + + +double ofxAubioOnsetDetection::framesToMillis(const double& frameCount){ + return ((frameCount*onsetDetector.hopsize*1000.0)/44100.0); +} + + +void ofxAubioOnsetDetection::printOnsetList(){ + printf("PRINT ONSET LIST\n"); + for (int i = 0;i < chromaOnsets.size();i++){ + printf("%i:", i); + chromaOnsets[i].printInfo(); + } + printf("PRONT COMPLETE\n"); +} + + + +void ofxAubioOnsetDetection::drawOnsetDetection(){ + + drawOnsetDetection(0, amplitudeNumber, window); +// ofDrawBitmapString("amp no"+ofToString(amplitudeNumber),40,40); + +}//end draw onset fn + +void ofxAubioOnsetDetection::drawOnsetDetectionScrolling(){ + + int startFrame = (int)(playPositionFrames/amplitudeNumber)* amplitudeNumber; + //setDrawParams(); + + drawParams.windowStartFrame = startFrame; + + drawOutlineAndSetParams(window); + + if (trackType == 0 || trackType == 2) + drawOnsetDetection(startFrame, startFrame+amplitudeNumber, window); + + setDrawParams(window); + drawChromaOnsetData(startFrame, startFrame+amplitudeNumber, window); + + drawScrollLine(startFrame, window); +}//end draw onset fn + + +void ofxAubioOnsetDetection::drawOutlineAndSetParams(const ofxWindowRegion& screenRegion){ + ofBackground(0); + setDrawParams(screenRegion); + ofSetColor(100,150,250); + screenRegion.drawOutline(); +} + + +void ofxAubioOnsetDetection::drawOnsetDetection(int startIndex, int endIndex, const ofxWindowRegion& screenRegion){ + + + + int tmpIndex = onsetIndex; + float width = screenRegion.width / (float) amplitudeNumber; + float maximumValue = onsetDetector.maximumDetectionValue; + float minimumValue = 0;//minimumDetectionFunction ; + float difference = maximumValue - minimumValue; + float scale_factor = screenRegion.height/ difference; + + endIndex = min(endIndex, startIndex+amplitudeNumber); + +// drawChromaOnsetData(startIndex, endIndex, screenRegion); + + for (int Xvalue = startIndex;Xvalue < endIndex; Xvalue++){ + + int Xindex = Xvalue;//(endIndex - Xvalue) ; + + int previousIndex = (Xindex-1); + if (Xindex < 0){ + Xindex += NUM_DETECTION_SAMPLES; + if (previousIndex < 0) + previousIndex += NUM_DETECTION_SAMPLES; + } + + //onsetFunction[] also processed but not shown - Brossier's? + + + ofSetColor(155);//,200,55); + + + int previousXpos = (int) (screenRegion.x + (width*(Xvalue - startIndex - 1))); + int Xpos = (int) (screenRegion.x +(width*(Xvalue - startIndex))); + + ofLine(previousXpos, screenRegion.y + screenRegion.height - (scale_factor*(rawOnsetFunction[previousIndex]- minimumValue)), + Xpos, screenRegion.y + screenRegion.height - (scale_factor*(rawOnsetFunction[Xindex]- minimumValue)) ); + + + + //median of Onset fn + ofSetColor(0,105,0); + ofLine(previousXpos, screenRegion.y + screenRegion.height - (scale_factor*(medianOnsetFunction[previousIndex]- minimumValue)), + Xpos, screenRegion.y + screenRegion.height - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) ); + + + if (medianOnsetRecorded[Xindex] == true){ + ofSetColor(0,255,0); + ofCircle(Xpos, screenRegion.y + screenRegion.height - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) , 4); + } + + + ofSetColor(0,0,160); + ofLine(previousXpos, screenRegion.y + screenRegion.height - (scale_factor*(highSlopeOnsetFunction[previousIndex]- minimumValue)), + Xpos, screenRegion.y + screenRegion.height - (scale_factor*(highSlopeOnsetFunction[Xindex]- minimumValue)) ); + + //bright blue - slope based onsets + if (highSlopeOnsetRecorded[Xindex] == true){ + ofSetColor(0,0,255); + ofCircle(Xpos, screenRegion.y + screenRegion.height - (scale_factor*(highSlopeOnsetFunction[Xindex]- minimumValue)) , 4); + } + + //long term average in dull grey + ofSetColor(100); + ofLine(previousXpos, screenRegion.y + screenRegion.height - (scale_factor*(aubioLongTermAverage[previousIndex]- minimumValue)), + Xpos, screenRegion.y + screenRegion.height - (scale_factor*(aubioLongTermAverage[Xindex]- minimumValue)) ); + + + ofSetColor(255,100,0); + + }//end for Xvalue (across the recent observations of osc data) + + + //some axis stuff deleted + + +// string tmpInfoString = "(windowed)max val "+ofToString(onsetDetector.maximumDetectionValue,2); +// tmpInfoString += " diff "+ofToString(difference); +// ofDrawBitmapString(tmpInfoString, 100,200); + +}//end draw onset fn + +void ofxAubioOnsetDetection::drawScrollLine(const int& startIndex, const ofxWindowRegion& screenRegion){ + //play position + float width = screenRegion.width / (float) amplitudeNumber; + ofSetColor(255,255,255); + playPositionFrames = playPosition * frameCountIndex; + ofLine(screenRegion.x + width*(playPositionFrames-startIndex), screenRegion.y , screenRegion.x + width*(playPositionFrames-startIndex), screenRegion.y + screenRegion.height); +} + + +void ofxAubioOnsetDetection::drawChromaOnsetData(const int& startIndex, const int& endIndex, const ofxWindowRegion& screenRegion){ + + int chromaIndex = 0;//chromaOnsets.size()/2; + while (chromaIndex > 0 && chromaOnsets[chromaIndex].onsetIndex > startIndex) + chromaIndex--; + + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].onsetIndex < startIndex) + chromaIndex++; + + switch (trackType) { + case 1: + drawPitchLines(chromaIndex, endIndex, screenRegion); + break; + case 3: + drawChromaStripes(chromaIndex, endIndex, screenRegion); + break; + case 0: + ofSetColor(100,0,0); + drawOnsetStripes(chromaIndex, endIndex, screenRegion); + break; + case 2: + ofSetColor(100,100,0); + drawOnsetStripes(chromaIndex, endIndex, screenRegion); + break; + }//end switch + + + +}//end draw chroma + +void ofxAubioOnsetDetection::drawOnsetStripes(int chromaIndex, const int& frameEndIndex, const ofxWindowRegion& screenRegion){ + + + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].chromaCalculated && chromaOnsets[chromaIndex].onsetIndex < frameEndIndex) { + + //ofSetColor(255,100,255); + + int Xindex = chromaOnsets[chromaIndex].onsetIndex; + int Xvalue = frameEndIndex - Xindex; + + // for (int j = 0;j < 12;j++){ + + // if (!chromaOnsets[chromaIndex].matched) + // ofSetColor(0,0,255*chromaOnsets[chromaIndex].chromaValues[11-j], 20); + // else + // ofSetColor(255*chromaOnsets[chromaIndex].chromaValues[11-j],0,0, 20); + + ofRect(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y, 4, screenRegion.height); + // } + + // ofCircle(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height - (drawParams.scale_factor*(highSlopeOnsetFunction[Xindex]- drawParams.minimumValue)) , 4); + + chromaIndex++; + } + +}//end draw chroma + +void ofxAubioOnsetDetection::drawChromaStripes(int chromaIndex, const int& frameEndIndex, const ofxWindowRegion& screenRegion){ + + + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].chromaCalculated && chromaOnsets[chromaIndex].onsetIndex < frameEndIndex) { + + ofSetColor(255,100,255); + + int Xindex = chromaOnsets[chromaIndex].onsetIndex; + int Xvalue = frameEndIndex - Xindex; + + for (int j = 0;j < 12;j++){ + + if (!chromaOnsets[chromaIndex].matched) + ofSetColor(0,0,255*chromaOnsets[chromaIndex].chromaValues[11-j], 20); + else + ofSetColor(255*chromaOnsets[chromaIndex].chromaValues[11-j],0,0, 20); + + ofRect(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height*j/12.0, 20, screenRegion.height/12); + } + + ofCircle(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height - (drawParams.scale_factor*(highSlopeOnsetFunction[Xindex]- drawParams.minimumValue)) , 4); + + chromaIndex++; + } + +}//end draw chroma + +void ofxAubioOnsetDetection::drawPitchLines(int chromaIndex, const int& frameEndIndex, const ofxWindowRegion& screenRegion){ + + ofSetLineWidth(2); + + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].chromaCalculated && chromaOnsets[chromaIndex].onsetIndex < frameEndIndex) { + + int Xindex = chromaOnsets[chromaIndex].onsetIndex; + int Xvalue = frameEndIndex - Xindex; + + //now do pitch in log freq + float heightFactor = 0; + if (chromaOnsets[chromaIndex].aubioPitch > 0) + heightFactor = log(chromaOnsets[chromaIndex].aubioPitch/minimumAubioPitch) / log(maximumAubioPitch/minimumAubioPitch); + heightFactor = 1 - heightFactor; + //red lines for freq + ofSetColor(255,0,0); + //ofSetLineWidth(8); + ofLine(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height*heightFactor, + screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue) + 50, screenRegion.y + screenRegion.height*heightFactor); + + ofSetColor(255,0,255); + ofDrawBitmapString(ofToString(chromaOnsets[chromaIndex].aubioPitch, 1) , screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue) + 4, screenRegion.y + screenRegion.height*heightFactor - 4); + chromaIndex++; + } + + ofSetLineWidth(1); + + +}//end draw pitch lines + +void ofxAubioOnsetDetection::setDrawParams(){ + screenWidth = ofGetWidth(); + screenHeight = ofGetHeight();//justin case + + drawParams.width = screenWidth / (float) amplitudeNumber; + drawParams.maximumValue = onsetDetector.maximumDetectionValue; + drawParams.minimumValue = 0;//minimumDetectionFunction ; + drawParams.difference = drawParams.maximumValue - drawParams.minimumValue; + drawParams.scale_factor = screenHeight/ drawParams.difference; + +} + +void ofxAubioOnsetDetection::setDrawParams(const ofxWindowRegion& screenRegion){ + + drawParams.width = screenRegion.width / (float) amplitudeNumber; + drawParams.maximumValue = onsetDetector.maximumDetectionValue; + drawParams.minimumValue = 0;//minimumDetectionFunction ; + drawParams.difference = drawParams.maximumValue - drawParams.minimumValue; + drawParams.scale_factor = screenRegion.height/ drawParams.difference; +} + + +void ofxAubioOnsetDetection::windowResized(const int& w, const int& h){ + screenWidth = ofGetWidth(); + screenHeight = ofGetHeight(); + window.resized(w, h); + fullScreen.resized(w, h); +} + + +void ofxAubioOnsetDetection::printChromaInfo(){ + for (int i = 0;i < chromaOnsets.size();i++) + chromaOnsets[i].printInfo(); + + printf("max value on printing is %f\n", onsetDetector.maximumDetectionValue); +} + +void ofxAubioOnsetDetection::aubioOnsetDetect_energy(){ + onsetDetector.onsetclass_energy(); + printf("Energy based onset detection now used by aubioOnsetDetect~."); +} + +void ofxAubioOnsetDetection::aubioOnsetDetect_hfc(){ + /** High Frequency Content onset detection function + + This method computes the High Frequency Content (HFC) of the input spectral + frame. The resulting function is efficient at detecting percussive onsets. + + Paul Masri. Computer modeling of Sound for Transformation and Synthesis of + Musical Signal. PhD dissertation, University of Bristol, UK, 1996.*/ + + onsetDetector.onsetclass_hfc(); + printf("High Frequency Content (Masri '96) detection now used by aubioOnsetDetect~."); +} + + +void ofxAubioOnsetDetection::aubioOnsetDetect_complex(){ + //Complex Domain Method onset detection function + //Christopher Duxbury, Mike E. Davies, and Mark B. Sandler. Complex domain + //onset detection for musical signals. In Proceedings of the Digital Audio + //Effects Conference, DAFx-03, pages 90-93, London, UK, 2003. + onsetDetector.onsetclass_complex(); + printf("Complex domain onset detection (Duxbury et al., DaFx '03) now used by aubioOnsetDetect~."); + +} + +void ofxAubioOnsetDetection::aubioOnsetDetect_phase(){ + /** Phase Based Method onset detection function + + Juan-Pablo Bello, Mike P. Davies, and Mark B. Sandler. Phase-based note onset + detection for music signals. In Proceedings of the IEEE International + Conference on Acoustics Speech and Signal Processing, pages 441Â444, + Hong-Kong, 2003.*/ + + onsetDetector.onsetclass_phase(); + printf("Phase-based detection (Bello et al., IEEE '03) now used by aubioOnsetDetect~."); +} + +void ofxAubioOnsetDetection::aubioOnsetDetect_specdiff(){ + /* Spectral difference method onset detection function + Jonhatan Foote and Shingo Uchihashi. The beat spectrum: a new approach to + rhythm analysis. In IEEE International Conference on Multimedia and Expo + (ICME 2001), pages 881Â884, Tokyo, Japan, August 2001. + */ + //aubio_onsetdetection_type + //aubio_onsetdetection_free (x->o); + onsetDetector.onsetclass_specdiff(); + printf("Spectral Difference (Foote and Shingo Uchihashi, ICME '01) detection now used by aubioOnsetDetect~."); + + +} + +void ofxAubioOnsetDetection::aubioOnsetDetect_kl(){ + //aubio_onsetdetection_type + //aubio_onsetdetection_free (x->o); + /** Kullback-Liebler onset detection function + + Stephen Hainsworth and Malcom Macleod. Onset detection in music audio + signals. In Proceedings of the International Computer Music Conference + (ICMC), Singapore, 2003. + */ + + onsetDetector.onsetclass_kl(); + printf("Kullback-Liebler (Hainsworth and McLeod, ICMC '03) detection now used by aubioOnsetDetect~."); +} + +void ofxAubioOnsetDetection::aubioOnsetDetect_mkl(){ + /** Modified Kullback-Liebler onset detection function + + Paul Brossier, ``Automatic annotation of musical audio for interactive + systems'', Chapter 2, Temporal segmentation, PhD thesis, Centre for Digital + music, Queen Mary University of London, London, UK, 2003.*/ + onsetDetector.onsetclass_mkl(); + printf("Modified Kullback-Liebler (Brossier, PhD thesis '03) detection now used by aubioOnsetDetect~."); +} + + +/* + axis stuff end + //label y axis + int axisHeight, stepSize; + ofSetColor(255,255,255); + stepSize = 1000; + + while((difference / stepSize) < 3) + stepSize /= 2; + + while ((difference / stepSize) > 7)// maximum 6 numbers to display + stepSize *= 2; + + + for (axisHeight = 0; axisHeight < maximumDetectionFunction; axisHeight += stepSize){ + ofDrawBitmapString( ofToString((int)axisHeight), ofGetWidth()-50, + (int) ((TEXT_HEIGHT/2) +(screenHeight - (scale_factor*(axisHeight- minimumValue)))) ); + } + + for (axisHeight = max(0, (int)minimumDetectionFunction); axisHeight > min(0, (int)minimumDetectionFunction); axisHeight -= stepSize){ + ofDrawBitmapString( ofToString((int)axisHeight), ofGetWidth()-50, + (int) ((TEXT_HEIGHT/2) +(screenHeight - (scale_factor*(axisHeight- minimumValue)))) ); + } + + //label x axis + stepSize = 20;//need to make sure not too many of these: + + while((amplitudeNumber / stepSize) < 4) + stepSize /= 2; + + while ((amplitudeNumber / stepSize) > 8) + stepSize *= 2; + + int labelIndex = onsetIndex - (onsetIndex % stepSize); + for (int y = labelIndex; y > onsetIndex - amplitudeNumber; y -= stepSize){ + ofDrawBitmapString( ofToString((int)y), (int) (width*(amplitudeNumber - (onsetIndex - y))), (int) ((TEXT_HEIGHT+2) + (screenHeight - (scale_factor*(0 - minimumValue)))) ); + } + */ + + + + + + +void ofxAubioOnsetDetection::drawOnsetDetection(int startIndex, int endIndex){ + ofBackground(0); + setDrawParams(); + + int tmpIndex = onsetIndex; + float width = screenWidth / (float) amplitudeNumber; + float maximumValue = onsetDetector.maximumDetectionValue; + float minimumValue = 0;//minimumDetectionFunction ; + float difference = maximumValue - minimumValue; + float scale_factor = screenHeight/ difference; + + //draw axis + ofSetColor(255,255,255); + ofDrawBitmapString(ofToString((startIndex)), 20, 20); + + ofLine(0, screenHeight - (scale_factor*(0 - minimumValue)), + (int) (width*(amplitudeNumber)), screenHeight - (scale_factor*(0 - minimumValue)) ); + + + + endIndex = min(endIndex, startIndex+amplitudeNumber); + + drawChromaOnsetData(startIndex, endIndex); + + for (int Xvalue = startIndex;Xvalue < endIndex; Xvalue++){ + + int Xindex = Xvalue;//(endIndex - Xvalue) ; + + int previousIndex = (Xindex-1); + if (Xindex < 0){ + Xindex += NUM_DETECTION_SAMPLES; + if (previousIndex < 0) + previousIndex += NUM_DETECTION_SAMPLES; + } + + //onsetFunction[] also processed but not shown - Brossier's? + + + ofSetColor(155);//,200,55); + + + int previousXpos = (int) (width*(Xvalue - startIndex - 1)); + int Xpos = (int) (width*(Xvalue - startIndex)); + + ofLine(previousXpos, screenHeight - (scale_factor*(rawOnsetFunction[previousIndex]- minimumValue)), + Xpos, screenHeight - (scale_factor*(rawOnsetFunction[Xindex]- minimumValue)) ); + + + + //median of Onset fn + ofSetColor(0,105,0); + ofLine(previousXpos, screenHeight - (scale_factor*(medianOnsetFunction[previousIndex]- minimumValue)), + Xpos, screenHeight - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) ); + + + if (medianOnsetRecorded[Xindex] == true){ + ofSetColor(0,255,0); + ofCircle(Xpos, screenHeight - (scale_factor*(medianOnsetFunction[Xindex]- minimumValue)) , 4); + } + + + ofSetColor(0,0,160); + ofLine(previousXpos, screenHeight - (scale_factor*(highSlopeOnsetFunction[previousIndex]- minimumValue)), + Xpos, screenHeight - (scale_factor*(highSlopeOnsetFunction[Xindex]- minimumValue)) ); + + //bright blue - slope based onsets + if (highSlopeOnsetRecorded[Xindex] == true){ + ofSetColor(0,0,255); + ofCircle(Xpos, screenHeight - (scale_factor*(highSlopeOnsetFunction[Xindex]- minimumValue)) , 4); + } + + //long term average in dull grey + ofSetColor(100); + ofLine(previousXpos, screenHeight - (scale_factor*(aubioLongTermAverage[previousIndex]- minimumValue)), + Xpos, screenHeight - (scale_factor*(aubioLongTermAverage[Xindex]- minimumValue)) ); + + + ofSetColor(255,100,0); + + }//end for Xvalue (across the recent observations of osc data) + + //axis stuff at end + + //play position + ofSetColor(255,255,255); + playPositionFrames = playPosition * frameCountIndex; + ofLine(width*(playPositionFrames-startIndex), 0, width*(playPositionFrames-startIndex), screenHeight); + + + //ofDrawBitmapString("max val "+ofToString(onsetDetector.maximumDetectionValue,2), 100,200); +}//end draw onset fn + + + +void ofxAubioOnsetDetection::drawChromaOnsetData(const int& startIndex, const int& endIndex){ + + int chromaIndex = 0;//chromaOnsets.size()/2; + while (chromaIndex > 0 && chromaOnsets[chromaIndex].onsetIndex > startIndex) + chromaIndex--; + + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].onsetIndex < startIndex) + chromaIndex++; + + + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].chromaCalculated && chromaOnsets[chromaIndex].onsetIndex < endIndex) { + + ofSetColor(255,100,255); + + int Xindex = chromaOnsets[chromaIndex].onsetIndex; + int Xvalue = endIndex - Xindex; + + for (int j = 0;j < 12;j++){ + ofSetColor(0,0,255*chromaOnsets[chromaIndex].chromaValues[11-j], 20); + ofRect(drawParams.width*(amplitudeNumber - Xvalue), screenHeight*j/12.0, 6, screenHeight/12); + } + + ofCircle(drawParams.width*(amplitudeNumber - Xvalue), screenHeight - (drawParams.scale_factor*(highSlopeOnsetFunction[Xindex]- drawParams.minimumValue)) , 4); + + //now do pitch in log freq + float heightFactor = 0; + if (chromaOnsets[chromaIndex].aubioPitch > 0) + heightFactor = log(chromaOnsets[chromaIndex].aubioPitch) / log(maximumAubioPitch); + heightFactor = 1 - heightFactor; + ofSetColor(255,0,0); + //ofSetLineWidth(8); + ofLine(drawParams.width*(amplitudeNumber - Xvalue), heightFactor*screenHeight, drawParams.width*(amplitudeNumber - Xvalue) + 50, heightFactor*screenHeight); + + ofSetColor(0,0,255); + ofDrawBitmapString(ofToString(chromaOnsets[chromaIndex].aubioPitch, 1) , drawParams.width*(amplitudeNumber - Xvalue), heightFactor*screenHeight-4); + chromaIndex++; + } + + ofSetColor(255,255,235); + ofDrawBitmapString("full drawparams width "+ofToString(drawParams.width), 100, 100); + ofDrawBitmapString("full x"+ofToString(fullScreen.x)+" width "+ofToString(fullScreen.width), 100, 120); +}//end draw chroma + + + +/* + DRAW CHROMA JUNK + while (chromaIndex < chromaOnsets.size() && chromaOnsets[chromaIndex].chromaCalculated && chromaOnsets[chromaIndex].onsetIndex < endIndex) { + + ofSetColor(255,100,255); + + int Xindex = chromaOnsets[chromaIndex].onsetIndex; + int Xvalue = endIndex - Xindex; + + for (int j = 0;j < 12;j++){ + + if (!chromaOnsets[chromaIndex].matched) + ofSetColor(0,0,255*chromaOnsets[chromaIndex].chromaValues[11-j], 20); + else + ofSetColor(255*chromaOnsets[chromaIndex].chromaValues[11-j],0,0, 20); + + ofRect(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height*j/12.0, 6, screenRegion.height/12); + } + + ofCircle(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height - (drawParams.scale_factor*(highSlopeOnsetFunction[Xindex]- drawParams.minimumValue)) , 4); + + //now do pitch in log freq + float heightFactor = 0; + if (chromaOnsets[chromaIndex].aubioPitch > 0) + heightFactor = log(chromaOnsets[chromaIndex].aubioPitch) / log(maximumAubioPitch); + heightFactor = 1 - heightFactor; + //red lines for freq + ofSetColor(255,0,0); + //ofSetLineWidth(8); + ofLine(screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue), screenRegion.y + screenRegion.height*heightFactor, + screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue) + 50, screenRegion.y + screenRegion.height*heightFactor); + + ofSetColor(0,0,255); + ofDrawBitmapString(ofToString(chromaOnsets[chromaIndex].aubioPitch, 1) , screenRegion.x + drawParams.width*(amplitudeNumber - Xvalue) + 4, screenRegion.y + screenRegion.height*heightFactor - 4); + chromaIndex++; + } + */ + +// ofSetColor(255,255,235); +// ofDrawBitmapString("windowed drawparams width "+ofToString(drawParams.width), 100, 100); +// ofDrawBitmapString("windowed x"+ofToString(screenRegion.x)+" width "+ofToString(screenRegion.width), 100, 120); +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAubioOnsetDetection/ofxAubioOnsetDetection.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,146 @@ +/* + * ofxAubioOnsetDetection.h + * ofxOnsetDetection + * + * Created by Andrew Robertson on 24/11/2011. + * Copyright 2011 Centre for Digital Music, QMUL. All rights reserved. + * + */ + + +#ifndef OFX_AUBDIO_ONSET_DETECTION_H_ +#define OFX_AUBIO_ONSET_DETECTION_H_ + +#pragma once + +#define NUM_DETECTION_SAMPLES 24000 +#define TEXT_HEIGHT 16 + +#include "ofMain.h" +#include "AubioOnsetDetector.h" +#include "ChromaOnset.h" +#include "ofxWindowRegion.h" +#include "AubioPitch.h" +#include "Chromagram.h" +#include "PreciseOnsetLocator.h" + +//#include "OnsetDetectionFunction.h" + +//this builds on aubioOsetDetector class +//but that doesn't store any values +//for drawing, perhpas we need to + + +struct DrawOnsetParameters{ + float width;//= screenWidth / (float) amplitudeNumber; + float maximumValue;// = onsetDetector->maximumDetectionValue; + float minimumValue;// = 0;//minimumDetectionFunction ; + float difference;// = maximumValue - minimumValue; + float scale_factor;// = screenHeight/ difference; + int windowStartFrame; +}; + +class ofxAubioOnsetDetection{ +public: + ofxAubioOnsetDetection(); + ~ofxAubioOnsetDetection(); + AubioOnsetDetector onsetDetector; + //OnsetDetectionFunction *qmOnsetDetector; + + void reset(); + void initialiseValues(); + double dfSample; + + void processFrame(double* frame, const int& n); + void processFrame(float* frame, const int& n); + + void printOnsetList();//print the vector of chromaOnset times - onsets with timing and chroma info + + //switch between different onset methods + void aubioOnsetDetect_energy(); + void aubioOnsetDetect_complex(); + void aubioOnsetDetect_kl(); + void aubioOnsetDetect_hfc(); + void aubioOnsetDetect_specdiff(); + void aubioOnsetDetect_phase();//this is pretty bad I think + void aubioOnsetDetect_mkl(); + + void drawOnsetDetection(); + void drawOnsetDetectionScrolling();//float of how far thru file - e.g 0.6 60% through + void drawScrollLine(const int& startIndex, const ofxWindowRegion& screenRegion); + + void drawOnsetDetection(int startIndex, int endIndex); + void drawOnsetDetection(int startIndex, int endIndex, const ofxWindowRegion& screenRegion);//overloaded + int onsetIndex, frameCountIndex; + + + float onsetFunction[NUM_DETECTION_SAMPLES]; + bool aubioOnsetRecorded[NUM_DETECTION_SAMPLES]; + + float rawOnsetFunction[NUM_DETECTION_SAMPLES]; + bool highSlopeOnsetRecorded[NUM_DETECTION_SAMPLES];//true/false for onset + + float medianOnsetFunction[NUM_DETECTION_SAMPLES]; + bool medianOnsetRecorded[NUM_DETECTION_SAMPLES];//true/false for onset + + float highSlopeOnsetFunction[NUM_DETECTION_SAMPLES]; + + float aubioLongTermAverage[NUM_DETECTION_SAMPLES]; + + float maximumDetectionFunction; + float minimumDetectionFunction; + + float maxValue; + + int amplitudeNumber; + bool onsetFound; + + typedef std::vector<double> DoubleVector; + DoubleVector highSlopeOnsetsFrames; + DoubleVector highSlopeOnsetsMillis; + double framesToMillis(const double& frameCount); + double playPosition, playPositionFrames;//play position is between 0 and 1 of the file + + typedef std::vector<ChromaOnset> ChromaOnsetVector; + ChromaOnsetVector chromaOnsets; + + int trackType; + + void printChromaInfo(); + + void checkChromaAndPitch(float* tmpFrame, const int& n); + + void drawChromaOnsetData(const int& startIndex, const int& endIndex); + void drawChromaOnsetData(const int& startIndex, const int& endIndex, const ofxWindowRegion& screenRegion); + + void drawOnsetStripes(int chromaIndex, const int& frameEndIndex, const ofxWindowRegion& screenRegion); + void drawChromaStripes(int chromaIndex, const int& frameEndIndex, const ofxWindowRegion& screenRegion); + void drawPitchLines(int chromaIndex, const int& frameEndIndex, const ofxWindowRegion& screenRegion); + + + DrawOnsetParameters drawParams ; + void setDrawParams(); + void setDrawParams(const ofxWindowRegion& screenRegion); + void drawOutlineAndSetParams(const ofxWindowRegion& screenRegion); + + ChromaOnset* chromaOnsetPtr; + + AubioPitch pitchDetector; + //AubioPitch pitchDetectorTwo; + float maximumAubioPitch, minimumAubioPitch; + + //basic screen stuff + float screenWidth;//= ofGetWidth(); + float screenHeight;// = ofGetHeight(); + void windowResized(const int& w, const int& h); + + ofxWindowRegion window; + ofxWindowRegion fullScreen; + + + PreciseOnsetLocator precisionLocator; + +}; + + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/AudioAnalysis.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,226 @@ +/* + * AudioAnalysis.cpp + * audioFileLoader4 + * + * Created by Andrew on 14/08/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "AudioAnalysis.h" + + +AudioAnalysis::AudioAnalysis(){ +// chromoGramm.initialise(FRAMESIZE,2048); + + scrollWidth = 1600; + +} + + + +void AudioAnalysis::drawEnergyVectorFromPointer(){ + DoubleVector* energyVec; + energyVec = &energyVector; + //xxx above + + ofSetColor(0xFF0066); + float screenHeight = ofGetHeight() ; + float screenWidth = ofGetWidth(); + float heightFactor = 8; + int i, j, startingFrame; + startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in + startingFrame *= scrollWidth; + + for (i = 0; i < scrollWidth - 1; i++){ + j = i + startingFrame; + if (j < (*energyVec).size()) + ofLine(i*screenWidth/scrollWidth, screenHeight - ((*energyVec)[j]*screenHeight/heightFactor), + screenWidth*(i+1)/scrollWidth, screenHeight - ((*energyVec)[j+1]*screenHeight/heightFactor)); + + } +} + +void AudioAnalysis::drawSpectralDifference(){ + DoubleMatrix* dMatrix; + dMatrix = &chromaMatrix; + //get rid of these! + + int matrixSize = (*dMatrix).size(); + if (matrixSize > 0){ + + float screenHeight = ofGetHeight() ; + float screenWidth = ofGetWidth(); + float heightFactor = 8; + double difference; + int i, j, startingFrame; + startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in + startingFrame *= scrollWidth;//starting frame in terms of energy frames + startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames + + float chromoLength = scrollWidth/CHROMA_CONVERSION_FACTOR; + for (i = 1; i < chromoLength; i++){//changed to add 1 + j = i + startingFrame; + for (int y = 0;y < 12;y++){ + + if (j < matrixSize) + difference = (*dMatrix)[j][11-y] - (*dMatrix)[j-1][11-y]; + else + difference = 0; + + if (difference < 0) + difference = 0;//half wave rectify + + ofSetColor(0,0,255 * difference);//, 0; + ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12); + }//end y + }//end i + + }///end if matrix has content + else{ + printf("Error - please load audio first"); + } + +} + + +/* +void testApp::initialiseVariables(){ + + energyIndex = 0; + // frameIndex = 0; + chromaIndex = 0; + chromoGramm.initialise(FRAMESIZE,2048);//framesize 512 and hopsize 2048 +} + + +//-------------------------------------------------------------- +void testApp::draw(){ + switch (screenToDraw){ + case 0: + if (drawSpectralDifferenceFunction) + drawSpectralDifference(&chromaMatrix); + else + drawDoubleMatrix(&chromaMatrix); + + drawEnergyVectorFromPointer(&firstEnergyVector); + break; + case 1: + // audioHolder.drawAudioVectorMillis(1000, 1000+audioScale); + audioHolder.drawAudioVectorSamples(audioHolder.playPosition, audioHolder.playPosition+audioHolder.audioScaleSamples); + break; + } + + + + //ofSetColor(255,0,0); + //drawEnergyVectorFromPointer(&audioVector); + + ofSetColor(0xFFFFFF); + ofLine(audioPosition*width, 0, audioPosition*width, height); + + ofDrawBitmapString(soundFileName,80,480); + +} + + +void testApp::drawEnergyVectorFromPointer(DoubleVector* energyVec){ + + ofSetColor(0xFF0066); + float screenHeight = ofGetHeight() ; + float screenWidth = ofGetWidth(); + float heightFactor = 8; + int i, j, startingFrame; + startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in + startingFrame *= scrollWidth; + + for (i = 0; i < scrollWidth - 1; i++){ + j = i + startingFrame; + if (j < (*energyVec).size()) + ofLine(i*screenWidth/scrollWidth, screenHeight - ((*energyVec)[j]*screenHeight/heightFactor), + screenWidth*(i+1)/scrollWidth, screenHeight - ((*energyVec)[j+1]*screenHeight/heightFactor)); + + } +} + +void testApp::drawSpectralDifference(DoubleMatrix* dMatrix){ + int matrixSize = (*dMatrix).size(); + if (matrixSize > 0){ + + float screenHeight = ofGetHeight() ; + float screenWidth = ofGetWidth(); + float heightFactor = 8; + double difference; + int i, j, startingFrame; + startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in + startingFrame *= scrollWidth;//starting frame in terms of energy frames + startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames + + float chromoLength = scrollWidth/CHROMA_CONVERSION_FACTOR; + for (i = 1; i < chromoLength; i++){//changed to add 1 + j = i + startingFrame; + for (int y = 0;y < 12;y++){ + + if (j < matrixSize) + difference = (*dMatrix)[j][11-y] - (*dMatrix)[j-1][11-y]; + else + difference = 0; + + if (difference < 0) + difference = 0;//half wave rectify + + ofSetColor(0,0,255 * difference);//, 0; + ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12); + }//end y + }//end i + + }///end if matrix has content + else{ + printf("Error - please load audio first"); + } + +} + + +void testApp::drawDoubleMatrix(DoubleMatrix* dMatrix){ + //used to draw the chromagram matrix + int matrixSize = (*dMatrix).size(); + if (matrixSize > 0){ + + float screenHeight = ofGetHeight() ; + float screenWidth = ofGetWidth(); + float heightFactor = 8; + int i, j, startingFrame; + startingFrame = currentPlayingFrame / scrollWidth;//i.e. number of scroll widths in + startingFrame *= scrollWidth;//starting frame in terms of energy frames + startingFrame /= CHROMA_CONVERSION_FACTOR; //in terms of chroma frames + + float chromoLength = scrollWidth/CHROMA_CONVERSION_FACTOR; + for (i = 0; i < chromoLength; i++){ + j = i + startingFrame; + for (int y = 0;y < 12;y++){ + + if (j < matrixSize) + ofSetColor(0,0,255 * (*dMatrix)[j][11-y]); + else + ofSetColor(0,0,0); + + ofRect(i*screenWidth/chromoLength,y*screenHeight/12,screenWidth/chromoLength,screenHeight/12); + }//end y + }//end i + + }///end if matrix has content + else{ + printf("Error - please load audio first"); + } + + +} + + + + + +*/ + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/AudioAnalysis.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,91 @@ +/* + * AudioAnalysis.h + * audioFileLoader4 + * + * Created by Andrew on 14/08/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#ifndef AUDIO_ANALYSIS_H +#define AUDIO_ANALYSIS_H + + +//#include "fftw3.h" +#include "ofMain.h" +//#include "chromaGram.h" +//#include "ChordDetect.h" +#include "sndfile.h" +#include "ofxFileDialogOSX.h" +#include "AudioFile.h" + +#define FRAMESIZE 512 +#define ENERGY_LENGTH 80000 +#define CHROMA_LENGTH 12000 +#define CHROMA_CONVERSION_FACTOR 16 //16 times as many frames in energy as in chroma + + +//this does a chromagram analysis and aubio onset analysis +//held in double matrix and doubleVector respectively +//these are dynamic vectors, so size set by what's needed for the file + +class AudioAnalysis{ + +public: + + AudioAnalysis(); + + typedef std::vector<double> DoubleVector; + typedef std::vector<DoubleVector> DoubleMatrix; + + DoubleMatrix chromaMatrix; +// DoubleMatrix* matrixPtr; + DoubleVector energyVector; + + AudioFile* audioHolder; + void loadNewAudio(string soundFileName);//?? + +// Chromagram chromoGramm; + int currentPlayingFrame; + +// ChordDetect chord; + + double getEnergyOfFrame(); + int scrollWidth; + //int totalFrames; + void drawEnergyVectorFromPointer(); + void drawSpectralDifference(); + + /* + double getEnergyOfFrame(); + + + void initialiseVariables(); + + + void initialiseVariables(); + + + AudioFile audioHolder; + + void drawDoubleMatrix(DoubleMatrix* dMatrix);//DoubleMatrix* dMatrix); WOULD BE NICE TO USE POINTER BUT NOT WORKING YET + + + DoubleVector firstEnergyVector; + + void drawEnergyVectorFromPointer(DoubleVector* energyVec); + + void processAudioToDoubleMatrix(Chromagram* chromaG, DoubleMatrix* myDoubleMatrix, DoubleVector* energyVector); + + void loadNewAudio(string soundFileName); + + + + */ + + +}; +#endif + + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/AudioFile.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,123 @@ +/* + * audioFile.cpp + * audioFileLoader3 + * + * Created by Andrew on 31/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "AudioFile.h" + +const double samplingFrequency = 44100.0; + +AudioFile::AudioFile(){ + audioScaleSamples = 44100; + playPosition = 0; + +} + +void AudioFile::drawAudioVectorMillis(double startTimeMillis, double endTimeMillis){ + + ofBackground(255); + double startTimeSamples = startTimeMillis * samplingFrequency / 1000.0; + double endTimeSamples = endTimeMillis * samplingFrequency / 1000.0; + double screenHeight = ofGetHeight() ; + double screenWidth = ofGetWidth(); + + ofSetColor(255,0,0); + double numberOfSamples = endTimeSamples - startTimeSamples; + double samplesPerPixel = numberOfSamples / screenWidth; + string samplesString = "millis : sps "; + samplesString += ofToString(samplesPerPixel, 2); + samplesString += " , \n"; + + int lastSampleIndex = (int) startTimeSamples; + + for (int i = 1;i < screenWidth;i++){// && startTimeSamples + samplesPerPixel * i < endTimeSamples;i += 1){ + int sampleIndex = (int) min((startTimeSamples + samplesPerPixel * i), (double) length-1); + //if (sampleIndex < 0) + // sampleIndex = 0; + ofLine(i-1, screenHeight - (1-audioVector[sampleIndex])*screenHeight/2.0 , i, screenHeight - (1-audioVector[lastSampleIndex])*screenHeight/2.0); + samplesString += ofToString(audioVector[i])+" , \n"; + lastSampleIndex = sampleIndex; + + } + ofDrawBitmapString(samplesString, 20,20); + + ofSetColor(100,100,100); + ofLine(screenWidth/2, 0, screenWidth/2, screenHeight); + + +} + + + +void AudioFile::drawAudioVectorSamples(double startTimeSample, double endTimeSample){ + + ofBackground(255); + screenHeight = ofGetHeight() ; + double screenWidth = ofGetWidth(); + + ofSetColor(255,0,0); + double numberOfSamples = endTimeSample - startTimeSample; + double samplesPerPixel = numberOfSamples / screenWidth; + + double halfHeight = screenHeight/2; + + int lastSampleIndex = (int) startTimeSample; + /* + for (int i = 1;i < screenWidth;i++){// && startTimeSamples + samplesPerPixel * i < endTimeSamples;i += 1){ + int sampleIndex = (int) (startTimeSample + samplesPerPixel * i); + ofLine(i-1, screenHeight - (1-audioVector[sampleIndex])*screenHeight/2.0 , i, screenHeight - (1-audioVector[lastSampleIndex])*screenHeight/2.0); + lastSampleIndex = sampleIndex; + + } + */ + double firstXpos = halfHeight; + double firstYpos = getPosition(startTimeSample);//screenHeight - ((1-audioVector[startTimeSample])*screenHeight/2.0); + + int stepSize = 1;//(int) samplesPerPixel); optimize !! XXX + for (int sampleIndex = startTimeSample+1;sampleIndex < min(endTimeSample, (double) length);sampleIndex+= stepSize){ + + double secondXpos = (sampleIndex - startTimeSample) * screenWidth/numberOfSamples; + double secondYpos = getPosition(sampleIndex);//screenHeight - ((1-audioVector[sampleIndex])*screenHeight/2.0); + ofLine(firstXpos, firstYpos, secondXpos, secondYpos); + + if (numberOfSamples < 100) + ofCircle(secondXpos, secondYpos, 2); + + firstXpos = secondXpos; + firstYpos = secondYpos; + + + } + + string samplesString = "samples: sps " + ofToString(samplesPerPixel, 2); + samplesString += ", number of smaplers " + ofToString(numberOfSamples, 2); + samplesString += " , \n"; + + + string textString; + textString = ofToString(playPosition, 1); + ofDrawBitmapString(textString, 20, 20); + ofDrawBitmapString(samplesString, 20, 60); + + ofSetColor(0,0,255); + ofLine(0, halfHeight, screenWidth, halfHeight); + +} +/* +double testApp::getXposition(int index, int startTimeSampleIndex){ + if (index >= 0 && index < audioVector.size()) + return (index - startTimeSampleIndex) * screenWidth/numberOfSamples; +} +*/ +double AudioFile::getPosition(int index){ + if (index >= 0 && index < audioVector.size()) + return screenHeight - ((1-audioVector[index])*screenHeight/2.0); + else + return screenHeight /2 ; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/AudioFile.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,44 @@ +/* + * audioFile.h + * audioFileLoader3 + * + * Created by Andrew on 31/07/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +//Holds the actual samples loaded in from the audio file +//in a double matrix, so multilpe channels used + + +#ifndef AUDIOFILE_H +#define AUDIOFILE_H + +#include "ofMain.h" + + +class AudioFile +{ +public: + AudioFile(); // constructor +// ~AudioFile(); + + + + void drawAudioVectorMillis(double startTimeMillis, double endTimeMillis); + void drawAudioVectorSamples(double startTimeSample, double endTimeSample); + double getPosition(int index); + + typedef std::vector<double> DoubleVector; + typedef std::vector<DoubleVector> DoubleMatrix; + DoubleVector audioVector; + DoubleMatrix audioMatrix; + + double screenHeight; + int length; + double audioScaleSamples; + double playPosition;//in samples + +}; + +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/LoadedAudioHolder.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,93 @@ +/* + * LoadedAudioHolder.cpp + * fileLoaderAndOnsetDetection + * + * Created by Andrew on 28/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "LoadedAudioHolder.h" + +LoadedAudioHolder::LoadedAudioHolder(){ + audioPaused = true; + audioPlaying = false; + trackType = 0; +} + +void LoadedAudioHolder::updateToPlayPosition(){ + fileLoader.updateToAudioPosition(loadedAudio.getPosition()); +} + +void LoadedAudioHolder::updateToMillisPosition(const double& millis){ + fileLoader.updateToMillisPosition(millis); +} + +void LoadedAudioHolder::updatePlaybackPositionToMillis(const double& millis){ + printf("updatePlay %f", millis * 44.1 / (double) fileLoader.totalNumberOfSamples ); + + loadedAudio.setPosition(millis * 44.1 / (double) fileLoader.totalNumberOfSamples ); +} + +void LoadedAudioHolder::draw(){ + fileLoader.drawFile(); +} + +void LoadedAudioHolder::loadAudioFile(string soundFileName){ + loadedAudio.loadSound(soundFileName); + fileLoader.loadNewAudio(soundFileName); + audioPlaying = false; + loadedFileName = soundFileName; + copyOnsetTimes(); + +} + +void LoadedAudioHolder::copyOnsetTimes(){ + + onsetTimesMillis.clear(); + + for (int i = 0;i < fileLoader.onsetDetect.chromaOnsets.size();i++) + onsetTimesMillis.push_back(fileLoader.onsetDetect.chromaOnsets[i].millisTime); + +} + +void LoadedAudioHolder::setTrackType(const int& i){ + fileLoader.onsetDetect.trackType = i; + trackType = i; +} + +void LoadedAudioHolder::togglePlay(){ + if (!audioPlaying) { + loadedAudio.play(); + loadedAudio.setPaused(false); + audioPlaying = true; + audioPaused = false; + printf("playing %s\n", loadedFileName.c_str()); + } + else{ + audioPaused = !audioPaused; + loadedAudio.setPaused(audioPaused); + } +} + +void LoadedAudioHolder::stop(){ + audioPlaying = false; + loadedAudio.setPaused(true); + loadedAudio.setPosition(0.0); +} + +void LoadedAudioHolder::switchScreens(){ + fileLoader.screenToDraw = 1 - fileLoader.screenToDraw; +} + +void LoadedAudioHolder::windowResized(const int& w, const int& h){ + fileLoader.onsetDetect.windowResized(w, h); +} + + +void LoadedAudioHolder::printEvents(){ + for (int i = 0;i < fileLoader.onsetDetect.chromaOnsets.size();i++){ + printf("Event time %f millis %i frames pitch %f\n", fileLoader.onsetDetect.chromaOnsets[i].millisTime, + fileLoader.onsetDetect.chromaOnsets[i].frameTime, fileLoader.onsetDetect.chromaOnsets[i].aubioPitch); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/LoadedAudioHolder.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,62 @@ +/* + * LoadedAudioHolder.h + * fileLoaderAndOnsetDetection + * + * Created by Andrew Robertson on 28/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +//Holds the player ofSoundplayer +//and the analysis - ofxSoundFileLoader +//latter consists of the audio samples - in AudioFile.h +//and the onset detection, chroma and pitch analysis - in ofxAubioOnsetDetection + + +#ifndef LOADED_AUDIO_HOLDER_H +#define LOADED_AUDIO_HOLDER_H + + +#include "ofMain.h" +#include "ofxSoundFileLoader.h" + +class LoadedAudioHolder{ + + public: + + LoadedAudioHolder(); + + void updateToPlayPosition(); + void updateToMillisPosition(const double& millis); + void updatePlaybackPositionToMillis(const double& millis); + + void draw(); + void windowResized(const int& w, const int& h); + + void loadAudioFile(string soundFileName); + + void togglePlay();//pauses if playing and vice-versa + void stop(); + void switchScreens(); + + void printEvents(); + + //Samples to show or iterate through + ofxSoundFileLoader fileLoader; + ofSoundPlayer loadedAudio; + std::string loadedFileName; + + int trackType; + void setTrackType(const int& type); + + typedef vector<double> DoubleVector; + DoubleVector onsetTimesMillis; + void copyOnsetTimes(); + +private: + + //Audio To PLay + bool audioPlaying, audioPaused; + +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/ofxSoundFileLoader.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,155 @@ +/* + * ofxSoundFileLoader.cpp + * audioFileLoaderSVN1 + * + * Created by Andrew on 04/09/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "ofxSoundFileLoader.h" + +//NB zooming relies on screenToDraw - this needs to be 1 + +ofxSoundFileLoader::ofxSoundFileLoader(){ + sfinfo.format = 0; +// onsetDetect = new ofxAubioOnsetDetection(); + //onsetDetect->reset(); + + soundFileName = ""; + screenToDraw = 1; +} + +ofxSoundFileLoader::~ofxSoundFileLoader(){ +// delete onsetDetect ; +// printf("file loader delete onset detect\n"); + +} + +void ofxSoundFileLoader::updateToAudioPosition(const float& audioPosition){ + + audioHolder.playPosition = audioPosition * audioHolder.audioVector.size(); + onsetDetect.playPosition = audioPosition; +} + +void ofxSoundFileLoader::updateToMillisPosition(const double& millis){ + +// audioHolder.playPosition = audioPosition * audioHolder.audioVector.size(); + onsetDetect.playPosition = millis * 44.1 / (double)totalNumberOfSamples; + +} + +void ofxSoundFileLoader::drawFile(){ + if (screenToDraw == 0){ + audioHolder.drawAudioVectorSamples(audioHolder.playPosition - audioHolder.audioScaleSamples*0.5, + audioHolder.playPosition + audioHolder.audioScaleSamples*0.5); + }else{ + onsetDetect.drawOnsetDetectionScrolling(); + } + +} + +#pragma mark -loadAudio +void ofxSoundFileLoader::loadNewAudio(std::string filename){ + loadLibSndFile(filename.c_str()); +} + +void ofxSoundFileLoader::loadLibSndFile(const char *infilename){ + +// if (!sf_close(infile)){ +// printf("closed sndfile okay \n"); +// } + + // Open Input File with lib snd file + if (! (infile = sf_open (infilename, SFM_READ, &sfinfo))) + { // Open failed + printf ("SF OPEN routine Not able to open input file %s.\n", infilename) ; + // Print the error message from libsndfile. + puts (sf_strerror (NULL)) ; + + } else{ + printf("SF OPEN : file %s okay, ", infilename); + printf("number of channels is %i\n", sfinfo.channels); + soundFileName = infilename; + //sndfileInfoString = "Opened okay "; + + }; + + readAudio(); + onsetDetect.printOnsetList(); + printf("max val of onset det is %f\n", onsetDetect.onsetDetector.maximumDetectionValue); +} + +void ofxSoundFileLoader::readAudio(){ + + onsetDetect.reset(); + //could add this in - check the stored github + + // HERE IS THE CLASSIC LOADING FILE CODE + //DEALS WITH MORE THAN MONO + int channels = sfinfo.channels; + int blocksize = FRAMESIZE; + + float buf [channels * blocksize] ; + int k, m, readcount ; + + DoubleVector d; + while ((readcount = sf_readf_float (infile, buf, blocksize)) > 0){ + for (k = 0 ; k < readcount ; k++){ + //readcount is a chunk - eg 512 samples - of audio that is processed + d.clear(); + for (m = 0 ; m < channels ; m++){ + d.push_back(buf [k * channels + m]); + // fprintf (outfile, " % 12.10f", buf [k * channels + m]) ; + // fprintf (outfile, "\n") ; + if (m == 0){ + //makes the vector hold the mono file - the left channel + audioHolder.audioVector.push_back(buf[k * channels + 0]); + frame[k] = buf[k*channels + 0]; + } + + } + audioHolder.audioMatrix.push_back(d); + //storing the full soundfile in multiple channels in the audioMatrix + } + //printf("processing at readcount %i\n", readcount); + //could call this here + onsetDetect.processFrame(&frame[0], blocksize); + + + }//end readcount + + //printf("audio vector size is %i\n", (int) audioHolder.audioVector.size()); + audioHolder.length = (int) audioHolder.audioVector.size(); + totalNumberOfSamples = audioHolder.length; + + printf("Total number of samples %i onset frames %i\n", totalNumberOfSamples, onsetDetect.frameCountIndex); + + freeMemory(); +} + + +void ofxSoundFileLoader::freeMemory(){ + printf("FREE MEMORY in file loader\n"); + audioHolder.audioMatrix.clear(); + audioHolder.audioVector.clear(); +} + +void ofxSoundFileLoader::zoomOut(){ + if (screenToDraw == 0){ + audioHolder.audioScaleSamples *= 2.; + } + if (screenToDraw == 1){ + onsetDetect.amplitudeNumber *= 2; + } +} + +void ofxSoundFileLoader::zoomIn(){ + if (screenToDraw == 0){ + audioHolder.audioScaleSamples /= 2.; + } + if (screenToDraw == 1 && onsetDetect.amplitudeNumber > 2){ + onsetDetect.amplitudeNumber /= 2; + } +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/ofxSoundFileLoader.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,66 @@ +/* + * ofxSoundFileLoader.h + * audioFileLoaderSVN1 + * + * Created by Andrew on 04/09/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#ifndef SOUND_FILE_LOADER_H +#define SOUND_FILE_LOADER_H + + +#include "ofMain.h" +#include "sndfile.h" +#include "AudioFile.h" +#include "ofxAubioOnsetDetection.h" + + +#define FRAMESIZE 512 + + + +class ofxSoundFileLoader{ + +public: + ofxSoundFileLoader(); + ~ofxSoundFileLoader(); + float frame[FRAMESIZE]; + + void updateToAudioPosition(const float& audioPosition); + void updateToMillisPosition(const double& millis); + void drawFile(); + void zoomOut(); + void zoomIn(); + + void loadLibSndFile(const char *infilename); + +// void openNewFileWithDialogBox(); + void loadNewAudio(std::string filename); + + typedef std::vector<double> DoubleVector; +// typedef std::vector<DoubleVector> DoubleMatrix; + + //0 draws audio vector samples + //1 draws the onset fn, pitch and chroma data + int screenToDraw; + + AudioFile audioHolder; + + ofxAubioOnsetDetection onsetDetect; + //chromaOnsetHolder chromaHolder; - add in here + + int totalNumberOfSamples; + + void readAudio(); + + string soundFileName; + SNDFILE *infile; // define input and output sound files + SF_INFO sfinfo ; // struct to hold info about sound file + + void freeMemory(); + + +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxAudioFileLoader/testApp.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,62 @@ +#ifndef _TEST_APP +#define _TEST_APP + + +#include "ofMain.h" +#include "sndfile.h" +#include "ofxFileDialogOSX.h" +#include "LoadedAudioHolder.h" +//#include "ofxSoundFileLoader.h" +#include "LoadedAudioHolder.h" + +//note the dependency on sndfile (libsndfile library needs to be accessible) +//also the file dialogue addon + +//main commands: +//O: open a new file +//see the key pressed function for other bits - e.g. can view spectral difference + +//TO DO +//Move all the soundfile stuff to the ofxSoundFileLoader +//can hold the player, the audio samples and the onset class there + +//length in terms of frames (at 512 samples per frame - there are 90 per second) => 900: 10 seconds + +class testApp : public ofBaseApp{ + + public: + + + void setup(); + void update(); + void draw(); + + void keyPressed (int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + + void audioRequested (float * input, int bufferSize, int nChannels); + + bool getFilenameFromDialogBox(string* fileNameToSave); + void openNewAudioFileWithdialogBox(); + void loadNewAudio(string soundFileName); + + LoadedAudioHolder audioFilePlayer; + + +//live audio input + float pan; + int sampleRate; + bool bNoise; + float volume; + float * lAudio; + float * rAudio; + + +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxWindowRegion/windowRegion/ofxPlotFunction.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,163 @@ +/* + * ofxPlotFunction.cpp + * + * + * Created by Andrew on 14/11/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +#include "ofxPlotFunction.h" + + +ofxPlotFunction :: ofxPlotFunction(){ + fullScreen.resetToFullScreen(); +} + +ofxPlotFunction :: ~ofxPlotFunction(){ + +} + + +void ofxPlotFunction::drawVector(DoubleVector& energyVec, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxNumberOfIndexPoints, const double& maxValue){ + + float screenHeight = window.height; + float screenWidth = window.width; + + double numberOfIndexPoints = min(maxNumberOfIndexPoints, (double) maxIndex - minIndex); + double indicesPerStep = (maxIndex - minIndex) / numberOfIndexPoints; + double pixelsPerStep = window.width / numberOfIndexPoints; + + int i, j; + + double heightScalar = window.height / (1.0*maxValue); + + int lastHeight = window.y + screenHeight - (energyVec[minIndex]*heightScalar);; + int newHeight; + int xPosition; + int lastXposition = window.x; + + double exactIndex; + for (exactIndex = minIndex; exactIndex < maxIndex; exactIndex += indicesPerStep){ + j = round(exactIndex); + i = j - minIndex; + + if (j < energyVec.size()){ + xPosition = window.x + i*pixelsPerStep; + newHeight = window.y + screenHeight - (energyVec[j]*heightScalar); + + ofLine(lastXposition, lastHeight, xPosition, newHeight); + + lastHeight = newHeight; + lastXposition = xPosition; + + } + } +} + + +void ofxPlotFunction::drawVector(DoubleVector& energyVec, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxResolution){ + + + minIndex = max(0, minIndex); + maxIndex = min((int)energyVec.size()-1, maxIndex); + int tmpTwenty = 20; + double maximumValue = 1.1*getMaximum(energyVec, minIndex, maxIndex, tmpTwenty); + drawVector(energyVec, minIndex, maxIndex, window, maxResolution, maximumValue); + +} + + + +void ofxPlotFunction::drawArray(float* energyArray, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxResolution){ + + minIndex = max(0, minIndex); + // maxIndex = min((int)sizeof(energyArray)-1, maxIndex); + int tmpStepVal = 100; + double maximumValue = 1; + if (maxIndex > minIndex) + maximumValue = getMaximumArray(energyArray, minIndex, maxIndex, tmpStepVal); + + drawArray(energyArray, minIndex, maxIndex, window, maxResolution, maximumValue); +} + +void ofxPlotFunction::drawArray(float* energyArray, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxNumberOfIndexPoints, const double& maximumValue){ + + + float screenHeight = window.height; + float screenWidth = window.width; + + double numberOfIndexPoints= min(maxNumberOfIndexPoints, (double) maxIndex - minIndex); + int indicesPerStep = (int) round((maxIndex - minIndex) / numberOfIndexPoints); + indicesPerStep = max(1, indicesPerStep); + double pixelsPerStep = window.width / numberOfIndexPoints; + + string pixelstring = ofToString(indicesPerStep); + ofDrawBitmapString("max val "+pixelstring, 500,100); + + int i, j; + + double heightScalar = window.height / (1.2*maximumValue); + + int lastHeight = window.y + screenHeight - (energyArray[minIndex]*heightScalar);; + int newHeight; + int xPosition; + int lastXposition = window.x; + + int exactIndex; + for (exactIndex = minIndex - minIndex%indicesPerStep; exactIndex < maxIndex; exactIndex += indicesPerStep){ + j = exactIndex;// - exactIndex % indicesPerStep ; + i = j - minIndex; + + xPosition = window.x + i*pixelsPerStep; + if (j >= 0) + newHeight = window.y + screenHeight - (energyArray[j]*heightScalar); + + if (j < 16) + cout << "j is " << j << ", i is " << i << endl; + + ofLine(lastXposition, lastHeight, xPosition, newHeight); + // window.x+screenWidth*(i+1)/scrollWidth, window.y + screenHeight - (energyVec[j]*screenHeight/heightFactor)); + + lastHeight = newHeight; + lastXposition = xPosition; + + + } + + +} + + +double ofxPlotFunction::getMaximum(DoubleVector& energyVec, const int& minIndex, const int& maxIndex, int& numberOfSteps){ + + int step = max(1, (int)((maxIndex - minIndex) / (float) numberOfSteps)); + double maximumValue = energyVec[minIndex]; + int index = minIndex; + while (index < maxIndex && index < energyVec.size()){ + index += step; + if (energyVec[index] > maximumValue){ + maximumValue = energyVec[index]; + } + } + return maximumValue; + +} + + + +double ofxPlotFunction::getMaximumArray(float* energyArray, const int& minIndex, const int& maxIndex, int& numberOfSteps){ + + int step = max(1, (int)((maxIndex - minIndex) / (float) numberOfSteps)); + double maximumValue = energyArray[minIndex]; + int index = minIndex; + while (index < maxIndex ){//&& index < sizeof(energyArray) + index += step; + if (energyArray[index] > maximumValue){ + maximumValue = energyArray[index]; + } + } + return maximumValue; + +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxWindowRegion/windowRegion/ofxPlotFunction.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,40 @@ +/* + * ofxPlotFunction.h + * BTrackPortAudioMultipleAnalyser + * + * Created by Andrew Robertson on 14/11/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + + +#ifndef PLOT_FUNCTION_H +#define PLOT_FUNCTION_H + +#include "ofMain.h" +#include "ofxWindowRegion.h" + + +struct ofxPlotFunction { + public: + + ofxPlotFunction(); + ~ofxPlotFunction(); + + typedef std::vector<double> DoubleVector; + typedef std::vector<int> IntVector; + typedef std::vector<DoubleVector> DoubleMatrix; + + ofxWindowRegion fullScreen; + void drawVector(DoubleVector& energyVec, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxResolution, const double& maxValue); + void drawVector(DoubleVector& energyVec, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxResolution); + void drawArray(float* energyArray, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxResolution); + void drawArray(float* energyArray, int minIndex, int maxIndex, const ofxWindowRegion& window, const double& maxResolution, const double& maximumValue); + + + double getMaximum(DoubleVector& energyVec, const int& minIndex, const int& maxIndex, int& numberOfSteps); + + double getMaximumArray(float* energyArray, const int& minIndex, const int& maxIndex, int& numberOfSteps); + +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxWindowRegion/windowRegion/ofxWindowRegion.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,110 @@ +/* + * ofxWindowRegion.cpp + * BTrackPortAudioMultipleAnalyser + * + * Created by Andrew Robertson on 13/10/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + +//WARNING - if window is resized, you must make a manual check function in testApp that calls +//yourWindow.resize(w, h); +//it does not use a listener (which would be preferable) + +#include "ofxWindowRegion.h" + +ofxWindowRegion::ofxWindowRegion(){ + x = 0; + y = 0; + width = ofGetWidth(); + height = ofGetHeight(); + + fullScreenX = ofGetWidth(); + fullScreenY = ofGetHeight(); + + getRelativeSize();//store in case we resize! + printf("set window with x %i, y %i, width %i, height %i\n", x, y, width, height); +} + +ofxWindowRegion::ofxWindowRegion(int _x, int _y, int _width, int _height){ + if (_x >= 0 && _x <= ofGetWidth()) + x = _x; + + if (_y >= 0 && _y <= ofGetHeight()) + y = _y; + + if (_width > 0) + width = _width; + + if (_height > 0) + height = _height; + + fullScreenX = ofGetWidth(); + fullScreenY = ofGetHeight(); + + getRelativeSize(); + printf("set window with x %i, y %i, width %i, height %i\n", x, y, width, height); +} + +void ofxWindowRegion::getRelativeSize(){ + relativeX = (double)x / fullScreenX; + relativeY = (double)y / fullScreenY; + relativeWidth = (double)width / fullScreenX; + relativeHeight = (double)height / fullScreenY; +} + +void ofxWindowRegion::setToRelativeSize(){ + x = relativeX * fullScreenX; + y = relativeY * fullScreenY; + width = relativeWidth * fullScreenX; + height = relativeHeight * fullScreenY; +} + +void ofxWindowRegion::setToRelativeSize(double _xr, double _yr, double _wr, double _hr){ + relativeX = _xr; + relativeY = _yr;; + relativeWidth = _wr;; + relativeHeight = _hr; + setToRelativeSize(); + printf("window set to relative size\n"); +} + +void ofxWindowRegion::resized(int w, int h){ + fullScreenX = w; + fullScreenY = h; + setToRelativeSize(); +} + + +void ofxWindowRegion::setWindowDimensions(int _x, int _y, int _width, int _height){ + if (_x >= 0 && _x <= ofGetWidth()) + x = _x; + + if (_y >= 0 && _y <= ofGetHeight()) + y = _y; + + if (_width > 0) + width = _width; + + if (_height > 0) + height = _height; + + getRelativeSize(); + printf("set window with x %i, y %i, width %i, height %i\n", x, y, width, height); +} + +void ofxWindowRegion::resetToFullScreen(){ + x = 0; + y = 0; + width = ofGetWidth(); + height = ofGetHeight(); +} + + +void ofxWindowRegion::drawOutline() const{ + ofLine(x, y, x+width, y); + ofLine(x+width, y, x+width, y+height); + ofLine(x, y+height, x+width, y+height); + ofLine(x, y, x, y+height); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/ofxWindowRegion/windowRegion/ofxWindowRegion.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,40 @@ +/* + * ofxWindowRegion.h + * BTrackPortAudioMultipleAnalyser + * + * Created by Andrew on 13/10/2011. + * Copyright 2011 QMUL. All rights reserved. + * + */ + + +#ifndef WINDOW_REGION_H +#define WINDOW_REGION_H + + +#include "ofMain.h" + +struct ofxWindowRegion { +public: + ofxWindowRegion(); + ofxWindowRegion(int _x, int _y, int _width, int _height); + void setWindowDimensions(int _x, int _y, int _width, int _height); + void resetToFullScreen(); + void resized(int w, int h); + void getRelativeSize(); + void setToRelativeSize(); + void setToRelativeSize(double _xr, double _yr, double _wr, double _hr); + + int x; + int y; + int width; + int height; + + double relativeX, relativeY, relativeWidth, relativeHeight; + double fullScreenX; + double fullScreenY; + + void drawOutline() const; + +}; +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/DrumTimingLoader.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,44 @@ +/* + * DrumTimingLoader.cpp + * DrumTimingLoader + * + * Created by Andrew on 09/08/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "DrumTimingLoader.h" + +DrumTimingLoader::DrumTimingLoader(){ + +} + + +void DrumTimingLoader::initialise(){ + + recordedTracks.loadTestAudio(); + /* + calculateRecordedTempoData(); + printf("\n audioeventmatcher\nFIRST PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); + setTempoPrior(recordedTempoData.playingTempo); + calculateRecordedTempoData();//now calculate again using better prior + + printf("\n audioeventmatcher\nSECOND PASS: FINAL recorded tempo is %f\n", recordedTempoData.playingTempo); + printf("GLOBAL TEMPO of RECORDED FILES\n"); + */ + +} + + + +void DrumTimingLoader::draw(){ + bool drawTracks = false; + if (drawTracks) + recordedTracks.drawTracks(); + else + recordedTracks.drumTimingAnalyser.drawTempoCurve(); +} + +void DrumTimingLoader::windowResized(int w, int h){ + recordedTracks.windowResized(w, h); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/DrumTimingLoader.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,31 @@ +/* + * DrumTimingLoader.h + * DrumTimingLoader + * + * Created by Andrew on 09/08/2012. + * Copyright 2012 QMUL. All rights reserved. + *file://localhost/Users/andrew/Dropbox/DrumTiming/DrumTimingLoader_OF/PerformanceAnalyserSrc/ + */ + +#ifndef DRUM_TIMING_LOADER +#define DRUM_TIMING_LOADER + +#include "RecordedMultipleAudio.h" + +// basic file operations for text file stuff +#include <iostream> +#include <fstream> +using namespace std; + + +class DrumTimingLoader{ + + public: + DrumTimingLoader(); + void initialise(); + void draw(); + void windowResized(int w, int h); + RecordedMultipleAudio recordedTracks; + +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/RecordedMultipleAudio.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,525 @@ +/* + * RecordedMultipleAudio.cpp + * MultipleAudioMathcher + * + * Created by Andrew on 31/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + +#include "RecordedMultipleAudio.h" + +RecordedMultipleAudio::RecordedMultipleAudio(){ + + infoFilepath = "../../../data/errorData.txt"; + //infoFilepath = "/Users/andrew/errorData.txt"; + + timingOffset = 0; +} + +void RecordedMultipleAudio::loadTestAudio(){ + + + numberOfAudioTracks = 2; + + printf("loaded max val is %f\n", loadedAudioFiles[0].fileLoader.onsetDetect.onsetDetector.maximumDetectionValue); + + int multitrackToLoad = 5; + setDifferentMultitracks(multitrackToLoad);//command to load this set of audio files - see below + + drumTimingAnalyser.phaseCost = 1000;//v high - i.e. dont do phase + + drawWindow = 1; + trackScreenHeight = 0.25; + + + +// printf("AFTER LOADING: \n"); +// printInfo(); + +} +#pragma mark -loadingPrerecordedTracks +void RecordedMultipleAudio::setDifferentMultitracks(const int& setToLoad){ + const char *kickfilename ;//= "../../../data/sound/LiveDues/kick_liveDues.wav"; + const char *roomfilename ;//"../../../data/sound/LiveDues/bass_upsideLive.wav"; + const char *snarefilename ; + std::string sonicVizBeatsFilename ; + + switch (setToLoad) { + case 0: + kickfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/kickFuture.wav"; + roomfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/roomFuture.wav"; + snarefilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/snareFuture.wav"; + sonicVizBeatsFilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/futureHides/FutureHidesBeats.txt"; + break; + + + case 1: + roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/Mixdown/PennyArcade_StudioMixdown.wav"; + kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/kick.wav"; + snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/snare.wav"; + sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcadeStudio14aMultitrack/Mixdown/PennyArcade_StudioMixdown_beats.txt"; + break; + + case 2: + roomfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/colesL_bip.wav"; + kickfilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/Kick_bip.wav"; + snarefilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/Snare_bip.wav"; + sonicVizBeatsFilename = "/Users/andrew/Documents/work/programming/MadMax/AudioFiles/MattIngramGreenSection/IngramGreenSectionBeats.txt"; + break; + + case 3: + roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/coles_bip.wav"; + kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/kick d112_bip.wav"; + snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/snare bottom_bip.wav"; + sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDiamondWhite/tractorsDiamondWhite/Bounces/diamondWhiteMultiTakeOne/TakeOneBeats.txt"; + break; + + case 4: + roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/neuamnn_bip.wav"; + kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/kick_bip.wav"; + snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/snare_bip.wav"; + sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeOne_4/PennyArcade_take4_beats.txt"; + break; + + case 5: + roomfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/neuamnn_bip.wav"; + kickfilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/kick_bip.wav"; + snarefilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/snare_bip.wav"; + sonicVizBeatsFilename = "/Volumes/Supersaurus/TractorsAlbum/tractorsDemo/Bounces/PennyArcade_Multitracks/TakeTwo_5/PennyArcade_take5_beats.txt"; + break; + + + + } + if (kickfilename != NULL){ + + loadAudioTrack(kickfilename, 0); + } + + if (roomfilename != NULL){ + printf("roomfilename: %s\n", roomfilename); + loadAudioTrack(roomfilename, 1); + } + + if (snarefilename != NULL) + loadAudioTrack(snarefilename, 2); + + if (sonicVizBeatsFilename.c_str() != NULL){ + readInBeatsFile(sonicVizBeatsFilename); + printBeatTimes(); + checkFileErrors(0); + checkFileErrors(2); + findBeatOnsets(); + } +} + +void RecordedMultipleAudio::loadAudioTrack(std::string name, const int& channel){ + //kick - track type 0 + //bass - type 1 + //snare type 2 + //guitar type 3 + if (channel >= 0 && channel <= numberOfAudioTracks){ + loadedAudioPtr = new LoadedAudioHolder; + //set tracktype before we do analysis + //so we dont do unnecessary chroma and pitch calculations + if (channel == 0 || channel == 2){ + loadedAudioPtr->setTrackType(channel); + } + else{ + loadedAudioPtr->setTrackType(0); + } + loadedAudioPtr->loadAudioFile(name); + + loadedAudioFiles[channel] = *loadedAudioPtr; + loadedAudioFiles[channel].fileLoader.onsetDetect.window.setToRelativeSize(0, trackScreenHeight*channel, 1, trackScreenHeight); + //loadedAudioFiles[channel].setTrackType(channel); + } +} + + + +void RecordedMultipleAudio::readInBeatsFile(std::string& pathName){ + + // "/Users/andrew/Documents/work/MuseScore/RWC/ANNOTATION/RM-C002_annotation+WavPos.csv" + beatTimes.clear(); + + printf("- - - - \n\nREAD FILE %s\n", pathName.c_str()); + ifstream file ( pathName.c_str()); + string value, tmpLine; + stringstream iss; + int count = 0; + + while ( file.good() ) + { + getline(file, tmpLine); + iss << tmpLine; + int lineCount = 0; + // printf("tmp line %s\n", tmpLine.c_str()); + while(getline ( iss, value, '\t' )){ // read a string until next comma: http://www.cplusplus.com/reference/string/getline/ + // cout << string( value, 1, value.length()-2 ); // display value removing the first and the last character from it + // printf("line:%s\n", value.c_str()); + string::size_type start = value.find_first_not_of(" ,\t\v\n"); + + string part = value.substr(start, string::npos); + + //printf("%s\n", firstpart.c_str()); + if (lineCount == 0){ + //printf("First part of line found '%s'\n", part.c_str()); + double newBeatTime = atof(part.c_str()); + beatTimes.push_back(newBeatTime); + } + lineCount++; + + }//end while reading line + iss.clear(); + + + }//end while + + // printBeatTimes(); + printf("There are %i BEAT annotations\n", (int)beatTimes.size()); + +} + +void RecordedMultipleAudio::printBeatTimes(){ + for (int i = 0;i < beatTimes.size();i++){ + printf("Beat[%i] = %f\n", i, beatTimes[i]); + } +} + + +void RecordedMultipleAudio::checkFileErrors(int channel){ + int beatIndex = 0; + int cutoff = 50;//ms width to check + for (int i = 0;i < loadedAudioFiles[channel].onsetTimesMillis.size();i++){ + while (beatIndex < beatTimes.size() && 1000.0*beatTimes[beatIndex] < loadedAudioFiles[channel].onsetTimesMillis[i] - cutoff) { + beatIndex++; + } + double error = (1000.0*beatTimes[beatIndex] - loadedAudioFiles[channel].onsetTimesMillis[i]); + if (fabs(error) < cutoff){ + if (channel == 0) + printf("Pos: %i Beat Time %f Kick Time %f Error %f\n", beatIndex%4, 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); + else + printf("Pos: %i Beat Time %f Snare Time %f Error %f\n", beatIndex%4, 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); + + }else{ + if (channel == 0) + printf("Out of Beat: Kick Time %f beat error %f\n", 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); + else + printf("Out of Beat: %f Snare Time %f best error %f\n", 1000.0*beatTimes[beatIndex], loadedAudioFiles[0].onsetTimesMillis[i], error); + + } + } +} + + +#pragma mark -labelExactOnsets + +void RecordedMultipleAudio::findBeatOnsets(){ +//tries to find kicks on 1, 3; snares on 2,4 + int beatIndex = 0; + int kickIndex = 0; + int snareIndex = 0; + double kickTime, snareTime; + int cutoff = 50;//ms width to check + + onsetInfo.clear(); + +// kickErrors.clear(); +// snareErrors.clear(); + + bool beatFound; + for (int k = 0;k < beatTimes.size();k++){ + beatFound = false; + double newBeatTime = beatTimes[k]*1000.0; + int beatPosition = k % 4; + OnsetInformation information; + switch (beatPosition) { + case 0: case 2://check for kick when it is on the `one' or 'three' (0 or 2 in our metrical position) + // printf("check %i kindex %i\n", beatPosition, kickIndex); + while (kickIndex < loadedAudioFiles[0].onsetTimesMillis.size() && loadedAudioFiles[0].onsetTimesMillis[kickIndex] < newBeatTime - cutoff){ + kickIndex++; + kickTime = loadedAudioFiles[0].onsetTimesMillis[kickIndex]; + // printf("checking beat[%i] %f kick %f error %f\n", k, beatTimes[k]*1000.0, kickTime, (kickTime - beatTimes[k]*1000.0)); + if (fabs(kickTime - beatTimes[k]*1000.0) < cutoff){ + beatFound = true; + printf("beat[%i] %f kick %f error %f\n", k, beatTimes[k]*1000.0, kickTime, (kickTime - beatTimes[k]*1000.0)); + + information.error = (kickTime - beatTimes[k]*1000.0);//FOR NOW ONLY + information.metricalPosition = beatPosition; + information.type = 0; + information.exactOnsetTime = kickTime; + // exactBeatPositions.push_back(kickTime); + } + } + + break; + case 1: case 3://snare + while (snareIndex < loadedAudioFiles[1].onsetTimesMillis.size() && loadedAudioFiles[1].onsetTimesMillis[snareIndex] < newBeatTime - cutoff ){ + snareIndex++; + snareTime = loadedAudioFiles[1].onsetTimesMillis[snareIndex]; + if (fabs(snareTime - beatTimes[k]*1000.0) < cutoff){ + beatFound = true; + // snareErrors.push_back((beatTimes[k]*1000.0 - snareTime)); + information.error = (snareTime - beatTimes[k]*1000.0); + information.metricalPosition = beatPosition;//.push_back(beatPosition); + information.type = 1; + information.exactOnsetTime = snareTime; + printf("beat[%i] %f snare %f error %f\n", k, beatTimes[k]*1000.0, snareTime, (snareTime - beatTimes[k]*1000.0)); + // exactBeatPositions.push_back(snareTime); + } + } + + break; + } + if (!beatFound){ + information.type = -1;//not a kick or snare + information.exactOnsetTime = beatTimes[k]*1000.0; + information.metricalPosition = beatPosition;//.push_ + // exactBeatPositions.push_back(beatTimes[k]*1000.0);//have to go with the annotated beat instead (no matching kick or snare) + + printf("beat[%i] %f NOT FOUND, kicktime %f snaretime %f\n", k, beatTimes[k]*1000.0, kickTime, snareTime ); + } + + onsetInfo.push_back(information); + + }//end for all beat annotations + + correctExactBeatTiming();//get rid of the first onset time + + calculateTimingAnalysis(); + +} + +#pragma mark -doTimingAnalysis +void RecordedMultipleAudio::correctExactBeatTiming(){ + //get rid of firtst onset time + if (onsetInfo.size() > 0){ + timingOffset = onsetInfo[0].exactOnsetTime;//s[0]; + double tmpPosn; + for (int i = 0;i < onsetInfo.size();i++){ + onsetInfo[i].beatTimeToProcess = onsetInfo[i].exactOnsetTime - timingOffset; + printf("exact [%i] type %i %f, corrected %f\n", i, onsetInfo[i].type, onsetInfo[i].exactOnsetTime, onsetInfo[i].beatTimeToProcess ); + } + } +} + +void RecordedMultipleAudio::calculateTimingAnalysis(){ + + for (int i = 0;i < onsetInfo.size();i++){ + drumTimingAnalyser.updateCostToPoint(onsetInfo[i].beatTimeToProcess, i); + //updatecounter is the beat position for this note event - can be used to do other kinds of durations than just simple beats + + drumTimingAnalyser.beatPosition.push_back(onsetInfo[i].exactOnsetTime); + } + drumTimingAnalyser.processPathHistory(); + drumTimingAnalyser.calculateTempoLimits(); + + getErrorTimesFromAnalysis(); + + alternativeKickRelativeAnalysis(); + + exportErrorInformation(); + + displayKickRelativeMedianErrors();//NB messes ther order of these + + //this was how we did it in multimatch program +// timer.processPathHistory(); +// timer.calculateTempoLimits(); +// timer.exportTimingData(); +// timer.exportProcessedBeatTimes(firstNoteTime); +} + +void RecordedMultipleAudio::getErrorTimesFromAnalysis(){ + printf("\nDrumTimingLoader: get error times from analysis!!!\n"); + setUpErrorsByMetricalPosition(); + //gets the errors from the drum timing analyser (i.e. ISMIR paper code) and attributes these to the onsets + for (int i = 0;i < drumTimingAnalyser.timingData.size();i++){ + onsetInfo[i].error = drumTimingAnalyser.timingData[i][5]; + onsetInfo[i].clickTime = drumTimingAnalyser.timingData[i][1] + timingOffset;//this is where teh timing analyser placed the click times + errorsByMetricalPosition[onsetInfo[i].metricalPosition].push_back(onsetInfo[i].error); + printf("beat %i metrical posn %i exact beat time %f error %i\n", i, onsetInfo[i].metricalPosition, onsetInfo[i].exactOnsetTime, (int)onsetInfo[i].error); + } + displayMedianErrors(); +} + + +void RecordedMultipleAudio::alternativeKickRelativeAnalysis(){ + printf("\n\nAnalysis Relative to the Kick Drum on the ONE\n"); + //this sees kicks as ON the beat, looks at relative error of the three other beats if we chop the bar evenly + + double recentBeatTime, currentTempo; + kickRelativeErrors.clear(); + kickRelativeClickTimes.clear(); + + for (int i = 0;i < drumTimingAnalyser.timingData.size();i++){ + int beatPosition = i%4; + if (beatPosition == 0){ + recentBeatTime = onsetInfo[i].exactOnsetTime; + if (i+4 < onsetInfo.size()) + currentTempo = (onsetInfo[i+4].exactOnsetTime - onsetInfo[i].exactOnsetTime)/4.0; + printf("new beat time %f tempo %f\n", recentBeatTime, currentTempo); + } + double error = onsetInfo[i].exactOnsetTime - (recentBeatTime + beatPosition*currentTempo); + printf("Beat %i KR Predicted Beat %f Actual exact %f KRerror %f DTerror %i\n", beatPosition, (recentBeatTime + beatPosition*currentTempo), onsetInfo[i].exactOnsetTime, error, (int)onsetInfo[i].error); + kickRelativeErrors.push_back(error); + kickRelativeClickTimes.push_back(recentBeatTime + beatPosition*currentTempo); + } +} + +#pragma label -exportInfo +void RecordedMultipleAudio::exportErrorInformation(){ + printf("Export final timing information\n"); + + ofstream ofs(infoFilepath.c_str()); + for (int i = 0;i < onsetInfo.size() && kickRelativeErrors.size();i++){// drumTimingAnalyser.timingData.size() + ofs << i << "," << (i%4) << "," << onsetInfo[i].exactOnsetTime << ","; + ofs << onsetInfo[i].clickTime << "," << onsetInfo[i].error << ",";//the error for the ISMIR timing analyser + ofs << kickRelativeClickTimes[i] << "," << kickRelativeErrors[i];//the click and error for beats evenly between kicks + ofs << endl; + } + +} + +void RecordedMultipleAudio::printKickRelativeErrors(){ + for (int i = 0;i < kickRelativeErrors.size();i++){ + printf("KR error [%i] : %.1f\n", i, kickRelativeErrors[i]); + } +} + +void RecordedMultipleAudio::setUpErrorsByMetricalPosition(){ + //clear this matrix + errorsByMetricalPosition.clear(); + for (int i = 0;i < 4;i++){ + DoubleVector v; + errorsByMetricalPosition.push_back(v); + } + +} + +void RecordedMultipleAudio::displayMedianErrors(){ + printf("Medians of the Decoded Tempo variations\n"); + for (int i = 0;i < 4;i++){ + //printErrorsForMetricalPosition(i); + std::sort(errorsByMetricalPosition[i].begin(), errorsByMetricalPosition[i].end());//sort vector + double median = errorsByMetricalPosition[i][(int)(errorsByMetricalPosition[i].size()/2)]; + printf("median for metrical position %i is %f\n", i, median); + } +} + + +void RecordedMultipleAudio::displayKickRelativeMedianErrors(){ + printf("Medians of the KR variations\n"); + + DoubleVector tmpKRErrors; + + + for (int i = 0;i < 4;i++){ + + tmpKRErrors.clear(); + int index = 0; + + while (index+i < kickRelativeErrors.size()) { + tmpKRErrors.push_back(kickRelativeErrors[index + i]); + index += 4; + } + +// for (int k = 0;k < tmpKRErrors.size();k++) +// printf("kr %i [%i] = %f\n", i, k, tmpKRErrors[k]); + + //printErrorsForMetricalPosition(i); + std::sort(tmpKRErrors.begin(), tmpKRErrors.end());//sort vector + +// for (int k = 0;k < tmpKRErrors.size();k++) +// printf("sorted kr %i [%i] = %f\n", i, k, tmpKRErrors[k]); + + + double median = tmpKRErrors[(int)(tmpKRErrors.size()/2)]; + printf("median for metrical position %i is %f\n", i, median); + } +} + +void RecordedMultipleAudio::printErrorsForMetricalPosition(const int& i){ + for (int k = 0;k < errorsByMetricalPosition[i].size();k++){ + printf("metrical posn %i, [%i] = %f\n", i, k, errorsByMetricalPosition[i][k]); + } +} + +#pragma mark -drawTracks + +void RecordedMultipleAudio::drawTracks(){ + if (drawWindow == 0){ + for (int i = 0;i < numberOfAudioTracks;i++){ + loadedAudioFiles[i].draw(); + } + } else { + drumTimingAnalyser.drawTempoCurve(); + } +} + +#pragma mark -update +void RecordedMultipleAudio::updatePosition(){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].updateToPlayPosition(); +} + +void RecordedMultipleAudio::updatePositionToMillis(const double& millis){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].updateToMillisPosition(millis); +} + +void RecordedMultipleAudio::updatePlaybackPositionToMillis(const double& millis){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].updatePlaybackPositionToMillis(millis); +} + +void RecordedMultipleAudio::switchScreens(){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].switchScreens(); +} + + +void RecordedMultipleAudio::togglePlay(){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].togglePlay(); +} + +void RecordedMultipleAudio::stop(){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].stop(); +} + + +void RecordedMultipleAudio::printInfo(){ + loadedAudioFiles[0].fileLoader.onsetDetect.printChromaInfo(); + loadedAudioFiles[0].printEvents(); +} + +void RecordedMultipleAudio::windowResized(const int& w, const int& h){ + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].windowResized(w, h); +} + +void RecordedMultipleAudio::zoomIn(){ + if (drawWindow == 0){ + printf("zoom in\n"); + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].fileLoader.zoomIn(); + } + + if (drawWindow == 1) + drumTimingAnalyser.zoomIn();//numberOfPointsPerPage /= 2; +} + +void RecordedMultipleAudio::zoomOut(){ + printf("zoom out\n"); + for (int i = 0;i < numberOfAudioTracks;i++) + loadedAudioFiles[i].fileLoader.zoomOut(); + + if (drawWindow == 1) + drumTimingAnalyser.zoomOut();//numberOfPointsPerPage *= 2; + +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/RecordedMultipleAudio.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,105 @@ +/* + * RecordedMultipleAudio.h + * MultipleAudioMathcher + * + * Created by Andrew on 31/01/2012. + * Copyright 2012 QMUL. All rights reserved. + * + */ + + +#ifndef RECORDED_MULTIPLE_AUDIO_H +#define RECORDED_MULTIPLE_AUDIO_H + + +#include "ofMain.h" +#include "ChromaOnset.h" +#include "LoadedAudioHolder.h" +#include "TimingAnalyser.h" + +typedef std::vector<double> DoubleVector; +typedef std::vector<int> IntVector; + +struct OnsetInformation{//stores all the beat positions, the onset type and metrical position + double error; + int metricalPosition; + double exactOnsetTime; + double beatTimeToProcess; + double clickTime;//from the Timing Analyser + int type;//0 for kick, 1 for snare +}; + +typedef std::vector<OnsetInformation> OnsetVector; + +class RecordedMultipleAudio{ + + public: + RecordedMultipleAudio(); + + void loadTestAudio(); + void updatePosition(); + void updatePositionToMillis(const double& millis); + void updatePlaybackPositionToMillis(const double& millis); + + void drawTracks(); + void switchScreens(); + void togglePlay(); + + void stop(); + void printInfo(); + void windowResized(const int& w, const int& h); + void zoomIn(); + void zoomOut(); + void setDifferentMultitracks(const int& setToLoad); + void loadAudioTrack(std::string name, const int& channel); +// void matchNewPitchEvent(const int& channel, const double& pitchIn, const double& timeIn); + +// bool checkMatch(const double& recordedPitch, const double& livePitch); + + //variables + int numberOfAudioTracks; + LoadedAudioHolder* loadedAudioPtr; + LoadedAudioHolder loadedAudioFiles[5]; + + double trackScreenHeight; + + + //Sonic Vizualiser Beats code + void readInBeatsFile(std::string& pathName); + void printBeatTimes(); + + DoubleVector beatTimes; + void checkFileErrors(int channel); + void findBeatOnsets(); + +// OnsetInformation kickInformation, snareInformation; + + TimingAnalyser drumTimingAnalyser; + +// DoubleVector exactBeatPositions; + OnsetVector onsetInfo; + double timingOffset; + void correctExactBeatTiming(); + void calculateTimingAnalysis(); + void getErrorTimesFromAnalysis(); + void setUpErrorsByMetricalPosition(); + void displayMedianErrors(); + void printErrorsForMetricalPosition(const int& i); + + DoubleMatrix errorsByMetricalPosition; +// DoubleVector kickErrors, snareErrors; + int drawWindow; + //plan is + //we get beats via the beatTimes vector + //then get new EXACT beat times by looking for the nearby kicks and snares + //these should go into + + DoubleVector kickRelativeErrors; + void printKickRelativeErrors(); + void alternativeKickRelativeAnalysis(); + DoubleVector kickRelativeClickTimes; + std::string infoFilepath; + void exportErrorInformation(); + void displayKickRelativeMedianErrors(); +}; +#endif \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/main.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,16 @@ +#include "ofMain.h" +#include "testApp.h" +#include "ofAppGlutWindow.h" + +//======================================================================== +int main( ){ + + ofAppGlutWindow window; + ofSetupOpenGL(&window, 1024,768, OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp( new testApp()); + +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/testApp.cpp Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,71 @@ +#include "testApp.h" + +//-------------------------------------------------------------- +void testApp::setup(){ + drumTimer.initialise(); +} + +//-------------------------------------------------------------- +void testApp::update(){ + +} + +//-------------------------------------------------------------- +void testApp::draw(){ + drumTimer.draw(); +} + +//-------------------------------------------------------------- +void testApp::keyPressed(int key){ + + + if (key == OF_KEY_UP){ + drumTimer.recordedTracks.zoomOut(); + + } + + if (key == OF_KEY_DOWN){ + drumTimer.recordedTracks.zoomIn(); + } + +} + +//-------------------------------------------------------------- +void testApp::keyReleased(int key){ + +} + +//-------------------------------------------------------------- +void testApp::mouseMoved(int x, int y ){ + +} + +//-------------------------------------------------------------- +void testApp::mouseDragged(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::mousePressed(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::mouseReleased(int x, int y, int button){ + +} + +//-------------------------------------------------------------- +void testApp::windowResized(int w, int h){ + drumTimer.windowResized(w, h); +} + +//-------------------------------------------------------------- +void testApp::gotMessage(ofMessage msg){ + +} + +//-------------------------------------------------------------- +void testApp::dragEvent(ofDragInfo dragInfo){ + +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DrumTimingLoader_OF/src/testApp.h Mon Oct 01 22:24:32 2012 +0100 @@ -0,0 +1,27 @@ +#pragma once + +#include "ofMain.h" + +#include "DrumTimingLoader.h" + +class testApp : public ofBaseApp{ + + public: + void setup(); + void update(); + void draw(); + + void keyPressed (int key); + void keyReleased(int key); + void mouseMoved(int x, int y ); + void mouseDragged(int x, int y, int button); + void mousePressed(int x, int y, int button); + void mouseReleased(int x, int y, int button); + void windowResized(int w, int h); + void dragEvent(ofDragInfo dragInfo); + void gotMessage(ofMessage msg); + + DrumTimingLoader drumTimer; + + +};