From 7350f983b056b4ddbc463d0ec4986f610805b5fe Mon Sep 17 00:00:00 2001 From: Vesa Date: Thu, 3 Apr 2014 21:52:23 +0300 Subject: [PATCH] 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; } }