Merge pull request #2150 from Wallacoloo/SampleBufferCleanup

Fix deadlock in SampleBuffer
This commit is contained in:
Colin Wallace
2015-07-13 19:02:23 -07:00
2 changed files with 106 additions and 132 deletions

View File

@@ -29,6 +29,7 @@
#include <QtCore/QReadWriteLock>
#include <QtCore/QObject>
#include <QtCore/QRect>
#include <QtCore/QWriteLocker>
#include <samplerate.h>
@@ -151,26 +152,23 @@ public:
void setLoopStartFrame( f_cnt_t _start )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_loopStartFrame = _start;
m_varLock.unlock();
}
void setLoopEndFrame( f_cnt_t _end )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_loopEndFrame = _end;
m_varLock.unlock();
}
void setAllPointFrames( f_cnt_t _start, f_cnt_t _end, f_cnt_t _loopstart, f_cnt_t _loopend )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_startFrame = _start;
m_endFrame = _end;
m_loopStartFrame = _loopstart;
m_loopEndFrame = _loopend;
m_varLock.unlock();
}
inline f_cnt_t frames() const
@@ -205,16 +203,14 @@ public:
inline void setFrequency( float _freq )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_frequency = _freq;
m_varLock.unlock();
}
inline void setSampleRate( sample_rate_t _rate )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_sampleRate = _rate;
m_varLock.unlock();
}
inline const sampleFrame * data() const
@@ -222,8 +218,8 @@ public:
return m_data;
}
QString openAudioFile() const;
QString openAndSetAudioFile();
QString openAudioFile() const;
QString openAndSetAudioFile();
QString openAndSetWaveformFile();
QString & toBase64( QString & _dst ) const;
@@ -272,8 +268,8 @@ public slots:
private:
void update( bool _keep_settings = false );
void convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels);
void directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels);
void convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels);
void directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels);
f_cnt_t decodeSampleSF( const char * _f, sample_t * & _buf,
ch_cnt_t & _channels,

View File

@@ -31,6 +31,7 @@
#include <QFileInfo>
#include <QMessageBox>
#include <QPainter>
#include <QReadLocker>
#include <cstring>
@@ -209,33 +210,33 @@ void SampleBuffer::update( bool _keep_settings )
{
#ifdef LMMS_HAVE_OGGVORBIS
// workaround for a bug in libsndfile or our libsndfile decoder
// causing some OGG files to be distorted -> try with OGG Vorbis
// decoder first if filename extension matches "ogg"
if( m_frames == 0 && fileInfo.suffix() == "ogg" )
{
m_frames = decodeSampleOGGVorbis( f, buf, channels, samplerate );
}
// workaround for a bug in libsndfile or our libsndfile decoder
// causing some OGG files to be distorted -> try with OGG Vorbis
// decoder first if filename extension matches "ogg"
if( m_frames == 0 && fileInfo.suffix() == "ogg" )
{
m_frames = decodeSampleOGGVorbis( f, buf, channels, samplerate );
}
#endif
if( m_frames == 0 )
{
m_frames = decodeSampleSF( f, fbuf, channels,
samplerate );
}
if( m_frames == 0 )
{
m_frames = decodeSampleSF( f, fbuf, channels,
samplerate );
}
#ifdef LMMS_HAVE_OGGVORBIS
if( m_frames == 0 )
{
m_frames = decodeSampleOGGVorbis( f, buf, channels,
samplerate );
}
if( m_frames == 0 )
{
m_frames = decodeSampleOGGVorbis( f, buf, channels,
samplerate );
}
#endif
if( m_frames == 0 )
{
m_frames = decodeSampleDS( f, buf, channels,
samplerate );
}
if( m_frames == 0 )
{
m_frames = decodeSampleDS( f, buf, channels,
samplerate );
}
delete[] f;
delete[] f;
if ( m_frames == 0 ) // if still no frames, bail
{
@@ -253,9 +254,6 @@ void SampleBuffer::update( bool _keep_settings )
}
}
}
else
{
@@ -279,81 +277,73 @@ void SampleBuffer::update( bool _keep_settings )
void SampleBuffer::convertIntToFloat ( int_sample_t * & _ibuf, f_cnt_t _frames, int _channels)
{
// following code transforms int-samples into
// float-samples and does amplifying & reversing
const float fac = 1 / OUTPUT_SAMPLE_MULTIPLIER;
m_data = MM_ALLOC( sampleFrame, _frames );
const int ch = ( _channels > 1 ) ? 1 : 0;
// if reversing is on, we also reverse when
// scaling
if( m_reversed )
{
int idx = ( _frames - 1 ) * _channels;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _ibuf[idx+0] * fac;
m_data[frame][1] = _ibuf[idx+ch] * fac;
idx -= _channels;
}
}
else
{
int idx = 0;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _ibuf[idx+0] * fac;
m_data[frame][1] = _ibuf[idx+ch] * fac;
idx += _channels;
}
}
delete[] _ibuf;
// following code transforms int-samples into
// float-samples and does amplifying & reversing
const float fac = 1 / OUTPUT_SAMPLE_MULTIPLIER;
m_data = MM_ALLOC( sampleFrame, _frames );
const int ch = ( _channels > 1 ) ? 1 : 0;
// if reversing is on, we also reverse when
// scaling
if( m_reversed )
{
int idx = ( _frames - 1 ) * _channels;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _ibuf[idx+0] * fac;
m_data[frame][1] = _ibuf[idx+ch] * fac;
idx -= _channels;
}
}
else
{
int idx = 0;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _ibuf[idx+0] * fac;
m_data[frame][1] = _ibuf[idx+ch] * fac;
idx += _channels;
}
}
delete[] _ibuf;
}
void SampleBuffer::directFloatWrite ( sample_t * & _fbuf, f_cnt_t _frames, int _channels)
{
m_data = MM_ALLOC( sampleFrame, _frames );
const int ch = ( _channels > 1 ) ? 1 : 0;
// if reversing is on, we also reverse when
// scaling
if( m_reversed )
{
int idx = ( _frames - 1 ) * _channels;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _fbuf[idx+0];
m_data[frame][1] = _fbuf[idx+ch];
idx -= _channels;
}
}
else
{
int idx = 0;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _fbuf[idx+0];
m_data[frame][1] = _fbuf[idx+ch];
idx += _channels;
}
}
delete[] _fbuf;
m_data = MM_ALLOC( sampleFrame, _frames );
const int ch = ( _channels > 1 ) ? 1 : 0;
// if reversing is on, we also reverse when
// scaling
if( m_reversed )
{
int idx = ( _frames - 1 ) * _channels;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _fbuf[idx+0];
m_data[frame][1] = _fbuf[idx+ch];
idx -= _channels;
}
}
else
{
int idx = 0;
for( f_cnt_t frame = 0; frame < _frames;
++frame )
{
m_data[frame][0] = _fbuf[idx+0];
m_data[frame][1] = _fbuf[idx+ch];
idx += _channels;
}
}
delete[] _fbuf;
}
@@ -420,12 +410,12 @@ f_cnt_t SampleBuffer::decodeSampleSF( const char * _f,
"sample %s: %s", _f, sf_strerror( NULL ) );
#endif
}
//write down either directly or convert i->f depending on file type
//write down either directly or convert i->f depending on file type
if ( frames > 0 && _buf != NULL )
{
directFloatWrite ( _buf, frames, _channels);
}
if ( frames > 0 && _buf != NULL )
{
directFloatWrite ( _buf, frames, _channels);
}
return frames;
}
@@ -606,7 +596,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
const float _freq,
const LoopMode _loopmode )
{
m_varLock.lockForRead();
QReadLocker readLocker(&m_varLock);
f_cnt_t startFrame = m_startFrame;
f_cnt_t endFrame = m_endFrame;
@@ -615,7 +605,6 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
if( endFrame == 0 || _frames == 0 )
{
m_varLock.unlock();
return false;
}
@@ -632,35 +621,25 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
if( total_frames_for_current_pitch == 0 )
{
m_varLock.unlock();
return false;
}
// this holds the number of the first frame to play
f_cnt_t play_frame = _state->m_frameIndex;
if( play_frame < startFrame )
{
play_frame = startFrame;
}
// this holds the index of the first frame to play
f_cnt_t play_frame = qMax(_state->m_frameIndex, startFrame);
if( _loopmode == LoopOff )
{
if( play_frame >= endFrame )
if( play_frame >= endFrame || ( endFrame - play_frame ) / freq_factor == 0 )
{
m_varLock.unlock();
// the sample is done being played
return false;
}
if( ( endFrame - play_frame ) / freq_factor == 0 ) return false;
}
else if( _loopmode == LoopOn )
{
play_frame = getLoopedIndex( play_frame, loopStartFrame, loopEndFrame );
}
else
{
play_frame = getPingPongIndex( play_frame, loopStartFrame, loopEndFrame );
@@ -778,7 +757,6 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state,
_ab[i][1] *= m_amplification;
}
m_varLock.unlock();
return true;
}
@@ -806,7 +784,9 @@ sampleFrame * SampleBuffer::getSampleFragment( f_cnt_t _index,
else
{
if( ! *_backwards && _index + _frames < _loopend )
return m_data + _index;
{
return m_data + _index;
}
}
*_tmp = MM_ALLOC( sampleFrame, _frames );
@@ -1376,9 +1356,8 @@ void SampleBuffer::loadFromBase64( const QString & _data )
void SampleBuffer::setStartFrame( const f_cnt_t _s )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_startFrame = _s;
m_varLock.unlock();
}
@@ -1386,9 +1365,8 @@ void SampleBuffer::setStartFrame( const f_cnt_t _s )
void SampleBuffer::setEndFrame( const f_cnt_t _e )
{
m_varLock.lockForWrite();
QWriteLocker writeLocker(&m_varLock);
m_endFrame = _e;
m_varLock.unlock();
}