diff --git a/plugins/AudioFileProcessor/AudioFileProcessor.cpp b/plugins/AudioFileProcessor/AudioFileProcessor.cpp index a941e773f..24d5694a6 100644 --- a/plugins/AudioFileProcessor/AudioFileProcessor.cpp +++ b/plugins/AudioFileProcessor/AudioFileProcessor.cpp @@ -27,7 +27,6 @@ #include #include #include - #include #include "AudioEngine.h" @@ -40,6 +39,7 @@ #include "NotePlayHandle.h" #include "PathUtil.h" #include "PixmapButton.h" +#include "SampleLoader.h" #include "Song.h" #include "StringPairDrag.h" #include "Clipboard.h" @@ -77,7 +77,7 @@ Plugin::Descriptor PLUGIN_EXPORT audiofileprocessor_plugin_descriptor = AudioFileProcessor::AudioFileProcessor( InstrumentTrack * _instrument_track ) : Instrument( _instrument_track, &audiofileprocessor_plugin_descriptor ), - m_sampleBuffer(), + m_sample(std::make_shared()), m_ampModel( 100, 0, 500, 1, this, tr( "Amplify" ) ), m_startPointModel( 0, 0, 1, 0.0000001f, this, tr( "Start of sample" ) ), m_endPointModel( 1, 0, 1, 0.0000001f, this, tr( "End of sample" ) ), @@ -125,18 +125,18 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n, // played. if( m_stutterModel.value() == true && _n->frequency() < 20.0 ) { - m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayStartPoint = m_sample->startFrame(); m_nextPlayBackwards = false; return; } if( !_n->m_pluginData ) { - if( m_stutterModel.value() == true && m_nextPlayStartPoint >= m_sampleBuffer.endFrame() ) + if (m_stutterModel.value() == true && m_nextPlayStartPoint >= m_sample->endFrame()) { // Restart playing the note if in stutter mode, not in loop mode, // and we're at the end of the sample. - m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayStartPoint = m_sample->startFrame(); m_nextPlayBackwards = false; } // set interpolation mode for libsamplerate @@ -153,28 +153,29 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n, 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 ); + _n->m_pluginData = new Sample::PlaybackState(_n->hasDetuningInfo(), srcmode); + (static_cast(_n->m_pluginData))->setFrameIndex(m_nextPlayStartPoint); + (static_cast(_n->m_pluginData))->setBackwards(m_nextPlayBackwards); // debug code -/* qDebug( "frames %d", m_sampleBuffer.frames() ); - qDebug( "startframe %d", m_sampleBuffer.startFrame() ); +/* qDebug( "frames %d", m_sample->frames() ); + qDebug( "startframe %d", m_sample->startFrame() ); qDebug( "nextPlayStartPoint %d", m_nextPlayStartPoint );*/ } if( ! _n->isFinished() ) { - if( m_sampleBuffer.play( _working_buffer + offset, - (handleState *)_n->m_pluginData, + // TODO C++20: Deprecated, use std::atomic instead + if (std::atomic_load(&m_sample)->play(_working_buffer + offset, + static_cast(_n->m_pluginData), frames, _n->frequency(), - static_cast( m_loopModel.value() ) ) ) + static_cast(m_loopModel.value()))) { applyRelease( _working_buffer, _n ); instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); - emit isPlaying( ((handleState *)_n->m_pluginData)->frameIndex() ); + emit isPlaying((static_cast(_n->m_pluginData)->frameIndex())); } else { @@ -188,8 +189,8 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n, } if( m_stutterModel.value() == true ) { - m_nextPlayStartPoint = ((handleState *)_n->m_pluginData)->frameIndex(); - m_nextPlayBackwards = ((handleState *)_n->m_pluginData)->isBackwards(); + m_nextPlayStartPoint = (static_cast(_n->m_pluginData))->frameIndex(); + m_nextPlayBackwards = (static_cast(_n->m_pluginData)->isBackwards()); } } @@ -198,7 +199,7 @@ void AudioFileProcessor::playNote( NotePlayHandle * _n, void AudioFileProcessor::deleteNotePluginData( NotePlayHandle * _n ) { - delete (handleState *)_n->m_pluginData; + delete static_cast(_n->m_pluginData); } @@ -206,11 +207,10 @@ void AudioFileProcessor::deleteNotePluginData( NotePlayHandle * _n ) void AudioFileProcessor::saveSettings(QDomDocument& doc, QDomElement& elem) { - elem.setAttribute("src", m_sampleBuffer.audioFile()); - if (m_sampleBuffer.audioFile().isEmpty()) + elem.setAttribute("src", m_sample->sampleFile()); + if (m_sample->sampleFile().isEmpty()) { - QString s; - elem.setAttribute("sampledata", m_sampleBuffer.toBase64(s)); + elem.setAttribute("sampledata", m_sample->toBase64()); } m_reverseModel.saveSettings(doc, elem, "reversed"); m_loopModel.saveSettings(doc, elem, "looped"); @@ -231,16 +231,18 @@ void AudioFileProcessor::loadSettings(const QDomElement& elem) { setAudioFile(elem.attribute("src"), false); - QString absolutePath = PathUtil::toAbsolute(m_sampleBuffer.audioFile()); + QString absolutePath = PathUtil::toAbsolute(m_sample->sampleFile()); if (!QFileInfo(absolutePath).exists()) { - QString message = tr("Sample not found: %1").arg(m_sampleBuffer.audioFile()); + QString message = tr("Sample not found: %1").arg(m_sample->sampleFile()); Engine::getSong()->collectError(message); } } else if (!elem.attribute("sampledata").isEmpty()) { - m_sampleBuffer.loadFromBase64(elem.attribute("srcdata")); + auto buffer = gui::SampleLoader::createBufferFromBase64(elem.attribute("srcdata")); + // TODO C++20: Deprecated, use std::atomic instead + std::atomic_store(&m_sample, std::make_shared(std::move(buffer))); } m_loopModel.loadSettings(elem, "looped"); @@ -271,6 +273,7 @@ void AudioFileProcessor::loadSettings(const QDomElement& elem) } pointChanged(); + emit sampleUpdated(); } @@ -298,7 +301,7 @@ int AudioFileProcessor::getBeatLen( NotePlayHandle * _n ) const const float freq_factor = baseFreq / _n->frequency() * Engine::audioEngine()->processingSampleRate() / Engine::audioEngine()->baseSampleRate(); - return static_cast( floorf( ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() ) * freq_factor ) ); + return static_cast(floorf((m_sample->endFrame() - m_sample->startFrame()) * freq_factor)); } @@ -319,16 +322,20 @@ void AudioFileProcessor::setAudioFile( const QString & _audio_file, // is current channel-name equal to previous-filename?? if( _rename && ( instrumentTrack()->name() == - QFileInfo( m_sampleBuffer.audioFile() ).fileName() || - m_sampleBuffer.audioFile().isEmpty() ) ) + QFileInfo(m_sample->sampleFile()).fileName() || + m_sample->sampleFile().isEmpty())) { // then set it to new one instrumentTrack()->setName( PathUtil::cleanName( _audio_file ) ); } // else we don't touch the track-name, because the user named it self - m_sampleBuffer.setAudioFile( _audio_file ); + auto buffer = gui::SampleLoader::createBufferFromFile(_audio_file); + // TODO C++20: Deprecated, use std::atomic instead + std::atomic_store(&m_sample, std::make_shared(std::move(buffer))); + loopPointChanged(); + emit sampleUpdated(); } @@ -336,9 +343,10 @@ void AudioFileProcessor::setAudioFile( const QString & _audio_file, void AudioFileProcessor::reverseModelChanged() { - m_sampleBuffer.setReversed( m_reverseModel.value() ); - m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_sample->setReversed(m_reverseModel.value()); + m_nextPlayStartPoint = m_sample->startFrame(); m_nextPlayBackwards = false; + emit sampleUpdated(); } @@ -346,13 +354,14 @@ void AudioFileProcessor::reverseModelChanged() void AudioFileProcessor::ampModelChanged() { - m_sampleBuffer.setAmplification( m_ampModel.value() / 100.0f ); + m_sample->setAmplification(m_ampModel.value() / 100.0f); + emit sampleUpdated(); } void AudioFileProcessor::stutterModelChanged() { - m_nextPlayStartPoint = m_sampleBuffer.startFrame(); + m_nextPlayStartPoint = m_sample->startFrame(); m_nextPlayBackwards = false; } @@ -421,14 +430,14 @@ void AudioFileProcessor::loopPointChanged() void AudioFileProcessor::pointChanged() { - const auto f_start = static_cast(m_startPointModel.value() * m_sampleBuffer.frames()); - const auto f_end = static_cast(m_endPointModel.value() * m_sampleBuffer.frames()); - const auto f_loop = static_cast(m_loopPointModel.value() * m_sampleBuffer.frames()); + const auto f_start = static_cast(m_startPointModel.value() * m_sample->sampleSize()); + const auto f_end = static_cast(m_endPointModel.value() * m_sample->sampleSize()); + const auto f_loop = static_cast(m_loopPointModel.value() * m_sample->sampleSize()); m_nextPlayStartPoint = f_start; m_nextPlayBackwards = false; - m_sampleBuffer.setAllPointFrames( f_start, f_end, f_loop, f_end ); + m_sample->setAllPointFrames(f_start, f_end, f_loop, f_end); emit dataChanged(); } @@ -596,7 +605,7 @@ void AudioFileProcessorView::newWaveView() delete m_waveView; m_waveView = 0; } - m_waveView = new AudioFileProcessorWaveView( this, 245, 75, castModel()->m_sampleBuffer ); + m_waveView = new AudioFileProcessorWaveView(this, 245, 75, castModel()->m_sample.get()); m_waveView->move( 2, 172 ); m_waveView->setKnobs( dynamic_cast( m_startKnob ), @@ -642,7 +651,8 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * ) auto a = castModel(); QString file_name = ""; - int idx = a->m_sampleBuffer.audioFile().length(); + + int idx = a->m_sample->sampleFile().length(); p.setFont( pointSize<8>( font() ) ); @@ -653,7 +663,7 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * ) while( idx > 0 && fm.size( Qt::TextSingleLine, file_name + "..." ).width() < 210 ) { - file_name = a->m_sampleBuffer.audioFile()[--idx] + file_name; + file_name = a->m_sample->sampleFile()[--idx] + file_name; } if( idx > 0 ) @@ -670,6 +680,7 @@ void AudioFileProcessorView::paintEvent( QPaintEvent * ) void AudioFileProcessorView::sampleUpdated() { + m_waveView->m_sample = castModel()->m_sample.get(); m_waveView->updateSampleRange(); m_waveView->update(); update(); @@ -681,7 +692,7 @@ void AudioFileProcessorView::sampleUpdated() void AudioFileProcessorView::openAudioFile() { - QString af = castModel()->m_sampleBuffer.openAudioFile(); + QString af = SampleLoader::openAudioFile(); if (af.isEmpty()) { return; } castModel()->setAudioFile(af); @@ -695,8 +706,7 @@ void AudioFileProcessorView::openAudioFile() void AudioFileProcessorView::modelChanged() { auto a = castModel(); - connect( &a->m_sampleBuffer, SIGNAL( sampleUpdated() ), - this, SLOT( sampleUpdated() ) ); + connect(a, &AudioFileProcessor::sampleUpdated, this, &AudioFileProcessorView::sampleUpdated); m_ampKnob->setModel( &a->m_ampModel ); m_startKnob->setModel( &a->m_startPointModel ); m_endKnob->setModel( &a->m_endPointModel ); @@ -713,20 +723,20 @@ void AudioFileProcessorView::modelChanged() void AudioFileProcessorWaveView::updateSampleRange() { - if( m_sampleBuffer.frames() > 1 ) + if (m_sample->sampleSize() > 1) { - const f_cnt_t marging = ( m_sampleBuffer.endFrame() - m_sampleBuffer.startFrame() ) * 0.1; - m_from = qMax( 0, m_sampleBuffer.startFrame() - marging ); - m_to = qMin( m_sampleBuffer.endFrame() + marging, m_sampleBuffer.frames() ); + const f_cnt_t marging = (m_sample->endFrame() - m_sample->startFrame()) * 0.1; + m_from = qMax(0, m_sample->startFrame() - marging); + m_to = qMin(m_sample->endFrame() + marging, m_sample->sampleSize()); } } -AudioFileProcessorWaveView::AudioFileProcessorWaveView( QWidget * _parent, int _w, int _h, SampleBuffer& buf ) : +AudioFileProcessorWaveView::AudioFileProcessorWaveView(QWidget * _parent, int _w, int _h, Sample* buf) : QWidget( _parent ), - m_sampleBuffer( buf ), + m_sample(buf), m_graph( QPixmap( _w - 2 * s_padding, _h - 2 * s_padding ) ), m_from( 0 ), - m_to( m_sampleBuffer.frames() ), + m_to(m_sample->sampleSize()), m_last_from( 0 ), m_last_to( 0 ), m_last_amp( 0 ), @@ -874,11 +884,11 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe ) const QRect graph_rect( s_padding, s_padding, width() - 2 * s_padding, height() - 2 * s_padding ); const f_cnt_t frames = m_to - m_from; - m_startFrameX = graph_rect.x() + ( m_sampleBuffer.startFrame() - m_from ) * + m_startFrameX = graph_rect.x() + (m_sample->startFrame() - m_from) * double( graph_rect.width() ) / frames; - m_endFrameX = graph_rect.x() + ( m_sampleBuffer.endFrame() - m_from ) * + m_endFrameX = graph_rect.x() + (m_sample->endFrame() - m_from) * double( graph_rect.width() ) / frames; - m_loopFrameX = graph_rect.x() + ( m_sampleBuffer.loopStartFrame() - m_from ) * + m_loopFrameX = graph_rect.x() + (m_sample->loopStartFrame() - m_from) * double( graph_rect.width() ) / frames; const int played_width_px = ( m_framesPlayed - m_from ) * double( graph_rect.width() ) / frames; @@ -953,7 +963,7 @@ void AudioFileProcessorWaveView::paintEvent( QPaintEvent * _pe ) p.setFont( pointSize<8>( font() ) ); QString length_text; - const int length = m_sampleBuffer.sampleLength(); + const int length = m_sample->sampleDuration(); if( length > 20000 ) { @@ -982,38 +992,38 @@ void AudioFileProcessorWaveView::updateGraph() { if( m_to == 1 ) { - m_to = m_sampleBuffer.frames() * 0.7; + m_to = m_sample->sampleSize() * 0.7; slideSamplePointToFrames( Point::End, m_to * 0.7 ); } - if( m_from > m_sampleBuffer.startFrame() ) + if (m_from > m_sample->startFrame()) { - m_from = m_sampleBuffer.startFrame(); + m_from = m_sample->startFrame(); } - if( m_to < m_sampleBuffer.endFrame() ) + if (m_to < m_sample->endFrame()) { - m_to = m_sampleBuffer.endFrame(); + m_to = m_sample->endFrame(); } - if( m_sampleBuffer.reversed() != m_reversed ) + if (m_sample->reversed() != m_reversed) { reverse(); } - else if( m_last_from == m_from && m_last_to == m_to && m_sampleBuffer.amplification() == m_last_amp ) + else if (m_last_from == m_from && m_last_to == m_to && m_sample->amplification() == m_last_amp) { return; } m_last_from = m_from; m_last_to = m_to; - m_last_amp = m_sampleBuffer.amplification(); + m_last_amp = m_sample->amplification(); m_graph.fill( Qt::transparent ); QPainter p( &m_graph ); p.setPen( QColor( 255, 255, 255 ) ); - m_sampleBuffer.visualize( + m_sample->visualize( p, QRect( 0, 0, m_graph.width(), m_graph.height() ), m_from, m_to @@ -1025,9 +1035,9 @@ void AudioFileProcessorWaveView::updateGraph() void AudioFileProcessorWaveView::zoom( const bool _out ) { - const f_cnt_t start = m_sampleBuffer.startFrame(); - const f_cnt_t end = m_sampleBuffer.endFrame(); - const f_cnt_t frames = m_sampleBuffer.frames(); + const f_cnt_t start = m_sample->startFrame(); + const f_cnt_t end = m_sample->endFrame(); + const f_cnt_t frames = m_sample->sampleSize(); const f_cnt_t d_from = start - m_from; const f_cnt_t d_to = m_to - end; @@ -1060,7 +1070,7 @@ void AudioFileProcessorWaveView::zoom( const bool _out ) ); } - if( double( new_to - new_from ) / m_sampleBuffer.sampleRate() > 0.05 ) + if (static_cast(new_to - new_from) / m_sample->sampleRate() > 0.05) { m_from = new_from; m_to = new_to; @@ -1079,8 +1089,8 @@ void AudioFileProcessorWaveView::slide( int _px ) step = -step; } - f_cnt_t step_from = qBound( 0, m_from + step, m_sampleBuffer.frames() ) - m_from; - f_cnt_t step_to = qBound( m_from + 1, m_to + step, m_sampleBuffer.frames() ) - m_to; + f_cnt_t step_from = qBound(0, m_from + step, m_sample->sampleSize()) - m_from; + f_cnt_t step_to = qBound(m_from + 1, m_to + step, m_sample->sampleSize()) - m_to; step = qAbs( step_from ) < qAbs( step_to ) ? step_from : step_to; @@ -1141,7 +1151,7 @@ void AudioFileProcessorWaveView::slideSamplePointByFrames( Point _point, f_cnt_t } else { - const double v = static_cast( _frames ) / m_sampleBuffer.frames(); + const double v = static_cast(_frames) / m_sample->sampleSize(); if( _slide_to ) { a_knob->slideTo( v ); @@ -1158,11 +1168,11 @@ void AudioFileProcessorWaveView::slideSamplePointByFrames( Point _point, f_cnt_t void AudioFileProcessorWaveView::slideSampleByFrames( f_cnt_t _frames ) { - if( m_sampleBuffer.frames() <= 1 ) + if (m_sample->sampleSize() <= 1) { return; } - const double v = static_cast( _frames ) / m_sampleBuffer.frames(); + const double v = static_cast(_frames) / m_sample->sampleSize(); if( m_startKnob ) { m_startKnob->slideBy( v, false ); } @@ -1180,14 +1190,14 @@ void AudioFileProcessorWaveView::slideSampleByFrames( f_cnt_t _frames ) void AudioFileProcessorWaveView::reverse() { slideSampleByFrames( - m_sampleBuffer.frames() - - m_sampleBuffer.endFrame() - - m_sampleBuffer.startFrame() + m_sample->sampleSize() + - m_sample->endFrame() + - m_sample->startFrame() ); const f_cnt_t from = m_from; - m_from = m_sampleBuffer.frames() - m_to; - m_to = m_sampleBuffer.frames() - from; + m_from = m_sample->sampleSize() - m_to; + m_to = m_sample->sampleSize() - from; m_reversed = ! m_reversed; } @@ -1229,8 +1239,7 @@ void AudioFileProcessorWaveView::knob::slideTo( double _v, bool _check_bound ) float AudioFileProcessorWaveView::knob::getValue( const QPoint & _p ) { const double dec_fact = ! m_waveView ? 1 : - double( m_waveView->m_to - m_waveView->m_from ) - / m_waveView->m_sampleBuffer.frames(); + static_cast(m_waveView->m_to - m_waveView->m_from) / m_waveView->m_sample->sampleSize(); const float inc = Knob::getValue( _p ) * dec_fact; return inc; @@ -1251,12 +1260,12 @@ bool AudioFileProcessorWaveView::knob::checkBound( double _v ) const return false; const double d1 = qAbs( m_relatedKnob->model()->value() - model()->value() ) - * ( m_waveView->m_sampleBuffer.frames() ) - / m_waveView->m_sampleBuffer.sampleRate(); + * (m_waveView->m_sample->sampleSize()) + / m_waveView->m_sample->sampleRate(); const double d2 = qAbs( m_relatedKnob->model()->value() - _v ) - * ( m_waveView->m_sampleBuffer.frames() ) - / m_waveView->m_sampleBuffer.sampleRate(); + * (m_waveView->m_sample->sampleSize()) + / m_waveView->m_sample->sampleRate(); return d1 < d2 || d2 > 0.005; } diff --git a/plugins/AudioFileProcessor/AudioFileProcessor.h b/plugins/AudioFileProcessor/AudioFileProcessor.h index 5fed10862..4397fb39a 100644 --- a/plugins/AudioFileProcessor/AudioFileProcessor.h +++ b/plugins/AudioFileProcessor/AudioFileProcessor.h @@ -31,6 +31,7 @@ #include "ComboBoxModel.h" #include "Instrument.h" #include "InstrumentView.h" +#include "Sample.h" #include "SampleBuffer.h" #include "Knob.h" @@ -93,12 +94,12 @@ private slots: signals: void isPlaying( lmms::f_cnt_t _current_frame ); - + void sampleUpdated(); private: using handleState = SampleBuffer::handleState; - SampleBuffer m_sampleBuffer; + std::shared_ptr m_sample; FloatModel m_ampModel; FloatModel m_startPointModel; @@ -247,7 +248,7 @@ private: SampleLoop } ; - SampleBuffer& m_sampleBuffer; + Sample* m_sample; QPixmap m_graph; f_cnt_t m_from; f_cnt_t m_to; @@ -267,8 +268,10 @@ private: f_cnt_t m_framesPlayed; bool m_animation; + friend class AudioFileProcessorView; + public: - AudioFileProcessorWaveView( QWidget * _parent, int _w, int _h, SampleBuffer& buf ); + AudioFileProcessorWaveView(QWidget * _parent, int _w, int _h, Sample* buf); void setKnobs(knob *_start, knob *_end, knob *_loop );