From 7f4c6ff482637ea9be4fe69448099fc3cebe73fd Mon Sep 17 00:00:00 2001 From: Chris Kiefer Date: Fri, 5 Jul 2013 11:03:20 +0100 Subject: sample looping methods --- ofxMaxim/ofxMaxim/libs/maximilian.cpp | 106 ++++++++++++++++++++++++++++++---- ofxMaxim/ofxMaxim/libs/maximilian.h | 47 +++++++++++---- 2 files changed, 130 insertions(+), 23 deletions(-) diff --git a/ofxMaxim/ofxMaxim/libs/maximilian.cpp b/ofxMaxim/ofxMaxim/libs/maximilian.cpp index 68de474..e26e153 100644 --- a/ofxMaxim/ofxMaxim/libs/maximilian.cpp +++ b/ofxMaxim/ofxMaxim/libs/maximilian.cpp @@ -566,8 +566,8 @@ bool maxiSample::read() { bool result; ifstream inFile( myPath.c_str(), ios::in | ios::binary); - result = inFile; - if (inFile) { + result = inFile.is_open(); + if (result) { bool datafound = false; inFile.seekg(4, ios::beg); inFile.read( (char*) &myChunkSize, 4 ); // read the ChunkSize @@ -645,7 +645,16 @@ bool maxiSample::read() double maxiSample::play() { position++; - if ((long) position == length) position=0; + if ((long) position >= length) position=0; + output = (double) temp[(long)position]/32767.0; + return output; +} + +//start end and points are between 0 and 1 +double maxiSample::playLoop(double start, double end) { + position++; + if (position < length * start) position = length * start; + if ((long) position >= length * end) position = length * start; output = (double) temp[(long)position]/32767.0; return output; } @@ -661,6 +670,20 @@ double maxiSample::playOnce() { } +void maxiSample::setPosition(double newPos) { + position = maxiMap::clamp(newPos, 0.0, 1.0) * length; +} + +double maxiSample::playUntil(double end) { + position++; + if ((long) position maxValue) { + maxValue = abs(temp[i]); + } + } + float scale = 32767.0 * maxLevel / (float) maxValue; + for(int i=0; i < length; i++) { + temp[i] = round(scale * (float) temp[i]); + } +} + +void maxiSample::autoTrim(float alpha, float threshold, bool trimStart, bool trimEnd) { + + int startMarker=0; + if(trimStart) { + maxiLagExp startLag(alpha, 0); + while(startMarker < length) { + startLag.addSample(abs(temp[startMarker])); + if (startLag.value() > threshold) { + break; + } + startMarker++; + } + } + + int endMarker = length-1; + if(trimEnd) { + maxiLagExp endLag(alpha, 0); + while(endMarker > 0) { + endLag.addSample(abs(temp[endMarker])); + if (endLag.value() > threshold) { + break; + } + endMarker--; + } + } + + cout << "Autotrim: start: " << startMarker << ", end: " << endMarker << endl; + + int newLength = endMarker - startMarker; + if (newLength > 0) { + short *newData = (short*) malloc(sizeof(short) * newLength); + for(int i=0; i < newLength; i++) { + newData[i] = temp[i+startMarker]; + } + free(temp); + temp = newData; + myDataSize = newLength * 2; + length=newLength; + position=0; + recordPosition=0; + //envelope the start + int fadeSize=min((long)100, length); + for(int i=0; i < fadeSize; i++) { + float factor = i / (float) fadeSize; + temp[i] = round(temp[i] * factor); + temp[length - 1 - i] = round(temp[length - 1 - i] * factor); + } + } +} + + + + + + @@ -1248,12 +1339,3 @@ double convert::mtof(int midinote) { return mtofarray[midinote]; } - -void maxiEnvelopeFollower::setAttack(double attackMS) { - attack = pow( 0.01, 1.0 / (attackMS * maxiSettings::sampleRate * 0.001 ) ); -} - -void maxiEnvelopeFollower::setRelease(double releaseMS) { - release = pow( 0.01, 1.0 / (releaseMS * maxiSettings::sampleRate * 0.001 ) ); -} - diff --git a/ofxMaxim/ofxMaxim/libs/maximilian.h b/ofxMaxim/ofxMaxim/libs/maximilian.h index ce3ddd1..f46a2e3 100755 --- a/ofxMaxim/ofxMaxim/libs/maximilian.h +++ b/ofxMaxim/ofxMaxim/libs/maximilian.h @@ -30,6 +30,12 @@ * */ +/* + Feature request: + maxiNANINFAlarm + maxiLimiter + */ + #ifndef MAXIMILIAN_H #define MAXIMILIAN_H @@ -262,8 +268,9 @@ public: //read an ogg file into this class using stb_vorbis bool readOgg(); - void loopRecord(double newSample, const bool recordEnabled, const double recordMix) { + void loopRecord(double newSample, const bool recordEnabled, const double recordMix, double start = 0.0, double end = 1.0) { loopRecordLag.addSample(recordEnabled); + if (recordPosition < start * length) recordPosition = start * length; if(recordEnabled) { double currentSample = temp[(unsigned long)recordPosition] / 32767.0; newSample = (recordMix * currentSample) + ((1.0 - recordMix) * newSample); @@ -271,8 +278,8 @@ public: temp[(unsigned long)recordPosition] = newSample * 32767; } ++recordPosition; - if (recordPosition == length) - recordPosition=0; + if (recordPosition >= end * length) + recordPosition= start * length; } void clear(); @@ -280,10 +287,16 @@ public: void reset(); double play(); + + double playLoop(double start, double end); // start and end are between 0.0 and 1.0 double playOnce(); double playOnce(double speed); + + void setPosition(double newPos); // between 0.0 and 1.0 + + double playUntil(double end); double play(double speed); @@ -335,12 +348,16 @@ public: 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); 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 }; class maxiMap { public: static double inline linlin(double val, double inMin, double inMax, double outMin, double outMax) { + val = max(min(val, inMax), inMin); return ((val - inMin) / (inMax - inMin) * (outMax - outMin)) + outMin; } @@ -490,16 +507,21 @@ inline double maxiChorus::chorus(const double input, const unsigned int delay, c return (output1 + output2 + input) / 3.0; } -class maxiEnvelopeFollower { +template +class maxiEnvelopeFollowerType { public: - maxiEnvelopeFollower() { + maxiEnvelopeFollowerType() { setAttack(100); setRelease(100); env = 0; } - void setAttack(double attackMS); - void setRelease(double releaseMS); - inline double play(double input) { + void setAttack(T attackMS) { + attack = pow( 0.01, 1.0 / (attackMS * maxiSettings::sampleRate * 0.001 ) ); + } + void setRelease(T releaseMS) { + release = pow( 0.01, 1.0 / (releaseMS * maxiSettings::sampleRate * 0.001 ) ); + } + inline T play(T input) { input = fabs(input); if (input>env) env = attack * (env - input) + input; @@ -508,12 +530,15 @@ public: return env; } void reset() {env=0;} - inline double getEnv(){return env;} - inline void setEnv(double val){env = val;} + inline T getEnv(){return env;} + inline void setEnv(T val){env = val;} private: - double attack, release, env; + T attack, release, env; }; +typedef maxiEnvelopeFollowerType maxiEnvelopeFollower; +typedef maxiEnvelopeFollowerType maxiEnvelopeFollowerF; + //from https://ccrma.stanford.edu/~jos/filters/DC_Blocker_Software_Implementations.html class maxiDCBlocker { public: -- cgit v1.3