/* * Author: Harry van Haaren 2013 * harryhaaren@gmail.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "looperclip.hxx" #include #include "config.hxx" #include "jack.hxx" #include "event.hxx" #include "eventhandler.hxx" #include "audiobuffer.hxx" #include "controllerupdater.hxx" #include "timemanager.hxx" extern Jack* jack; LooperClip::LooperClip(int t, int s) : Stately(), track(t), scene(s) { _buffer = new AudioBuffer(); _buffer->nonRtResize( 4410 ); init(); } void LooperClip::init() { _loaded = false; _playing = false; _recording = false; _queuePlay = false; _queueStop = false; _queueRecord= false; if ( _buffer ) { _buffer->init(); } _newBufferInTransit = false; _playhead = 0; _recordhead = 0; } void LooperClip::save() { // ensure the buffer exists, and is saveable (not recording) if ( _loaded && !_recording && !_queueRecord ) { char buffer [50]; sprintf (buffer, "LC::save() track %i, scene %i", track,scene); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); int frames = _buffer->getAudioFrames(); EventRequestSaveBuffer e2( track, scene, frames ); writeToGuiRingbuffer( &e2 ); } else { // notify of "success" of save if there *is* no state to save Stately::success(); } } void LooperClip::reset() { // TODO make the LooperClip reset to initial state if ( _loaded ) { char buffer [50]; sprintf (buffer, "LC::reset() track %i, scene %i", track,scene); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); // set "progress" to zero as there's no clip anymore jack->getControllerUpdater()->setTrackSceneProgress(track, scene, 0 ); } else { //SaveAble::done(); } init(); } /// loads a sample: eg from disk, unloading current sample if necessary void LooperClip::load( AudioBuffer* ab ) { _loaded = true; _recording = false; if ( _buffer ) { EventDeallocateBuffer e( _buffer ); writeToGuiRingbuffer( &e ); } _buffer = ab; _playhead = 0; // set the endpoint to the buffer's size _recordhead = _buffer->getData().size(); #ifdef DEBUG_BUFFER char buffer [50]; sprintf (buffer, "LC::load() t %i, s %i, aF %i",track, scene, int(_buffer->getAudioFrames()) ); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); #endif } void LooperClip::setRequestedBuffer( AudioBuffer* ab ) { if ( _buffer ) { size_t size = _buffer->getData().size(); memcpy( &ab->getData().at(0), &_buffer->getData().at(0), sizeof(float)*size); ab->setID ( _buffer->getID() ); ab->setBeats( _buffer->getBeats() ); EventDeallocateBuffer e( _buffer ); writeToGuiRingbuffer( &e ); } _buffer = ab; _newBufferInTransit = false; } void LooperClip::recieveSaveBuffer( AudioBuffer* saveBuffer ) { if ( saveBuffer->getData().size() >= _buffer->getData().at(0) ) { // copy current contents into save buffer, size_t framesBySize = _buffer->getAudioFrames(); memcpy( &saveBuffer->getData().at(0), &_buffer->getData().at(0), sizeof(float)*framesBySize); saveBuffer->setID ( _buffer->getID() ); saveBuffer->setBeats( _buffer->getBeats() ); saveBuffer->setAudioFrames( _buffer->getAudioFrames() ); EventStateSaveBuffer e ( track, scene, saveBuffer ); writeToGuiRingbuffer( &e ); Stately::success(); } else { char buffer [50]; sprintf (buffer, "LC:: %i, %i: can't save, buf too small",track, scene ); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); Stately::error(""); } } void LooperClip::record(int count, float* L, float* R) { // write "count" samples into current buffer. if ( _buffer ) { size_t size = _buffer->getData().size(); for(int i = 0; i < count; i++) { if ( _recordhead < size ) { _buffer->getData().at( _recordhead ) = *L++; _recordhead++; } else { // break: this is *BAD*, audio data is lost but the buffer isn't here // yet to hold new audio data so there's no option. This has not been // encountered in actual usage, only during the development process. char buffer [50]; sprintf (buffer, "LooperClip t %i, s %i, Error: out of mem!",track, scene ); EventGuiPrint e( buffer ); writeToGuiRingbuffer( &e ); #ifdef BUILD_TESTS LUPPP_WARN("%s","buffer has no space"); #endif break; } } } _loaded = true; } unsigned long LooperClip::recordSpaceAvailable() { if ( _buffer ) return _buffer->getData().size() - _recordhead; return 0; } size_t LooperClip::audioBufferSize() { if ( _buffer ) { return _buffer->getData().size(); } return 0; } void LooperClip::setBeats(int beats) { if ( _buffer ) { _buffer->setBeats( beats ); } } int LooperClip::getBeats() { if ( _buffer ) return _buffer->getBeats(); return 0; } long LooperClip::getBufferLenght() { return _recordhead; } void LooperClip::bar() { bool change = false; GridLogic::State s = GridLogic::STATE_EMPTY; // first update the buffer, as time has passed if ( _recording ) { // FIXME: assumes 4 beats in a bar _buffer->setBeats( _buffer->getBeats() + 4 ); _buffer->setAudioFrames( jack->getTimeManager()->getFpb() * _buffer->getBeats() ); } if ( _playhead > 0.9 * _recordhead ) { _playhead = 0.f; } if ( _queuePlay && _loaded ) { //LUPPP_NOTE("QPLay + loaded" ); _playing = true; s = GridLogic::STATE_PLAYING; _recording = false; _queuePlay = false; change = true; _playhead = 0; } else if ( _queueStop && _loaded ) { _playing = false; s = GridLogic::STATE_STOPPED; _recording = false; _queueStop = false; change = true; // set "progress" to zero, as we're stopped! jack->getControllerUpdater()->setTrackSceneProgress(track, scene, 0 ); } else if ( _queueRecord ) { _recording = true; s = GridLogic::STATE_RECORDING; _playing = false; _queueRecord = false; change = true; if ( _buffer ) { _buffer->setBeats( 0 ); } _recordhead = 0; } else if ( _queuePlay ) { // clip was queued, but there's nothing loaded _queuePlay = false; change = true; } if ( change ) { jack->getControllerUpdater()->setSceneState(track, scene, s ); } } void LooperClip::neutralize() { _queuePlay = false; _queueRecord = false; _queueStop = false; } bool LooperClip::somethingQueued() { if ( _queuePlay || _queueStop || _queueRecord ) { return true; } return false; } void LooperClip::queuePlay(bool qP) { _queuePlay = true; _queueStop = false; _queueRecord = false; } void LooperClip::queueStop() { // comment if ( _loaded ) { _queueStop = true; _queuePlay = false; } } void LooperClip::queueRecord() { _queueRecord = true; _queuePlay = false; _queueStop = false; } GridLogic::State LooperClip::getState() { GridLogic::State s = GridLogic::STATE_EMPTY; if ( _loaded ) s = GridLogic::STATE_STOPPED; if ( _playing ) s = GridLogic::STATE_PLAYING; if ( _recording ) s = GridLogic::STATE_RECORDING; if ( _queuePlay ) s = GridLogic::STATE_PLAY_QUEUED; if ( _queueStop ) s = GridLogic::STATE_STOP_QUEUED; if ( _queueRecord ) s = GridLogic::STATE_RECORD_QUEUED; return s; } bool LooperClip::playing() { return _playing; } bool LooperClip::getQueueStop() { return _queueStop; } bool LooperClip::getQueuePlay() { return _queuePlay; } bool LooperClip::getLoaded() { return _loaded; } bool LooperClip::recording() { return _recording; } void LooperClip::newBufferInTransit(bool n) { _newBufferInTransit = n; } bool LooperClip::newBufferInTransit() { return _newBufferInTransit; } float LooperClip::getSample(float playSpeed) { if ( _buffer && _buffer->getData().size() > 0 ) { if ( _playhead >= _recordhead || _playhead >= _buffer->getData().size() || _playhead < 0 ) { _playhead = 0; EventGuiPrint e( "LooperClip resetting _playhead" ); //writeToGuiRingbuffer( &e ); } std::vector& v = _buffer->getData(); float tmp = v.at(_playhead); _playhead += playSpeed; return tmp; } return 0.f; } float LooperClip::getProgress() { if ( _buffer && _playing ) { float p = float(_playhead) / _recordhead; //printf("LooperClip progress %f\n", p ); return p; } return 0.f; } #ifdef BUILD_TESTS void LooperClip::setState( bool load, bool play, bool rec, bool qPlay, bool qStop, bool qRec ) { _loaded = load; _playing = play; _recording = rec; _queuePlay = qPlay; _queueStop = qStop; _queueRecord = qRec; } #endif