From fa67d0b436b56b51362c14079f9133778c6d927f Mon Sep 17 00:00:00 2001 From: Vesa Date: Wed, 23 Apr 2014 12:18:35 +0300 Subject: [PATCH] AFP: Add interpolation selector, fix segfault-causing bug with reverse mode --- include/SampleBuffer.h | 16 +++++-- .../audio_file_processor.cpp | 46 ++++++++++++++++++- .../audio_file_processor.h | 4 +- src/core/SampleBuffer.cpp | 16 ++----- 4 files changed, 65 insertions(+), 17 deletions(-) diff --git a/include/SampleBuffer.h b/include/SampleBuffer.h index f60518d76..dcc4d7499 100644 --- a/include/SampleBuffer.h +++ b/include/SampleBuffer.h @@ -37,12 +37,16 @@ #include "lmms_basics.h" #include "lmms_math.h" #include "shared_object.h" +#include "Mixer.h" class QPainter; - -const f_cnt_t MARGIN = 4; +// values for buffer margins, used for various libsamplerate interpolation modes +// the array positions correspond to the converter_type parameter values in libsamplerate +// if there appears problems with playback on some interpolation mode, then the value for that mode +// may need to be higher - conversely, to optimize, some may work with lower values +const f_cnt_t MARGIN[] = { 64, 64, 64, 4, 4 }; class EXPORT SampleBuffer : public QObject, public sharedObject { @@ -56,7 +60,7 @@ public: class EXPORT handleState { public: - handleState( bool _varying_pitch = false ); + handleState( bool _varying_pitch = false, int interp_mode = SRC_LINEAR ); virtual ~handleState(); inline const f_cnt_t frameIndex() const @@ -78,6 +82,11 @@ public: { m_isBackwards = _backwards; } + + inline int interpMode() const + { + return m_interpMode; + } private: @@ -85,6 +94,7 @@ public: const bool m_varyingPitch; bool m_isBackwards; SRC_STATE * m_resamplingData; + int m_interpMode; friend class SampleBuffer; diff --git a/plugins/audio_file_processor/audio_file_processor.cpp b/plugins/audio_file_processor/audio_file_processor.cpp index 0a885718f..d965d6148 100644 --- a/plugins/audio_file_processor/audio_file_processor.cpp +++ b/plugins/audio_file_processor/audio_file_processor.cpp @@ -29,6 +29,7 @@ #include #include +#include #include "audio_file_processor.h" #include "engine.h" @@ -78,6 +79,7 @@ audioFileProcessor::audioFileProcessor( InstrumentTrack * _instrument_track ) : m_reverseModel( false, this, tr( "Reverse sample" ) ), m_loopModel( 0, 0, 2, this, tr( "Loop mode" ) ), m_stutterModel( false, this, tr( "Stutter" ) ), + m_interpModel( this, tr( "Interpolation mode" ) ), m_nextPlayStartPoint( 0 ), m_nextPlayBackwards( false ) { @@ -93,6 +95,13 @@ audioFileProcessor::audioFileProcessor( InstrumentTrack * _instrument_track ) : this, SLOT( loopPointChanged() ) ); connect( &m_stutterModel, SIGNAL( dataChanged() ), this, SLOT( stutterModelChanged() ) ); + +//interpolation modes + m_interpModel.addItem( tr( "None" ) ); + m_interpModel.addItem( tr( "Linear" ) ); + m_interpModel.addItem( tr( "Sinc" ) ); + m_interpModel.setValue( 1 ); + loopPointChanged(); } @@ -130,7 +139,21 @@ void audioFileProcessor::playNote( NotePlayHandle * _n, m_nextPlayStartPoint = m_sampleBuffer.startFrame(); m_nextPlayBackwards = false; } - _n->m_pluginData = new handleState( _n->hasDetuningInfo() ); + // set interpolation mode for libsamplerate + int srcmode = SRC_LINEAR; + switch( m_interpModel.value() ) + { + case 0: + srcmode = SRC_ZERO_ORDER_HOLD; + break; + case 1: + srcmode = SRC_LINEAR; + break; + case 2: + srcmode = SRC_SINC_MEDIUM_QUALITY; + break; + } + _n->m_pluginData = new handleState( _n->hasDetuningInfo(), srcmode ); ((handleState *)_n->m_pluginData)->setFrameIndex( m_nextPlayStartPoint ); ((handleState *)_n->m_pluginData)->setBackwards( m_nextPlayBackwards ); @@ -197,6 +220,7 @@ void audioFileProcessor::saveSettings( QDomDocument & _doc, m_endPointModel.saveSettings( _doc, _this, "eframe" ); m_loopPointModel.saveSettings( _doc, _this, "lframe" ); m_stutterModel.saveSettings( _doc, _this, "stutter" ); + m_interpModel.saveSettings( _doc, _this, "interp" ); } @@ -214,7 +238,6 @@ void audioFileProcessor::loadSettings( const QDomElement & _this ) m_sampleBuffer.loadFromBase64( _this.attribute( "srcdata" ) ); } - m_reverseModel.loadSettings( _this, "reversed" ); m_loopModel.loadSettings( _this, "looped" ); m_ampModel.loadSettings( _this, "amp" ); m_endPointModel.loadSettings( _this, "eframe" ); @@ -231,7 +254,17 @@ void audioFileProcessor::loadSettings( const QDomElement & _this ) m_startPointModel.setValue( m_loopPointModel.value() ); } + m_reverseModel.loadSettings( _this, "reversed" ); + m_stutterModel.loadSettings( _this, "stutter" ); + if( _this.hasAttribute( "interp" ) ) + { + m_interpModel.loadSettings( _this, "interp" ); + } + else + { + m_interpModel.setValue( 1 ); //linear by default + } loopPointChanged(); } @@ -299,6 +332,8 @@ void audioFileProcessor::setAudioFile( const QString & _audio_file, void audioFileProcessor::reverseModelChanged( void ) { m_sampleBuffer.setReversed( m_reverseModel.value() ); + m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayBackwards = false; } @@ -501,7 +536,12 @@ AudioFileProcessorView::AudioFileProcessorView( Instrument * _instrument, tr( "With this knob you can set the point where " "the loop starts. " ) ); +// interpolation selector + m_interpBox = new comboBox( this ); + m_interpBox->setGeometry( 142, 62, 82, 22 ); + m_interpBox->setFont( pointSize<8>( m_interpBox->font() ) ); +// wavegraph m_waveView = new AudioFileProcessorWaveView( this, 245, 75, castModel()->m_sampleBuffer ); m_waveView->move( 2, 172 ); m_waveView->setKnobs( @@ -652,6 +692,7 @@ void AudioFileProcessorView::modelChanged( void ) m_reverseButton->setModel( &a->m_reverseModel ); m_loopGroup->setModel( &a->m_loopModel ); m_stutterButton->setModel( &a->m_stutterModel ); + m_interpBox->setModel( &a->m_interpModel ); sampleUpdated(); } @@ -668,6 +709,7 @@ AudioFileProcessorWaveView::AudioFileProcessorWaveView( QWidget * _parent, int _ m_last_to( 0 ), m_startKnob( 0 ), m_endKnob( 0 ), + m_loopKnob( 0 ), m_isDragging( false ), m_reversed( false ), m_framesPlayed( 0 ), diff --git a/plugins/audio_file_processor/audio_file_processor.h b/plugins/audio_file_processor/audio_file_processor.h index 1f0558ab5..f795620f6 100644 --- a/plugins/audio_file_processor/audio_file_processor.h +++ b/plugins/audio_file_processor/audio_file_processor.h @@ -35,7 +35,7 @@ #include "knob.h" #include "pixmap_button.h" #include "automatable_button.h" - +#include "combobox.h" class audioFileProcessor : public Instrument @@ -94,6 +94,7 @@ private: BoolModel m_reverseModel; IntModel m_loopModel; BoolModel m_stutterModel; + ComboBoxModel m_interpModel; f_cnt_t m_nextPlayStartPoint; bool m_nextPlayBackwards; @@ -141,6 +142,7 @@ private: pixmapButton * m_reverseButton; automatableButtonGroup * m_loopGroup; pixmapButton * m_stutterButton; + comboBox * m_interpBox; } ; diff --git a/src/core/SampleBuffer.cpp b/src/core/SampleBuffer.cpp index 99c4d69c4..ba86c1443 100644 --- a/src/core/SampleBuffer.cpp +++ b/src/core/SampleBuffer.cpp @@ -24,7 +24,6 @@ #include "SampleBuffer.h" -#include "Mixer.h" #include @@ -664,7 +663,7 @@ bool SampleBuffer::play( sampleFrame * _ab, handleState * _state, { SRC_DATA src_data; // Generate output - f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN; + f_cnt_t fragment_size = (f_cnt_t)( _frames * freq_factor ) + MARGIN[ _state->interpMode() ]; src_data.data_in = getSampleFragment( play_frame, fragment_size, _loopmode, &tmp, &is_backwards, loopStartFrame, loopEndFrame, endFrame )[0]; @@ -1439,22 +1438,17 @@ QString SampleBuffer::tryToMakeAbsolute( const QString & _file ) -SampleBuffer::handleState::handleState( bool _varying_pitch ) : +SampleBuffer::handleState::handleState( bool _varying_pitch, int interp_mode ) : m_frameIndex( 0 ), m_varyingPitch( _varying_pitch ), m_isBackwards( false ) { int error; + m_interpMode = interp_mode; - if( ( m_resamplingData = src_new(/* - ( engine::mixer()->highQuality() == true ) ? - SRC_SINC_FASTEST :*/ - engine::mixer()->currentQualitySettings(). - libsrcInterpolation(), - /*SRC_LINEAR,*/ - DEFAULT_CHANNELS, &error ) ) == NULL ) + if( ( m_resamplingData = src_new( interp_mode, DEFAULT_CHANNELS, &error ) ) == NULL ) { - printf( "Error: src_new() failed in sample_buffer.cpp!\n" ); + qDebug( "Error: src_new() failed in sample_buffer.cpp!\n" ); } }