float AlgorhythmicAudioIO::PlayDoubleArray(double * array, int size)//, int swapaindex, int swapbindex) { mzsortdata.approxEvals+=size; if(array!=mzsortdata.doubleArray || size != mzsortdata.doubleArraySize) { LockSortData(); mzsortdata.doubleArray=array; mzsortdata.doubleArraySize=size; unLockSortData(); } if(mzsortdata.durationsSize<size) { LockSortData(); if(mzsortdata.durationsSize) delete [] mzsortdata.durations; mzsortdata.durationsSize=size; //durations needs one greater for the noise seperator duration. mzsortdata.durations = new double[size+1]; unLockSortData(); } mzsortdata.sampleCursor=0; mzsortdata.phase=0; mzsortdata.usedouble=true; mzsortdata.lastNoteIndex=0; float secDuration = 0.0; int min = INT_MAX; int max = INT_MIN; for(int i=0;i<size;i++) { min = mymin(array[i],min); max = mymax(array[i],max); } //make up some durations based on the number. for(int i=0;i< size;i++) { //calculate the delay per note, // mzsortdata.durations[i] = (((int)array[i])%20)/20.0 + 0.05 ; //short notes // { // int chop; // chop = (int)array[i]; // mzsortdata.durations[i] = 0.05; // while(fabs(chop) > 0) // { // mzsortdata.durations[i] *= 1.75; // chop = chop/3; // } // } { float cursor; cursor = (array[i] - min)/(max-min); cursor = 1.0-cursor; cursor = exp2cursor(cursor,7); mzsortdata.durations[i] =m_speed;//(0.05 + cursor * (0.45) )* m_speed; } //we sum up the durations secDuration += mzsortdata.durations[i]; } //duration of break mzsortdata.durations[size] = 0.0;//(m_seperatorOn?1.0:0.0) *m_speed; secDuration += mzsortdata.durations[size]; mzsortdata.duration=secDuration; return secDuration; }
//at start time it should retun 1.0 at end time mEndCoef //the second parameter is for recursive calls since this uses incompatable static variables double Interpolation::ValueAtTime(double time) { double cursor =mymin(mymax(0.0,time-mStartTime)/mDuration,1.0); double phase; double ret; __thread static InterpolationMetaData *meta; if (!meta) { meta = new InterpolationMetaData; /*TODO:leak*/ } //get the list of our local parameters and copy them. std::vector<double> &instantParams = meta->instantParams; bool &instantParamsCleared = meta->instantParamsCleared; if(instantParamsCleared) { for(int i =0;i<mInterpParams.GetNumParameters();i++) instantParams.push_back(mInterpParams.GetValue((Parameter)i)); instantParamsCleared=false; } else { for(int i =0;i<mInterpParams.GetNumParameters();i++) instantParams[i]=mInterpParams.GetValue((Parameter)i); } //check to see if we have metaInterps attached to us and apply them. for(int i=0;i<mAttachedMetaInterps.size();i++) { //caution - MetaInterpolation::Apply uses ValueAtTime mAttachedMetaInterps[i]->Apply(time,&instantParams); } // assert(mStartTime <=time); // assert(mStartTime+mDuration>=time); // switch(mType) { case eLinear: ret= cursor*(mEndCoef-1.0) + 1.0; break; case eExp2: ret= exp2cursor(cursor)*mEndCoef+(1.0-exp2cursor(cursor)); break; case eStep: ret= (mEndCoef-1.0)*((float)(floor((cursor+0.001) * floor(instantParams[eInterpTypeVariable]))))/floor(instantParams[eInterpTypeVariable]) + 1.0; break; case eExp2Step: ret= (mEndCoef-1.0)*exp2cursor(((float)(floor((cursor+0.001) * floor(instantParams[eInterpTypeVariable]))))/floor(instantParams[eInterpTypeVariable]))+1.0; break; case eSquare: //need to implement some fading to bandlimit the square. // while(phase>2*3.141592) // phase-=2*3.141592; // if(phase>(2*3.141592*interpTypeVariable) <kSquareTransitSamples/44100.0) // return (mEndCoef-1.0) + 1.0; phase=modf( (2 * cursor * (floor(instantParams[eInterpTypeVariable])/**mDuration*/+0.5 ) - 0.5)/2.0,&phase);//we just clober the intpart with the return value phase = 3.141592*2* phase; ret= phase<3.141592?1.0:mEndCoef; break; case ePeriodic: //sinusoid that starts at -1 (-pi/2) and continues for (n+0.5)periods to end up at +1 (pi/2) //we also shrink it down soo that -pi/2 comes to 1.0 and pi/2 comes to mEndCoef. phase=modf( (2 * cursor * (floor(instantParams[eInterpTypeVariable])/**mDuration*/+0.5 ) - 0.5)/2.0,&phase);//we just clober the intpart with the return value phase = 3.141592*2* phase; ret= (sin(phase)*(mEndCoef-1.0)/2.0)+(mEndCoef-1.0)/2.0 + 1.0; break; default: assert(1==0);//shouldn't reach here. break; } return ret; }
/* This routine will be called by the PortAudio engine when audio is needed. ** It may called at interrupt level on some machines so don't do anything ** that could mess up the system like calling malloc() or free(). */ static int SortingPortAudioCallback( const void *inputBuffer, void *outputBuffer, unsigned long framesPerBuffer, const PaStreamCallbackTimeInfo* timeInfo, PaStreamCallbackFlags statusFlags, void *userData ) { int noisefactor; noisefactor = 1; float vol = AlgorhythmicAudioIO::Instance()->GetVolume(); float freqMin = AlgorhythmicAudioIO::Instance()->GetFreqMin(); float freqRange = AlgorhythmicAudioIO::Instance()->GetFreqMax() - freqMin; bool notesOn = AlgorhythmicAudioIO::Instance()->IsNotesOn(); bool sepOn = AlgorhythmicAudioIO::Instance()->IsSeperatorOn(); bool click = false; for( int z = 0; z < NUM_CHANNELS; z++ ) memset(((float*)outputBuffer)+framesPerBuffer*z, 0, framesPerBuffer*sizeof(float)); //sonify stuff struct ssortdata* dataa = AlgorhythmicAudioIO::Instance()->GetSortData(); int index; if(dataa->usedouble) { AlgorhythmicAudioIO::Instance()->LockSortData(); //if this is a fresh array if(!dataa->seperatorPlayed) { click = true; nb_samples_left = nb_samples_total = dataa->duration * SAMPLE_RATE/8; dataa->seperatorPlayed=true; } //double array. //duration is for the entire array. //get the index of the number we are interested in by looking at how much we've played back so far. if(dataa->durations && dataa->lastNoteIndex< dataa->durationsSize && dataa->sampleCursor > dataa->durations[dataa->lastNoteIndex] * SAMPLE_RATE) { dataa->sampleCursor=0; dataa->lastNoteIndex++; } index = dataa->lastNoteIndex; ComputeCurrentIndex(index); if(dataa->doubleArray && index <= dataa->doubleArraySize && dataa->durations && dataa->durations[dataa->lastNoteIndex]* SAMPLE_RATE> dataa->sampleCursor) { float pan = 0.5f; float freq = 0.0f; if(index < dataa->doubleArraySize) { freq = (dataa->doubleArray[index] + 100) / 200.0; //hack - values range from -100 to 100 freq = freqRange*exp2cursor(freq, (logf(freqRange+freqMin)/logf(2) - logf(freqMin)/logf(2)))+freqMin; pan = ((float)index)/dataa->doubleArraySize; } if(sepOn && nb_samples_left) { nb_freq = 10000/(dataa->seperatorDepth + 1); NoiseBandFillFrame((float*) outputBuffer, framesPerBuffer, vol); for(int i=0;i<framesPerBuffer;i++) { ((float*)outputBuffer)[i*2] *= (float)nb_samples_left/nb_samples_total; ((float*)outputBuffer)[i*2+1] *= (float)nb_samples_left/nb_samples_total; if(nb_samples_left>0) nb_samples_left--; } } for(unsigned int i = 0; i < framesPerBuffer*NUM_CHANNELS; i+=2) { float sinval; sinval = sin(dataa->phase); if(notesOn)//old sep || (index == dataa->doubleArraySize && sepOn )) { ((float*)outputBuffer)[i] += sinval * (1.0-pan) * vol * 0.5; ((float*)outputBuffer)[i+1] += sinval * pan * vol * 0.5; } if(1 || click) { float bassmult = 16*dataa->seperatorDepth+1; // ((float*)outputBuffer)[i] += vol*2*((float)mymax(0,(framesPerBuffer*NUM_CHANNELS-(i*bassmult)))/framesPerBuffer*NUM_CHANNELS); // ((float*)outputBuffer)[i+1] += vol*2*((float)mymax(0,(framesPerBuffer*NUM_CHANNELS-(i*bassmult)))/framesPerBuffer*NUM_CHANNELS); } //inc phase if we are under the size, otherwise use noise. if(index < dataa->doubleArraySize) { dataa->phase+=2.0*3.14592 *freq / SAMPLE_RATE; while(dataa->phase>2.0*3.14592) dataa->phase-=2.0*3.14592; } else { //noise if(dataa->lastNoteIndex<= dataa->doubleArraySize && dataa->durations[dataa->lastNoteIndex] !=0) { dataa->phase = randfloat(2.0*3.14592); pan = 0.5; } } dataa->sampleCursor++; //see if we've stepped over a boundry if(dataa->sampleCursor > dataa->durations[dataa->lastNoteIndex] * SAMPLE_RATE) { dataa->sampleCursor=0; dataa->lastNoteIndex++; index = dataa->lastNoteIndex; ComputeCurrentIndex(index); if(!(dataa->lastNoteIndex<= dataa->doubleArraySize)) break; else if (dataa->lastNoteIndex < dataa->doubleArraySize) { freq = (dataa->doubleArray[index] + 100) / 200.0; //hack - values range from -100 to 100 freq = freqRange*exp2cursor(freq, (logf(freqRange+freqMin)/logf(2) - logf(freqMin)/logf(2)))+freqMin; pan = ((float)index)/dataa->doubleArraySize; } } } } AlgorhythmicAudioIO::Instance()->unLockSortData(); } // Clip output to [-1.0,+1.0] range for(unsigned int i = 0; i < framesPerBuffer*NUM_CHANNELS; i++) { float f = ((float*)outputBuffer)[i]; if (f > 1.0f) ((float*)outputBuffer)[i] = 1.0f; else if (f < -1.0f) ((float*)outputBuffer)[i] = -1.0f; } return 0; }