made sampleBuffer reentrant so that several threads can use sampleBuffer::play() simultanously - fixes crashes when using AudioFileProcessor or Patman in multithreaded mode
git-svn-id: https://lmms.svn.sf.net/svnroot/lmms/trunk/lmms@769 0778d3d1-df1d-0410-868b-ea421aaaa00d
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
2008-03-07 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* include/sample_buffer.h:
|
||||
* src/lib/sample_buffer.cpp:
|
||||
made sampleBuffer reentrant so that several threads can use
|
||||
sampleBuffer::play() simultanously - fixes crashes when using
|
||||
AudioFileProcessor or Patman in multithreaded mode
|
||||
|
||||
2008-03-06 Tobias Doerffel <tobydox/at/users/dot/sourceforge/dot/net>
|
||||
|
||||
* plugins/sf2_player/sf2_player.h:
|
||||
|
||||
1
TODO
1
TODO
@@ -24,7 +24,6 @@
|
||||
- recording-functionality
|
||||
- do not hang when saving while loading VST-plugin (because then we call dispatcher while the load-process is still going on)
|
||||
- tempo-recogn. and sync of beat-samples
|
||||
- separate GUI and data/sound-processing-code
|
||||
- make color-scheme switchable: LMMS / user
|
||||
- autosave every 30s (configurable!) and offer recovery at startup after crash
|
||||
- make piano-roll use rubberband instead of implementing a simple one on it's own
|
||||
|
||||
12
configure.in
12
configure.in
@@ -2,8 +2,8 @@
|
||||
# Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.50)
|
||||
AC_INIT(lmms, 0.4.0-svn20080303, lmms-devel/at/lists/dot/sf/dot/net)
|
||||
AM_INIT_AUTOMAKE(lmms, 0.4.0-svn20080303)
|
||||
AC_INIT(lmms, 0.4.0-svn20080307, lmms-devel/at/lists/dot/sf/dot/net)
|
||||
AM_INIT_AUTOMAKE(lmms, 0.4.0-svn20080307)
|
||||
|
||||
AM_CONFIG_HEADER(config.h)
|
||||
|
||||
@@ -53,15 +53,15 @@ AM_CONDITIONAL(BUILD_LINUX, test "$build_linux" = "true")
|
||||
|
||||
# -fomit-frame-pointer crashes wine on Ubuntu Dapper--Danny 7/21/06
|
||||
#DEFAULTFLAGS="-floop-optimize2 -fomit-frame-pointer -fgcse-sm -fgcse-las"
|
||||
DEFAULTFLAGS="-O2 -fPIC" #"-floop-optimize2 -fgcse-sm -fgcse-las"
|
||||
#DEFAULTFLAGS="-O2 -fPIC" #"-floop-optimize2 -fgcse-sm -fgcse-las"
|
||||
|
||||
# Tested with GCC 4.0--needs to be tested with 4.1--Danny 7/21/06
|
||||
if test "x`$CC --version|head -1|cut -d\ -f3|cut -d. -f1`" = "x4" ; then
|
||||
DEFAULTFLAGS="$DEFAULTFLAGS -ftree-vectorize -ftree-loop-linear"
|
||||
#if test "x`$CC --version|head -1|cut -d\ -f3|cut -d. -f1`" = "x4" ; then
|
||||
# DEFAULTFLAGS="$DEFAULTFLAGS -ftree-vectorize -ftree-loop-linear"
|
||||
# if test "x`$CC --version|head -1|cut -d\ -f3|cut -d. -f2`" != "x0" ; then
|
||||
# DEFAULTFLAGS="$DEFAULTFLAGS -funsafe-loop-optimizations"
|
||||
# fi
|
||||
fi
|
||||
#fi
|
||||
|
||||
CFLAGS="$DEFAULTFLAGS $CFLAGS"
|
||||
CXXFLAGS="$DEFAULTFLAGS $CXXFLAGS"
|
||||
|
||||
@@ -61,9 +61,10 @@ public:
|
||||
|
||||
|
||||
private:
|
||||
f_cnt_t m_frame_index;
|
||||
const bool m_varying_pitch;
|
||||
SRC_STATE * m_resampling_data;
|
||||
f_cnt_t m_frameIndex;
|
||||
const bool m_varyingPitch;
|
||||
SRC_STATE * m_resamplingData;
|
||||
int m_eof;
|
||||
|
||||
friend class sampleBuffer;
|
||||
|
||||
@@ -82,7 +83,7 @@ public:
|
||||
bool FASTCALL play( sampleFrame * _ab, handleState * _state,
|
||||
const fpp_t _frames,
|
||||
const float _freq = BASE_FREQ,
|
||||
const bool _looped = FALSE );
|
||||
const bool _looped = FALSE ) const;
|
||||
|
||||
void FASTCALL visualize( QPainter & _p, const QRect & _dr,
|
||||
const QRect & _clip );
|
||||
@@ -143,7 +144,7 @@ public:
|
||||
|
||||
inline void setSampleRate( sample_rate_t _rate )
|
||||
{
|
||||
m_sample_rate = _rate;
|
||||
m_sampleRate = _rate;
|
||||
}
|
||||
|
||||
inline const sampleFrame * data( void ) const
|
||||
@@ -247,16 +248,12 @@ private:
|
||||
float m_amplification;
|
||||
bool m_reversed;
|
||||
float m_frequency;
|
||||
sample_rate_t m_sample_rate;
|
||||
sample_rate_t m_sampleRate;
|
||||
|
||||
void initResampling( void );
|
||||
|
||||
SRC_DATA m_srcData;
|
||||
|
||||
sampleFrame * m_sample_fragment;
|
||||
sampleFrame * getSampleFragment( f_cnt_t _start, f_cnt_t _frames,
|
||||
bool _looped );
|
||||
f_cnt_t getLoopedIndex( f_cnt_t _index );
|
||||
bool _looped,
|
||||
sampleFrame * * _tmp ) const;
|
||||
f_cnt_t getLoopedIndex( f_cnt_t _index ) const;
|
||||
|
||||
|
||||
signals:
|
||||
|
||||
@@ -88,14 +88,12 @@ sampleBuffer::sampleBuffer( const QString & _audio_file,
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( FALSE ),
|
||||
m_frequency( BASE_FREQ ),
|
||||
m_sample_rate( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ),
|
||||
m_sample_fragment( NULL )
|
||||
m_sampleRate( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] )
|
||||
{
|
||||
#ifdef SDL_SDL_SOUND_H
|
||||
// init sound-file-system of SDL
|
||||
Sound_Init();
|
||||
#endif
|
||||
initResampling();
|
||||
if( _is_base64_data == TRUE )
|
||||
{
|
||||
loadFromBase64( _audio_file );
|
||||
@@ -119,8 +117,7 @@ sampleBuffer::sampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) :
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( FALSE ),
|
||||
m_frequency( BASE_FREQ ),
|
||||
m_sample_rate( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ),
|
||||
m_sample_fragment( NULL )
|
||||
m_sampleRate( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] )
|
||||
{
|
||||
if( _frames > 0 )
|
||||
{
|
||||
@@ -132,7 +129,6 @@ sampleBuffer::sampleBuffer( const sampleFrame * _data, const f_cnt_t _frames ) :
|
||||
// init sound-file-system of SDL
|
||||
Sound_Init();
|
||||
#endif
|
||||
initResampling();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -152,8 +148,7 @@ sampleBuffer::sampleBuffer( const f_cnt_t _frames ) :
|
||||
m_amplification( 1.0f ),
|
||||
m_reversed( FALSE ),
|
||||
m_frequency( BASE_FREQ ),
|
||||
m_sample_rate( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] ),
|
||||
m_sample_fragment( NULL )
|
||||
m_sampleRate( SAMPLE_RATES[DEFAULT_QUALITY_LEVEL] )
|
||||
{
|
||||
if( _frames > 0 )
|
||||
{
|
||||
@@ -165,7 +160,6 @@ sampleBuffer::sampleBuffer( const f_cnt_t _frames ) :
|
||||
// init sound-file-system of SDL
|
||||
Sound_Init();
|
||||
#endif
|
||||
initResampling();
|
||||
update();
|
||||
}
|
||||
|
||||
@@ -176,7 +170,6 @@ sampleBuffer::~sampleBuffer()
|
||||
{
|
||||
delete[] m_origData;
|
||||
delete[] m_data;
|
||||
delete[] m_sample_fragment;
|
||||
}
|
||||
|
||||
|
||||
@@ -583,19 +576,13 @@ f_cnt_t sampleBuffer::decodeSampleDS( const char * _f,
|
||||
|
||||
|
||||
|
||||
void sampleBuffer::initResampling( void )
|
||||
{
|
||||
m_srcData.end_of_input = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
const fpp_t _frames,
|
||||
const float _freq,
|
||||
const bool _looped )
|
||||
const bool _looped ) const
|
||||
{
|
||||
// static QMutex m;
|
||||
// QMutexLocker ml( &m );
|
||||
engine::getMixer()->clearAudioBuffer( _ab, _frames );
|
||||
|
||||
if( m_endFrame == 0 || _frames == 0 )
|
||||
@@ -604,7 +591,7 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
}
|
||||
|
||||
const double freq_factor = (double) _freq / (double) m_frequency
|
||||
* m_sample_rate / engine::getMixer()->sampleRate();
|
||||
* m_sampleRate / engine::getMixer()->sampleRate();
|
||||
|
||||
// calculate how many frames we have in requested pitch
|
||||
const f_cnt_t total_frames_for_current_pitch = static_cast<f_cnt_t>( (
|
||||
@@ -616,7 +603,7 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
}
|
||||
|
||||
// this holds the number of the first frame to play
|
||||
f_cnt_t play_frame = _state->m_frame_index;
|
||||
f_cnt_t play_frame = _state->m_frameIndex;
|
||||
if( play_frame < m_startFrame )
|
||||
{
|
||||
play_frame = m_startFrame;
|
||||
@@ -646,33 +633,38 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
}
|
||||
}
|
||||
|
||||
sampleFrame * tmp = NULL;
|
||||
|
||||
// check whether we have to change pitch...
|
||||
if( freq_factor != 1.0 || _state->m_varying_pitch )
|
||||
if( freq_factor != 1.0 || _state->m_varyingPitch )
|
||||
{
|
||||
SRC_DATA src_data;
|
||||
// Generate output
|
||||
const f_cnt_t margin = 64;
|
||||
f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor )
|
||||
+ margin;
|
||||
m_srcData.data_in = getSampleFragment( play_frame,
|
||||
fragment_size, _looped )[0];
|
||||
m_srcData.data_out = _ab[0];
|
||||
m_srcData.input_frames = fragment_size;
|
||||
m_srcData.output_frames = _frames;
|
||||
m_srcData.src_ratio = 1.0 / freq_factor;
|
||||
int error = src_process( _state->m_resampling_data,
|
||||
&m_srcData );
|
||||
src_data.data_in = getSampleFragment( play_frame,
|
||||
fragment_size, _looped, &tmp )[0];
|
||||
src_data.data_out = _ab[0];
|
||||
src_data.input_frames = fragment_size;
|
||||
src_data.output_frames = _frames;
|
||||
src_data.src_ratio = 1.0 / freq_factor;
|
||||
src_data.end_of_input = _state->m_eof;
|
||||
int error = src_process( _state->m_resamplingData,
|
||||
&src_data );
|
||||
if( error )
|
||||
{
|
||||
printf( "sampleBuffer: error while resampling: %s\n",
|
||||
src_strerror( error ) );
|
||||
}
|
||||
if( m_srcData.output_frames_gen != _frames )
|
||||
if( src_data.output_frames_gen > _frames )
|
||||
{
|
||||
printf( "sampleBuffer: not enough frames: %ld / %d\n",
|
||||
m_srcData.output_frames_gen, _frames );
|
||||
src_data.output_frames_gen, _frames );
|
||||
}
|
||||
_state->m_eof = src_data.end_of_input;
|
||||
// Advance
|
||||
play_frame += m_srcData.input_frames_used;
|
||||
play_frame += src_data.input_frames_used;
|
||||
if( _looped )
|
||||
{
|
||||
play_frame = getLoopedIndex( play_frame );
|
||||
@@ -684,7 +676,8 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
// as is into pitched-copy-buffer
|
||||
|
||||
// Generate output
|
||||
memcpy( _ab, getSampleFragment( play_frame, _frames, _looped ),
|
||||
memcpy( _ab,
|
||||
getSampleFragment( play_frame, _frames, _looped, &tmp ),
|
||||
_frames * BYTES_PER_FRAME );
|
||||
// Advance
|
||||
play_frame += _frames;
|
||||
@@ -694,7 +687,9 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
}
|
||||
}
|
||||
|
||||
_state->m_frame_index = play_frame;
|
||||
delete[] tmp;
|
||||
|
||||
_state->m_frameIndex = play_frame;
|
||||
|
||||
return( TRUE );
|
||||
|
||||
@@ -704,7 +699,7 @@ bool FASTCALL sampleBuffer::play( sampleFrame * _ab, handleState * _state,
|
||||
|
||||
|
||||
sampleFrame * sampleBuffer::getSampleFragment( f_cnt_t _start,
|
||||
f_cnt_t _frames, bool _looped )
|
||||
f_cnt_t _frames, bool _looped, sampleFrame * * _tmp ) const
|
||||
{
|
||||
if( _looped )
|
||||
{
|
||||
@@ -721,20 +716,17 @@ sampleFrame * sampleBuffer::getSampleFragment( f_cnt_t _start,
|
||||
}
|
||||
}
|
||||
|
||||
delete[] m_sample_fragment;
|
||||
m_sample_fragment = new sampleFrame[_frames];
|
||||
*_tmp = new sampleFrame[_frames];
|
||||
|
||||
if( _looped )
|
||||
{
|
||||
f_cnt_t copied = m_loop_endFrame - _start;
|
||||
memcpy( m_sample_fragment, m_data + _start, copied
|
||||
* BYTES_PER_FRAME );
|
||||
memcpy( *_tmp, m_data + _start, copied * BYTES_PER_FRAME );
|
||||
f_cnt_t loop_frames = m_loop_endFrame - m_loop_startFrame;
|
||||
while( _frames - copied > 0 )
|
||||
{
|
||||
f_cnt_t todo = tMin( _frames - copied, loop_frames );
|
||||
memcpy( m_sample_fragment + copied,
|
||||
m_data + m_loop_startFrame,
|
||||
memcpy( *_tmp + copied, m_data + m_loop_startFrame,
|
||||
todo * BYTES_PER_FRAME );
|
||||
copied += todo;
|
||||
}
|
||||
@@ -742,19 +734,18 @@ sampleFrame * sampleBuffer::getSampleFragment( f_cnt_t _start,
|
||||
else
|
||||
{
|
||||
f_cnt_t available = m_endFrame - _start;
|
||||
memcpy( m_sample_fragment, m_data + _start, available
|
||||
* BYTES_PER_FRAME );
|
||||
memset( m_sample_fragment + available, 0, ( _frames -
|
||||
available ) * BYTES_PER_FRAME );
|
||||
memcpy( *_tmp, m_data + _start, available * BYTES_PER_FRAME );
|
||||
memset( *_tmp + available, 0, ( _frames - available ) *
|
||||
BYTES_PER_FRAME );
|
||||
}
|
||||
|
||||
return( m_sample_fragment );
|
||||
return( *_tmp );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
f_cnt_t sampleBuffer::getLoopedIndex( f_cnt_t _index )
|
||||
f_cnt_t sampleBuffer::getLoopedIndex( f_cnt_t _index ) const
|
||||
{
|
||||
if( _index < m_loop_endFrame )
|
||||
{
|
||||
@@ -1260,11 +1251,12 @@ QString sampleBuffer::tryToMakeAbsolute( const QString & _file )
|
||||
|
||||
|
||||
sampleBuffer::handleState::handleState( bool _varying_pitch ) :
|
||||
m_frame_index( 0 ),
|
||||
m_varying_pitch( _varying_pitch )
|
||||
m_frameIndex( 0 ),
|
||||
m_varyingPitch( _varying_pitch ),
|
||||
m_eof( 0 )
|
||||
{
|
||||
int error;
|
||||
if( ( m_resampling_data = src_new(/*
|
||||
if( ( m_resamplingData = src_new(/*
|
||||
( engine::getMixer()->highQuality() == TRUE ) ?
|
||||
SRC_SINC_FASTEST :*/
|
||||
SRC_LINEAR,
|
||||
@@ -1279,7 +1271,7 @@ sampleBuffer::handleState::handleState( bool _varying_pitch ) :
|
||||
|
||||
sampleBuffer::handleState::~handleState()
|
||||
{
|
||||
src_delete( m_resampling_data );
|
||||
src_delete( m_resamplingData );
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user