diff --git a/openFrameworks/ofxMaxim/libs/maximilian.cpp b/openFrameworks/ofxMaxim/libs/maximilian.cpp index 7ba4978c..47205033 100644 --- a/openFrameworks/ofxMaxim/libs/maximilian.cpp +++ b/openFrameworks/ofxMaxim/libs/maximilian.cpp @@ -16,11 +16,11 @@ * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT @@ -34,16 +34,16 @@ #include "maximilian.h" #include "math.h" -/* Maximilian can be configured to load ogg vorbis format files using the -* loadOgg() method. -* Uncomment the following to include Sean Barrett's Ogg Vorbis decoder. -* If you're on windows, make sure to add the files std_vorbis.c and std_vorbis.h to your project*/ +/* Maximilian can be configured to load ogg vorbis format files using the + * loadOgg() method. + * Uncomment the following to include Sean Barrett's Ogg Vorbis decoder. + * If you're on windows, make sure to add the files std_vorbis.c and std_vorbis.h to your project*/ //#define VORBIS #ifdef VORBIS extern "C" { - #include "stb_vorbis.h" +#include "stb_vorbis.h" } #endif @@ -55,7 +55,7 @@ int maxiSettings::channels = 2; int maxiSettings::bufferSize = 1024; -//this is a 514-point sinewave table that has many uses. +//this is a 514-point sinewave table that has many uses. double sineBuffer[514]={0,0.012268,0.024536,0.036804,0.049042,0.06131,0.073547,0.085785,0.097992,0.1102,0.12241,0.13455,0.1467,0.15884,0.17093,0.18301,0.19507,0.20709,0.21909,0.23105,0.24295,0.25485,0.26669,0.2785,0.29025,0.30197,0.31366,0.32529,0.33685,0.34839,0.35986,0.37128,0.38266,0.39395,0.40521,0.41641,0.42752,0.4386,0.44958,0.46051,0.47137,0.48215,0.49286,0.50351,0.51407,0.52457,0.53497,0.54529,0.55554,0.5657,0.57578,0.58575,0.59567,0.60547,0.6152,0.62482,0.63437,0.6438,0.65314,0.66238,0.67151,0.68057,0.68951,0.69833,0.70706,0.7157,0.72421,0.7326,0.74091,0.74908,0.75717,0.76514,0.77298,0.7807,0.7883,0.79581,0.80316,0.81042,0.81754,0.82455,0.83142,0.8382,0.84482,0.85132,0.8577,0.86392,0.87006,0.87604,0.88187,0.8876,0.89319,0.89862,0.90396,0.90912,0.91415,0.91907,0.92383,0.92847,0.93295,0.93729,0.9415,0.94556,0.94949,0.95325,0.95691,0.96039,0.96375,0.96692,0.97,0.9729,0.97565,0.97827,0.98074,0.98306,0.98523,0.98724,0.98914,0.99084,0.99243,0.99387,0.99515,0.99628,0.99725,0.99808,0.99875,0.99927,0.99966,0.99988,0.99997,0.99988,0.99966,0.99927,0.99875,0.99808,0.99725,0.99628,0.99515,0.99387,0.99243,0.99084,0.98914,0.98724,0.98523,0.98306,0.98074,0.97827,0.97565,0.9729,0.97,0.96692,0.96375,0.96039,0.95691,0.95325,0.94949,0.94556,0.9415,0.93729,0.93295,0.92847,0.92383,0.91907,0.91415,0.90912,0.90396,0.89862,0.89319,0.8876,0.88187,0.87604,0.87006,0.86392,0.8577,0.85132,0.84482,0.8382,0.83142,0.82455,0.81754,0.81042,0.80316,0.79581,0.7883,0.7807,0.77298,0.76514,0.75717,0.74908,0.74091,0.7326,0.72421,0.7157,0.70706,0.69833,0.68951,0.68057,0.67151,0.66238,0.65314,0.6438,0.63437,0.62482,0.6152,0.60547,0.59567,0.58575,0.57578,0.5657,0.55554,0.54529,0.53497,0.52457,0.51407,0.50351,0.49286,0.48215,0.47137,0.46051,0.44958,0.4386,0.42752,0.41641,0.40521,0.39395,0.38266,0.37128,0.35986,0.34839,0.33685,0.32529,0.31366,0.30197,0.29025,0.2785,0.26669,0.25485,0.24295,0.23105,0.21909,0.20709,0.19507,0.18301,0.17093,0.15884,0.1467,0.13455,0.12241,0.1102,0.097992,0.085785,0.073547,0.06131,0.049042,0.036804,0.024536,0.012268,0,-0.012268,-0.024536,-0.036804,-0.049042,-0.06131,-0.073547,-0.085785,-0.097992,-0.1102,-0.12241,-0.13455,-0.1467,-0.15884,-0.17093,-0.18301,-0.19507,-0.20709,-0.21909,-0.23105,-0.24295,-0.25485,-0.26669,-0.2785,-0.29025,-0.30197,-0.31366,-0.32529,-0.33685,-0.34839,-0.35986,-0.37128,-0.38266,-0.39395,-0.40521,-0.41641,-0.42752,-0.4386,-0.44958,-0.46051,-0.47137,-0.48215,-0.49286,-0.50351,-0.51407,-0.52457,-0.53497,-0.54529,-0.55554,-0.5657,-0.57578,-0.58575,-0.59567,-0.60547,-0.6152,-0.62482,-0.63437,-0.6438,-0.65314,-0.66238,-0.67151,-0.68057,-0.68951,-0.69833,-0.70706,-0.7157,-0.72421,-0.7326,-0.74091,-0.74908,-0.75717,-0.76514,-0.77298,-0.7807,-0.7883,-0.79581,-0.80316,-0.81042,-0.81754,-0.82455,-0.83142,-0.8382,-0.84482,-0.85132,-0.8577,-0.86392,-0.87006,-0.87604,-0.88187,-0.8876,-0.89319,-0.89862,-0.90396,-0.90912,-0.91415,-0.91907,-0.92383,-0.92847,-0.93295,-0.93729,-0.9415,-0.94556,-0.94949,-0.95325,-0.95691,-0.96039,-0.96375,-0.96692,-0.97,-0.9729,-0.97565,-0.97827,-0.98074,-0.98306,-0.98523,-0.98724,-0.98914,-0.99084,-0.99243,-0.99387,-0.99515,-0.99628,-0.99725,-0.99808,-0.99875,-0.99927,-0.99966,-0.99988,-0.99997,-0.99988,-0.99966,-0.99927,-0.99875,-0.99808,-0.99725,-0.99628,-0.99515,-0.99387,-0.99243,-0.99084,-0.98914,-0.98724,-0.98523,-0.98306,-0.98074,-0.97827,-0.97565,-0.9729,-0.97,-0.96692,-0.96375,-0.96039,-0.95691,-0.95325,-0.94949,-0.94556,-0.9415,-0.93729,-0.93295,-0.92847,-0.92383,-0.91907,-0.91415,-0.90912,-0.90396,-0.89862,-0.89319,-0.8876,-0.88187,-0.87604,-0.87006,-0.86392,-0.8577,-0.85132,-0.84482,-0.8382,-0.83142,-0.82455,-0.81754,-0.81042,-0.80316,-0.79581,-0.7883,-0.7807,-0.77298,-0.76514,-0.75717,-0.74908,-0.74091,-0.7326,-0.72421,-0.7157,-0.70706,-0.69833,-0.68951,-0.68057,-0.67151,-0.66238,-0.65314,-0.6438,-0.63437,-0.62482,-0.6152,-0.60547,-0.59567,-0.58575,-0.57578,-0.5657,-0.55554,-0.54529,-0.53497,-0.52457,-0.51407,-0.50351,-0.49286,-0.48215,-0.47137,-0.46051,-0.44958,-0.4386,-0.42752,-0.41641,-0.40521,-0.39395,-0.38266,-0.37128,-0.35986,-0.34839,-0.33685,-0.32529,-0.31366,-0.30197,-0.29025,-0.2785,-0.26669,-0.25485,-0.24295,-0.23105,-0.21909,-0.20709,-0.19507,-0.18301,-0.17093,-0.15884,-0.1467,-0.13455,-0.12241,-0.1102,-0.097992,-0.085785,-0.073547,-0.06131,-0.049042,-0.036804,-0.024536,-0.012268,0,0.012268 }; @@ -200,138 +200,138 @@ double mtofarray[129]={0, 8.661957, 9.177024, 9.722718, 10.3, 10.913383, 11.5623 void setup();//use this to do any initialisation if you want. -void play(double *channels);//run dac! +void play(double *channels);//run dac! maxiOsc::maxiOsc(){ //When you create an oscillator, the constructor sets the phase of the oscillator to 0. - phase = 0.0; + phase = 0.0; } double maxiOsc::noise() { //White Noise - //always the same unless you seed it. - float r = rand()/(float)RAND_MAX; - output=r*2-1; - return(output); + //always the same unless you seed it. + float r = rand()/(float)RAND_MAX; + output=r*2-1; + return(output); } void maxiOsc::phaseReset(double phaseIn) { //This allows you to set the phase of the oscillator to anything you like. - phase=phaseIn; - + phase=phaseIn; + } double maxiOsc::sinewave(double frequency) { //This is a sinewave oscillator - output=sin (phase*(TWOPI)); - if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - return(output); - + output=sin (phase*(TWOPI)); + if ( phase >= 1.0 ) phase -= 1.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + return(output); + } double maxiOsc::sinebuf4(double frequency) { //This is a sinewave oscillator that uses 4 point interpolation on a 514 point buffer - double remainder; - double a,b,c,d,a1,a2,a3; - phase += 512./(maxiSettings::sampleRate/(frequency)); - if ( phase >= 511 ) phase -=512; - remainder = phase - floor(phase); - - if (phase==0) { - a=sineBuffer[(long) 512]; - b=sineBuffer[(long) phase]; - c=sineBuffer[(long) phase+1]; - d=sineBuffer[(long) phase+2]; - - } else { - a=sineBuffer[(long) phase-1]; - b=sineBuffer[(long) phase]; - c=sineBuffer[(long) phase+1]; - d=sineBuffer[(long) phase+2]; - - } - - a1 = 0.5f * (c - a); - a2 = a - 2.5 * b + 2.f * c - 0.5f * d; - a3 = 0.5f * (d - a) + 1.5f * (b - c); - output = double (((a3 * remainder + a2) * remainder + a1) * remainder + b); - return(output); + double remainder; + double a,b,c,d,a1,a2,a3; + phase += 512./(maxiSettings::sampleRate/(frequency)); + if ( phase >= 511 ) phase -=512; + remainder = phase - floor(phase); + + if (phase==0) { + a=sineBuffer[(long) 512]; + b=sineBuffer[(long) phase]; + c=sineBuffer[(long) phase+1]; + d=sineBuffer[(long) phase+2]; + + } else { + a=sineBuffer[(long) phase-1]; + b=sineBuffer[(long) phase]; + c=sineBuffer[(long) phase+1]; + d=sineBuffer[(long) phase+2]; + + } + + a1 = 0.5f * (c - a); + a2 = a - 2.5 * b + 2.f * c - 0.5f * d; + a3 = 0.5f * (d - a) + 1.5f * (b - c); + output = double (((a3 * remainder + a2) * remainder + a1) * remainder + b); + return(output); } double maxiOsc::sinebuf(double frequency) { //specify the frequency of the oscillator in Hz / cps etc. //This is a sinewave oscillator that uses linear interpolation on a 514 point buffer - double remainder; - phase += 512./(maxiSettings::sampleRate/(frequency*chandiv)); - if ( phase >= 511 ) phase -=512; - remainder = phase - floor(phase); - output = (double) ((1-remainder) * sineBuffer[1+ (long) phase] + remainder * sineBuffer[2+(long) phase]); - return(output); + double remainder; + phase += 512./(maxiSettings::sampleRate/(frequency*chandiv)); + if ( phase >= 511 ) phase -=512; + remainder = phase - floor(phase); + output = (double) ((1-remainder) * sineBuffer[1+ (long) phase] + remainder * sineBuffer[2+(long) phase]); + return(output); } double maxiOsc::coswave(double frequency) { //This is a cosine oscillator - output=cos (phase*(TWOPI)); - if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - return(output); - + output=cos (phase*(TWOPI)); + if ( phase >= 1.0 ) phase -= 1.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + return(output); + } double maxiOsc::phasor(double frequency) { - //This produces a floating point linear ramp between 0 and 1 at the desired frequency - output=phase; - if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - return(output); -} + //This produces a floating point linear ramp between 0 and 1 at the desired frequency + output=phase; + if ( phase >= 1.0 ) phase -= 1.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + return(output); +} double maxiOsc::square(double frequency) { //This is a square wave - if (phase<0.5) output=-1; - if (phase>0.5) output=1; - if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - return(output); + if (phase<0.5) output=-1; + if (phase>0.5) output=1; + if ( phase >= 1.0 ) phase -= 1.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + return(output); } double maxiOsc::pulse(double frequency, double duty) { //This is a pulse generator that creates a signal between -1 and 1. - if (duty<0.) duty=0; - if (duty>1.) duty=1; - if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - if (phaseduty) output=1.; - return(output); + if (duty<0.) duty=0; + if (duty>1.) duty=1; + if ( phase >= 1.0 ) phase -= 1.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + if (phaseduty) output=1.; + return(output); } double maxiOsc::phasor(double frequency, double startphase, double endphase) { - //This is a phasor that takes a value for the start and end of the ramp. - output=phase; - if (phase= endphase ) phase = startphase; - phase += ((endphase-startphase)/(maxiSettings::sampleRate/(frequency))); - return(output); + //This is a phasor that takes a value for the start and end of the ramp. + output=phase; + if (phase= endphase ) phase = startphase; + phase += ((endphase-startphase)/(maxiSettings::sampleRate/(frequency))); + return(output); } double maxiOsc::saw(double frequency) { - //Sawtooth generator. This is like a phasor but goes between -1 and 1 - output=phase; - if ( phase >= 1.0 ) phase -= 2.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - return(output); - + //Sawtooth generator. This is like a phasor but goes between -1 and 1 + output=phase; + if ( phase >= 1.0 ) phase -= 2.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + return(output); + } double maxiOsc::sawn(double frequency) { - //Bandlimited sawtooth generator. Woohoo. + //Bandlimited sawtooth generator. Woohoo. if ( phase >= 0.5 ) phase -= 1.0; phase += (1./(maxiSettings::sampleRate/(frequency))); - double temp=(8820.22/frequency)*phase; + double temp=(8820.22/frequency)*phase; if (temp<-0.5) { temp=-0.5; } @@ -342,205 +342,206 @@ double maxiOsc::sawn(double frequency) { temp+=500.0f; double remainder = temp - floor(temp); output = (double) ((1.0f-remainder) * transition[(long)temp] + remainder * transition[1+(long)temp]) - phase; - return(output); - + return(output); + } double maxiOsc::rect(double frequency, double duty) { - + return (output); } double maxiOsc::triangle(double frequency) { //This is a triangle wave. - if ( phase >= 1.0 ) phase -= 1.0; - phase += (1./(maxiSettings::sampleRate/(frequency))); - if (phase <= 0.5 ) { - output =(phase - 0.25) * 4; - } else { - output =((1.0-phase) - 0.25) * 4; - } - return(output); - -} + if ( phase >= 1.0 ) phase -= 1.0; + phase += (1./(maxiSettings::sampleRate/(frequency))); + if (phase <= 0.5 ) { + output =(phase - 0.25) * 4; + } else { + output =((1.0-phase) - 0.25) * 4; + } + return(output); + +} double maxiEnvelope::line(int numberofsegments,double segments[1000]) { - //This is a basic multi-segment ramp generator that you can use for more or less anything. + //This is a basic multi-segment ramp generator that you can use for more or less anything. //However, it's not that intuitive. if (isPlaying==1) {//only make a sound once you've been triggered - period=4./(segments[valindex+1]*0.0044); - nextval=segments[valindex+2]; - currentval=segments[valindex]; - if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) { - amplitude += ((currentval-startval)/(maxiSettings::sampleRate/period)); - } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) { - amplitude -= (((currentval-startval)*(-1))/(maxiSettings::sampleRate/period)); - } else if (valindex >numberofsegments-1) { - valindex=numberofsegments-2; - } else { - valindex=valindex+2; - startval=currentval; - } - output=amplitude; - - } - else { - output=0; - - } - return(output); + period=4./(segments[valindex+1]*0.0044); + nextval=segments[valindex+2]; + currentval=segments[valindex]; + if (currentval-amplitude > 0.0000001 && valindex < numberofsegments) { + amplitude += ((currentval-startval)/(maxiSettings::sampleRate/period)); + } else if (currentval-amplitude < -0.0000001 && valindex < numberofsegments) { + amplitude -= (((currentval-startval)*(-1))/(maxiSettings::sampleRate/period)); + } else if (valindex >numberofsegments-1) { + valindex=numberofsegments-2; + } else { + valindex=valindex+2; + startval=currentval; + } + output=amplitude; + + } + else { + output=0; + + } + return(output); } //and this void maxiEnvelope::trigger(int index, double amp) { - isPlaying=1;//ok the envelope is being used now. - valindex=index; - amplitude=amp; - + isPlaying=1;//ok the envelope is being used now. + valindex=index; + amplitude=amp; + } //Delay with feedback maxiDelayline::maxiDelayline() { - memset( memory, 0, 88200*sizeof (double) ); + memset( memory, 0, 88200*sizeof (double) ); } double maxiDelayline::dl(double input, int size, double feedback) { - if ( phase >=size ) { - phase = 0; - } - output=memory[phase]; - memory[phase]=(memory[phase]*feedback)+(input*feedback)*0.5; - phase+=1; - return(output); - + if ( phase >=size ) { + phase = 0; + } + output=memory[phase]; + memory[phase]=(memory[phase]*feedback)+(input*feedback)*0.5; + phase+=1; + return(output); + } double maxiDelayline::dl(double input, int size, double feedback, int position) { - if ( phase >=size ) phase = 0; - if ( position >=size ) position = 0; - output=memory[position]; - memory[phase]=(memory[phase]*feedback)+(input*feedback)*chandiv; - phase+=1; - return(output); - + if ( phase >=size ) phase = 0; + if ( position >=size ) position = 0; + output=memory[position]; + memory[phase]=(memory[phase]*feedback)+(input*feedback)*chandiv; + phase+=1; + return(output); + } //I particularly like these. cutoff between 0 and 1 double maxiFilter::lopass(double input, double cutoff) { - output=outputs[0] + cutoff*(input-outputs[0]); - outputs[0]=output; - return(output); + output=outputs[0] + cutoff*(input-outputs[0]); + outputs[0]=output; + return(output); } + //as above double maxiFilter::hipass(double input, double cutoff) { - output=input-(outputs[0] + cutoff*(input-outputs[0])); - outputs[0]=output; - return(output); + output=input-(outputs[0] + cutoff*(input-outputs[0])); + outputs[0]=output; + return(output); } //awesome. cuttof is freq in hz. res is between 1 and whatever. Watch out! double maxiFilter::lores(double input,double cutoff1, double resonance) { - cutoff=cutoff1; - if (cutoff<10) cutoff=10; - if (cutoff>(maxiSettings::sampleRate)) cutoff=(maxiSettings::sampleRate); - if (resonance<1.) resonance = 1.; - z=cos(TWOPI*cutoff/maxiSettings::sampleRate); - c=2-2*z; - double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1)); - x=x+(input-y)*c; - y=y+x; - x=x*r; - output=y; - return(output); + cutoff=cutoff1; + if (cutoff<10) cutoff=10; + if (cutoff>(maxiSettings::sampleRate)) cutoff=(maxiSettings::sampleRate); + if (resonance<1.) resonance = 1.; + z=cos(TWOPI*cutoff/maxiSettings::sampleRate); + c=2-2*z; + double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1)); + x=x+(input-y)*c; + y=y+x; + x=x*r; + output=y; + return(output); } //working hires filter double maxiFilter::hires(double input,double cutoff1, double resonance) { - cutoff=cutoff1; - if (cutoff<10) cutoff=10; - if (cutoff>(maxiSettings::sampleRate)) cutoff=(maxiSettings::sampleRate); - if (resonance<1.) resonance = 1.; - z=cos(TWOPI*cutoff/maxiSettings::sampleRate); - c=2-2*z; - double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1)); - x=x+(input-y)*c; - y=y+x; - x=x*r; - output=input-y; - return(output); + cutoff=cutoff1; + if (cutoff<10) cutoff=10; + if (cutoff>(maxiSettings::sampleRate)) cutoff=(maxiSettings::sampleRate); + if (resonance<1.) resonance = 1.; + z=cos(TWOPI*cutoff/maxiSettings::sampleRate); + c=2-2*z; + double r=(sqrt(2.0)*sqrt(-pow((z-1.0),3.0))+resonance*(z-1))/(resonance*(z-1)); + x=x+(input-y)*c; + y=y+x; + x=x*r; + output=input-y; + return(output); } //This works a bit. Needs attention. double maxiFilter::bandpass(double input,double cutoff1, double resonance) { - cutoff=cutoff1; - if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); - if (resonance>=1.) resonance=0.999999; - z=cos(TWOPI*cutoff/maxiSettings::sampleRate); - inputs[0] = (1-resonance)*(sqrt(resonance*(resonance-4.0*pow(z,2.0)+2.0)+1)); - inputs[1] = 2*z*resonance; - inputs[2] = pow((resonance*-1),2); - - output=inputs[0]*input+inputs[1]*outputs[1]+inputs[2]*outputs[2]; - outputs[2]=outputs[1]; - outputs[1]=output; - return(output); + cutoff=cutoff1; + if (cutoff>(maxiSettings::sampleRate*0.5)) cutoff=(maxiSettings::sampleRate*0.5); + if (resonance>=1.) resonance=0.999999; + z=cos(TWOPI*cutoff/maxiSettings::sampleRate); + inputs[0] = (1-resonance)*(sqrt(resonance*(resonance-4.0*pow(z,2.0)+2.0)+1)); + inputs[1] = 2*z*resonance; + inputs[2] = pow((resonance*-1),2); + + output=inputs[0]*input+inputs[1]*outputs[1]+inputs[2]*outputs[2]; + outputs[2]=outputs[1]; + outputs[1]=output; + return(output); } //stereo bus double *maxiMix::stereo(double input,double two[2],double x) { - if (x>1) x=1; - if (x<0) x=0; - two[0]=input*sqrt(1.0-x); - two[1]=input*sqrt(x); - return(two); -} + if (x>1) x=1; + if (x<0) x=0; + two[0]=input*sqrt(1.0-x); + two[1]=input*sqrt(x); + return(two); +} //quad bus double *maxiMix::quad(double input,double four[4],double x,double y) { - if (x>1) x=1; - if (x<0) x=0; - if (y>1) y=1; - if (y<0) y=0; - four[0]=input*sqrt((1.0-x)*y); - four[1]=input*sqrt((1.0-x)*(1.0-y)); - four[2]=input*sqrt(x*y); - four[3]=input*sqrt(x*(1.0-y)); - return(four); + if (x>1) x=1; + if (x<0) x=0; + if (y>1) y=1; + if (y<0) y=0; + four[0]=input*sqrt((1.0-x)*y); + four[1]=input*sqrt((1.0-x)*(1.0-y)); + four[2]=input*sqrt(x*y); + four[3]=input*sqrt(x*(1.0-y)); + return(four); } //ambisonic bus double *maxiMix::ambisonic(double input,double eight[8],double x,double y,double z) { - if (x>1) x=1; - if (x<0) x=0; - if (y>1) y=1; - if (y<0) y=0; - if (z>1) y=1; - if (z<0) y=0; - eight[0]=input*(sqrt((1.0-x)*y)*1.0-z); - eight[1]=input*(sqrt((1.0-x)*(1.0-y))*1.0-z); - eight[2]=input*(sqrt(x*y)*1.0-z); - eight[3]=input*(sqrt(x*(1.0-y))*1.0-z); - eight[4]=input*(sqrt((1.0-x)*y)*z); - eight[5]=input*(sqrt((1.0-x)*(1.0-y))*z); - eight[6]=input*sqrt((x*y)*z); - eight[7]=input*sqrt((x*(1.0-y))*z); - return(eight); + if (x>1) x=1; + if (x<0) x=0; + if (y>1) y=1; + if (y<0) y=0; + if (z>1) y=1; + if (z<0) y=0; + eight[0]=input*(sqrt((1.0-x)*y)*1.0-z); + eight[1]=input*(sqrt((1.0-x)*(1.0-y))*1.0-z); + eight[2]=input*(sqrt(x*y)*1.0-z); + eight[3]=input*(sqrt(x*(1.0-y))*1.0-z); + eight[4]=input*(sqrt((1.0-x)*y)*z); + eight[5]=input*(sqrt((1.0-x)*(1.0-y))*z); + eight[6]=input*sqrt((x*y)*z); + eight[7]=input*sqrt((x*(1.0-y))*z); + return(eight); } //This is the maxiSample load function. It just calls read. bool maxiSample::load(string fileName, int channel) { - myPath = fileName; - readChannel=channel; - return read(); + myPath = fileName; + readChannel=channel; + return read(); } // This is for OGG loading bool maxiSample::loadOgg(string fileName, int channel) { #ifdef VORBIS bool result; - readChannel=channel; + readChannel=channel; int channelx; -// cout << fileName << endl; + // cout << fileName << endl; free(temp); myDataSize = stb_vorbis_decode_filename(const_cast(fileName.c_str()), &channelx, &temp); result = myDataSize > 0; @@ -558,105 +559,105 @@ bool maxiSample::loadOgg(string fileName, int channel) { position++; } } - return result; // this should probably be something more descriptive + return result; // this should probably be something more descriptive #endif return 0; } //This sets the playback position to the start of a sample void maxiSample::trigger() { - position = 0; + position = 0; recordPosition = 0; } //This is the main read function. bool maxiSample::read() { - bool result; - ifstream inFile( myPath.c_str(), ios::in | ios::binary); - result = inFile.is_open(); - if (result) { - bool datafound = false; - inFile.seekg(4, ios::beg); - inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize - - inFile.seekg(16, ios::beg); - inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size - - //inFile.seekg(20, ios::beg); - inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM - - //inFile.seekg(22, ios::beg); - inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2) - - //inFile.seekg(24, ios::beg); - inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate - - //inFile.seekg(28, ios::beg); - inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate - - //inFile.seekg(32, ios::beg); - inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign - - //inFile.seekg(34, ios::beg); - inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample - - //ignore any extra chunks - char chunkID[5]=""; - chunkID[4] = 0; - int filePos = 20 + mySubChunk1Size; - while(!datafound && !inFile.eof()) { - inFile.seekg(filePos, ios::beg); - inFile.read((char*) &chunkID, sizeof(char) * 4); - inFile.seekg(filePos + 4, ios::beg); - inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data - filePos += 8; - if (strcmp(chunkID,"data") == 0) { - datafound = true; - }else{ - filePos += myDataSize; - } - } - - // read the data chunk - char * myData = (char*) malloc(myDataSize * sizeof(char)); - inFile.seekg(filePos, ios::beg); - inFile.read(myData, myDataSize); - length=myDataSize*(0.5/myChannels); - inFile.close(); // close the input file - + bool result; + ifstream inFile( myPath.c_str(), ios::in | ios::binary); + result = inFile.is_open(); + if (result) { + bool datafound = false; + inFile.seekg(4, ios::beg); + inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize + + inFile.seekg(16, ios::beg); + inFile.read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size + + //inFile.seekg(20, ios::beg); + inFile.read( (char*) &myFormat, sizeof(short) ); // read the file format. This should be 1 for PCM + + //inFile.seekg(22, ios::beg); + inFile.read( (char*) &myChannels, sizeof(short) ); // read the # of channels (1 or 2) + + //inFile.seekg(24, ios::beg); + inFile.read( (char*) &mySampleRate, sizeof(int) ); // read the samplerate + + //inFile.seekg(28, ios::beg); + inFile.read( (char*) &myByteRate, sizeof(int) ); // read the byterate + + //inFile.seekg(32, ios::beg); + inFile.read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign + + //inFile.seekg(34, ios::beg); + inFile.read( (char*) &myBitsPerSample, sizeof(short) ); // read the bitspersample + + //ignore any extra chunks + char chunkID[5]=""; + chunkID[4] = 0; + int filePos = 20 + mySubChunk1Size; + while(!datafound && !inFile.eof()) { + inFile.seekg(filePos, ios::beg); + inFile.read((char*) &chunkID, sizeof(char) * 4); + inFile.seekg(filePos + 4, ios::beg); + inFile.read( (char*) &myDataSize, sizeof(int) ); // read the size of the data + filePos += 8; + if (strcmp(chunkID,"data") == 0) { + datafound = true; + }else{ + filePos += myDataSize; + } + } + + // read the data chunk + char * myData = (char*) malloc(myDataSize * sizeof(char)); + inFile.seekg(filePos, ios::beg); + inFile.read(myData, myDataSize); + length=myDataSize*(0.5/myChannels); + inFile.close(); // close the input file + cout << "Ch: " << myChannels << ", len: " << length << endl; - if (myChannels>1) { - int position=0; - int channel=readChannel*2; - for (int i=channel;i1) { + int position=0; + int channel=readChannel*2; + for (int i=channel;i= length) position=0; - output = (double) temp[(long)position]/32767.0; - return output; + position++; + if ((long) position >= length) position=0; + output = (double) temp[(long)position]/32767.0; + return output; } void maxiSample::setPosition(double newPos) { @@ -685,404 +686,404 @@ double maxiSample::playUntil(double end) { //This plays back at the correct speed. Only plays once. To retrigger, you have to manually reset the position double maxiSample::playOnce() { - position++; - if ((long) position=0) { - - if ((long) position>=length-1) position=1; - remainder = position - floor(position); - if (position+1=0) { - a=position-1; - - } - else { - a=0; - } - if (position-2>=0) { - b=position-2; - } - else { - b=0; - } - output = (double) ((-1-remainder) * temp[a] + remainder * temp[b])/32767;//linear interpolation - } - return(output); + double remainder; + long a,b; + position=position+((speed*chandiv)/(maxiSettings::sampleRate/mySampleRate)); + if (speed >=0) { + + if ((long) position>=length-1) position=1; + remainder = position - floor(position); + if (position+1=0) { + a=position-1; + + } + else { + a=0; + } + if (position-2>=0) { + b=position-2; + } + else { + b=0; + } + output = (double) ((-1-remainder) * temp[a] + remainder * temp[b])/32767;//linear interpolation + } + return(output); } //placeholder double maxiSample::play(double frequency, double start, double end) { - return play(frequency, start, end, position); + return play(frequency, start, end, position); } //This allows you to say how often a second you want a specific chunk of audio to play double maxiSample::play(double frequency, double start, double end, double &pos) { - double remainder; - if (end>=length) end=length-1; - long a,b; - - if (frequency >0.) { - if (pos= end ) pos = start; - pos += ((end-start)/((maxiSettings::sampleRate)/(frequency*chandiv))); - remainder = pos - floor(pos); - long posl = floor(pos); - if (posl+1=0) { - a=posl-1; - } - else { - a=0; - } - if (posl-2>=0) { - b=posl-2; - } - else { - b=0; - } - output = (double) ((-1-remainder) * temp[a] + - remainder * temp[b])/32767;//linear interpolation - - } - - return(output); + double remainder; + if (end>=length) end=length-1; + long a,b; + + if (frequency >0.) { + if (pos= end ) pos = start; + pos += ((end-start)/((maxiSettings::sampleRate)/(frequency*chandiv))); + remainder = pos - floor(pos); + long posl = floor(pos); + if (posl+1=0) { + a=posl-1; + } + else { + a=0; + } + if (posl-2>=0) { + b=posl-2; + } + else { + b=0; + } + output = (double) ((-1-remainder) * temp[a] + + remainder * temp[b])/32767;//linear interpolation + + } + + return(output); } //Same as above. better cubic inerpolation. Cobbled together from various (pd externals, yehar, other places). double maxiSample::play4(double frequency, double start, double end) { - double remainder; - double a,b,c,d,a1,a2,a3; - if (frequency >0.) { - if (position= end ) position = start; - position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); - remainder = position - floor(position); - if (position>0) { - a=temp[(int)(floor(position))-1]; - - } else { - a=temp[0]; - - } - - b=temp[(long) position]; - if (position0.) { + if (position= end ) position = start; + position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = position - floor(position); + if (position>0) { + a=temp[(int)(floor(position))-1]; + + } else { + a=temp[0]; + + } + + b=temp[(long) position]; + if (positionstart && position < end-1) { - a=temp[(long) position+1]; - - } else { - a=temp[0]; - - } - - b=temp[(long) position]; - if (position>start) { - c=temp[(long) position-1]; - - } else { - c=temp[0]; - - } - if (position>start+1) { - d=temp[(long) position-2]; - - } else { - d=temp[0]; - } - a1 = 0.5f * (c - a); - a2 = a - 2.5 * b + 2.f * c - 0.5f * d; - a3 = 0.5f * (d - a) + 1.5f * (b - c); - output = (double) (((a3 * remainder + a2) * -remainder + a1) * -remainder + b) / 32767; - - } - - return(output); + if ( position <= start ) position = end; + position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = position - floor(position); + if (position>start && position < end-1) { + a=temp[(long) position+1]; + + } else { + a=temp[0]; + + } + + b=temp[(long) position]; + if (position>start) { + c=temp[(long) position-1]; + + } else { + c=temp[0]; + + } + if (position>start+1) { + d=temp[(long) position-2]; + + } else { + d=temp[0]; + } + a1 = 0.5f * (c - a); + a2 = a - 2.5 * b + 2.f * c - 0.5f * d; + a3 = 0.5f * (d - a) + 1.5f * (b - c); + output = (double) (((a3 * remainder + a2) * -remainder + a1) * -remainder + b) / 32767; + + } + + return(output); } //You don't need to worry about this stuff. double maxiSample::bufferPlay(unsigned char &bufferin,long length) { - double remainder; - short* buffer = (short *)&bufferin; - position=(position+1); - remainder = position - (long) position; - if ((long) position>length) position=0; - output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation - return(output); + double remainder; + short* buffer = (short *)&bufferin; + position=(position+1); + remainder = position - (long) position; + if ((long) position>length) position=0; + output = (double) ((1-remainder) * buffer[1+ (long) position] + remainder * buffer[2+(long) position])/32767;//linear interpolation + return(output); } double maxiSample::bufferPlay(unsigned char &bufferin,double speed,long length) { - double remainder; - long a,b; - short* buffer = (short *)&bufferin; - position=position+((speed*chandiv)/(maxiSettings::sampleRate/mySampleRate)); - if (speed >=0) { - - if ((long) position>=length-1) position=1; - remainder = position - floor(position); - if (position+1=0) { - a=position-1; - - } - else { - a=0; - } - if (position-2>=0) { - b=position-2; - } - else { - b=0; - } - output = (double) ((-1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation - } - return(output); + double remainder; + long a,b; + short* buffer = (short *)&bufferin; + position=position+((speed*chandiv)/(maxiSettings::sampleRate/mySampleRate)); + if (speed >=0) { + + if ((long) position>=length-1) position=1; + remainder = position - floor(position); + if (position+1=0) { + a=position-1; + + } + else { + a=0; + } + if (position-2>=0) { + b=position-2; + } + else { + b=0; + } + output = (double) ((-1-remainder) * buffer[a] + remainder * buffer[b])/32767;//linear interpolation + } + return(output); } double maxiSample::bufferPlay(unsigned char &bufferin,double frequency, double start, double end) { - double remainder; - length=end; - long a,b; - short* buffer = (short *)&bufferin; - if (frequency >0.) { - if (position= end ) position = start; - position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); - remainder = position - floor(position); - long pos = floor(position); - if (pos+10.) { + if (position= end ) position = start; + position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = position - floor(position); + long pos = floor(position); + if (pos+1=0) { - a=pos-1; - } - else { - a=0; - } - if (pos-2>=0) { - b=pos-2; - } - else { - b=0; - } - output = (double) ((-1-remainder) * buffer[a] + - remainder * buffer[b])/32767;//linear interpolation - - } - - return(output); + if ( position <= start ) position = end; + position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = position - floor(position); + long pos = floor(position); + if (pos-1>=0) { + a=pos-1; + } + else { + a=0; + } + if (pos-2>=0) { + b=pos-2; + } + else { + b=0; + } + output = (double) ((-1-remainder) * buffer[a] + + remainder * buffer[b])/32767;//linear interpolation + + } + + return(output); } //better cubic inerpolation. Cobbled together from various (pd externals, yehar, other places). double maxiSample::bufferPlay4(unsigned char &bufferin,double frequency, double start, double end) { - double remainder; - double a,b,c,d,a1,a2,a3; - short* buffer = (short*)&bufferin; - if (frequency >0.) { - if (position= end ) position = start; - position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); - remainder = position - floor(position); - if (position>0) { - a=buffer[(int)(floor(position))-1]; - - } else { - a=buffer[0]; - - } - - b=buffer[(long) position]; - if (position0.) { + if (position= end ) position = start; + position += ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = position - floor(position); + if (position>0) { + a=buffer[(int)(floor(position))-1]; + + } else { + a=buffer[0]; + + } + + b=buffer[(long) position]; + if (positionstart && position < end-1) { - a=buffer[(long) position+1]; - - } else { - a=buffer[0]; - - } - - b=buffer[(long) position]; - if (position>start) { - c=buffer[(long) position-1]; - - } else { - c=buffer[0]; - - } - if (position>start+1) { - d=buffer[(long) position-2]; - - } else { - d=buffer[0]; - } - a1 = 0.5f * (c - a); - a2 = a - 2.5 * b + 2.f * c - 0.5f * d; - a3 = 0.5f * (d - a) + 1.5f * (b - c); - output = (double) (((a3 * remainder + a2) * -remainder + a1) * -remainder + b) / 32767; - - } - - return(output); + if ( position <= start ) position = end; + position -= ((end-start)/(maxiSettings::sampleRate/(frequency*chandiv))); + remainder = position - floor(position); + if (position>start && position < end-1) { + a=buffer[(long) position+1]; + + } else { + a=buffer[0]; + + } + + b=buffer[(long) position]; + if (position>start) { + c=buffer[(long) position-1]; + + } else { + c=buffer[0]; + + } + if (position>start+1) { + d=buffer[(long) position-2]; + + } else { + d=buffer[0]; + } + a1 = 0.5f * (c - a); + a2 = a - 2.5 * b + 2.f * c - 0.5f * d; + a3 = 0.5f * (d - a) + 1.5f * (b - c); + output = (double) (((a3 * remainder + a2) * -remainder + a1) * -remainder + b) / 32767; + + } + + return(output); } void maxiSample::getLength() { - length=myDataSize*0.5; + length=myDataSize*0.5; } void maxiSample::setLength(unsigned long numSamples) { @@ -1174,77 +1175,77 @@ void maxiSample::autoTrim(float alpha, float threshold, bool trimStart, bool tri -/* OK this compressor and gate are now ready to use. The envelopes, like all the envelopes in this recent update, use stupid algorithms for +/* OK this compressor and gate are now ready to use. The envelopes, like all the envelopes in this recent update, use stupid algorithms for incrementing - consequently a long attack is something like 0.0001 and a long release is like 0.9999. Annoyingly, a short attack is 0.1, and a short release is 0.99. I'll sort this out laters */ double maxiDyn::gate(double input, double threshold, long holdtime, double attack, double release) { - - if (fabs(input)>threshold && attackphase!=1){ - holdcount=0; - releasephase=0; - attackphase=1; - if(amplitude==0) amplitude=0.01; - } - - if (attackphase==1 && amplitude<1) { - amplitude*=(1+attack); - output=input*amplitude; - } - - if (amplitude>=1) { - attackphase=0; - holdphase=1; - } - - if (holdcount0.) { - output=input*(amplitude*=release); - - } - - return output; + + if (fabs(input)>threshold && attackphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + if(amplitude==0) amplitude=0.01; + } + + if (attackphase==1 && amplitude<1) { + amplitude*=(1+attack); + output=input*amplitude; + } + + if (amplitude>=1) { + attackphase=0; + holdphase=1; + } + + if (holdcount0.) { + output=input*(amplitude*=release); + + } + + return output; } double maxiDyn::compressor(double input, double ratio, double threshold, double attack, double release) { - - if (fabs(input)>threshold && attackphase!=1){ - holdcount=0; - releasephase=0; - attackphase=1; - if(currentRatio==0) currentRatio=ratio; - } - - if (attackphase==1 && currentRatio=ratio-1) { - attackphase=0; - releasephase=1; - } - - if (releasephase==1 && currentRatio>0.) { - currentRatio*=release; - } - - if (input>0.) { - output = input/(1.+currentRatio); - } else { - output = input/(1.+currentRatio); - } - - return output*(1+log(ratio)); + + if (fabs(input)>threshold && attackphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + if(currentRatio==0) currentRatio=ratio; + } + + if (attackphase==1 && currentRatio=ratio-1) { + attackphase=0; + releasephase=1; + } + + if (releasephase==1 && currentRatio>0.) { + currentRatio*=release; + } + + if (input>0.) { + output = input/(1.+currentRatio); + } else { + output = input/(1.+currentRatio); + } + + return output*(1+log(ratio)); } double maxiDyn::compress(double input) { @@ -1283,44 +1284,44 @@ double maxiDyn::compress(double input) { It takes mental numbers for attack and release tho. Basically, they're exponentials. I'll map them out later so that it's a bit more intuitive */ double maxiEnv::ar(double input, double attack, double release, long holdtime, int trigger) { - - if (trigger==1 && attackphase!=1 && holdphase!=1){ - holdcount=0; - releasephase=0; - attackphase=1; - } - - if (attackphase==1) { - amplitude+=(1*attack); - output=input*amplitude; - } - - if (amplitude>=1) { - amplitude=1; - attackphase=0; - holdphase=1; - } - - if (holdcount0.) { - output=input*(amplitude*=release); - - } - - return output; + + if (trigger==1 && attackphase!=1 && holdphase!=1){ + holdcount=0; + releasephase=0; + attackphase=1; + } + + if (attackphase==1) { + amplitude+=(1*attack); + output=input*amplitude; + } + + if (amplitude>=1) { + amplitude=1; + attackphase=0; + holdphase=1; + } + + if (holdcount0.) { + output=input*(amplitude*=release); + + } + + return output; } /* adsr. It's not bad, very simple to use*/ @@ -1466,8 +1467,8 @@ void maxiDyn::setRatio(double ratioF) { double convert::mtof(int midinote) { - - return mtofarray[midinote]; + + return mtofarray[midinote]; } @@ -1476,6 +1477,532 @@ template<> void maxiEnvelopeFollower::setAttack(double attackMS) { } template<> void maxiEnvelopeFollower::setRelease(double releaseMS) { - release = pow( 0.01, 1.0 / ( releaseMS * maxiSettings::sampleRate * 0.001 ) ); + release = pow( 0.01, 1.0 / ( releaseMS * maxiSettings::sampleRate * 0.001 ) ); } +double pitchRatios[256]= {0.0006517771980725,0.0006905338959768,0.0007315951515920, 0.0007750981021672, 0.0008211878011934, 0.0008700182079338, 0.0009217521874234, 0.0009765623835847, 0.0010346318595111, 0.0010961542138830, 0.0011613349197432, 0.0012303915573284, 0.0013035543961450, 0.0013810677919537, 0.0014631903031841, 0.0015501962043345, 0.0016423756023869, 0.0017400364158675, 0.0018435043748468, 0.0019531247671694, 0.0020692637190223, 0.0021923084277660, 0.0023226698394865, 0.0024607831146568, 0.0026071087922901, 0.0027621355839074, 0.0029263808391988, 0.0031003924086690, 0.0032847514376044, 0.0034800728317350, 0.0036870087496936, 0.0039062497671694, 0.0041385274380445, 0.0043846168555319, 0.0046453396789730, 0.0049215662293136, 0.0052142175845802, 0.0055242711678147, 0.0058527616783977, 0.0062007848173380, 0.0065695028752089, 0.0069601456634700, 0.0073740174993873, 0.0078124995343387, 0.0082770548760891, 0.0087692337110639, 0.0092906802892685, 0.0098431324586272, 0.0104284351691604, 0.0110485423356295, 0.0117055233567953, 0.0124015696346760, 0.0131390057504177, 0.0139202913269401, 0.0147480349987745, 0.0156249990686774, 0.0165541097521782, 0.0175384692847729, 0.0185813605785370, 0.0196862649172544, 0.0208568722009659, 0.0220970865339041, 0.0234110467135906, 0.0248031392693520, 0.0262780115008354, 0.0278405826538801, 0.0294960699975491, 0.0312499981373549, 0.0331082195043564, 0.0350769385695457, 0.0371627211570740, 0.0393725298345089, 0.0417137444019318, 0.0441941730678082, 0.0468220934271812, 0.0496062822639942, 0.0525560230016708, 0.0556811690330505, 0.0589921437203884, 0.0624999962747097, 0.0662164390087128, 0.0701538771390915, 0.0743254423141479, 0.0787450596690178, 0.0834274888038635, 0.0883883461356163, 0.0936441868543625, 0.0992125645279884, 0.1051120460033417, 0.1113623380661011, 0.1179842874407768, 0.1249999925494194, 0.1324328780174255, 0.1403077542781830, 0.1486508846282959, 0.1574901193380356, 0.1668549776077271, 0.1767766922712326, 0.1872883737087250, 0.1984251290559769, 0.2102240920066833, 0.2227246761322021, 0.2359685748815536, 0.2500000000000000, 0.2648657560348511, 0.2806155085563660, 0.2973017692565918, 0.3149802684783936, 0.3337099552154541, 0.3535533845424652, 0.3745767772197723, 0.3968502581119537, 0.4204482138156891, 0.4454493522644043, 0.4719371497631073, 0.5000000000000000, 0.5297315716743469, 0.5612310171127319, 0.5946035385131836, 0.6299605369567871, 0.6674199104309082, 0.7071067690849304, 0.7491535544395447, 0.7937005162239075, 0.8408964276313782, 0.8908987045288086, 0.9438742995262146, 1.0000000000000000, 1.0594631433486938, 1.1224620342254639, 1.1892070770263672, 1.2599210739135742, 1.3348398208618164, 1.4142135381698608, 1.4983071088790894, 1.5874010324478149, 1.6817928552627563, 1.7817974090576172, 1.8877485990524292, 2.0000000000000000, 2.1189262866973877, 2.2449240684509277, 2.3784141540527344, 2.5198421478271484, 2.6696796417236328, 2.8284270763397217, 2.9966142177581787, 3.1748020648956299, 3.3635857105255127, 3.5635950565338135, 3.7754974365234375, 4.0000000000000000, 4.2378525733947754, 4.4898481369018555, 4.7568287849426270, 5.0396842956542969, 5.3393597602844238, 5.6568546295166016, 5.9932284355163574, 6.3496046066284180, 6.7271714210510254, 7.1271901130676270, 7.5509948730468750, 8.0000000000000000, 8.4757051467895508, 8.9796962738037109, 9.5136575698852539, 10.0793685913085938, 10.6787195205688477, 11.3137092590332031, 11.9864568710327148, 12.6992092132568359, 13.4543428421020508, 14.2543802261352539, 15.1019897460937500, 16.0000000000000000, 16.9514102935791016, 17.9593944549560547, 19.0273151397705078, 20.1587371826171875, 21.3574390411376953, 22.6274185180664062, 23.9729137420654297, 25.3984184265136719, 26.9086875915527344, 28.5087604522705078, 30.2039794921875000, 32.0000000000000000, 33.9028205871582031, 35.9187889099121094, 38.0546302795410156, 40.3174743652343750, 42.7148780822753906, 45.2548370361328125, 47.9458274841308594, 50.7968368530273438, 53.8173751831054688, 57.0175209045410156, 60.4079589843750000, 64.0000076293945312, 67.8056411743164062, 71.8375778198242188, 76.1092605590820312, 80.6349563598632812, 85.4297561645507812, 90.5096740722656250, 95.8916625976562500, 101.5936737060546875, 107.6347503662109375, 114.0350418090820312, 120.8159179687500000, 128.0000152587890625, 135.6112823486328125, 143.6751556396484375, 152.2185211181640625, 161.2699127197265625, 170.8595123291015625, 181.0193481445312500, 191.7833251953125000, 203.1873474121093750, 215.2695007324218750, 228.0700836181640625, 241.6318511962890625, 256.0000305175781250, 271.2225646972656250, 287.3503112792968750, 304.4370422363281250, 322.5398254394531250, 341.7190246582031250, 362.0386962890625000, 383.5666503906250000, 406.3746948242187500, 430.5390014648437500, 456.1401977539062500, 483.2637023925781250, 512.0000610351562500, 542.4451293945312500, 574.7006225585937500, 608.8740844726562500, 645.0796508789062500, 683.4380493164062500, 724.0773925781250000, 767.1333007812500000, 812.7494506835937500, 861.0780029296875000, 912.2803955078125000, 966.5274047851562500, 1024.0001220703125000, 1084.8903808593750000, 1149.4012451171875000, 1217.7481689453125000, 1290.1593017578125000, 1366.8762207031250000, 1448.1549072265625000, 1534.2666015625000000, 1625.4989013671875000}; + +maxiKick::maxiKick(){ + + maxiKick::envelope.setAttack(0); + maxiKick::setPitch(200); + maxiKick::envelope.setDecay(1); + maxiKick::envelope.setSustain(1); + maxiKick::envelope.setRelease(500); + maxiKick::envelope.holdtime=1; + maxiKick::envelope.trigger=0; + +}; + +double maxiKick::play(){ + + envOut=envelope.adsr(1.,envelope.trigger); + + if (inverse) { + + envOut=fabs(1-envOut); + + } + + output=kick.sinewave(pitch*envOut)*envOut; + + if (envelope.trigger==1) { + envelope.trigger=0; + } + + if (useDistortion) { + + output=distort.fastAtanDist(output, distortion); + } + + if (useFilter) { + + output=filter.lores(output, cutoff, resonance); + + } + + if (useLimiter) { + + if (output*gain > 1) { + + return 1.; + + } else if (output*gain < -1) { + + return -1.; + + } else { + + return output*gain; + + } + + + + } else { + + return output*gain; + + } +}; + +void maxiKick::setRelease(double release) { + + envelope.setRelease(release); + +} + +void maxiKick::setPitch(double newPitch) { + + pitch=newPitch; + +} + +void maxiKick::trigger() { + + envelope.trigger=1; + +} + +maxiSnare::maxiSnare(){ + + maxiSnare::envelope.setAttack(0); + maxiSnare::setPitch(800); + maxiSnare::envelope.setDecay(20); + maxiSnare::envelope.setSustain(0.05); + maxiSnare::envelope.setRelease(300); + maxiSnare::envelope.holdtime=1; + maxiSnare::envelope.trigger=0; + +}; + +double maxiSnare::play(){ + + envOut=envelope.adsr(1.,envelope.trigger); + + if (inverse) { + + envOut=fabs(1-envOut); + + } + + output=(tone.triangle(pitch*(0.1+(envOut*0.85)))+noise.noise())*envOut; + + if (envelope.trigger==1) { + envelope.trigger=0; + } + + if (useDistortion) { + + output=distort.fastAtanDist(output, distortion); + } + + if (useFilter) { + + output=filter.lores(output, cutoff, resonance); + + } + + if (useLimiter) { + + if (output*gain > 1) { + + return 1.; + + } else if (output*gain < -1) { + + return -1.; + + } else { + + return output*gain; + + } + + + + } else { + + return output*gain; + + } + +}; + +void maxiSnare::setRelease(double release) { + + envelope.setRelease(release); + +} + +void maxiSnare::setPitch(double newPitch) { + + pitch=newPitch; + +} + +void maxiSnare::trigger() { + + envelope.trigger=1; + +} + +maxiHats::maxiHats(){ + + maxiHats::envelope.setAttack(0); + maxiHats::setPitch(12000); + maxiHats::envelope.setDecay(20); + maxiHats::envelope.setSustain(0.1); + maxiHats::envelope.setRelease(300); + maxiHats::envelope.holdtime=1; + maxiHats::envelope.trigger=0; + maxiHats::filter.setCutoff(8000); + maxiHats::filter.setResonance(1); + +}; + +double maxiHats::play(){ + + envOut=envelope.adsr(1.,envelope.trigger); + + if (inverse) { + + envOut=fabs(1-envOut); + + } + + output=(tone.sinebuf(pitch)+noise.noise())*envOut; + + if (envelope.trigger==1) { + envelope.trigger=0; + } + + if (useDistortion) { + + output=distort.fastAtanDist(output, distortion); + } + + if (useFilter) { + + output=filter.play(output, 0., 0., 1., 0.); + + } + + if (useLimiter) { + + if (output*gain > 1) { + + return 1.; + + } else if (output*gain < -1) { + + return -1.; + + } else { + + return output*gain; + + } + + + + } else { + + return output*gain; + + } + +}; + +void maxiHats::setRelease(double release) { + + envelope.setRelease(release); + +} + +void maxiHats::setPitch(double newPitch) { + + pitch=newPitch; + +} + +void maxiHats::trigger() { + + envelope.trigger=1; + +} + + + +maxiClock::maxiClock() { + + playHead=0; + currentCount=0; + lastCount=0; + bpm=120; + ticks=1; + maxiClock::setTempo(bpm); + +} + + +void maxiClock::ticker() { + + tick=false; + currentCount=floor(timer.phasor(bps));//this sets up a metronome that ticks n times a second + + if (lastCount!=currentCount) {//if we have a new timer int this sample, + + tick=true; + playHead++;//iterate the playhead + + } + +} + + +void maxiClock::setTempo(double bpmIn) { + + bpm=bpmIn; + bps=(bpm/60.)*ticks; +} + + +void maxiClock::setTicksPerBeat(int ticksPerBeat) { + + ticks=ticksPerBeat; + maxiClock::setTempo(bpm); + +} + +maxiSampler::maxiSampler() { + + maxiSampler::voices=32; + maxiSampler::currentVoice=0; + + + for (int i=0;i0.) { + outputs[i]=samples[i].play(pitchRatios[(int)pitch[i]+originalPitch]*((1./samples[i].length)*maxiSettings::sampleRate),0,samples[i].length)*envOut[i]; + output+=outputs[i]/voices; + + if (envelopes[i].trigger==1 && !sustain) { + envelopes[i].trigger=0; + + } + + } + + } return output; + +} + +void maxiSampler::load(string inFile, bool setall) { + + if (setall) { + for (int i=0;i #include #include "math.h" - #ifdef _WIN32 //|| _WIN64 #include #endif @@ -55,191 +54,191 @@ using namespace std; class maxiSettings { public: - static int sampleRate; - static int channels; - static int bufferSize; - static void setup(int initSampleRate, int initChannels, int initBufferSize) { - maxiSettings::sampleRate = initSampleRate; - maxiSettings::channels = initChannels; - maxiSettings::bufferSize = initBufferSize; - } + static int sampleRate; + static int channels; + static int bufferSize; + static void setup(int initSampleRate, int initChannels, int initBufferSize) { + maxiSettings::sampleRate = initSampleRate; + maxiSettings::channels = initChannels; + maxiSettings::bufferSize = initBufferSize; + } }; class maxiOsc { - - double frequency; - double phase; - double startphase; - double endphase; - double output; - double tri; - - + + double frequency; + double phase; + double startphase; + double endphase; + double output; + double tri; + + public: - maxiOsc(); - double sinewave(double frequency); - double coswave(double frequency); - double phasor(double frequency); - double phasor(double frequency, double startphase, double endphase); - double saw(double frequency); - double triangle(double frequency); - double square(double frequency); - double pulse(double frequency, double duty); - double noise(); - double sinebuf(double frequency); - double sinebuf4(double frequency); + maxiOsc(); + double sinewave(double frequency); + double coswave(double frequency); + double phasor(double frequency); + double phasor(double frequency, double startphase, double endphase); + double saw(double frequency); + double triangle(double frequency); + double square(double frequency); + double pulse(double frequency, double duty); + double noise(); + double sinebuf(double frequency); + double sinebuf4(double frequency); double sawn(double frequency); double rect(double frequency, double duty=0.5); - void phaseReset(double phaseIn); - + void phaseReset(double phaseIn); + }; class maxiEnvelope { - - double period; - double output; - double startval; - double currentval; - double nextval; - int isPlaying; - -public: - double line(int numberofsegments,double segments[100]); - void trigger(int index,double amp); - int valindex; - double amplitude; - + + double period; + double output; + double startval; + double currentval; + double nextval; + int isPlaying; + +public: + double line(int numberofsegments,double segments[100]); + void trigger(int index,double amp); + int valindex; + double amplitude; + }; class maxiDelayline { - double frequency; - int phase; - double startphase; - double endphase; - double output; - double memory[88200]; - + double frequency; + int phase; + double startphase; + double endphase; + double output; + double memory[88200]; + public: - maxiDelayline(); - double dl(double input, int size, double feedback); - double dl(double input, int size, double feedback, int position); - - + maxiDelayline(); + double dl(double input, int size, double feedback); + double dl(double input, int size, double feedback, int position); + + }; -class maxiFilter { - double gain; - double input; - double output; - double inputs[10]; - double outputs[10]; - double cutoff1; - double x;//speed - double y;//pos - double z;//pole - double c;//filter coefficient +class maxiFilter { + double gain; + double input; + double output; + double inputs[10]; + double outputs[10]; + double cutoff1; + double x;//speed + double y;//pos + double z;//pole + double c;//filter coefficient public: - maxiFilter():x(0.0), y(0.0), z(0.0), c(0.0){}; - double cutoff; - double resonance; - double lores(double input,double cutoff1, double resonance); - double hires(double input,double cutoff1, double resonance); - double bandpass(double input,double cutoff1, double resonance); - double lopass(double input,double cutoff); - double hipass(double input,double cutoff); - + maxiFilter():x(0.0), y(0.0), z(0.0), c(0.0){}; + double cutoff; + double resonance; + double lores(double input,double cutoff1, double resonance); + double hires(double input,double cutoff1, double resonance); + double bandpass(double input,double cutoff1, double resonance); + double lopass(double input,double cutoff); + double hipass(double input,double cutoff); + }; class maxiMix { - double input; - double two[2]; - double four[4]; - double eight[8]; + double input; + double two[2]; + double four[4]; + double eight[8]; public: - double x; - double y; - double z; - double *stereo(double input,double two[2],double x); - double *quad(double input,double four[4], double x,double y); - double *ambisonic(double input,double eight[8],double x,double y, double z); - + double x; + double y; + double z; + double *stereo(double input,double two[2],double x); + double *quad(double input,double four[4], double x,double y); + double *ambisonic(double input,double eight[8],double x,double y, double z); + }; //lagging with an exponential moving average //a lower alpha value gives a slower lag -template +template class maxiLagExp { public: - T alpha, alphaReciprocal; - T val; - - maxiLagExp() { - init(0.5, 0.0); - }; - - maxiLagExp(T initAlpha, T initVal) { - init(initAlpha, initVal); - } - - void init(T initAlpha, T initVal) { - alpha = initAlpha; - alphaReciprocal = 1.0 - alpha; - val = initVal; - } - - inline void addSample(T newVal) { - val = (alpha * newVal) + (alphaReciprocal * val); - } - - inline T value() { - return val; - } + T alpha, alphaReciprocal; + T val; + + maxiLagExp() { + init(0.5, 0.0); + }; + + maxiLagExp(T initAlpha, T initVal) { + init(initAlpha, initVal); + } + + void init(T initAlpha, T initVal) { + alpha = initAlpha; + alphaReciprocal = 1.0 - alpha; + val = initVal; + } + + inline void addSample(T newVal) { + val = (alpha * newVal) + (alphaReciprocal * val); + } + + inline T value() { + return val; + } }; class maxiSample { - + private: - string myPath; - int myChunkSize; - int mySubChunk1Size; - int readChannel; - short myFormat; - int myByteRate; - short myBlockAlign; - short myBitsPerSample; - double position, recordPosition; - double speed; - double output; + string myPath; + int myChunkSize; + int mySubChunk1Size; + int readChannel; + short myFormat; + int myByteRate; + short myBlockAlign; + double position, recordPosition; + double speed; + double output; maxiLagExp loopRecordLag; - + public: - int myDataSize; - short myChannels; - int mySampleRate; - long length; - void getLength(); - void setLength(unsigned long numSamples); - - -// char* myData; + int myDataSize; + short myChannels; + int mySampleRate; + long length; + void getLength(); + void setLength(unsigned long numSamples); + short myBitsPerSample; + + + // char* myData; short* temp; - - // get/set for the Path property - - ~maxiSample() - { -// if (myData) free(myData); + + // get/set for the Path property + + ~maxiSample() + { + // if (myData) free(myData); if (temp) free(temp); printf("freeing SampleData"); - - } - + + } + maxiSample():temp(NULL),position(0), recordPosition(0), myChannels(1), mySampleRate(maxiSettings::sampleRate) {}; maxiSample& operator=(const maxiSample &source) { @@ -256,17 +255,17 @@ class maxiSample { length = source.length; return *this; } - - bool load(string fileName, int channel=0); + + bool load(string fileName, int channel=0); bool loadOgg(string filename,int channel=0); - - void trigger(); - - // read a wav file into this class - bool read(); - - //read an ogg file into this class using stb_vorbis + + void trigger(); + + // read a wav file into this class + bool read(); + + //read an ogg file into this class using stb_vorbis bool readOgg(); void loopRecord(double newSample, const bool recordEnabled, const double recordMix, double start = 0.0, double end = 1.0) { @@ -318,8 +317,8 @@ class maxiSample { return save(myPath); } - bool save(string filename) - { + bool save(string filename) + { fstream myFile (filename.c_str(), ios::out | ios::binary); // write the wav file per the wav file format @@ -340,16 +339,16 @@ class maxiSample { myFile.write ((char*) temp, myDataSize); return true; - } - - // return a printable summary of the wav file - char *getSummary() - { - char *summary = new char[250]; - sprintf(summary, " Format: %d\n Channels: %d\n SampleRate: %d\n ByteRate: %d\n BlockAlign: %d\n BitsPerSample: %d\n DataSize: %d\n", myFormat, myChannels, mySampleRate, myByteRate, myBlockAlign, myBitsPerSample, myDataSize); - std::cout << myDataSize; - return summary; - } + } + + // return a printable summary of the wav file + char *getSummary() + { + char *summary = new char[250]; + sprintf(summary, " Format: %d\n Channels: %d\n SampleRate: %d\n ByteRate: %d\n BlockAlign: %d\n BitsPerSample: %d\n DataSize: %d\n", myFormat, myChannels, mySampleRate, myByteRate, myBlockAlign, myBitsPerSample, myDataSize); + std::cout << myDataSize; + return summary; + } void normalise(float maxLevel = 0.99); //0 < maxLevel < 1.0 void autoTrim(float alpha = 0.3, float threshold = 6000, bool trimStart = true, bool trimEnd = true); //alpha of lag filter (lower == slower reaction), threshold to mark start and end, < 32767 @@ -385,63 +384,63 @@ class maxiMap { } return v; } - + }; class maxiDyn { - - + + public: -// double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995); -// double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995); + // double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995); + // double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995); double gate(double input, double threshold=0.9, long holdtime=1, double attack=1, double release=0.9995); double compressor(double input, double ratio, double threshold=0.9, double attack=1, double release=0.9995); double compress(double input); double input; - double ratio; - double currentRatio; - double threshold; - double output; - double attack; - double release; - double amplitude; + double ratio; + double currentRatio; + double threshold; + double output; + double attack; + double release; + double amplitude; void setAttack(double attackMS); void setRelease(double releaseMS); void setThreshold(double thresholdI); void setRatio(double ratioF); - long holdtime; - long holdcount; - int attackphase,holdphase,releasephase; + long holdtime; + long holdcount; + int attackphase,holdphase,releasephase; }; class maxiEnv { - - + + public: - double ar(double input, double attack=1, double release=0.9, long holdtime=1, int trigger=0); - double adsr(double input, double attack=1, double decay=0.99, double sustain=0.125, double release=0.9, long holdtime=1, int trigger=0); + double ar(double input, double attack=1, double release=0.9, long holdtime=1, int trigger=0); + double adsr(double input, double attack=1, double decay=0.99, double sustain=0.125, double release=0.9, long holdtime=1, int trigger=0); double adsr(double input,int trigger); - double input; - double output; - double attack; - double decay; - double sustain; - double release; - double amplitude; + double input; + double output; + double attack; + double decay; + double sustain; + double release; + double amplitude; void setAttack(double attackMS); void setRelease(double releaseMS); void setDecay(double decayMS); void setSustain(double sustainL); - int trigger; - long holdtime=1; - long holdcount; - int attackphase,decayphase,sustainphase,holdphase,releasephase; + int trigger; + long holdtime=1; + long holdcount; + int attackphase,decayphase,sustainphase,holdphase,releasephase; }; class convert { public: - double mtof(int midinote); + double mtof(int midinote); }; @@ -482,7 +481,7 @@ class maxiFlanger { double flange(const double input, const unsigned int delay, const double feedback, const double speed, const double depth); maxiDelayline dl; maxiOsc lfo; - + }; inline double maxiFlanger::flange(const double input, const unsigned int delay, const double feedback, const double speed, const double depth) @@ -490,7 +489,7 @@ inline double maxiFlanger::flange(const double input, const unsigned int delay, //todo: needs fixing double output; double lfoVal = lfo.triangle(speed); - output = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ; + output = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ; double normalise = (1 - fabs(output)); output *= normalise; return (output + input) / 2.0; @@ -515,8 +514,8 @@ inline double maxiChorus::chorus(const double input, const unsigned int delay, c double output1, output2; double lfoVal = lfo.noise(); lfoVal = lopass.lores(lfoVal, speed, 1.0) * 2.0; - output1 = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ; - output2 = dl2.dl(input, (delay + (lfoVal * depth * delay * 1.02) + 1) * 0.98, feedback * 0.99) ; + output1 = dl.dl(input, delay + (lfoVal * depth * delay) + 1, feedback) ; + output2 = dl2.dl(input, (delay + (lfoVal * depth * delay * 1.02) + 1) * 0.98, feedback * 0.99) ; output1 *= (1.0 - fabs(output1)); output2 *= (1.0 - fabs(output2)); return (output1 + output2 + input) / 3.0; @@ -633,5 +632,169 @@ class maxiSVF { }; +class maxiKick { + +public: + maxiKick(); + double play(); + void setPitch(double pitch); + void setRelease(double releaseD); + void trigger(); + double pitch; + double output = 0 ; + double outputD =0 ; + double envOut; + bool useDistortion = false; + bool useLimiter = false; + bool useFilter = false; + double distortion = 0; + bool inverse = false; + double cutoff; + double resonance; + double gain = 1; + maxiOsc kick; + maxiEnv envelope; + maxiDistortion distort; + maxiFilter filter; +}; + +class maxiSnare { +public: + maxiSnare(); + double play(); + void setPitch(double pitch); + void setRelease(double releaseD); + void trigger(); + double pitch; + double output = 0 ; + double outputD = 0 ; + double envOut; + bool useDistortion = false; + bool useLimiter = false; + bool useFilter = true; + double distortion = 0; + bool inverse = false; + double cutoff; + double resonance; + double gain = 1; + maxiOsc tone; + maxiOsc noise; + maxiEnv envelope; + maxiDistortion distort; + maxiFilter filter; + + + +}; + +class maxiHats { + +public: + maxiHats(); + double play(); + void setPitch(double pitch); + void setRelease(double releaseD); + void trigger(); + double pitch; + double output = 0; + double outputD = 0; + double envOut; + bool useDistortion = false; + bool useLimiter = false; + bool useFilter = false; + double distortion = 0; + bool inverse = false; + double cutoff; + double resonance; + double gain = 1; + maxiOsc tone; + maxiOsc noise; + maxiEnv envelope; + maxiDistortion distort; + maxiSVF filter; + + +}; + + +class maxiSynth { + + + +}; + + +class granularSynth { + + + +}; + + +class maxiSampler { + +public: + maxiSampler(); + double play(); + void setPitch(double pitch, bool setall=false); + void midiNoteOn(double pitch, double velocity, bool setall=false); + void midiNoteOff(double pitch, double velocity, bool setall=false); + void setAttack(double attackD,bool setall=true); + void setDecay(double decayD,bool setall=true); + void setSustain(double sustainD,bool setall=true); + void setRelease(double releaseD,bool setall=true); + void setPosition(double positionD,bool setall=true); + void load(string inFile,bool setall=true); + void setNumVoices(int numVoices); + double position; + void trigger(); + double pitch[32]; + int originalPitch=67; + double outputs[32]; + double outputD = 0; + double envOut[32]; + double envOutGain[32]; + double output; + bool useDistortion = false; + bool useLimiter = false; + bool useFilter = false; + double distortion = 0; + bool inverse = false; + double cutoff; + double resonance; + double gain = 1; + int voices; + int currentVoice=0; + convert mtof; + maxiOsc LFO1; + maxiOsc LFO2; + maxiOsc LFO3; + maxiOsc LFO4; + maxiSample samples[32]; + maxiEnv envelopes[32]; + maxiDistortion distort; + maxiSVF filters[32]; + bool sustain = true; + + +}; + +class maxiClock { +public: + maxiClock(); + void ticker(); + void setTempo(double bpm); + void setTicksPerBeat(int ticksPerBeat); + maxiOsc timer; + int currentCount; + int lastCount; + int playHead; + double bps; + double bpm; + int ticks; + bool tick; + +}; + #endif