#include "looper.hxx" #include "jack.hxx" #include "audiobuffer.hxx" #include "eventhandler.hxx" #include "controllerupdater.hxx" extern Jack* jack; Looper::Looper(int t) : track(t), scene(0), state(STATE_STOPPED), fpb(120), gain(1.f), numBeats (4), playedBeats(0), stopRecordOnBar(false), endPoint (0), playPoint (0), lastWrittenSampleIndex(0) { // pre-zero the internal sample for(int i = 0; i < 10; i++) { //memset( sample[int(i)][0], 0, SAMPLE_SIZE ); } sample = &samples[0][0]; printf("Looper ID %i\n" , track ); // init faust pitch shift variables fSamplingFreq = 44100; IOTA = 0; int bufferSize = 1024; for ( int i = 0; i < bufferSize; i++) tmpBuffer.push_back(0.f); for (int i=0; i<65536; i++) fVec0[i] = 0; semitoneShift = 0.0f; windowSize = 1000; crossfadeSize = 1000; for (int i=0; i<2; i++) fRec0[i] = 0; } void Looper::midi(unsigned char* data) { if ( data[0] - 144 == track ) { switch ( data[1] ) { case 48: setState( STATE_RECORD_QUEUED ); break; case 53: setState( STATE_PLAY_QUEUED ); break; case 52: setState( STATE_STOP_QUEUED ); break; } } else if ( data[0] - 128 == track ) { switch ( data[1] ) { case 48: setState( STATE_STOP_QUEUED ); } } else if ( data[0] - 176 == track ) { switch ( data[1] ) { case 7: gain = int(data[2])/127.f; break; } } } void Looper::setState(State s) { // quantize recording to next bar event if ( state == STATE_RECORDING ) { stopRecordOnBar = true; } state = s; updateControllers(); } void Looper::updateControllers() { if (state == STATE_RECORD_QUEUED ) { numBeats = 0; jack->getControllerUpdater()->recordArm(track, true); jack->getControllerUpdater()->clipSelect(track, scene, Controller::CLIP_MODE_RECORD_QUEUED); } else if (state == STATE_RECORDING ) { jack->getControllerUpdater()->recordArm(track, true); jack->getControllerUpdater()->clipSelect(track, scene, Controller::CLIP_MODE_RECORDING); } else { jack->getControllerUpdater()->recordArm(track, false); } if (state == STATE_PLAY_QUEUED ) { jack->getControllerUpdater()->clipSelect(track, scene, Controller::CLIP_MODE_PLAY_QUEUED); } if ( state == STATE_PLAYING ) { jack->getControllerUpdater()->clipSelect(track, scene, Controller::CLIP_MODE_PLAYING); } if (state == STATE_STOP_QUEUED ) { jack->getControllerUpdater()->clipSelect(track, scene, Controller::CLIP_MODE_STOP_QUEUED); } else if ( state == STATE_STOPPED ) { jack->getControllerUpdater()->clipSelect(track, scene, Controller::CLIP_MODE_LOADED); } } void Looper::setSample(int scene, AudioBuffer* ab) { vector& buf = ab->get(); if ( buf.size() > SAMPLE_SIZE ) { EventGuiPrint e( "Looper setSample() ERROR size > incoming sample" ); writeToGuiRingbuffer( &e ); } else { numBeats = ab->getBeats(); float* s = &sample[0]; float* b = &buf[0]; for (int i = 0; i < buf.size(); i++) { *s++ = *b++; } endPoint = buf.size(); lastWrittenSampleIndex = buf.size(); //memcpy( &sample[0], &buf[0], buf.size() ); // copy sample data to pre-allocated buffer } } void Looper::process(int nframes, Buffers* buffers) { float* in = buffers->audio[Buffers::MASTER_INPUT]; float* out = buffers->audio[Buffers::TRACK_0 + track]; float playbackSpeed = endPoint / ( float(numBeats) * fpb ); semitoneShift = -( 12 * log ( playbackSpeed ) / log (2) ); if ( state == STATE_PLAYING || (state == STATE_STOP_QUEUED && !stopRecordOnBar) ) { for(int i = 0; i < nframes; i++) { if ( playPoint < endPoint ) { tmpBuffer[i] = sample[int(playPoint)] * gain; } playPoint += playbackSpeed; } // now pitch-shift the audio in the buffer pitchShift( nframes, &tmpBuffer[0], out); float prog = (float(playPoint) / (fpb*numBeats)); EventLooperProgress e(track, prog ); writeToGuiRingbuffer( &e ); } // stopRecordOnBar ensures we record right up to the bar measure else if ( state == STATE_RECORDING || stopRecordOnBar ) { for(int i = 0; i < nframes; i++) { if ( lastWrittenSampleIndex < 44100 * 60 ) { sample[lastWrittenSampleIndex++] = in[i]; } } } } void Looper::bar() { int barTmpState = state; // queue stop recording -> stop recording, now calculate beats in loop if ( stopRecordOnBar ) { stopRecordOnBar = false; } if ( playedBeats >= numBeats ) { playPoint = 0; playedBeats = 0; } if ( state == STATE_PLAY_QUEUED ) { EventGuiPrint e( "Looper Q->Playing" ); writeToGuiRingbuffer( &e ); state = STATE_PLAYING; playPoint = 0; endPoint = lastWrittenSampleIndex; int scene = 0; EventLooperState e2( track, scene, STATE_PLAYING ); writeToGuiRingbuffer( &e2 ); } if ( state == STATE_RECORD_QUEUED ) { EventGuiPrint e( "Looper Q->Recording" ); writeToGuiRingbuffer( &e ); int scene = 0; EventLooperState e2( track, scene, STATE_RECORDING ); writeToGuiRingbuffer( &e2 ); state = STATE_RECORDING; playPoint = 0; endPoint = 0; lastWrittenSampleIndex = 0; } if ( state == STATE_STOP_QUEUED ) { EventGuiPrint e( "Looper Q->Stopped" ); writeToGuiRingbuffer( &e ); int scene = 0; EventLooperState e2( track, scene, STATE_STOPPED ); writeToGuiRingbuffer( &e2 ); state = STATE_STOPPED; endPoint = lastWrittenSampleIndex; } if ( barTmpState != state ) { updateControllers(); } } void Looper::beat() { if (state == STATE_RECORDING || stopRecordOnBar ) { numBeats++; } playedBeats++; } void Looper::setLoopLength(float l) { numBeats = l * 4; // smallest loop = 4 beats if ( numBeats < 4 ) numBeats = 4; char buffer [50]; sprintf (buffer, "Looper %i loop lenght = %i", track, numBeats ); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); } void Looper::pitchShift(int count, float* input, float* output) { float fSlow0 = windowSize; float fSlow1 = ((1 + fSlow0) - powf(2,(0.08333333333333333f * semitoneShift))); float fSlow2 = (1.0f / crossfadeSize); float fSlow3 = (fSlow0 - 1); float* input0 = &input[0]; float* output0 = &output[0]; for (int i=0; i