mirror of
https://github.com/LMMS/lmms.git
synced 2026-03-17 13:38:22 -04:00
Finish ping pong loop implementation in AFP
This commit is contained in:
@@ -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<f_cnt_t>( (
|
||||
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<f_cnt_t>(
|
||||
( m_loopEndFrame - play_frame ) /
|
||||
freq_factor );
|
||||
play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
|
||||
frames_for_loop = static_cast<f_cnt_t>( ( 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<f_cnt_t>( ( play_frame - m_loopStartFrame ) / freq_factor );
|
||||
frames_for_loop = static_cast<f_cnt_t>( ( play_frame - loopStartFrame ) / freq_factor );
|
||||
else
|
||||
frames_for_loop = static_cast<f_cnt_t>( ( m_loopEndFrame - play_frame ) / freq_factor );
|
||||
frames_for_loop = static_cast<f_cnt_t>( ( loopEndFrame - play_frame ) / freq_factor );
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if( play_frame >= m_endFrame )
|
||||
if( play_frame >= endFrame )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
frames_for_loop = static_cast<f_cnt_t>(
|
||||
( m_endFrame - play_frame ) /
|
||||
freq_factor );
|
||||
|
||||
frames_for_loop = static_cast<f_cnt_t>( ( 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 );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user