diff --git a/include/AudioDevice.h b/include/AudioDevice.h index 376aee26be4..7191edc7401 100644 --- a/include/AudioDevice.h +++ b/include/AudioDevice.h @@ -83,18 +83,10 @@ class AudioDevice void processNextBuffer(); - virtual void startProcessing() - { - m_inProcess = true; - } - + virtual void startProcessing(); virtual void stopProcessing(); protected: - // subclasses can re-implement this for being used in conjunction with - // processNextBuffer() - virtual void writeBuffer(const SampleFrame* /* _buf*/, const fpp_t /*_frames*/) {} - // called by according driver for fetching new sound-data fpp_t getNextBuffer(SampleFrame* _ab); @@ -130,12 +122,7 @@ class AudioDevice sample_rate_t m_sampleRate; ch_cnt_t m_channels; AudioEngine* m_audioEngine; - bool m_inProcess; - QMutex m_devMutex; - - SampleFrame* m_buffer; - }; } // namespace lmms diff --git a/include/AudioDummy.h b/include/AudioDummy.h index 607ea40f2f7..20f6eeb613f 100644 --- a/include/AudioDummy.h +++ b/include/AudioDummy.h @@ -94,15 +94,11 @@ class AudioDummy : public QThread, public AudioDevice while( true ) { timer.reset(); - const SampleFrame* b = audioEngine()->nextBuffer(); + const SampleFrame* b = audioEngine()->renderNextBuffer(); if( !b ) { break; } - if( audioEngine()->hasFifoWriter() ) - { - delete[] b; - } const int microseconds = static_cast( audioEngine()->framesPerPeriod() * 1000000.0f / audioEngine()->outputSampleRate() - timer.elapsed() ); if( microseconds > 0 ) diff --git a/include/AudioEngine.h b/include/AudioEngine.h index b22830221d9..91b467041ea 100644 --- a/include/AudioEngine.h +++ b/include/AudioEngine.h @@ -37,7 +37,6 @@ #include "lmms_basics.h" #include "SampleFrame.h" #include "LocklessList.h" -#include "FifoBuffer.h" #include "AudioEngineProfiler.h" #include "PlayHandle.h" @@ -50,11 +49,6 @@ class MidiClient; class AudioPort; class AudioEngineWorkerThread; - -constexpr fpp_t MINIMUM_BUFFER_SIZE = 32; -constexpr fpp_t DEFAULT_BUFFER_SIZE = 256; -constexpr fpp_t MAXIMUM_BUFFER_SIZE = 4096; - constexpr int BYTES_PER_SAMPLE = sizeof(sample_t); constexpr int BYTES_PER_INT_SAMPLE = sizeof(int_sample_t); constexpr int BYTES_PER_FRAME = sizeof(SampleFrame); @@ -65,6 +59,10 @@ class LMMS_EXPORT AudioEngine : public QObject { Q_OBJECT public: + constexpr static auto MinimumBufferSize = 32; + constexpr static auto DefaultBufferSize = 256; + constexpr static auto MaximumBufferSize = 1024; + /** * @brief RAII helper for requestChangesInModel. * Used by AudioEngine::requestChangesGuard. @@ -160,10 +158,7 @@ class LMMS_EXPORT AudioEngine : public QObject //! Set new audio device. Old device will be deleted, //! unless it's stored using storeAudioDevice - void setAudioDevice( AudioDevice * _dev, - const struct qualitySettings & _qs, - bool _needs_fifo, - bool startNow ); + void setAudioDevice(AudioDevice* _dev, const struct qualitySettings& _qs, bool startNow); void storeAudioDevice(); void restoreAudioDevice(); inline AudioDevice * audioDev() @@ -278,11 +273,6 @@ class LMMS_EXPORT AudioEngine : public QObject bool criticalXRuns() const; - inline bool hasFifoWriter() const - { - return m_fifoWriter != nullptr; - } - void pushInputFrames( SampleFrame* _ab, const f_cnt_t _frames ); inline const SampleFrame* inputBuffer() @@ -295,10 +285,7 @@ class LMMS_EXPORT AudioEngine : public QObject return m_inputBufferFrames[ m_inputBufferRead ]; } - inline const SampleFrame* nextBuffer() - { - return hasFifoWriter() ? m_fifo->read() : renderNextBuffer(); - } + const SampleFrame* renderNextBuffer(); void changeQuality(const struct qualitySettings & qs); @@ -322,31 +309,10 @@ class LMMS_EXPORT AudioEngine : public QObject private: - using Fifo = FifoBuffer; - - class fifoWriter : public QThread - { - public: - fifoWriter( AudioEngine * audioEngine, Fifo * fifo ); - - void finish(); - - - private: - AudioEngine * m_audioEngine; - Fifo * m_fifo; - volatile bool m_writing; - - void run() override; - - void write(SampleFrame* buffer); - } ; - - AudioEngine( bool renderOnly ); ~AudioEngine() override; - void startProcessing(bool needsFifo = true); + void startProcessing(); void stopProcessing(); @@ -358,8 +324,6 @@ class LMMS_EXPORT AudioEngine : public QObject void renderStageEffects(); void renderStageMix(); - const SampleFrame* renderNextBuffer(); - void swapBuffers(); void clearInternal(); @@ -405,10 +369,6 @@ class LMMS_EXPORT AudioEngine : public QObject MidiClient * m_midiClient; QString m_midiClientName; - // FIFO stuff - Fifo * m_fifo; - fifoWriter * m_fifoWriter; - AudioEngineProfiler m_profiler; bool m_clearSignal; diff --git a/include/AudioFileDevice.h b/include/AudioFileDevice.h index dc9a786a4a8..0c7beaa27aa 100644 --- a/include/AudioFileDevice.h +++ b/include/AudioFileDevice.h @@ -27,6 +27,7 @@ #define LMMS_AUDIO_FILE_DEVICE_H #include +#include #include "AudioDevice.h" #include "OutputSettings.h" @@ -49,6 +50,8 @@ class AudioFileDevice : public AudioDevice OutputSettings const & getOutputSettings() const { return m_outputSettings; } + void processNextBuffer(); + virtual void writeBuffer(const SampleFrame* buffer, const f_cnt_t frames) = 0; protected: int writeData( const void* data, int len ); @@ -66,6 +69,7 @@ class AudioFileDevice : public AudioDevice private: QFile m_outputFile; OutputSettings m_outputSettings; + std::unique_ptr m_buffer; } ; using AudioFileDeviceInstantiaton diff --git a/include/AudioSampleRecorder.h b/include/AudioSampleRecorder.h index 691196be62c..402cbb8909a 100644 --- a/include/AudioSampleRecorder.h +++ b/include/AudioSampleRecorder.h @@ -48,7 +48,7 @@ class AudioSampleRecorder : public AudioDevice std::shared_ptr createSampleBuffer(); private: - void writeBuffer(const SampleFrame* _ab, const fpp_t _frames) override; + void writeBuffer(const SampleFrame* _ab, const fpp_t _frames); using BufferList = QList>; BufferList m_buffers; diff --git a/plugins/StereoEnhancer/StereoEnhancer.cpp b/plugins/StereoEnhancer/StereoEnhancer.cpp index f0cf830c52e..b9617c55d72 100644 --- a/plugins/StereoEnhancer/StereoEnhancer.cpp +++ b/plugins/StereoEnhancer/StereoEnhancer.cpp @@ -58,7 +58,7 @@ StereoEnhancerEffect::StereoEnhancerEffect( const Descriptor::SubPluginFeatures::Key * _key ) : Effect( &stereoenhancer_plugin_descriptor, _parent, _key ), m_seFX( DspEffectLibrary::StereoEnhancer( 0.0f ) ), - m_delayBuffer( new SampleFrame[DEFAULT_BUFFER_SIZE] ), + m_delayBuffer(Engine::audioEngine()->framesPerPeriod()), m_currFrame( 0 ), m_bbControls( this ) { @@ -71,11 +71,6 @@ StereoEnhancerEffect::StereoEnhancerEffect( StereoEnhancerEffect::~StereoEnhancerEffect() { - if( m_delayBuffer ) - { - delete [] m_delayBuffer; - } - m_currFrame = 0; } @@ -103,7 +98,7 @@ Effect::ProcessStatus StereoEnhancerEffect::processImpl(SampleFrame* buf, const if( frameIndex < 0 ) { // e.g. difference = -10, frameIndex = DBS - 10 - frameIndex += DEFAULT_BUFFER_SIZE; + frameIndex += m_delayBuffer.size(); } //sample_t s[2] = { buf[f][0], buf[f][1] }; //Vanilla @@ -116,7 +111,7 @@ Effect::ProcessStatus StereoEnhancerEffect::processImpl(SampleFrame* buf, const // Update currFrame m_currFrame += 1; - m_currFrame %= DEFAULT_BUFFER_SIZE; + m_currFrame %= m_delayBuffer.size(); } if( !isRunning() ) @@ -132,7 +127,7 @@ Effect::ProcessStatus StereoEnhancerEffect::processImpl(SampleFrame* buf, const void StereoEnhancerEffect::clearMyBuffer() { - for (auto i = std::size_t{0}; i < DEFAULT_BUFFER_SIZE; i++) + for (auto i = std::size_t{0}; i < m_delayBuffer.size(); i++) { m_delayBuffer[i][0] = 0.0f; m_delayBuffer[i][1] = 0.0f; diff --git a/plugins/StereoEnhancer/StereoEnhancer.h b/plugins/StereoEnhancer/StereoEnhancer.h index 3e27330add1..fcfcd1066b3 100644 --- a/plugins/StereoEnhancer/StereoEnhancer.h +++ b/plugins/StereoEnhancer/StereoEnhancer.h @@ -54,7 +54,7 @@ class StereoEnhancerEffect : public Effect private: DspEffectLibrary::StereoEnhancer m_seFX; - SampleFrame* m_delayBuffer; + std::vector m_delayBuffer; int m_currFrame; StereoEnhancerControls m_bbControls; diff --git a/plugins/VstEffect/VstEffect.cpp b/plugins/VstEffect/VstEffect.cpp index 53de4f4cc59..a9b7e874a19 100644 --- a/plugins/VstEffect/VstEffect.cpp +++ b/plugins/VstEffect/VstEffect.cpp @@ -82,7 +82,7 @@ VstEffect::VstEffect( Model * _parent, Effect::ProcessStatus VstEffect::processImpl(SampleFrame* buf, const fpp_t frames) { assert(m_plugin != nullptr); - static thread_local auto tempBuf = std::array(); + static thread_local auto tempBuf = std::array(); std::memcpy(tempBuf.data(), buf, sizeof(SampleFrame) * frames); if (m_pluginMutex.tryLock(Engine::getSong()->isExporting() ? -1 : 0)) diff --git a/src/core/AudioEngine.cpp b/src/core/AudioEngine.cpp index 435fa38fa56..5206fa3d05f 100644 --- a/src/core/AudioEngine.cpp +++ b/src/core/AudioEngine.cpp @@ -25,7 +25,6 @@ #include "AudioEngine.h" #include "MixHelpers.h" -#include "denormals.h" #include "lmmsconfig.h" @@ -73,7 +72,9 @@ static thread_local bool s_renderingThread = false; AudioEngine::AudioEngine( bool renderOnly ) : m_renderOnly( renderOnly ), - m_framesPerPeriod( DEFAULT_BUFFER_SIZE ), + m_framesPerPeriod(std::clamp(ConfigManager::inst() + ->value("audioengine", "framesperaudiobuffer", QString::number(AudioEngine::DefaultBufferSize)) + .toInt(), AudioEngine::MinimumBufferSize, AudioEngine::MaximumBufferSize)), m_baseSampleRate(std::max(ConfigManager::inst()->value("audioengine", "samplerate").toInt(), 44100)), m_inputBufferRead( 0 ), m_inputBufferWrite( 1 ), @@ -93,52 +94,17 @@ AudioEngine::AudioEngine( bool renderOnly ) : for( int i = 0; i < 2; ++i ) { m_inputBufferFrames[i] = 0; - m_inputBufferSize[i] = DEFAULT_BUFFER_SIZE * 100; - m_inputBuffer[i] = new SampleFrame[ DEFAULT_BUFFER_SIZE * 100 ]; + m_inputBufferSize[i] = m_framesPerPeriod * 100; + m_inputBuffer[i] = new SampleFrame[m_framesPerPeriod * 100]; zeroSampleFrames(m_inputBuffer[i], m_inputBufferSize[i]); } - // determine FIFO size and number of frames per period - int fifoSize = 1; - - // if not only rendering (that is, using the GUI), load the buffer - // size from user configuration - if( renderOnly == false ) - { - m_framesPerPeriod = - ( fpp_t ) ConfigManager::inst()->value( "audioengine", "framesperaudiobuffer" ).toInt(); - - // if the value read from user configuration is not set or - // lower than the minimum allowed, use the default value and - // save it to the configuration - if( m_framesPerPeriod < MINIMUM_BUFFER_SIZE ) - { - ConfigManager::inst()->setValue( "audioengine", - "framesperaudiobuffer", - QString::number( DEFAULT_BUFFER_SIZE ) ); - - m_framesPerPeriod = DEFAULT_BUFFER_SIZE; - } - // lmms works with chunks of size DEFAULT_BUFFER_SIZE (256) and only the final mix will use the actual - // buffer size. Plugins don't see a larger buffer size than 256. If m_framesPerPeriod is larger than - // DEFAULT_BUFFER_SIZE, it's set to DEFAULT_BUFFER_SIZE and the rest is handled by an increased fifoSize. - else if( m_framesPerPeriod > DEFAULT_BUFFER_SIZE ) - { - fifoSize = m_framesPerPeriod / DEFAULT_BUFFER_SIZE; - m_framesPerPeriod = DEFAULT_BUFFER_SIZE; - } - } - - // allocte the FIFO from the determined size - m_fifo = new Fifo( fifoSize ); - // now that framesPerPeriod is fixed initialize global BufferManager BufferManager::init( m_framesPerPeriod ); m_outputBufferRead = std::make_unique(m_framesPerPeriod); m_outputBufferWrite = std::make_unique(m_framesPerPeriod); - for( int i = 0; i < m_numWorkers+1; ++i ) { auto wt = new AudioEngineWorkerThread(this); @@ -167,12 +133,6 @@ AudioEngine::~AudioEngine() m_workers[w]->wait( 500 ); } - while( m_fifo->available() ) - { - delete[] m_fifo->read(); - } - delete m_fifo; - delete m_midiClient; delete m_audioDev; @@ -205,18 +165,8 @@ void AudioEngine::initDevices() -void AudioEngine::startProcessing(bool needsFifo) +void AudioEngine::startProcessing() { - if (needsFifo) - { - m_fifoWriter = new fifoWriter( this, m_fifo ); - m_fifoWriter->start( QThread::HighPriority ); - } - else - { - m_fifoWriter = nullptr; - } - m_audioDev->startProcessing(); } @@ -225,18 +175,7 @@ void AudioEngine::startProcessing(bool needsFifo) void AudioEngine::stopProcessing() { - if( m_fifoWriter != nullptr ) - { - m_fifoWriter->finish(); - m_fifoWriter->wait(); - m_audioDev->stopProcessing(); - delete m_fifoWriter; - m_fifoWriter = nullptr; - } - else - { - m_audioDev->stopProcessing(); - } + m_audioDev->stopProcessing(); } @@ -504,13 +443,7 @@ void AudioEngine::doSetAudioDevice( AudioDevice * _dev ) } } - - - -void AudioEngine::setAudioDevice(AudioDevice * _dev, - const struct qualitySettings & _qs, - bool _needs_fifo, - bool startNow) +void AudioEngine::setAudioDevice(AudioDevice* _dev, const struct qualitySettings& _qs, bool startNow) { stopProcessing(); @@ -521,7 +454,7 @@ void AudioEngine::setAudioDevice(AudioDevice * _dev, emit qualitySettingsChanged(); emit sampleRateChanged(); - if (startNow) {startProcessing( _needs_fifo );} + if (startNow) { startProcessing(); } } @@ -1072,50 +1005,4 @@ MidiClient * AudioEngine::tryMidiClients() return new MidiDummy; } - - - - - - - - - -AudioEngine::fifoWriter::fifoWriter( AudioEngine* audioEngine, Fifo * fifo ) : - m_audioEngine( audioEngine ), - m_fifo( fifo ), - m_writing( true ) -{ - setObjectName("AudioEngine::fifoWriter"); -} - - - - -void AudioEngine::fifoWriter::finish() -{ - m_writing = false; -} - - - - -void AudioEngine::fifoWriter::run() -{ - disable_denormals(); - - const fpp_t frames = m_audioEngine->framesPerPeriod(); - while( m_writing ) - { - auto buffer = new SampleFrame[frames]; - const SampleFrame* b = m_audioEngine->renderNextBuffer(); - memcpy(buffer, b, frames * sizeof(SampleFrame)); - m_fifo->write(buffer); - } - - // Let audio backend stop processing - m_fifo->write(nullptr); - m_fifo->waitUntilRead(); -} - } // namespace lmms diff --git a/src/core/ProjectRenderer.cpp b/src/core/ProjectRenderer.cpp index e5410e6f272..af00b6e5ca8 100644 --- a/src/core/ProjectRenderer.cpp +++ b/src/core/ProjectRenderer.cpp @@ -145,7 +145,7 @@ void ProjectRenderer::startProcessing() { // Have to do audio engine stuff with GUI-thread affinity in order to // make slots connected to sampleRateChanged()-signals being called immediately. - Engine::audioEngine()->setAudioDevice( m_fileDev, m_qualitySettings, false, false ); + Engine::audioEngine()->setAudioDevice(m_fileDev, m_qualitySettings, false); start( #ifndef LMMS_BUILD_WIN32 @@ -163,12 +163,12 @@ void ProjectRenderer::run() Engine::getSong()->startExport(); // Skip first empty buffer. - Engine::audioEngine()->nextBuffer(); + Engine::audioEngine()->renderNextBuffer(); m_progress = 0; // Now start processing - Engine::audioEngine()->startProcessing(false); + Engine::audioEngine()->startProcessing(); // Continually track and emit progress percentage to listeners. while (!Engine::getSong()->isExportDone() && !m_abort) diff --git a/src/core/audio/AudioDevice.cpp b/src/core/audio/AudioDevice.cpp index 2047fffe98b..f16a64a07c1 100644 --- a/src/core/audio/AudioDevice.cpp +++ b/src/core/audio/AudioDevice.cpp @@ -36,8 +36,7 @@ AudioDevice::AudioDevice( const ch_cnt_t _channels, AudioEngine* _audioEngine ) m_supportsCapture( false ), m_sampleRate( _audioEngine->outputSampleRate() ), m_channels( _channels ), - m_audioEngine( _audioEngine ), - m_buffer(new SampleFrame[audioEngine()->framesPerPeriod()]) + m_audioEngine( _audioEngine ) { } @@ -46,49 +45,30 @@ AudioDevice::AudioDevice( const ch_cnt_t _channels, AudioEngine* _audioEngine ) AudioDevice::~AudioDevice() { - delete[] m_buffer; m_devMutex.tryLock(); unlock(); } - - - -void AudioDevice::processNextBuffer() -{ - const fpp_t frames = getNextBuffer( m_buffer ); - if (frames) { writeBuffer(m_buffer, frames); } - else - { - m_inProcess = false; - } -} - fpp_t AudioDevice::getNextBuffer(SampleFrame* _ab) { fpp_t frames = audioEngine()->framesPerPeriod(); - const SampleFrame* b = audioEngine()->nextBuffer(); + const SampleFrame* b = audioEngine()->renderNextBuffer(); if (!b) { return 0; } memcpy(_ab, b, frames * sizeof(SampleFrame)); - if (audioEngine()->hasFifoWriter()) { delete[] b; } return frames; } +void AudioDevice::startProcessing() +{ +} void AudioDevice::stopProcessing() { - if( audioEngine()->hasFifoWriter() ) - { - while( m_inProcess ) - { - processNextBuffer(); - } - } } diff --git a/src/core/audio/AudioFileDevice.cpp b/src/core/audio/AudioFileDevice.cpp index f80d4a00f91..12019f44689 100644 --- a/src/core/audio/AudioFileDevice.cpp +++ b/src/core/audio/AudioFileDevice.cpp @@ -38,7 +38,8 @@ AudioFileDevice::AudioFileDevice( OutputSettings const & outputSettings, AudioEngine* _audioEngine ) : AudioDevice( _channels, _audioEngine ), m_outputFile( _file ), - m_outputSettings(outputSettings) + m_outputSettings(outputSettings), + m_buffer(std::make_unique(_audioEngine->framesPerPeriod())) { using gui::ExportProjectDialog; @@ -91,4 +92,12 @@ int AudioFileDevice::writeData( const void* data, int len ) return -1; } +void AudioFileDevice::processNextBuffer() +{ + if (const auto frames = getNextBuffer(m_buffer.get()); frames > 0) + { + writeBuffer(m_buffer.get(), frames); + } +} + } // namespace lmms diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 8f533119c8a..d88ab6bb00d 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -63,7 +63,7 @@ AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) : // to convert the buffers m_audioHandle.channels = channels(); - m_audioHandle.samples = std::max(f_cnt_t{1024}, audioEngine()->framesPerPeriod() * 2); + m_audioHandle.samples = audioEngine()->framesPerPeriod(); m_audioHandle.callback = sdlAudioCallback; m_audioHandle.userdata = this; diff --git a/src/gui/modals/SetupDialog.cpp b/src/gui/modals/SetupDialog.cpp index d71ede03f53..e30fbedc9fa 100644 --- a/src/gui/modals/SetupDialog.cpp +++ b/src/gui/modals/SetupDialog.cpp @@ -564,7 +564,7 @@ SetupDialog::SetupDialog(ConfigTab tab_to_open) : QHBoxLayout * bufferSizeSubLayout = new QHBoxLayout(); m_bufferSizeSlider = new QSlider(Qt::Horizontal, bufferSizeBox); - m_bufferSizeSlider->setRange(1, MAXIMUM_BUFFER_SIZE / BUFFERSIZE_RESOLUTION); + m_bufferSizeSlider->setRange(1, AudioEngine::MaximumBufferSize / AudioEngine::MinimumBufferSize); m_bufferSizeSlider->setTickInterval(8); m_bufferSizeSlider->setPageStep(8); m_bufferSizeSlider->setValue(m_bufferSize / BUFFERSIZE_RESOLUTION); @@ -1201,7 +1201,7 @@ void SetupDialog::updateBufferSizeWarning(int value) void SetupDialog::setBufferSize(int value) { - const int step = DEFAULT_BUFFER_SIZE / BUFFERSIZE_RESOLUTION; + const int step = AudioEngine::DefaultBufferSize / BUFFERSIZE_RESOLUTION; if(value > step && value % step) { int mod_value = value % step; @@ -1230,7 +1230,7 @@ void SetupDialog::setBufferSize(int value) void SetupDialog::resetBufferSize() { - setBufferSize(DEFAULT_BUFFER_SIZE / BUFFERSIZE_RESOLUTION); + setBufferSize(AudioEngine::DefaultBufferSize / BUFFERSIZE_RESOLUTION); }