aboutsummaryrefslogtreecommitdiffstats
path: root/libs
diff options
context:
space:
mode:
authormick grierson <mickgrierson@gmail.com>2016-03-04 14:14:56 +0000
committermick grierson <mickgrierson@gmail.com>2016-03-04 14:14:56 +0000
commitff891983f82464506b2f6545fd1d26c413638c64 (patch)
tree91900ad09aa69a7f6efcb79285727bc865da4403 /libs
parent5dad0e449fb7f4ea35c0da1ee1c61efef2c83bc5 (diff)
fixing maxiGrains
Diffstat (limited to 'libs')
-rw-r--r--libs/maxiGrains.h1019
1 files changed, 687 insertions, 332 deletions
diff --git a/libs/maxiGrains.h b/libs/maxiGrains.h
index a6b8c52..5fd5beb 100644
--- a/libs/maxiGrains.h
+++ b/libs/maxiGrains.h
@@ -1,13 +1,13 @@
-#ifndef _MAXI_GRAINS_H
-#define _MAXI_GRAINS_H
+#ifndef maxiGrains_2_hpp
+#define maxiGrains_2_hpp
#include "maximilian.h"
#if defined(__APPLE_CC__)
#include "accelerate/accelerate.h"
//Mac users can uncommment the line below to use Apple's accelerate framework for calculating grains. This gives ~300% speed improvement and better sound quality, but doesn't work well on all machines.
-//#define MAXIGRAINFAST
+//#define MAXIGRAINFAST
#endif
#include <list>
@@ -17,214 +17,184 @@ typedef unsigned long ulong;
//window functions from http://en.wikipedia.org/wiki/Window_function#High-_and_moderate-resolution_windows
struct hannWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return 0.5 * (1.0 - cos((2.0 * PI * windowPos) / (windowLength - 1)));
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return 0.5 * (1.0 - cos((2.0 * PI * windowPos) / (windowLength - 1)));
+ }
};
//this window can produce clicks
struct hammingWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return 0.54 - (0.46 * cos((2.0 * PI * windowPos) / (windowLength - 1)));
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return 0.54 - (0.46 * cos((2.0 * PI * windowPos) / (windowLength - 1)));
+ }
};
struct cosineWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return sin((PI * windowPos) / (windowLength - 1));
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return sin((PI * windowPos) / (windowLength - 1));
+ }
};
struct rectWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return 1;
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return 1;
+ }
};
struct triangleWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return (2.0 / (windowLength-1.0)) * (((windowLength-1.0)/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0)));
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return (2.0 / (windowLength-1.0)) * (((windowLength-1.0)/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0)));
+ }
};
struct triangleNZWinFunctor {
- //non zero end points
- inline double operator()(ulong windowLength, ulong windowPos) {
- return (2.0 / windowLength) * ((windowLength/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0)));
- }
+ //non zero end points
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return (2.0 / windowLength) * ((windowLength/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0)));
+ }
};
struct blackmanHarrisWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return 0.35875 -
- (0.48829 * cos((2 * PI * windowPos) / (windowLength-1))) +
- (0.14128 * cos((4 * PI * windowPos) / (windowLength-1))) +
- (0.01168 * cos((6 * PI * windowPos) / (windowLength-1)));
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return 0.35875 -
+ (0.48829 * cos((2 * PI * windowPos) / (windowLength-1))) +
+ (0.14128 * cos((4 * PI * windowPos) / (windowLength-1))) +
+ (0.01168 * cos((6 * PI * windowPos) / (windowLength-1)));
+ }
};
struct blackmanNutallWinFunctor {
- inline double operator()(ulong windowLength, ulong windowPos) {
- return 0.3635819 -
- (0.4891775 * cos((2 * PI * windowPos) / (windowLength-1))) +
- (0.1365995 * cos((4 * PI * windowPos) / (windowLength-1))) +
- (0.0106411 * cos((6 * PI * windowPos) / (windowLength-1)));
- }
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ return 0.3635819 -
+ (0.4891775 * cos((2 * PI * windowPos) / (windowLength-1))) +
+ (0.1365995 * cos((4 * PI * windowPos) / (windowLength-1))) +
+ (0.0106411 * cos((6 * PI * windowPos) / (windowLength-1)));
+ }
};
struct gaussianWinFunctor {
- double gausDivisor;
+ double o;
gaussianWinFunctor() {
- init(0.3);
- }
- gaussianWinFunctor(double kurtosis) {
- init(kurtosis);
+ o = 0.02; //compatible with MPTK
}
- void init(double kurtosis) {
- gausDivisor = (-2.0 * kurtosis * kurtosis);
+ inline double operator()(ulong windowLength, ulong windowPos) {
+ double p = 1.0/(2.0*o*(windowLength+1)*(windowLength+1));
+ double k = (double)windowPos-((double)(windowLength-1))/2.0;
+ return exp(-k*k*p);
}
- inline double operator()(ulong windowLength, ulong windowPos) {
- double phase = ((windowPos / (double) windowLength) - 0.5) * 2.0;
- return exp((phase * phase) / gausDivisor);
- }
};
template<typename F>
class maxiGrainWindowCache {
public:
- unsigned int cacheSize;
-
- maxiGrainWindowCache() {
- cacheSize = maxiSettings::sampleRate / 2.0; //allocate mem for up to 500ms grains
- cache = (double**)malloc(cacheSize * sizeof(double*));
- for(int i=0; i < cacheSize; i++) {
- cache[i] = NULL;
- }
- }
-
- ~maxiGrainWindowCache() {
- for(int i=0; i < cacheSize; i++) {
- if(NULL != cache[i]) {
- free(cache[i]);
- }
- }
+ unsigned int cacheSize;
+
+ maxiGrainWindowCache() {
+ cacheSize = maxiSettings::sampleRate / 2.0; //allocate mem for up to 500ms grains
+ cache = (double**)malloc(cacheSize * sizeof(double*));
+ for(int i=0; i < cacheSize; i++) {
+ cache[i] = NULL;
+ }
+ }
+
+ ~maxiGrainWindowCache() {
+ for(int i=0; i < cacheSize; i++) {
+ if(NULL != cache[i]) {
+ free(cache[i]);
+ }
+ }
free(cache);
- }
-
- double* getWindow(const unsigned int length) {
- if (NULL == cache[length]) {
- cache[length] = (double*)malloc(length * sizeof(double));
- for(int i=0; i < length; i++) {
- cache[length][i] = F()(length, i);
- }
- }
- return cache[length];
- }
-
+ }
+
+ double* getWindow(const unsigned int length) {
+ if (NULL == cache[length]) {
+ cache[length] = (double*)malloc(length * sizeof(double));
+ for(int i=0; i < length; i++) {
+ cache[length][i] = F()(length, i);
+ }
+ }
+ return cache[length];
+ }
+
private:
- double** cache;
-
+ double** cache;
+
};
class maxiGrainBase {
public:
- virtual double play() {}
+ virtual double play() {}
virtual ~maxiGrainBase() {}
- bool finished;
+ bool finished;
};
-template<typename F>
+template<class F, class maxiSample>
class maxiGrain : public maxiGrainBase {
public:
- maxiSample *sample;
+ maxiSample *sample;
double pos;
- double dur;
- long sampleStartPos;
- long sampleIdx;
- long sampleDur;
- long sampleEndPos;
- double freq;
- double speed;
- double inc;
- double frequency;
- double* window;
- short* buffer;
+ double dur;
+ long sampleStartPos;
+ long sampleIdx;
+ long sampleDur;
+ long sampleEndPos;
+ double freq;
+ double speed;
+ double inc;
+ double frequency;
+ double* window;
+ // short* buffer;
#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
- double* grainSamples;
+ // double* grainSamples;
#endif
- /*
- position between 0.0 and 1.0
- duration in seconds
- */
- maxiGrain(maxiSample *sample, const double position, const double duration, const double speed, maxiGrainWindowCache<F> *windowCache) :sample(sample), pos(position), dur(duration), speed(speed)
- {
- buffer = sample->temp;
- sampleStartPos = sample->length * pos;
- sampleDur = dur * (double)sample->mySampleRate;
- sampleDurMinusOne = sampleDur - 1;
- sampleIdx = 0;
- finished = 0;
- freq = 1.0 / dur;
- sampleEndPos = min(sample->length, sampleStartPos + sampleDur);
- frequency = freq * speed;
- if (frequency > 0) {
- pos = sampleStartPos;
- }else{
- pos = sampleEndPos;
- }
+ /*
+ position between 0.0 and 1.0
+ duration in seconds
+ */
+ maxiGrain(maxiSample *_sample, const double position, const double duration, const double speed, maxiGrainWindowCache<F> *windowCache) :sample(_sample), pos(position), dur(duration), speed(speed)
+ {
+ // buffer = sample->temp;
+ sampleStartPos = (sample->length) * pos;
+ sampleDur = dur * (double)maxiSettings::sampleRate;
+ sampleDurMinusOne = sampleDur - 1;
+ sampleIdx = 0;
+ finished = 0;
+ freq = 1.0 / dur;
+ sampleEndPos = min(sample->length, sampleStartPos + sampleDur);
+ frequency = freq * speed;
+ if (frequency > 0) {
+ pos = sampleStartPos;
+ }else{
+ pos = sampleEndPos;
+ }
if (frequency != 0) {
inc = sampleDur/(maxiSettings::sampleRate/frequency);
}else
inc = 0;
- window = windowCache->getWindow(sampleDur);
-
-#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
- //premake the grain using fast vector functions, and quadratic interpolation
- double *sourceData = (double*)malloc(sampleDur * sizeof(double));
- short* buffer = (short *)sample->temp;
- //convert sample to double data
- vDSP_vflt16D(buffer + sampleStartPos, 1, sourceData, 1, min(sampleDur, sample->length - sampleStartPos));
- //todo: wraping code
-
- grainSamples = (double*)malloc(sampleDur * sizeof(double));
- //make list of interpolation indexes
- double* interpIndexes = (double*)malloc(sampleDur * sizeof(double));
- double interpPos = sampleStartPos;
- for(int i=0; i < sampleDur; i++) {
- interpIndexes[i] = interpPos - sampleStartPos;
- interpPos += fabs(inc);
- }
- vDSP_vqintD(sourceData, interpIndexes, 1, grainSamples, 1, sampleDur, sampleDur);
- if (frequency < 0) {
- vDSP_vrvrsD(grainSamples,1, sampleDur);
- }
- static double divFactor = 32767.0;
- vDSP_vsdivD(grainSamples, 1, &divFactor, grainSamples, 1, sampleDur);
- vDSP_vmulD(grainSamples, 1, window, 1, grainSamples, 1, sampleDur);
- delete sourceData, interpIndexes;
-#endif
- }
-
- ~maxiGrain() {
+ window = windowCache->getWindow(sampleDur);
+
+ }
+
+ ~maxiGrain() {
#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
- delete[] grainSamples;
+ delete[] grainSamples;
#endif
- }
-
- inline double play() {
- double output = 0.0;
- if (!finished) {
+ }
+
+ inline double play() {
+ double output = 0.0;
+ if (!finished) {
#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
- output = grainSamples[sampleIdx];
+ // output = grainSamples[sampleIdx];
#else
- envValue = window[sampleIdx];
- double remainder;
+ envValue = window[sampleIdx];
+ double remainder;
pos += inc;
- if (pos >= sample->length)
+ if (pos >= sample->length)
pos -= sample->length;
- else if (pos < 0)
+ else if (pos < 0)
pos += sample->length;
long posl = floor(pos);
@@ -234,20 +204,21 @@ public:
if (b >= sample->length) {
b = 0;
}
- output = (double) ((1-remainder) * buffer[a] +
- remainder * buffer[b])/32767.0;//linear interpolation
- output *= envValue;
+ //output = (double) ((1-remainder) * sample->operator[](a) +
+ // remainder * sample->operator[](b))/32767.0;//linear interpolation
+ output = (double) ((1-remainder) * sample->temp[a] + remainder * sample->temp[b])/32767.0;//linear interpolation
+ output *= envValue;
#endif
- }
- sampleIdx++;
- if (sampleIdx == sampleDur) finished = true;
- return output;
- }
-
-protected:
- maxiGrain();
- double envValue;
- ulong sampleDurMinusOne;
+ }
+ sampleIdx++;
+ if (sampleIdx == sampleDur) finished = true;
+ return output;
+ }
+
+protected:
+ maxiGrain();
+ double envValue;
+ ulong sampleDurMinusOne;
};
@@ -255,173 +226,64 @@ typedef list<maxiGrainBase*> grainList;
class maxiGrainPlayer {
public:
- grainList grains;
- maxiSample *sample;
-
- maxiGrainPlayer(maxiSample *sample) : sample(sample) {
- }
-
- void addGrain(maxiGrainBase *g) {
- grains.push_back(g);
- }
-
- inline double play() {
- double total = 0.0;
- grainList::iterator it = grains.begin();
- while(it != grains.end()) {
- total += (*it)->play();
- if ((*it)->finished) {
- delete(*it);
- it = grains.erase(it);
- }else{
- it++;
- }
- }
- return total;
- }
-};
-
-template<typename F>
-class maxiTimestretch {
-protected:
- double position;
-public:
- maxiSample *sample;
- maxiGrainPlayer *grainPlayer;
- maxiGrainWindowCache<F> windowCache;
- double randomOffset;
- double looper;
-
-
-
- maxiTimestretch(maxiSample *sample) : sample(sample) {
- position=0;
- looper = 0;
- grainPlayer = new maxiGrainPlayer(sample);
- randomOffset=0;
- }
-
- ~maxiTimestretch() {
- delete grainPlayer;
- }
+ grainList grains;
+ // maxiSample *sample;
+ // source *sample;
- double getNormalisedPosition() {
- return position / (double) sample->length;
- }
- double getPosition() {
- return position;
- }
+ // maxiGrainPlayer(maxiSample *sample) : sample(sample) {
+ // }
- void setPosition(double pos) {
- position = pos * sample->length;
- position = maxiMap::clamp(position, 0, sample->length-1);
+ // maxiGrainPlayer(source *sample) : sample(sample) {
+ // }
+
+ void addGrain(maxiGrainBase *g) {
+ grains.push_back(g);
}
-
-
- //play at a speed
- inline double play(double speed, double grainLength, int overlaps, double posMod=0.0) {
- position = position + speed;
- looper++;
- if (position > sample->length) position-= sample->length;
- if (position < 0) position += sample->length;
- double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
- if (looper > cycleLength + randomOffset) {
- looper -= (cycleLength + randomOffset);
- speed = (speed > 0 ? 1 : -1);
- maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache);
- grainPlayer->addGrain(g);
- randomOffset = rand() % 10;
- }
- return grainPlayer->play();
- }
-
- //provide your own position iteration
- inline double play2(double pos, double grainLength, int overlaps) {
- looper++;
- pos *= sample->length;
- if (0 == floor(fmod(looper, grainLength * maxiSettings::sampleRate / overlaps))) {
- maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(pos / sample->length)),0.0), grainLength, 1, &windowCache);
- grainPlayer->addGrain(g);
- }
- return grainPlayer->play();
- }
-};
-
-//in maxiTimeStretch, the speed is either 1 or -1, and the actual speed value only affects the grain position
-//in maxiPitchShift, speed is uncoupled from position and allowed to set it's value incrementally, resulting in pitchshift.
-//with both high speed values and negative speed values there are some terrific artefacts!
-
-template<typename F>
-class maxiPitchShift {
-public:
- double position;
- long cycles;
- maxiSample *sample;
- maxiGrainPlayer *grainPlayer;
- maxiGrainWindowCache<F> windowCache;
- double randomOffset;
-
- maxiPitchShift(maxiSample *sample) : sample(sample) {
- position=0;
- cycles=0;
- grainPlayer = new maxiGrainPlayer(sample);
- randomOffset=0;
- }
-
- ~maxiPitchShift() {
- delete grainPlayer;
- }
-
- double play(double speed, double grainLength, int overlaps, double posMod=0.0) {
- position = position + 1;
- cycles++;
- if (position > sample->length) position=0;
- if (position < 0) position = sample->length;
- double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
- double cycleMod = fmod(cycles, cycleLength + randomOffset);
- if (0 == floor(cycleMod)) {
- // cout << cycleMod << endl;
- //speed = (speed > 0 ? 1 : -1);
- speed = speed - ((cycleMod / cycleLength) * 0.1);
- maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache);
- grainPlayer->addGrain(g);
- // cout << grainPlayer->grains.size() << endl;
- // randomOffset = rand() % 10;
- // randomOffset = rand() % 10;
- }
- return grainPlayer->play();
- }
-
+ inline double play() {
+ double total = 0.0;
+ grainList::iterator it = grains.begin();
+ while(it != grains.end()) {
+ total += (*it)->play();
+ if ((*it)->finished) {
+ delete(*it);
+ it = grains.erase(it);
+ }else{
+ it++;
+ }
+ }
+ return total;
+ }
};
//and here's maxiPitchStretch. Args to the play function are basically speed for 'pitch' and rate for playback rate.
//the rest is the same.
-template<typename F>
-class maxiPitchStretch {
+template<class F, class maxiSample>
+class maxiTimePitchStretch {
public:
- double position;
- maxiSample *sample;
- maxiGrainPlayer *grainPlayer;
- maxiGrainWindowCache<F> windowCache;
- double randomOffset;
+ double position;
+ maxiSample *sample;
+ maxiGrainPlayer *grainPlayer;
+ maxiGrainWindowCache<F> windowCache;
+ double randomOffset;
long loopStart, loopEnd, loopLength;
double looper;
-
- maxiPitchStretch(maxiSample *sample) : sample(sample) {
- grainPlayer = new maxiGrainPlayer(sample);
- randomOffset=0;
+
+ maxiTimePitchStretch(maxiSample *_sample) : sample(_sample) {
+ grainPlayer = new maxiGrainPlayer();
+ randomOffset=0;
loopStart = 0.0;
+ sample->getLength();
loopEnd = sample->length;
- loopLength =sample->length;
- position=0;
+ loopLength = sample->length;
+ position=0;
looper = 0;
- }
+ }
double getNormalisedPosition() {
- return position / (double) sample->length;
+ return position / (double) sample->getLength();
}
double getPosition() {
@@ -430,7 +292,7 @@ public:
void setPosition(double pos) {
position = pos * sample->length;
- position = maxiMap::clamp(position, 0, sample->length-1);
+ position = maxiMap::clamp<double>(position, 0, sample->length-1);
}
void setLoopStart(double val) {
@@ -442,26 +304,519 @@ public:
loopEnd = val * sample->length;
loopLength = loopEnd - loopStart;
}
-
- ~maxiPitchStretch() {
- delete grainPlayer;
- }
-
- inline double play(double speed, double rate, double grainLength, int overlaps, double posMod=0.0) {
- position = position + (1 * rate);
+
+
+ bool hasEnded() {
+ return position == loopEnd;
+ }
+
+ ~maxiTimePitchStretch() {
+ delete grainPlayer;
+ }
+
+ inline double play(double speed, double rate, double grainLength, int overlaps, double posMod=0.0) {
+ position = position + rate;
+ if (position >= loopEnd) position-= loopLength;
+ if (position < loopStart) position += loopLength;
+ return playNextGrain(speed, rate, grainLength, overlaps, posMod);
+ }
+
+ inline double playOnce(double speed, double rate, double grainLength, int overlaps, double posMod=0.0) {
+ position = position + rate;
+ if (position >= loopEnd) position = loopEnd;
+ if (position < loopStart) position = loopEnd;
+ float val = 0;
+ if (position < loopEnd)
+ val = playNextGrain(speed, rate, grainLength, overlaps, posMod);
+ return val;
+ }
+
+protected:
+ inline double playNextGrain(double speed, double rate, double grainLength, int overlaps, double posMod) {
looper++;
- if (position >= loopEnd) position-= loopLength;
- if (position < loopStart) position += loopLength;
- double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
+ double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
if (looper > cycleLength + randomOffset) {
looper -= (cycleLength + randomOffset);
- maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache);
- grainPlayer->addGrain(g);
+ double pos = max(min(static_cast<double>(1.0), (position / sample->length) + posMod),static_cast<double>(0.0));
+ maxiGrain<F, maxiSample> *g = new maxiGrain<F, maxiSample>(sample,
+ pos,
+ grainLength, speed, &windowCache);
+ grainPlayer->addGrain(g);
randomOffset = rand() % 10;
- }
- return grainPlayer->play();
- }
-
+ }
+ return grainPlayer->play();
+ }
+
};
-#endif \ No newline at end of file
+
+#endif /* maxiGrains_2_hpp */
+
+
+//
+//
+//#ifndef _MAXI_GRAINS_H
+//#define _MAXI_GRAINS_H
+//#include "maximilian.h"
+//
+//#if defined(__APPLE_CC__)
+//#include "accelerate/accelerate.h"
+////Mac users can uncommment the line below to use Apple's accelerate framework for calculating grains. This gives ~300% speed improvement and better sound quality, but doesn't work well on all machines.
+//#define MAXIGRAINFAST
+//#endif
+//
+//#include <list>
+//
+//typedef unsigned long ulong;
+//
+////window functions from http://en.wikipedia.org/wiki/Window_function#High-_and_moderate-resolution_windows
+//
+//struct hannWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return 0.5 * (1.0 - cos((2.0 * PI * windowPos) / (windowLength - 1)));
+// }
+//};
+//
+////this window can produce clicks
+//struct hammingWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return 0.54 - (0.46 * cos((2.0 * PI * windowPos) / (windowLength - 1)));
+// }
+//};
+//
+//
+//struct cosineWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return sin((PI * windowPos) / (windowLength - 1));
+// }
+//};
+//
+//struct rectWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return 1;
+// }
+//};
+//
+//struct triangleWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return (2.0 / (windowLength-1.0)) * (((windowLength-1.0)/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0)));
+// }
+//};
+//
+//struct triangleNZWinFunctor {
+// //non zero end points
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return (2.0 / windowLength) * ((windowLength/2.0) - fabs(windowPos - ((windowLength-1.0)/2.0)));
+// }
+//};
+//
+//struct blackmanHarrisWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return 0.35875 -
+// (0.48829 * cos((2 * PI * windowPos) / (windowLength-1))) +
+// (0.14128 * cos((4 * PI * windowPos) / (windowLength-1))) +
+// (0.01168 * cos((6 * PI * windowPos) / (windowLength-1)));
+// }
+//};
+//
+//struct blackmanNutallWinFunctor {
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// return 0.3635819 -
+// (0.4891775 * cos((2 * PI * windowPos) / (windowLength-1))) +
+// (0.1365995 * cos((4 * PI * windowPos) / (windowLength-1))) +
+// (0.0106411 * cos((6 * PI * windowPos) / (windowLength-1)));
+// }
+//};
+//
+//struct gaussianWinFunctor {
+// double gausDivisor;
+// gaussianWinFunctor() {
+// init(0.3);
+// }
+// gaussianWinFunctor(double kurtosis) {
+// init(kurtosis);
+// }
+// void init(double kurtosis) {
+// gausDivisor = (-2.0 * kurtosis * kurtosis);
+// }
+// inline double operator()(ulong windowLength, ulong windowPos) {
+// double phase = ((windowPos / (double) windowLength) - 0.5) * 2.0;
+// return exp((phase * phase) / gausDivisor);
+// }
+//};
+//
+//
+//template<typename F>
+//class maxiGrainWindowCache {
+//public:
+// unsigned int cacheSize;
+//
+// maxiGrainWindowCache() {
+// cacheSize = maxiSettings::sampleRate / 2.0; //allocate mem for up to 500ms grains
+// cache = (double**)malloc(cacheSize * sizeof(double*));
+// for(int i=0; i < cacheSize; i++) {
+// cache[i] = NULL;
+// }
+// }
+//
+// ~maxiGrainWindowCache() {
+// for(int i=0; i < cacheSize; i++) {
+// if(NULL != cache[i]) {
+// free(cache[i]);
+// }
+// }
+// free(cache);
+// }
+//
+// double* getWindow(const unsigned int length) {
+// if (NULL == cache[length]) {
+// cache[length] = (double*)malloc(length * sizeof(double));
+// for(int i=0; i < length; i++) {
+// cache[length][i] = F()(length, i);
+// }
+// }
+// return cache[length];
+// }
+//
+//private:
+// double** cache;
+//
+//};
+//
+//class maxiGrainBase {
+//public:
+// virtual double play() {}
+// virtual ~maxiGrainBase() {}
+// bool finished;
+//};
+//
+//template<typename F>
+//class maxiGrain : public maxiGrainBase {
+//public:
+// maxiSample *sample;
+// double pos;
+// double dur;
+// long sampleStartPos;
+// long sampleIdx;
+// long sampleDur;
+// long sampleEndPos;
+// double freq;
+// double speed;
+// double inc;
+// double frequency;
+// double* window;
+// short* buffer;
+//#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
+// double* grainSamples;
+//#endif
+// /*
+// position between 0.0 and 1.0
+// duration in seconds
+// */
+// maxiGrain(maxiSample *sample, const double position, const double duration, const double speed, maxiGrainWindowCache<F> *windowCache) :sample(sample), pos(position), dur(duration), speed(speed)
+// {
+// buffer = sample->temp;
+// sampleStartPos = sample->length * pos;
+// sampleDur = dur * (double)sample->mySampleRate;
+// sampleDurMinusOne = sampleDur - 1;
+// sampleIdx = 0;
+// finished = 0;
+// freq = 1.0 / dur;
+// sampleEndPos = min(sample->length, sampleStartPos + sampleDur);
+// frequency = freq * speed;
+// if (frequency > 0) {
+// pos = sampleStartPos;
+// }else{
+// pos = sampleEndPos;
+// }
+// if (frequency != 0) {
+// inc = sampleDur/(maxiSettings::sampleRate/frequency);
+// }else
+// inc = 0;
+// window = windowCache->getWindow(sampleDur);
+//
+//#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
+// //premake the grain using fast vector functions, and quadratic interpolation
+// double *sourceData = (double*)malloc(sampleDur * sizeof(double));
+// short* buffer = (short *)sample->temp;
+// //convert sample to double data
+// vDSP_vflt16D(buffer + sampleStartPos, 1, sourceData, 1, min(sampleDur, sample->length - sampleStartPos));
+// //todo: wraping code
+//
+// grainSamples = (double*)malloc(sampleDur * sizeof(double));
+// //make list of interpolation indexes
+// double* interpIndexes = (double*)malloc(sampleDur * sizeof(double));
+// double interpPos = sampleStartPos;
+// for(int i=0; i < sampleDur; i++) {
+// interpIndexes[i] = interpPos - sampleStartPos;
+// interpPos += fabs(inc);
+// }
+// vDSP_vqintD(sourceData, interpIndexes, 1, grainSamples, 1, sampleDur, sampleDur);
+// if (frequency < 0) {
+// vDSP_vrvrsD(grainSamples,1, sampleDur);
+// }
+// static double divFactor = 32767.0;
+// vDSP_vsdivD(grainSamples, 1, &divFactor, grainSamples, 1, sampleDur);
+// vDSP_vmulD(grainSamples, 1, window, 1, grainSamples, 1, sampleDur);
+// delete sourceData, interpIndexes;
+//#endif
+// }
+//
+// ~maxiGrain() {
+//#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
+// delete[] grainSamples;
+//#endif
+// }
+//
+// inline double play() {
+// double output = 0.0;
+// if (!finished) {
+//#if defined(__APPLE_CC__) && defined(MAXIGRAINFAST)
+// output = grainSamples[sampleIdx];
+//#else
+// envValue = window[sampleIdx];
+// double remainder;
+// pos += inc;
+// if (pos >= sample->length)
+// pos -= sample->length;
+// else if (pos < 0)
+// pos += sample->length;
+//
+// long posl = floor(pos);
+// remainder = pos - posl;
+// long a = posl;
+// long b = posl+1;
+// if (b >= sample->length) {
+// b = 0;
+// }
+// output = (double) ((1-remainder) * buffer[a] +
+// remainder * buffer[b])/32767.0;//linear interpolation
+// output *= envValue;
+//#endif
+// }
+// sampleIdx++;
+// if (sampleIdx == sampleDur) finished = true;
+// return output;
+// }
+//
+//protected:
+// maxiGrain();
+// double envValue;
+// ulong sampleDurMinusOne;
+//};
+//
+//
+//typedef list<maxiGrainBase*> grainList;
+//
+//class maxiGrainPlayer {
+//public:
+// grainList grains;
+// maxiSample *sample;
+//
+// maxiGrainPlayer(maxiSample *sample) : sample(sample) {
+// }
+//
+// void addGrain(maxiGrainBase *g) {
+// grains.push_back(g);
+// }
+//
+// inline double play() {
+// double total = 0.0;
+// grainList::iterator it = grains.begin();
+// while(it != grains.end()) {
+// total += (*it)->play();
+// if ((*it)->finished) {
+// delete(*it);
+// it = grains.erase(it);
+// }else{
+// it++;
+// }
+// }
+// return total;
+// }
+//};
+//
+//template<typename F>
+//class maxiTimestretch {
+//protected:
+// double position;
+//public:
+// maxiSample *sample;
+// maxiGrainPlayer *grainPlayer;
+// maxiGrainWindowCache<F> windowCache;
+// double randomOffset;
+// double looper;
+//
+//
+//
+// maxiTimestretch(maxiSample *sample) : sample(sample) {
+// position=0;
+// looper = 0;
+// grainPlayer = new maxiGrainPlayer(sample);
+// randomOffset=0;
+// }
+//
+// ~maxiTimestretch() {
+// delete grainPlayer;
+// }
+//
+// double getNormalisedPosition() {
+// return position / (double) sample->length;
+// }
+//
+// double getPosition() {
+// return position;
+// }
+//
+// void setPosition(double pos) {
+// position = pos * sample->length;
+// position = maxiMap::clamp<double>(position, 0, sample->length-1);
+// }
+//
+//
+// //play at a speed
+// inline double play(double speed, double grainLength, int overlaps, double posMod=0.0) {
+// position = position + speed;
+// looper++;
+// if (position > sample->length) position-= sample->length;
+// if (position < 0) position += sample->length;
+// double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
+// if (looper > cycleLength + randomOffset) {
+// looper -= (cycleLength + randomOffset);
+// speed = (speed > 0 ? 1 : -1);
+// maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache);
+// grainPlayer->addGrain(g);
+// randomOffset = rand() % 10;
+// }
+// return grainPlayer->play();
+// }
+//
+//
+// //provide your own position iteration
+// inline double play2(double pos, double grainLength, int overlaps) {
+// looper++;
+// pos *= sample->length;
+// if (0 == floor(fmod(looper, grainLength * maxiSettings::sampleRate / overlaps))) {
+// maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(pos / sample->length)),0.0), grainLength, 1, &windowCache);
+// grainPlayer->addGrain(g);
+// }
+// return grainPlayer->play();
+// }
+//};
+//
+////in maxiTimeStretch, the speed is either 1 or -1, and the actual speed value only affects the grain position
+////in maxiPitchShift, speed is uncoupled from position and allowed to set it's value incrementally, resulting in pitchshift.
+////with both high speed values and negative speed values there are some terrific artefacts!
+//
+//template<typename F>
+//class maxiPitchShift {
+//public:
+// double position;
+// long cycles;
+// maxiSample *sample;
+// maxiGrainPlayer *grainPlayer;
+// maxiGrainWindowCache<F> windowCache;
+// double randomOffset;
+//
+// maxiPitchShift(maxiSample *sample) : sample(sample) {
+// position=0;
+// cycles=0;
+// grainPlayer = new maxiGrainPlayer(sample);
+// randomOffset=0;
+// }
+//
+// ~maxiPitchShift() {
+// delete grainPlayer;
+// }
+//
+// double play(double speed, double grainLength, int overlaps, double posMod=0.0) {
+// position = position + 1;
+// cycles++;
+// if (position > sample->length) position=0;
+// if (position < 0) position = sample->length;
+// double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
+// double cycleMod = fmod(cycles, cycleLength + randomOffset);
+// if (0 == floor(cycleMod)) {
+// // cout << cycleMod << endl;
+// //speed = (speed > 0 ? 1 : -1);
+// speed = speed - ((cycleMod / cycleLength) * 0.1);
+// maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache);
+// grainPlayer->addGrain(g);
+// // cout << grainPlayer->grains.size() << endl;
+// // randomOffset = rand() % 10;
+// // randomOffset = rand() % 10;
+// }
+// return grainPlayer->play();
+// }
+//
+//};
+//
+////and here's maxiPitchStretch. Args to the play function are basically speed for 'pitch' and rate for playback rate.
+////the rest is the same.
+//
+//template<typename F>
+//class maxiPitchStretch {
+//public:
+// double position;
+// maxiSample *sample;
+// maxiGrainPlayer *grainPlayer;
+// maxiGrainWindowCache<F> windowCache;
+// double randomOffset;
+// long loopStart, loopEnd, loopLength;
+// double looper;
+//
+// maxiPitchStretch(maxiSample *sample) : sample(sample) {
+// grainPlayer = new maxiGrainPlayer(sample);
+// randomOffset=0;
+// loopStart = 0.0;
+// loopEnd = sample->length;
+// loopLength =sample->length;
+// position=0;
+// looper = 0;
+// }
+//
+// double getNormalisedPosition() {
+// return position / (double) sample->length;
+// }
+//
+// double getPosition() {
+// return position;
+// }
+//
+// void setPosition(double pos) {
+// position = pos * sample->length;
+// position = maxiMap::clamp<double>(position, 0, sample->length-1);
+// }
+//
+// void setLoopStart(double val) {
+// loopStart = val * sample->length;
+// loopLength = loopEnd - loopStart;
+// }
+//
+// void setLoopEnd(double val) {
+// loopEnd = val * sample->length;
+// loopLength = loopEnd - loopStart;
+// }
+//
+// ~maxiPitchStretch() {
+// delete grainPlayer;
+// }
+//
+// inline double play(double speed, double rate, double grainLength, int overlaps, double posMod=0.0) {
+// position = position + (1 * rate);
+// looper++;
+// if (position >= loopEnd) position-= loopLength;
+// if (position < loopStart) position += loopLength;
+// double cycleLength = grainLength * maxiSettings::sampleRate / overlaps;
+// if (looper > cycleLength + randomOffset) {
+// looper -= (cycleLength + randomOffset);
+// maxiGrain<F> *g = new maxiGrain<F>(sample, max(min(1.0,(position / sample->length) + posMod),0.0), grainLength, speed, &windowCache);
+// grainPlayer->addGrain(g);
+// randomOffset = rand() % 10;
+// }
+// return grainPlayer->play();
+// }
+//
+//};
+//
+//#endif \ No newline at end of file