From 0cfda7d1f4abf255a2563defa55b7c6df7f4434e Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 3 Apr 2014 03:50:20 +0300 Subject: [PATCH 1/3] Initial ping-pong loop implementation --- include/SampleBuffer.h | 25 ++- .../audio_file_processor.cpp | 2 +- plugins/patman/patman.cpp | 2 +- src/core/SampleBuffer.cpp | 177 +++++++++++++++--- 4 files changed, 178 insertions(+), 28 deletions(-) diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index 181956ea9..0016f6331 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -46,6 +46,11 @@ class EXPORT SampleBuffer : public QObject, public sharedObject { Q_OBJECT public: + enum LoopMode { + LoopOff = 0, + LoopOn, + LoopPingPong + }; class EXPORT handleState { public: @@ -62,11 +67,21 @@ public: m_frameIndex = _index; } + inline bool isBackwards() const + { + return m_isBackwards; + } + + inline void setBackwards( bool _backwards ) + { + m_isBackwards = _backwards; + } private: f_cnt_t m_frameIndex; const bool m_varyingPitch; + bool m_isBackwards; SRC_STATE * m_resamplingData; friend class SampleBuffer; @@ -86,7 +101,7 @@ public: bool play( sampleFrame * _ab, handleState * _state, const fpp_t _frames, const float _freq, - const bool _looped = false ); + const LoopMode _loopmode = LoopOff ); void visualize( QPainter & _p, const QRect & _dr, const QRect & _clip, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 ); inline void visualize( QPainter & _p, const QRect & _dr, f_cnt_t _from_frame = 0, f_cnt_t _to_frame = 0 ) @@ -108,7 +123,7 @@ public: { return m_endFrame; } - + inline f_cnt_t loopStartFrame() const { return m_loopStartFrame; @@ -273,9 +288,11 @@ private: sample_rate_t m_sampleRate; sampleFrame * getSampleFragment( f_cnt_t _start, f_cnt_t _frames, - bool _looped, - sampleFrame * * _tmp ) const; + LoopMode _loopmode, + sampleFrame * * _tmp, + bool * _backwards ) const; f_cnt_t getLoopedIndex( f_cnt_t _index ) const; + f_cnt_t getPingPongIndex( f_cnt_t _index ) const; signals: diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index a70fe52a4..787cd5cf3 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -141,7 +141,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n, if( m_sampleBuffer.play( _working_buffer, (handleState *)_n->m_pluginData, frames, _n->frequency(), - m_loopModel.value() ) ) + m_loopModel.value() ? SampleBuffer::LoopPingPong : SampleBuffer::LoopOff ) ) { applyRelease( _working_buffer, _n ); instrumentTrack()->processAudioBuffer( _working_buffer, diff --git a/plugins/patman/patman.cpp b/plugins/patman/patman.cpp index f5f24335f..58cf987bc 100644 --- a/plugins/patman/patman.cpp +++ b/plugins/patman/patman.cpp @@ -149,7 +149,7 @@ void patmanInstrument::playNote( NotePlayHandle * _n, hdata->sample->frequency(); if( hdata->sample->play( _working_buffer, hdata->state, frames, - play_freq, m_loopedModel.value() ) ) + play_freq, m_loopedModel.value() ? SampleBuffer::LoopOn : SampleBuffer::LoopOff ) ) { applyRelease( _working_buffer, _n ); instrumentTrack()->processAudioBuffer( _working_buffer, diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 2b656cb7a..5855de64c 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -610,7 +610,7 @@ f_cnt_t SampleBuffer::decodeSampleDS( const char * _f, bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, const fpp_t _frames, const float _freq, - const bool _looped ) + const LoopMode _loopmode ) { QMutexLocker ml( &m_varLock ); @@ -620,7 +620,10 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, { return false; } - + + // variable for determining if we should currently be playing backwards in a ping-pong loop + bool is_backwards = _state->isBackwards(); + const double freq_factor = (double) _freq / (double) m_frequency * m_sampleRate / engine::mixer()->processingSampleRate(); @@ -643,13 +646,21 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, // this holds the number of remaining frames in current loop f_cnt_t frames_for_loop; - if( _looped ) + if( _loopmode == LoopOn ) { play_frame = getLoopedIndex( play_frame ); frames_for_loop = static_cast( ( m_loopEndFrame - play_frame ) / freq_factor ); } + else if( _loopmode == LoopPingPong ) + { + play_frame = getPingPongIndex( play_frame ); + if( is_backwards ) + frames_for_loop = static_cast( ( play_frame - m_loopStartFrame ) / freq_factor ); + else + frames_for_loop = static_cast( ( m_loopEndFrame - play_frame ) / freq_factor ); + } else { if( play_frame >= m_endFrame ) @@ -676,7 +687,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + margin; src_data.data_in = getSampleFragment( play_frame, - fragment_size, _looped, &tmp )[0]; + fragment_size, _loopmode, &tmp, &is_backwards )[0]; src_data.data_out = _ab[0]; src_data.input_frames = fragment_size; src_data.output_frames = _frames; @@ -695,10 +706,32 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, src_data.output_frames_gen, _frames ); } // Advance - play_frame += src_data.input_frames_used; - if( _looped ) + switch( _loopmode ) { - play_frame = getLoopedIndex( play_frame ); + case LoopOff: + play_frame += src_data.input_frames_used; + break; + case LoopOn: + play_frame += src_data.input_frames_used; + play_frame = getLoopedIndex( play_frame ); + break; + case LoopPingPong: + { + f_cnt_t left = src_data.input_frames_used; + if( _state->isBackwards() ) + { + play_frame -= src_data.input_frames_used; + if( play_frame < m_loopStartFrame ) + { + left -= ( m_loopStartFrame - play_frame ); + play_frame = m_loopStartFrame; + } + else left = 0; + } + play_frame += left; + play_frame = getPingPongIndex( play_frame ); + break; + } } } else @@ -708,19 +741,42 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, // Generate output memcpy( _ab, - getSampleFragment( play_frame, _frames, _looped, &tmp ), + getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards ), _frames * BYTES_PER_FRAME ); // Advance - play_frame += _frames; - if( _looped ) + switch( _loopmode ) { - play_frame = getLoopedIndex( play_frame ); + case LoopOff: + play_frame += _frames; + break; + case LoopOn: + play_frame += _frames; + play_frame = getLoopedIndex( play_frame ); + break; + case LoopPingPong: + { + f_cnt_t left = _frames; + if( _state->isBackwards() ) + { + play_frame -= _frames; + if( play_frame < m_loopStartFrame ) + { + left -= ( m_loopStartFrame - play_frame ); + play_frame = m_loopStartFrame; + } + else left = 0; + } + play_frame += left; + play_frame = getPingPongIndex( play_frame ); + break; + } } } delete[] tmp; - _state->m_frameIndex = play_frame; + _state->setBackwards( is_backwards ); + _state->setFrameIndex( play_frame ); return true; @@ -730,28 +786,33 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, - f_cnt_t _frames, bool _looped, sampleFrame * * _tmp ) const + f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, bool * _backwards ) const { - if( _looped ) + if( _loopmode == LoopOn ) { if( _start + _frames <= m_loopEndFrame ) { return m_data + _start; } } - else + else if( _loopmode == LoopOff ) { if( _start + _frames <= m_endFrame ) { return m_data + _start; } } +/* else + { + if( ! *_backwards && _start + _frames < m_loopEndFrame ) + return m_data + _start; + }*/ *_tmp = new sampleFrame[_frames]; - if( _looped ) + if( _loopmode == LoopOn ) { - f_cnt_t copied = m_loopEndFrame - _start; + f_cnt_t copied = qMin( _frames, m_loopEndFrame - _start ); memcpy( *_tmp, m_data + _start, copied * BYTES_PER_FRAME ); f_cnt_t loop_frames = m_loopEndFrame - m_loopStartFrame; while( _frames - copied > 0 ) @@ -762,6 +823,62 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, copied += todo; } } + else if( _loopmode == LoopPingPong ) + { + f_cnt_t copied = 0; + bool backwards = *_backwards; + f_cnt_t pos = _start; + + if( backwards ) + { + copied = qMin( _frames, pos - m_loopStartFrame ); + for( int i=0; i < copied; i++ ) + { + //memcpy( *_tmp + i, m_data + pos - i, BYTES_PER_FRAME ); + (*_tmp)[i][0] = m_data[ pos - i ][0]; + (*_tmp)[i][1] = m_data[ pos - i ][1]; + } + pos -= copied; + if( pos == m_loopStartFrame ) backwards = false; + } + else + { + copied = qMin( _frames, m_loopEndFrame - pos ); + memcpy( *_tmp, m_data + pos, copied * BYTES_PER_FRAME ); + pos += copied; + if( pos == m_loopEndFrame ) backwards = true; + } + + while( copied < _frames ) + { + if( pos >= m_loopEndFrame ) backwards = true; + if( pos <= m_loopStartFrame ) backwards = false; + pos = qBound( m_loopStartFrame, pos, m_loopEndFrame ); + /*qDebug( backwards ? "backwards" : "forwards" ); + qDebug( "pos %d", pos );*/ + if( backwards ) + { + f_cnt_t todo = qMin( _frames - copied, pos - m_loopStartFrame ); + for ( int i=0; i < todo; i++ ) + { + //memcpy( *_tmp + ( copied + i ), m_data + ( pos - i ), BYTES_PER_FRAME ); + (*_tmp)[ copied + i ][0] = m_data[ pos - i ][0]; + (*_tmp)[ copied + i ][1] = m_data[ pos - i ][1]; + } + pos -= todo; + copied += todo; + if( pos == m_loopStartFrame ) backwards = false; + } + else + { + f_cnt_t todo = qMin( _frames - copied, m_loopEndFrame - pos ); + memcpy( *_tmp + copied, m_data + pos, todo * BYTES_PER_FRAME ); + pos += todo; + if( pos == m_loopEndFrame ) backwards = true; + } + } + *_backwards = backwards; + } else { f_cnt_t available = m_endFrame - _start; @@ -787,6 +904,21 @@ f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index ) const } +f_cnt_t SampleBuffer::getPingPongIndex( f_cnt_t _index ) const +{ + if( _index < m_loopEndFrame ) + { + return _index; + } + const f_cnt_t looplen = m_loopEndFrame - m_loopStartFrame; + const f_cnt_t looppos = ( _index - m_loopEndFrame ) % ( looplen*2 ); + + f_cnt_t r; + if( looppos < looplen ) r= m_loopEndFrame - looppos; + else r= m_loopStartFrame + ( looppos - looplen ); + qDebug( "index %d --- pingpongindex %d", _index, r ); + return r; +} void SampleBuffer::visualize( QPainter & _p, const QRect & _dr, @@ -915,19 +1047,19 @@ QString SampleBuffer::openAndSetWaveformFile() { m_audioFile = configManager::inst()->factorySamplesDir() + "waveforms/10saw.flac"; } - + QString fileName = this->openAudioFile(); if(!fileName.isEmpty()) { this->setAudioFile( fileName ); - } - else + } + else { m_audioFile = ""; } - return fileName; + return fileName; } @@ -1328,7 +1460,8 @@ QString SampleBuffer::tryToMakeAbsolute( const QString & _file ) SampleBuffer::handleState::handleState( bool _varying_pitch ) : m_frameIndex( 0 ), - m_varyingPitch( _varying_pitch ) + m_varyingPitch( _varying_pitch ), + m_isBackwards( false ) { int error; if( ( m_resamplingData = src_new(/* From 7350f983b056b4ddbc463d0ec4986f610805b5fe Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 3 Apr 2014 21:52:23 +0300 Subject: [PATCH 2/3] Ping-pong loop implementation: done, starting on AFP changes... --- .../audio_file_processor.cpp | 74 +++++++++++++----- .../audio_file_processor.h | 7 +- plugins/audio_file_processor/loop_off_off.png | Bin 0 -> 534 bytes plugins/audio_file_processor/loop_off_on.png | Bin 0 -> 463 bytes .../{loop_off.png => loop_on_off.png} | Bin .../{loop_on.png => loop_on_on.png} | Bin .../loop_pingpong_off.png | Bin 0 -> 655 bytes .../audio_file_processor/loop_pingpong_on.png | Bin 0 -> 611 bytes src/core/SampleBuffer.cpp | 32 ++++---- 9 files changed, 76 insertions(+), 37 deletions(-) create mode 100644 plugins/audio_file_processor/loop_off_off.png create mode 100644 plugins/audio_file_processor/loop_off_on.png rename plugins/audio_file_processor/{loop_off.png => loop_on_off.png} (100%) rename plugins/audio_file_processor/{loop_on.png => loop_on_on.png} (100%) create mode 100644 plugins/audio_file_processor/loop_pingpong_off.png create mode 100644 plugins/audio_file_processor/loop_pingpong_on.png diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index 787cd5cf3..16465e508 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -76,7 +76,7 @@ audioFileProcessor::audioFileProcessor( InstrumentTrack * _instrument_track ) : m_endPointModel( 1, 0, 1, 0.0000001f, this, tr( "End of sample" ) ), m_loopPointModel( 0, 0, 1, 0.0000001f, this, tr( "Loopback point" ) ), m_reverseModel( false, this, tr( "Reverse sample" ) ), - m_loopModel( false, this, tr( "Loop enabled" ) ), + m_loopModel( 0, 0, 2, this, tr( "Loop mode" ) ), m_stutterModel( false, this, tr( "Stutter" ) ), m_nextPlayStartPoint( 0 ) { @@ -383,7 +383,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, m_reverseButton = new pixmapButton( this ); m_reverseButton->setCheckable( TRUE ); - m_reverseButton->move( 174, 124 ); + m_reverseButton->move( 200, 124 ); m_reverseButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( "reverse_on" ) ); m_reverseButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( @@ -394,17 +394,50 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, "This is useful for cool effects, e.g. a reversed " "crash." ) ); - m_loopButton = new pixmapButton( this ); - m_loopButton->setCheckable( TRUE ); - m_loopButton->move( 200, 124 ); - m_loopButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( - "loop_on" ) ); - m_loopButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( - "loop_off" ) ); - toolTip::add( m_loopButton, tr( "Enable loop" ) ); - m_loopButton->setWhatsThis( - tr( "This button enables looping. " +// loop button group + + pixmapbutton * m_loopOffButton = new pixmapButton( this ); + m_loopOffButton->setCheckable( TRUE ); + m_loopOffButton->move( 174, 144 ); + m_loopOffButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_off_on" ) ); + m_loopOffButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_off_off" ) ); + toolTip::add( m_loopOffButton, tr( "Disable loop" ) ); + m_loopOffButton->setWhatsThis( + tr( "This button disables looping. " + "The sample plays only once from start to end. " ) ); + + + pixmapbutton * m_loopOnButton = new pixmapButton( this ); + m_loopOnButton->setCheckable( TRUE ); + m_loopOnButton->move( 200, 144 ); + m_loopOnButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_on_on" ) ); + m_loopOnButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_on_off" ) ); + toolTip::add( m_loopOnButton, tr( "Enable loop" ) ); + m_loopOnButton->setWhatsThis( + tr( "This button enables forwards-looping. " "The sample loops between the end point and the loop point." ) ); + + pixmapbutton * m_loopPingPongButton = new pixmapButton( this ); + m_loopPingPongButton->setCheckable( TRUE ); + m_loopPingPongButton->move( 226, 144 ); + m_loopPingPongButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_pingpong_on" ) ); + m_loopPingPongButton->setInactiveGraphic( PLUGIN_NAME::getIconPixmap( + "loop_pingpong_off" ) ); + toolTip::add( m_loopPingPongButton, tr( "Enable loop" ) ); + m_loopPingPongButton->setWhatsThis( + tr( "This button enables ping-pong-looping. " + "The sample loops backwards and forwards between the end point " + "and the loop point." ) ); + + m_loopGroup = new automatableButtonGroup( this ); + m_loopGroup->addButton( m_loopOffButton ); + m_loopGroup->addButton( m_loopOnButton ); + m_loopGroup->addButton( m_loopPingPongButton ); m_stutterButton = new pixmapButton( this ); m_stutterButton->setCheckable( true ); @@ -604,7 +637,7 @@ void AudioFileProcessorView::modelChanged( void ) m_endKnob->setModel( &a->m_endPointModel ); m_loopKnob->setModel( &a->m_loopPointModel ); m_reverseButton->setModel( &a->m_reverseModel ); - m_loopButton->setModel( &a->m_loopModel ); + m_loopGroup->setModel( &a->m_loopModel ); m_stutterButton->setModel( &a->m_stutterModel ); sampleUpdated(); } @@ -684,7 +717,7 @@ void AudioFileProcessorWaveView::mousePressEvent( QMouseEvent * _me ) if( start_dist < loop_dist ) { dt = sample_start; md = start_dist; } if( end_dist < start_dist ) { dt = sample_end; md = end_dist; } - if( md < 3 ) + if( md < 4 ) { m_draggingType = dt; } @@ -780,7 +813,6 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe ) p.drawPixmap( s_padding, s_padding, m_graph ); - p.setPen( QColor( 0xFF, 0xFF, 0xFF ) ); //TODO: put into a qproperty const QRect graph_rect( s_padding, s_padding, width() - 2 * s_padding, height() - 2 * s_padding ); const f_cnt_t frames = m_to - m_from; m_startFrameX = graph_rect.x() + ( m_sampleBuffer.startFrame() - m_from ) * @@ -792,6 +824,14 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe ) const int played_width_px = ( m_framesPlayed - m_from ) * double( graph_rect.width() ) / frames; + // loop point line + p.setPen( QColor( 0x7F, 0xFF, 0xFF ) ); //TODO: put into a qproperty + p.drawLine( m_loopFrameX, graph_rect.y(), + m_loopFrameX, + graph_rect.height() + graph_rect.y() ); + + // start/end lines + p.setPen( QColor( 0xFF, 0xFF, 0xFF ) ); //TODO: put into a qproperty p.drawLine( m_startFrameX, graph_rect.y(), m_startFrameX, graph_rect.height() + graph_rect.y() ); @@ -799,10 +839,6 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe ) m_endFrameX, graph_rect.height() + graph_rect.y() ); - p.setPen( QColor( 0x7F, 0xFF, 0xFF ) ); //TODO: put into a qproperty - p.drawLine( m_loopFrameX, graph_rect.y(), - m_loopFrameX, - graph_rect.height() + graph_rect.y() ); if( m_endFrameX - m_startFrameX > 2 ) { diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h index 0fd0f97f3..94472f88e 100644 --- a/plugins/audio_file_processor/audio_file_processor.h +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -34,6 +34,7 @@ #include "SampleBuffer.h" #include "knob.h" #include "pixmap_button.h" +#include "automatable_button.h" @@ -91,7 +92,7 @@ private: FloatModel m_endPointModel; FloatModel m_loopPointModel; BoolModel m_reverseModel; - BoolModel m_loopModel; + IntModel m_loopModel; BoolModel m_stutterModel; f_cnt_t m_nextPlayStartPoint; @@ -137,7 +138,7 @@ private: pixmapButton * m_openAudioFileButton; pixmapButton * m_reverseButton; - pixmapButton * m_loopButton; + automatableButtonGroup * m_loopGroup; pixmapButton * m_stutterButton; } ; @@ -270,7 +271,7 @@ private: static bool isCloseTo( int _a, int _b ) { - return qAbs( _a - _b ) < 3; + return qAbs( _a - _b ) < 4; } } ; diff --git a/plugins/audio_file_processor/loop_off_off.png b/plugins/audio_file_processor/loop_off_off.png new file mode 100644 index 0000000000000000000000000000000000000000..a66e94d99d6d3c2b0149c95a77a142a28af50eae GIT binary patch literal 534 zcmV+x0_pvUP)QE4dKcmr@Mw@_Ol|m&N6vV>b=kQ4_e1W*2O$v#Hs2oy=Q8+Og;w=_k zBvE#`PIVZDZ)X0PIl1w8eB*$^ zpb&!TbV?k@so*3@0B~IwRaNQrdhda*>*6@huUcCy78Hv`EX&FU3L%)!=Re{q3Wi}| znkMyn9f0k2i{m(t>OIfP21+TJ&1O$p_51x)aHG*+y$;gR*L9gpCQmS3*V99(R;y^5#`$~(;Opy)&1OTrUPse3eBa0SeU8T?x7+P8 zxNf(by@$H4W18lpvLs0mLLh{A*}7pEG@H%Wi`{OwiQ|~%a{2yN3k3|rz_#u8r>E;W z!{LxhrGn>qNGXY;2t`rI=kutlN~Kc4w(YlDkh*2dval=*DJ5YTW(xo3-{xNNUqE;J Y2cmhWs*FDGW&i*H07*qoM6N<$f*~9BSpWb4 literal 0 HcmV?d00001 diff --git a/plugins/audio_file_processor/loop_off_on.png b/plugins/audio_file_processor/loop_off_on.png new file mode 100644 index 0000000000000000000000000000000000000000..4cf0edf2e81ffa0af885ced06fb0fabd3a749462 GIT binary patch literal 463 zcmV;=0WkiFP)q| zeg*upD&!`PXqwa7v<2G^*_Mt^-71sfwtQ%1wlYU2oge&=Xo?9k4Z|| zO~i||)|gJGAfnzn9*<~K1E`dO<2WB-&r(Wt1GUx&g20-G!y%F+L0OhyW-v3#vczOE zv7RW3+JVfBIF7B+^SsvG0bsx1Ti<%UZU@$NZB2v009tEwNo(C`o0;E%RaIF-7>4*H z-}kNmcDps!{+vT&3_TtXJ6P*^&`#X%cPfga6;>1lrD@uLy#no}EEWsf#%MG` zmSs4dPPkky$nzYV%?7UPHd1gtpSxotrTlgNhzLoN^aq=nk>~lxVEew0-EP;Jgtw=s zltL6mn9t|7wb^Wj)oRrXdP;QthsGE(#*dKLWD!qs25*+{l002ovPDHLk FV1jWj#wP#( literal 0 HcmV?d00001 diff --git a/plugins/audio_file_processor/loop_off.png b/plugins/audio_file_processor/loop_on_off.png similarity index 100% rename from plugins/audio_file_processor/loop_off.png rename to plugins/audio_file_processor/loop_on_off.png diff --git a/plugins/audio_file_processor/loop_on.png b/plugins/audio_file_processor/loop_on_on.png similarity index 100% rename from plugins/audio_file_processor/loop_on.png rename to plugins/audio_file_processor/loop_on_on.png diff --git a/plugins/audio_file_processor/loop_pingpong_off.png b/plugins/audio_file_processor/loop_pingpong_off.png new file mode 100644 index 0000000000000000000000000000000000000000..6758d2c79f379449bf39be562c720f536e3edfec GIT binary patch literal 655 zcmV;A0&x9_P)q2hVkMUoZEc>-t|WO1ImM`H!M)3-EoPr>7?XEXzU&@o#{>@6+%1SuU4o znue;X#Bt2q+gsv8p-@26G^*7qCnqP_fS%`ZeSJ+31OS9#_-h8w&(8ojj*|(f0=TX# z!Lmfxb#z@%*rF)H_x*H+p69V%uce_>Dp9Fa5JF%W29{+3uv)E{PNzIRJ_7Lm{!S1C zDNeQf`+KR_w$0VmRiYWL>+No(`T2RK zPyLOz<#L&_<#IXl`8<_MC6hk@?I+or%|^c4?KXFJcZ6YxVHg}AA7k4#x3{+p1_K<& zK~+_bj*jSbI^TdhJ3A~E3jkhTUZkU5uT!trr9K*s==FNUaV)zWMG@oi7+u#nJw5#_ z*|zQP`qgX(JkMh|97?c1#dTfAOd5nmfM>EAq7H!5`rKEM?$g&9ExBt2tcA5Br=85;{dreEPd6TSY_RO5Kv(r^b68{ljKNa}CkK64A0O)i&FbpG^z(0^uay%Xr z0JGUFi^U>!T_=FhYPDMIcDuA~n{fb1dY;Extrj6Ct$aTJS#U5IB$9Pqk4*dh{Y@!l zMDXi$I^lFW1r`V)FrUv+uh&s57SZW+004)>0sH+P*XtFp*9*_*6Ta_9JzXpoLDz1# z%YQvR9*eq2!4Y4>GoaM4SlPsibA1) zX0wUeYzE)=-As3B(|IOJ-z3N?8r1WbUGl9@~jg;N@}&2&$@byWNr`4Z{eD)oL|* zo|haO05A*#ypJc)|LPO002ovPDHLkV1m4F1^)m5 literal 0 HcmV?d00001 diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 5855de64c..33dc7f1f4 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -620,10 +620,10 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, { return false; } - + // variable for determining if we should currently be playing backwards in a ping-pong loop bool is_backwards = _state->isBackwards(); - + const double freq_factor = (double) _freq / (double) m_frequency * m_sampleRate / engine::mixer()->processingSampleRate(); @@ -639,6 +639,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, // this holds the number of the first frame to play f_cnt_t play_frame = _state->m_frameIndex; + if( play_frame < m_startFrame ) { play_frame = m_startFrame; @@ -656,9 +657,9 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, else if( _loopmode == LoopPingPong ) { play_frame = getPingPongIndex( play_frame ); - if( is_backwards ) + if( is_backwards ) frames_for_loop = static_cast( ( play_frame - m_loopStartFrame ) / freq_factor ); - else + else frames_for_loop = static_cast( ( m_loopEndFrame - play_frame ) / freq_factor ); } else @@ -730,7 +731,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, } play_frame += left; play_frame = getPingPongIndex( play_frame ); - break; + break; } } } @@ -768,7 +769,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, } play_frame += left; play_frame = getPingPongIndex( play_frame ); - break; + break; } } } @@ -804,8 +805,9 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, } /* else { - if( ! *_backwards && _start + _frames < m_loopEndFrame ) - return m_data + _start; + if( ! *_backwards && pos + _frames < m_loopEndFrame ) + *_index = pos + _frames; + return m_data + pos; }*/ *_tmp = new sampleFrame[_frames]; @@ -815,20 +817,19 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, f_cnt_t copied = qMin( _frames, m_loopEndFrame - _start ); memcpy( *_tmp, m_data + _start, copied * BYTES_PER_FRAME ); f_cnt_t loop_frames = m_loopEndFrame - m_loopStartFrame; - while( _frames - copied > 0 ) + while( copied < _frames ) { f_cnt_t todo = qMin( _frames - copied, loop_frames ); - memcpy( *_tmp + copied, m_data + m_loopStartFrame, - todo * BYTES_PER_FRAME ); + memcpy( *_tmp + copied, m_data + m_loopStartFrame, todo * BYTES_PER_FRAME ); copied += todo; } } else if( _loopmode == LoopPingPong ) { - f_cnt_t copied = 0; - bool backwards = *_backwards; f_cnt_t pos = _start; - + bool backwards = *_backwards; + f_cnt_t copied = 0; + if( backwards ) { copied = qMin( _frames, pos - m_loopStartFrame ); @@ -866,7 +867,7 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, (*_tmp)[ copied + i ][1] = m_data[ pos - i ][1]; } pos -= todo; - copied += todo; + copied += todo; if( pos == m_loopStartFrame ) backwards = false; } else @@ -874,6 +875,7 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, f_cnt_t todo = qMin( _frames - copied, m_loopEndFrame - pos ); memcpy( *_tmp + copied, m_data + pos, todo * BYTES_PER_FRAME ); pos += todo; + copied += todo; if( pos == m_loopEndFrame ) backwards = true; } } From 0442be37297a70bb37c8b2a89f2de7444f2eec4d Mon Sep 17 00:00:00 2001 From: Vesa Date: Fri, 4 Apr 2014 00:24:23 +0300 Subject: [PATCH 3/3] Finish ping pong loop implementation in AFP --- include/SampleBuffer.h | 9 +- .../audio_file_processor.cpp | 87 +++++---- .../audio_file_processor.h | 1 + src/core/SampleBuffer.cpp | 171 +++++++++--------- 4 files changed, 150 insertions(+), 118 deletions(-) diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index 0016f6331..eeda62991 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -287,12 +287,13 @@ private: float m_frequency; sample_rate_t m_sampleRate; - sampleFrame * getSampleFragment( f_cnt_t _start, f_cnt_t _frames, + sampleFrame * getSampleFragment( f_cnt_t _index, f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, - bool * _backwards ) const; - f_cnt_t getLoopedIndex( f_cnt_t _index ) const; - f_cnt_t getPingPongIndex( f_cnt_t _index ) const; + bool * _backwards, f_cnt_t _loopstart, f_cnt_t _loopend, + f_cnt_t _end ) const; + f_cnt_t getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const; + f_cnt_t getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const; signals: diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index 16465e508..d285b4eaa 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -2,7 +2,7 @@ * audio_file_processor.cpp - instrument for using audio-files * * Copyright (c) 2004-2014 Tobias Doerffel - * + * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * * This program is free software; you can redistribute it and/or @@ -78,7 +78,8 @@ audioFileProcessor::audioFileProcessor( InstrumentTrack * _instrument_track ) : m_reverseModel( false, this, tr( "Reverse sample" ) ), m_loopModel( 0, 0, 2, this, tr( "Loop mode" ) ), m_stutterModel( false, this, tr( "Stutter" ) ), - m_nextPlayStartPoint( 0 ) + m_nextPlayStartPoint( 0 ), + m_nextPlayBackwards( false ) { connect( &m_reverseModel, SIGNAL( dataChanged() ), this, SLOT( reverseModelChanged() ) ); @@ -116,6 +117,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n, if( m_stutterModel.value() == true && _n->frequency() < 20.0 ) { m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayBackwards = false; return; } @@ -126,9 +128,11 @@ void audioFileProcessor::playNote( NotePlayHandle * _n, // Restart playing the note if in stutter mode, not in loop mode, // and we're at the end of the sample. m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayBackwards = false; } _n->m_pluginData = new handleState( _n->hasDetuningInfo() ); ((handleState *)_n->m_pluginData)->setFrameIndex( m_nextPlayStartPoint ); + ((handleState *)_n->m_pluginData)->setBackwards( m_nextPlayBackwards ); // debug code /* qDebug( "frames %d", m_sampleBuffer.frames() ); @@ -141,7 +145,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n, if( m_sampleBuffer.play( _working_buffer, (handleState *)_n->m_pluginData, frames, _n->frequency(), - m_loopModel.value() ? SampleBuffer::LoopPingPong : SampleBuffer::LoopOff ) ) + static_cast( m_loopModel.value() ) ) ) { applyRelease( _working_buffer, _n ); instrumentTrack()->processAudioBuffer( _working_buffer, @@ -161,6 +165,7 @@ void audioFileProcessor::playNote( NotePlayHandle * _n, if( m_stutterModel.value() == true ) { m_nextPlayStartPoint = ((handleState *)_n->m_pluginData)->frameIndex(); + m_nextPlayBackwards = ((handleState *)_n->m_pluginData)->isBackwards(); } } @@ -214,7 +219,7 @@ void audioFileProcessor::loadSettings( const QDomElement & _this ) m_ampModel.loadSettings( _this, "amp" ); m_startPointModel.loadSettings( _this, "sframe" ); m_endPointModel.loadSettings( _this, "eframe" ); - + // compat code for not having a separate loopback point if( _this.hasAttribute( "lframe" ) ) { @@ -307,6 +312,7 @@ void audioFileProcessor::ampModelChanged( void ) void audioFileProcessor::stutterModelChanged() { m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayBackwards = false; } @@ -321,28 +327,38 @@ void audioFileProcessor::loopPointChanged( void ) m_endPointModel.setValue( m_startPointModel.value() ); m_startPointModel.setValue( tmp ); } - + // check if start & end overlap and nudge end up if so if( m_startPointModel.value() == m_endPointModel.value() ) { m_endPointModel.setValue( qMin( m_endPointModel.value() + 0.001f, 1.0f ) ); } - - const f_cnt_t f_start = static_cast( m_startPointModel.value() * - ( m_sampleBuffer.frames()-1 ) ); - const f_cnt_t f_end = static_cast( m_endPointModel.value() * - ( m_sampleBuffer.frames()-1 ) ); - m_nextPlayStartPoint = f_start; - // check that loop point is between start-end points + // check that loop point is between start-end points and not overlapping with endpoint + // ...and move start/end points ahead if loop point is moved over them + if( m_loopPointModel.value() >= m_endPointModel.value() ) + { + m_endPointModel.setValue( m_loopPointModel.value() + 0.001f ); + if( m_endPointModel.value() == 1.0f ) + { + m_loopPointModel.setValue( 1.0f - 0.001f ); + } + } if( m_loopPointModel.value() < m_startPointModel.value() ) - m_loopPointModel.setValue( m_startPointModel.value() ); - if( m_loopPointModel.value() > m_endPointModel.value() ) - m_loopPointModel.setValue( m_endPointModel.value() ); + { + m_startPointModel.setValue( m_loopPointModel.value() ); + } + + const f_cnt_t f_start = static_cast( m_startPointModel.value() * ( m_sampleBuffer.frames()-1 ) ); + const f_cnt_t f_end = static_cast( m_endPointModel.value() * ( m_sampleBuffer.frames()-1 ) ); + const f_cnt_t f_loop = static_cast( m_loopPointModel.value() * ( m_sampleBuffer.frames()-1 ) ); + + m_nextPlayStartPoint = f_start; + m_nextPlayBackwards = false; m_sampleBuffer.setStartFrame( f_start ); m_sampleBuffer.setEndFrame( f_end ); - m_sampleBuffer.setLoopStartFrame( static_cast( m_loopPointModel.value() * ( m_sampleBuffer.frames()-1 ) ) ); + m_sampleBuffer.setLoopStartFrame( f_loop ); m_sampleBuffer.setLoopEndFrame( f_end ); emit dataChanged(); } @@ -377,7 +393,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, m_openAudioFileButton->setWhatsThis( tr( "Click here, if you want to open another audio-file. " "A dialog will appear where you can select your file. " - "Settings like looping-mode, start and end-points, " + "Settings like looping-mode, start and end-points, " "amplify-value, and so on are not reset. So, it may not " "sound like the original sample.") ); @@ -396,7 +412,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, // loop button group - pixmapbutton * m_loopOffButton = new pixmapButton( this ); + pixmapButton * m_loopOffButton = new pixmapButton( this ); m_loopOffButton->setCheckable( TRUE ); m_loopOffButton->move( 174, 144 ); m_loopOffButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( @@ -409,7 +425,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, "The sample plays only once from start to end. " ) ); - pixmapbutton * m_loopOnButton = new pixmapButton( this ); + pixmapButton * m_loopOnButton = new pixmapButton( this ); m_loopOnButton->setCheckable( TRUE ); m_loopOnButton->move( 200, 144 ); m_loopOnButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( @@ -421,7 +437,7 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, tr( "This button enables forwards-looping. " "The sample loops between the end point and the loop point." ) ); - pixmapbutton * m_loopPingPongButton = new pixmapButton( this ); + pixmapButton * m_loopPingPongButton = new pixmapButton( this ); m_loopPingPongButton->setCheckable( TRUE ); m_loopPingPongButton->move( 226, 144 ); m_loopPingPongButton->setActiveGraphic( PLUGIN_NAME::getIconPixmap( @@ -433,12 +449,12 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, tr( "This button enables ping-pong-looping. " "The sample loops backwards and forwards between the end point " "and the loop point." ) ); - + m_loopGroup = new automatableButtonGroup( this ); m_loopGroup->addButton( m_loopOffButton ); m_loopGroup->addButton( m_loopOnButton ); m_loopGroup->addButton( m_loopPingPongButton ); - + m_stutterButton = new pixmapButton( this ); m_stutterButton->setCheckable( true ); m_stutterButton->move( 226, 124 ); @@ -708,15 +724,22 @@ void AudioFileProcessorWaveView::mousePressEvent( QMouseEvent * _me ) { m_isDragging = true; m_draggingLastPoint = _me->pos(); - - const int start_dist = qAbs( m_startFrameX - _me->x() ); - const int end_dist = qAbs( m_endFrameX - _me->x() ); - const int loop_dist = qAbs( m_loopFrameX - _me->x() ); - + + const int x = _me->x(); + + const int start_dist = qAbs( m_startFrameX - x ); + const int end_dist = qAbs( m_endFrameX - x ); + const int loop_dist = qAbs( m_loopFrameX - x ); + draggingType dt = sample_loop; int md = loop_dist; if( start_dist < loop_dist ) { dt = sample_start; md = start_dist; } - if( end_dist < start_dist ) { dt = sample_end; md = end_dist; } - + else if( end_dist < loop_dist ) { dt = sample_end; md = end_dist; } + +/* qDebug( "x %d", x ); + qDebug( "loopframex %d", m_loopFrameX ); + qDebug( "dt %d", dt ); + qDebug( "md %d", md );*/ + if( md < 4 ) { m_draggingType = dt; @@ -838,7 +861,7 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe ) p.drawLine( m_endFrameX, graph_rect.y(), m_endFrameX, graph_rect.height() + graph_rect.y() ); - + if( m_endFrameX - m_startFrameX > 2 ) { @@ -1042,7 +1065,7 @@ void AudioFileProcessorWaveView::setKnobs( knob * _start, knob * _end, knob * _l m_endKnob->setWaveView( this ); m_endKnob->setRelatedKnob( m_startKnob ); - + m_loopKnob->setWaveView( this ); } @@ -1166,7 +1189,7 @@ bool AudioFileProcessorWaveView::knob::checkBound( double _v ) const { return true; } - + if( ( m_relatedKnob->model()->value() - _v > 0 ) != ( m_relatedKnob->model()->value() - model()->value() >= 0 ) ) return false; diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h index 94472f88e..1f0558ab5 100644 --- a/plugins/audio_file_processor/audio_file_processor.h +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -96,6 +96,7 @@ private: BoolModel m_stutterModel; f_cnt_t m_nextPlayStartPoint; + bool m_nextPlayBackwards; friend class AudioFileProcessorView; diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 33dc7f1f4..9ef094e0f 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -611,12 +611,17 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, const fpp_t _frames, const float _freq, const LoopMode _loopmode ) -{ +{ QMutexLocker ml( &m_varLock ); + + f_cnt_t startFrame = m_startFrame; + f_cnt_t endFrame = m_endFrame; + f_cnt_t loopStartFrame = m_loopStartFrame; + f_cnt_t loopEndFrame = m_loopEndFrame; engine::mixer()->clearAudioBuffer( _ab, _frames ); - if( m_endFrame == 0 || _frames == 0 ) + if( endFrame == 0 || _frames == 0 ) { return false; } @@ -629,7 +634,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, // calculate how many frames we have in requested pitch const f_cnt_t total_frames_for_current_pitch = static_cast( ( - m_endFrame - m_startFrame ) / + endFrame - startFrame ) / freq_factor ); if( total_frames_for_current_pitch == 0 ) @@ -637,45 +642,47 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, return false; } + // this holds the number of the first frame to play f_cnt_t play_frame = _state->m_frameIndex; - if( play_frame < m_startFrame ) + if( play_frame < startFrame ) { - play_frame = m_startFrame; + play_frame = startFrame; } // this holds the number of remaining frames in current loop f_cnt_t frames_for_loop; if( _loopmode == LoopOn ) { - play_frame = getLoopedIndex( play_frame ); - frames_for_loop = static_cast( - ( m_loopEndFrame - play_frame ) / - freq_factor ); + play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); + frames_for_loop = static_cast( ( loopEndFrame - play_frame ) / freq_factor ); } + else if( _loopmode == LoopPingPong ) { - play_frame = getPingPongIndex( play_frame ); + play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); if( is_backwards ) - frames_for_loop = static_cast( ( play_frame - m_loopStartFrame ) / freq_factor ); + frames_for_loop = static_cast( ( play_frame - loopStartFrame ) / freq_factor ); else - frames_for_loop = static_cast( ( m_loopEndFrame - play_frame ) / freq_factor ); + frames_for_loop = static_cast( ( loopEndFrame - play_frame ) / freq_factor ); } + else { - if( play_frame >= m_endFrame ) + if( play_frame >= endFrame ) { return false; } - frames_for_loop = static_cast( - ( m_endFrame - play_frame ) / - freq_factor ); + + frames_for_loop = static_cast( ( endFrame - play_frame ) / freq_factor ); + if( frames_for_loop == 0 ) { return false; } } + sampleFrame * tmp = NULL; @@ -685,10 +692,10 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, SRC_DATA src_data; // Generate output const f_cnt_t margin = 64; - f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) - + margin; - src_data.data_in = getSampleFragment( play_frame, - fragment_size, _loopmode, &tmp, &is_backwards )[0]; + f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + margin; + src_data.data_in = + getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards, + loopStartFrame, loopEndFrame, endFrame )[0]; src_data.data_out = _ab[0]; src_data.input_frames = fragment_size; src_data.output_frames = _frames; @@ -714,7 +721,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, break; case LoopOn: play_frame += src_data.input_frames_used; - play_frame = getLoopedIndex( play_frame ); + play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); break; case LoopPingPong: { @@ -722,15 +729,15 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, if( _state->isBackwards() ) { play_frame -= src_data.input_frames_used; - if( play_frame < m_loopStartFrame ) + if( play_frame < loopStartFrame ) { - left -= ( m_loopStartFrame - play_frame ); - play_frame = m_loopStartFrame; + left -= ( loopStartFrame - play_frame ); + play_frame = loopStartFrame; } else left = 0; } play_frame += left; - play_frame = getPingPongIndex( play_frame ); + play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); break; } } @@ -742,7 +749,8 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, // Generate output memcpy( _ab, - getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards ), + getSampleFragment( play_frame, _frames, _loopmode, &tmp, &is_backwards, + loopStartFrame, loopEndFrame, endFrame ), _frames * BYTES_PER_FRAME ); // Advance switch( _loopmode ) @@ -752,7 +760,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, break; case LoopOn: play_frame += _frames; - play_frame = getLoopedIndex( play_frame ); + play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame ); break; case LoopPingPong: { @@ -760,15 +768,15 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, if( _state->isBackwards() ) { play_frame -= _frames; - if( play_frame < m_loopStartFrame ) + if( play_frame < loopStartFrame ) { - left -= ( m_loopStartFrame - play_frame ); - play_frame = m_loopStartFrame; + left -= ( loopStartFrame - play_frame ); + play_frame = loopStartFrame; } else left = 0; } play_frame += left; - play_frame = getPingPongIndex( play_frame ); + play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame ); break; } } @@ -786,53 +794,61 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, -sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, - f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, bool * _backwards ) const +sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _index, + f_cnt_t _frames, LoopMode _loopmode, sampleFrame * * _tmp, bool * _backwards, + f_cnt_t _loopstart, f_cnt_t _loopend, f_cnt_t _end ) const { - if( _loopmode == LoopOn ) + + if( _loopmode == LoopOff ) { - if( _start + _frames <= m_loopEndFrame ) + if( _index + _frames <= _end ) { - return m_data + _start; + return m_data + _index; } } - else if( _loopmode == LoopOff ) + else if( _loopmode == LoopOn ) { - if( _start + _frames <= m_endFrame ) + if( _index + _frames <= _loopend ) { - return m_data + _start; + return m_data + _index; } } -/* else + else { - if( ! *_backwards && pos + _frames < m_loopEndFrame ) - *_index = pos + _frames; - return m_data + pos; - }*/ + if( ! *_backwards && _index + _frames < _loopend ) + return m_data + _index; + } *_tmp = new sampleFrame[_frames]; - if( _loopmode == LoopOn ) + if( _loopmode == LoopOff ) { - f_cnt_t copied = qMin( _frames, m_loopEndFrame - _start ); - memcpy( *_tmp, m_data + _start, copied * BYTES_PER_FRAME ); - f_cnt_t loop_frames = m_loopEndFrame - m_loopStartFrame; + f_cnt_t available = _end - _index; + memcpy( *_tmp, m_data + _index, available * BYTES_PER_FRAME ); + memset( *_tmp + available, 0, ( _frames - available ) * + BYTES_PER_FRAME ); + } + else if( _loopmode == LoopOn ) + { + f_cnt_t copied = qMin( _frames, _loopend - _index ); + memcpy( *_tmp, m_data + _index, copied * BYTES_PER_FRAME ); + f_cnt_t loop_frames = _loopend - _loopstart; while( copied < _frames ) { f_cnt_t todo = qMin( _frames - copied, loop_frames ); - memcpy( *_tmp + copied, m_data + m_loopStartFrame, todo * BYTES_PER_FRAME ); + memcpy( *_tmp + copied, m_data + _loopstart, todo * BYTES_PER_FRAME ); copied += todo; } } - else if( _loopmode == LoopPingPong ) + else { - f_cnt_t pos = _start; + f_cnt_t pos = _index; bool backwards = *_backwards; f_cnt_t copied = 0; if( backwards ) { - copied = qMin( _frames, pos - m_loopStartFrame ); + copied = qMin( _frames, pos - _loopstart ); for( int i=0; i < copied; i++ ) { //memcpy( *_tmp + i, m_data + pos - i, BYTES_PER_FRAME ); @@ -840,26 +856,26 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, (*_tmp)[i][1] = m_data[ pos - i ][1]; } pos -= copied; - if( pos == m_loopStartFrame ) backwards = false; + if( pos == _loopstart ) backwards = false; } else { - copied = qMin( _frames, m_loopEndFrame - pos ); + copied = qMin( _frames, _loopend - pos ); memcpy( *_tmp, m_data + pos, copied * BYTES_PER_FRAME ); pos += copied; - if( pos == m_loopEndFrame ) backwards = true; + if( pos == _loopend ) backwards = true; } while( copied < _frames ) { - if( pos >= m_loopEndFrame ) backwards = true; - if( pos <= m_loopStartFrame ) backwards = false; - pos = qBound( m_loopStartFrame, pos, m_loopEndFrame ); + if( pos >= _loopend ) backwards = true; + if( pos <= _loopstart ) backwards = false; + pos = qBound( _loopstart, pos, _loopend ); /*qDebug( backwards ? "backwards" : "forwards" ); qDebug( "pos %d", pos );*/ if( backwards ) { - f_cnt_t todo = qMin( _frames - copied, pos - m_loopStartFrame ); + f_cnt_t todo = qMin( _frames - copied, pos - _loopstart ); for ( int i=0; i < todo; i++ ) { //memcpy( *_tmp + ( copied + i ), m_data + ( pos - i ), BYTES_PER_FRAME ); @@ -868,26 +884,19 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, } pos -= todo; copied += todo; - if( pos == m_loopStartFrame ) backwards = false; + if( pos == _loopstart ) backwards = false; } else { - f_cnt_t todo = qMin( _frames - copied, m_loopEndFrame - pos ); + f_cnt_t todo = qMin( _frames - copied, _loopend - pos ); memcpy( *_tmp + copied, m_data + pos, todo * BYTES_PER_FRAME ); pos += todo; copied += todo; - if( pos == m_loopEndFrame ) backwards = true; + if( pos == _loopend ) backwards = true; } } *_backwards = backwards; } - else - { - f_cnt_t available = m_endFrame - _start; - memcpy( *_tmp, m_data + _start, available * BYTES_PER_FRAME ); - memset( *_tmp + available, 0, ( _frames - available ) * - BYTES_PER_FRAME ); - } return *_tmp; } @@ -895,31 +904,29 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _start, -f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index ) const +f_cnt_t SampleBuffer::getLoopedIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const { - if( _index < m_loopEndFrame ) + if( _index < _endf ) { return _index; } - return m_loopStartFrame + ( _index - m_loopStartFrame ) - % ( m_loopEndFrame - m_loopStartFrame ); + return _startf + ( _index - _startf ) + % ( _endf - _startf ); } -f_cnt_t SampleBuffer::getPingPongIndex( f_cnt_t _index ) const +f_cnt_t SampleBuffer::getPingPongIndex( f_cnt_t _index, f_cnt_t _startf, f_cnt_t _endf ) const { - if( _index < m_loopEndFrame ) + if( _index < _endf ) { return _index; } - const f_cnt_t looplen = m_loopEndFrame - m_loopStartFrame; - const f_cnt_t looppos = ( _index - m_loopEndFrame ) % ( looplen*2 ); + const f_cnt_t looplen = _endf - _startf; + const f_cnt_t looppos = ( _index - _endf ) % ( looplen*2 ); - f_cnt_t r; - if( looppos < looplen ) r= m_loopEndFrame - looppos; - else r= m_loopStartFrame + ( looppos - looplen ); - qDebug( "index %d --- pingpongindex %d", _index, r ); - return r; + return ( looppos < looplen ) + ? _endf - looppos + : _startf + ( looppos - looplen ); }