/********************************************/ /* Audio Data Input Base Class by Gary P. Scavone, 1999-2000 This class can handle multi-channel input. Multi-channel input is interleaved in the vector "data". Actual data input occurs in the subclasses of WvIn. Currently, STK is only supporting a few data types (16-bit integer .snd, .wav, .raw, and .aif files and 64-bit double MAT-files). In order to support more formats AND to make the writing of subclasses easier, a format ENUM could be defined and a generalized getData() function written within this WvIn class. Then, most subclasses of WvIn would only have to setup the appropriate parameters and all other processing would happen here. */ /********************************************/ #include "WvIn.h" #include WvIn :: WvIn() { fd = 0; chunking = 0; readPointer = 0; fileSize = 0; } WvIn :: ~WvIn() { if (fd) { fclose(fd); fd = 0; } if (data) { delete [ ] data; data = 0; } if (lastOutput) { delete [ ] lastOutput; lastOutput = 0; } } void WvIn :: reset() { finished = 0; time = (MY_FLOAT) 0.0; for (int i=0;inormalize((MY_FLOAT) 1.0); } // Normalize all channels equally by the greatest magnitude in all of data void WvIn :: normalize(MY_FLOAT newPeak) { /* Do nothing for streamed input ... cannot be normalized */ if (chunking) return; long i; MY_FLOAT max = (MY_FLOAT) 0.0; for (i=0;i max) max = (MY_FLOAT) fabs((double) data[i]); } if (max > 0.0) { max = (MY_FLOAT) 1.0 / max; max *= newPeak; for (i=0;i<=channels*bufferSize;i++) data[i] *= max; } } void WvIn :: setRate(MY_FLOAT aRate) { rate = aRate; // If negative rate and at beginning of sound, move pointer to end of sound. if ( (rate < 0) && (time == 0.0) ) time += rate + fileSize; if (fmod(rate, 1.0) != 0.0) interpolate = 1; else interpolate = 0; } void WvIn :: setFreq(MY_FLOAT aFreq) { // This is a looping frequency. if (looping) { rate = fileSize * (MY_FLOAT) ONE_OVER_SRATE * aFreq; if (fmod(rate, 1.0) != 0.0) interpolate = 1; else interpolate = 0; } } void WvIn :: addTime(MY_FLOAT aTime) { // Add an absolute time in samples time += aTime; while (time < 0.0) time += fileSize; while (time >= fileSize) time -= fileSize; } void WvIn :: addPhase(MY_FLOAT anAngle) { // Add a time in cycles (one cycle = fileSize) ... for looping. if (looping) { time += fileSize * anAngle; while (time < 0.0) time += fileSize; while (time >= fileSize) time -= fileSize; } } void WvIn :: addPhaseOffset(MY_FLOAT anAngle) { // Add a phase offset in cycles, where 1.0 = fileSize (looping). if (looping) phaseOffset = fileSize * anAngle; } void WvIn :: setInterpolate(int anInterpStatus) { interpolate = anInterpStatus; } void WvIn :: setLooping(int aLoopStatus) { time = (MY_FLOAT) 0.0; looping = aLoopStatus; if (looping && !chunking) { for (int i=0;iinformTick(); if (channels > 1) { MY_FLOAT tempout = 0.0; for (int i=0;iinformTick(); return lastOutput; } int WvIn :: informTick() { static MY_FLOAT temp, alpha; static long index; if (finished) return finished; if (looping) { // Check limits of time address ... if necessary, recalculate modulo fileSize. while (time < 0.0) time += fileSize; while (time >= fileSize) time -= fileSize; if (phaseOffset) { temp = time + phaseOffset; while (temp < 0.0) temp += fileSize; while (temp >= fileSize) temp -= fileSize; } else { temp = time; } } else { // oneshot: if out of bounds, we're done if ( (time < 0.0) || (time >= fileSize) ) { finished = 1; return finished; } temp = time; } if (chunking) { // check the time address vs. our current buffer limits if ( (temp < readPointer) || (temp >= readPointer+bufferSize) ) this->getData((long) temp); // adjust index for current buffer temp -= readPointer; } // integer part of time address index = (long) temp; if (interpolate) { // fractional part of time address alpha = temp - (MY_FLOAT) index; index *= channels; for (int i=0;i 1) { MY_FLOAT tempout = 0.0; for (int i=0;i