diff --git a/ChangeLog b/ChangeLog index d1d400f93..d352ad2a7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +2008-03-07 Tobias Doerffel + + * 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 * plugins/sf2_player/sf2_player.h: diff --git a/TODO b/TODO index 4044c17a8..5f2d230f5 100644 --- a/TODO +++ b/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 diff --git a/configure.in b/configure.in index 669327c17..2b179da50 100644 --- a/configure.in +++ b/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" diff --git a/include/sample_buffer.h b/include/sample_buffer.h index b0c947a74..dff5bb712 100644 --- a/include/sample_buffer.h +++ b/include/sample_buffer.h @@ -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: diff --git a/src/lib/sample_buffer.cpp b/src/lib/sample_buffer.cpp index d062ff08f..f984bb89a 100644 --- a/src/lib/sample_buffer.cpp +++ b/src/lib/sample_buffer.cpp @@ -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( ( @@ -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 ); }