diff --git a/include/AudioAlsa.h b/include/AudioAlsa.h index 92c47a6aceb..c5ab1eb244f 100644 --- a/include/AudioAlsa.h +++ b/include/AudioAlsa.h @@ -100,6 +100,7 @@ class AudioAlsa : public QThread, public AudioDevice snd_pcm_sw_params_t * m_swParams; bool m_convertEndian; + std::atomic m_stopped; } ; diff --git a/include/AudioDevice.h b/include/AudioDevice.h index 376aee26be4..91634ff181b 100644 --- a/include/AudioDevice.h +++ b/include/AudioDevice.h @@ -81,23 +81,10 @@ class AudioDevice return m_channels; } - 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); - // convert a given audio-buffer to a buffer in signed 16-bit samples // returns num of bytes in outbuf int convertToS16(const SampleFrame* _ab, @@ -130,12 +117,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..f0b08676314 100644 --- a/include/AudioDummy.h +++ b/include/AudioDummy.h @@ -80,30 +80,23 @@ class AudioDummy : public QThread, public AudioDevice private: void startProcessing() override { + m_stopped = false; start(); } void stopProcessing() override { + m_stopped = true; stopProcessingThread( this ); } void run() override { MicroTimer timer; - while( true ) + while (!m_stopped) { + audioEngine()->renderNextBuffer(); timer.reset(); - const SampleFrame* b = audioEngine()->nextBuffer(); - if( !b ) - { - break; - } - if( audioEngine()->hasFifoWriter() ) - { - delete[] b; - } - const int microseconds = static_cast( audioEngine()->framesPerPeriod() * 1000000.0f / audioEngine()->outputSampleRate() - timer.elapsed() ); if( microseconds > 0 ) { @@ -112,6 +105,7 @@ class AudioDummy : public QThread, public AudioDevice } } + std::atomic m_stopped; } ; } // namespace lmms diff --git a/include/AudioEngine.h b/include/AudioEngine.h index b22830221d9..1e0f01b5246 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" @@ -160,10 +159,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() @@ -214,6 +210,7 @@ class LMMS_EXPORT AudioEngine : public QObject return m_framesPerPeriod; } + fpp_t userFramesPerPeriod() const { return m_userFramesPerPeriod; } AudioEngineProfiler& profiler() { @@ -278,11 +275,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 +287,8 @@ 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 renderNextBufferChunked(SampleFrame* dst, std::size_t size); void changeQuality(const struct qualitySettings & qs); @@ -322,31 +312,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 +327,6 @@ class LMMS_EXPORT AudioEngine : public QObject void renderStageEffects(); void renderStageMix(); - const SampleFrame* renderNextBuffer(); - void swapBuffers(); void clearInternal(); @@ -369,6 +336,7 @@ class LMMS_EXPORT AudioEngine : public QObject std::vector m_audioPorts; fpp_t m_framesPerPeriod; + fpp_t m_userFramesPerPeriod; SampleFrame* m_inputBuffer[2]; f_cnt_t m_inputBufferFrames[2]; @@ -405,10 +373,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..41ef64ae920 100644 --- a/include/AudioFileDevice.h +++ b/include/AudioFileDevice.h @@ -49,6 +49,7 @@ class AudioFileDevice : public AudioDevice OutputSettings const & getOutputSettings() const { return m_outputSettings; } + virtual void writeBuffer(const SampleFrame* buf, const fpp_t frames) = 0; protected: int writeData( const void* data, int len ); diff --git a/include/AudioJack.h b/include/AudioJack.h index 234f6ebf234..e131b6c1cd6 100644 --- a/include/AudioJack.h +++ b/include/AudioJack.h @@ -110,11 +110,6 @@ private slots: std::atomic m_midiClient; std::vector m_outputPorts; - jack_default_audio_sample_t** m_tempOutBufs; - SampleFrame* m_outBuf; - - f_cnt_t m_framesDoneInCurBuf; - f_cnt_t m_framesToDoInCurBuf; #ifdef AUDIO_PORT_SUPPORT struct StereoPort diff --git a/include/AudioOss.h b/include/AudioOss.h index 91d45607344..8fe81bcc427 100644 --- a/include/AudioOss.h +++ b/include/AudioOss.h @@ -84,6 +84,7 @@ class setupWidget : public gui::AudioDeviceSetupWidget int m_audioFD; bool m_convertEndian; + std::atomic m_stopped; } ; diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index fbfa9b60dd6..554fbc769e2 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -145,11 +145,6 @@ class AudioPortAudio : public AudioDevice PaStreamParameters m_inputParameters; bool m_wasPAInitError; - - SampleFrame* m_outBuf; - std::size_t m_outBufPos; - fpp_t m_outBufSize; - bool m_stopped; } ; diff --git a/include/AudioPulseAudio.h b/include/AudioPulseAudio.h index db3c566bf53..b080f556350 100644 --- a/include/AudioPulseAudio.h +++ b/include/AudioPulseAudio.h @@ -90,11 +90,12 @@ class AudioPulseAudio : public QThread, public AudioDevice void stopProcessing() override; void run() override; - volatile bool m_quit; - bool m_convertEndian; bool m_connected; + + std::atomic m_stopped; + QSemaphore m_connectedSemaphore; } ; 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/include/AudioSdl.h b/include/AudioSdl.h index 651ed96be57..4c79c4b1a70 100644 --- a/include/AudioSdl.h +++ b/include/AudioSdl.h @@ -84,8 +84,6 @@ class AudioSdl : public AudioDevice SDL_AudioSpec m_audioHandle; - SampleFrame* m_outBuf; - size_t m_currentBufferFramePos; size_t m_currentBufferFramesCount; diff --git a/include/AudioSndio.h b/include/AudioSndio.h index beb4913eb4b..6088c64bf17 100644 --- a/include/AudioSndio.h +++ b/include/AudioSndio.h @@ -81,6 +81,7 @@ class AudioSndio : public QThread, public AudioDevice struct sio_par m_par; bool m_convertEndian; + std::atomic m_stopped; } ; diff --git a/include/AudioSoundIo.h b/include/AudioSoundIo.h index 1260951bffc..4115ffd3362 100644 --- a/include/AudioSoundIo.h +++ b/include/AudioSoundIo.h @@ -110,11 +110,6 @@ class AudioSoundIo : public AudioDevice SoundIo *m_soundio; SoundIoOutStream *m_outstream; - SampleFrame* m_outBuf; - int m_outBufSize; - fpp_t m_outBufFramesTotal; - fpp_t m_outBufFrameIndex; - bool m_stopped; bool m_outstreamStarted; diff --git a/src/core/AudioEngine.cpp b/src/core/AudioEngine.cpp index 435fa38fa56..982f0bd5790 100644 --- a/src/core/AudioEngine.cpp +++ b/src/core/AudioEngine.cpp @@ -74,6 +74,7 @@ static thread_local bool s_renderingThread = false; AudioEngine::AudioEngine( bool renderOnly ) : m_renderOnly( renderOnly ), m_framesPerPeriod( DEFAULT_BUFFER_SIZE ), + m_userFramesPerPeriod(ConfigManager::inst()->value("audioengine", "framesperaudiobuffer").toInt()), m_baseSampleRate(std::max(ConfigManager::inst()->value("audioengine", "samplerate").toInt(), 44100)), m_inputBufferRead( 0 ), m_inputBufferWrite( 1 ), @@ -98,40 +99,6 @@ AudioEngine::AudioEngine( bool renderOnly ) : 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 ); @@ -167,12 +134,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 +166,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 +176,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(); } @@ -416,7 +356,23 @@ const SampleFrame* AudioEngine::renderNextBuffer() return m_outputBufferRead.get(); } +void AudioEngine::renderNextBufferChunked(SampleFrame* dst, std::size_t size) +{ + static auto buffer = static_cast(nullptr); + static auto index = 0; + + auto framesCopied = std::size_t{0}; + while (framesCopied != size) + { + if (index == 0) { buffer = renderNextBuffer(); } + const auto numFramesToCopy = std::min(m_framesPerPeriod - index, size - framesCopied); + std::copy_n(buffer + index, numFramesToCopy, dst + framesCopied); + + framesCopied += numFramesToCopy; + index = (index + numFramesToCopy) % m_framesPerPeriod; + } +} void AudioEngine::swapBuffers() @@ -504,13 +460,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 +471,7 @@ void AudioEngine::setAudioDevice(AudioDevice * _dev, emit qualitySettingsChanged(); emit sampleRateChanged(); - if (startNow) {startProcessing( _needs_fifo );} + if (startNow) { startProcessing(); } } @@ -1073,49 +1023,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 c56c34068b4..cdb3f1d3920 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,17 +163,20 @@ 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) { - m_fileDev->processNextBuffer(); + const auto buffer = Engine::audioEngine()->renderNextBuffer(); + const auto framesPerPeriod = Engine::audioEngine()->framesPerPeriod(); + m_fileDev->writeBuffer(buffer, framesPerPeriod); + const int nprog = Engine::getSong()->getExportProgress(); if (m_progress != nprog) { diff --git a/src/core/audio/AudioAlsa.cpp b/src/core/audio/AudioAlsa.cpp index c41703e2271..9d807271870 100644 --- a/src/core/audio/AudioAlsa.cpp +++ b/src/core/audio/AudioAlsa.cpp @@ -228,6 +228,7 @@ void AudioAlsa::startProcessing() { if( !isRunning() ) { + m_stopped = false; start( QThread::HighPriority ); } } @@ -237,79 +238,25 @@ void AudioAlsa::startProcessing() void AudioAlsa::stopProcessing() { + m_stopped = true; stopProcessingThread( this ); } void AudioAlsa::run() { - auto temp = new SampleFrame[audioEngine()->framesPerPeriod()]; - auto outbuf = new int_sample_t[audioEngine()->framesPerPeriod() * channels()]; - auto pcmbuf = new int_sample_t[m_periodSize * channels()]; + static auto buf = std::vector(m_periodSize); + static auto outbuf = std::vector(buf.size() * channels()); - int outbuf_size = audioEngine()->framesPerPeriod() * channels(); - int outbuf_pos = 0; - int pcmbuf_size = m_periodSize * channels(); - - bool quit = false; - while( quit == false ) + while (true) { - int_sample_t * ptr = pcmbuf; - int len = pcmbuf_size; - while( len ) - { - if( outbuf_pos == 0 ) - { - // frames depend on the sample rate - const fpp_t frames = getNextBuffer( temp ); - if( !frames ) - { - quit = true; - memset( ptr, 0, len - * sizeof( int_sample_t ) ); - break; - } - outbuf_size = frames * channels(); - - convertToS16(temp, frames, outbuf, m_convertEndian); - } - int min_len = std::min(len, outbuf_size - outbuf_pos); - memcpy( ptr, outbuf + outbuf_pos, - min_len * sizeof( int_sample_t ) ); - ptr += min_len; - len -= min_len; - outbuf_pos += min_len; - outbuf_pos %= outbuf_size; - } + if (m_stopped) { break; } - f_cnt_t frames = m_periodSize; - ptr = pcmbuf; + audioEngine()->renderNextBufferChunked(buf.data(), buf.size()); + convertToS16(buf.data(), buf.size(), outbuf.data(), m_convertEndian); - while( frames ) - { - int err = snd_pcm_writei( m_handle, ptr, frames ); - - if( err == -EAGAIN ) - { - continue; - } - - if( err < 0 ) - { - if( handleError( err ) < 0 ) - { - printf( "Write error: %s\n", - snd_strerror( err ) ); - } - break; // skip this buffer - } - ptr += err * channels(); - frames -= err; - } + const auto err = snd_pcm_writei(m_handle, outbuf.data(), buf.size()); + if (handleError(err) < 0) { printf("Write error: %s\n", snd_strerror(err)); } } - - delete[] temp; - delete[] outbuf; - delete[] pcmbuf; } @@ -369,7 +316,7 @@ int AudioAlsa::setHWParams( const ch_cnt_t _channels, snd_pcm_access_t _access ) } } - m_periodSize = audioEngine()->framesPerPeriod(); + m_periodSize = audioEngine()->userFramesPerPeriod(); m_bufferSize = m_periodSize * 8; int dir; if (int err = snd_pcm_hw_params_set_period_size_near(m_handle, m_hwParams, &m_periodSize, &dir); err < 0) diff --git a/src/core/audio/AudioDevice.cpp b/src/core/audio/AudioDevice.cpp index 2047fffe98b..2b05092ec00 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,17 @@ AudioDevice::AudioDevice( const ch_cnt_t _channels, AudioEngine* _audioEngine ) AudioDevice::~AudioDevice() { - delete[] m_buffer; m_devMutex.tryLock(); unlock(); } - - -void AudioDevice::processNextBuffer() +void AudioDevice::startProcessing() { - 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(); - - if (!b) { return 0; } - - memcpy(_ab, b, frames * sizeof(SampleFrame)); - - if (audioEngine()->hasFifoWriter()) { delete[] b; } - return frames; } - - - void AudioDevice::stopProcessing() { - if( audioEngine()->hasFifoWriter() ) - { - while( m_inProcess ) - { - processNextBuffer(); - } - } } diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index bd5b8e514de..d002bc8a348 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -55,10 +55,6 @@ AudioJack::AudioJack(bool& successful, AudioEngine* audioEngineParam) , m_client(nullptr) , m_active(false) , m_midiClient(nullptr) - , m_tempOutBufs(new jack_default_audio_sample_t*[channels()]) - , m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()]) - , m_framesDoneInCurBuf(0) - , m_framesToDoInCurBuf(0) { m_stopped = true; @@ -86,10 +82,6 @@ AudioJack::~AudioJack() if (m_active) { jack_deactivate(m_client); } jack_client_close(m_client); } - - delete[] m_tempOutBufs; - - delete[] m_outBuf; } @@ -299,11 +291,6 @@ int AudioJack::processCallback(jack_nframes_t nframes) m_midiClient.load()->JackMidiWrite(nframes); } - for (int c = 0; c < channels(); ++c) - { - m_tempOutBufs[c] = (jack_default_audio_sample_t*)jack_port_get_buffer(m_outputPorts[c], nframes); - } - #ifdef AUDIO_PORT_SUPPORT const int frames = std::min(nframes, audioEngine()->framesPerPeriod()); for (JackPortMap::iterator it = m_portMap.begin(); it != m_portMap.end(); ++it) @@ -321,38 +308,26 @@ int AudioJack::processCallback(jack_nframes_t nframes) } #endif - jack_nframes_t done = 0; - while (done < nframes && !m_stopped) + if (m_stopped) { - jack_nframes_t todo = std::min(nframes - done, m_framesToDoInCurBuf - m_framesDoneInCurBuf); for (int c = 0; c < channels(); ++c) { - jack_default_audio_sample_t* o = m_tempOutBufs[c]; - for (jack_nframes_t frame = 0; frame < todo; ++frame) - { - o[done + frame] = m_outBuf[m_framesDoneInCurBuf + frame][c]; - } - } - done += todo; - m_framesDoneInCurBuf += todo; - if (m_framesDoneInCurBuf == m_framesToDoInCurBuf) - { - m_framesToDoInCurBuf = getNextBuffer(m_outBuf); - m_framesDoneInCurBuf = 0; - if (!m_framesToDoInCurBuf) - { - m_stopped = true; - break; - } + auto o = static_cast(jack_port_get_buffer(m_outputPorts[c], nframes)); + memset(o, 0, nframes); } + + return 0; } - if (nframes != done) + static auto buf = std::vector(nframes); + audioEngine()->renderNextBufferChunked(buf.data(), buf.size()); + + for (int c = 0; c < channels(); ++c) { - for (int c = 0; c < channels(); ++c) + auto o = static_cast(jack_port_get_buffer(m_outputPorts[c], nframes)); + for (jack_nframes_t frame = 0; frame < nframes; ++frame) { - jack_default_audio_sample_t* b = m_tempOutBufs[c] + done; - memset(b, 0, sizeof(*b) * (nframes - done)); + o[frame] = buf[frame][c]; } } diff --git a/src/core/audio/AudioOss.cpp b/src/core/audio/AudioOss.cpp index bd427523520..b594186e924 100644 --- a/src/core/audio/AudioOss.cpp +++ b/src/core/audio/AudioOss.cpp @@ -100,7 +100,7 @@ AudioOss::AudioOss( bool & _success_ful, AudioEngine* _audioEngine ) : int frag_spec; for (frag_spec = 0; - 1u << frag_spec < audioEngine()->framesPerPeriod() * channels() * BYTES_PER_INT_SAMPLE; + 1u << frag_spec < audioEngine()->userFramesPerPeriod() * channels() * BYTES_PER_INT_SAMPLE; ++frag_spec) { } @@ -241,6 +241,7 @@ void AudioOss::startProcessing() { if( !isRunning() ) { + m_stopped = false; start( QThread::HighPriority ); } } @@ -250,31 +251,23 @@ void AudioOss::startProcessing() void AudioOss::stopProcessing() { + m_stopped = true; stopProcessingThread( this ); } void AudioOss::run() { - auto temp = new SampleFrame[audioEngine()->framesPerPeriod()]; - auto outbuf = new int_sample_t[audioEngine()->framesPerPeriod() * channels()]; + static auto buf = std::vector(audioEngine()->userFramesPerPeriod()); + static auto outbuf = std::vector(buf.size() * channels()); - while( true ) + while (true) { - const fpp_t frames = getNextBuffer( temp ); - if( !frames ) - { - break; - } + if (m_stopped) { break; } - int bytes = convertToS16(temp, frames, outbuf, m_convertEndian); - if( write( m_audioFD, outbuf, bytes ) != bytes ) - { - break; - } + audioEngine()->renderNextBufferChunked(buf.data(), buf.size()); + const auto bytes = convertToS16(buf.data(), buf.size(), outbuf.data(), m_convertEndian); + if (write(m_audioFD, outbuf.data(), bytes) != bytes) { break; } } - - delete[] temp; - delete[] outbuf; } diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index eb5058bc6b5..29e459d6cb9 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -66,14 +66,10 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine DEFAULT_CHANNELS, DEFAULT_CHANNELS), _audioEngine), m_paStream( nullptr ), - m_wasPAInitError( false ), - m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()]), - m_outBufPos( 0 ) + m_wasPAInitError(false) { _success_ful = false; - m_outBufSize = audioEngine()->framesPerPeriod(); - PaError err = Pa_Initialize(); if( err != paNoError ) { @@ -123,7 +119,7 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, AudioEngine * _audioEngine //inLatency = Pa_GetDeviceInfo( inDevIdx )->defaultLowInputLatency; //outLatency = Pa_GetDeviceInfo( outDevIdx )->defaultLowOutputLatency; - const int samples = audioEngine()->framesPerPeriod(); + const int samples = audioEngine()->userFramesPerPeriod(); // Configure output parameters. m_outputParameters.device = outDevIdx; @@ -193,7 +189,6 @@ AudioPortAudio::~AudioPortAudio() { Pa_Terminate(); } - delete[] m_outBuf; } @@ -243,36 +238,7 @@ int AudioPortAudio::process_callback(const float* _inputBuffer, float* _outputBu return paComplete; } - while( _framesPerBuffer ) - { - if( m_outBufPos == 0 ) - { - // frames depend on the sample rate - const fpp_t frames = getNextBuffer( m_outBuf ); - if( !frames ) - { - m_stopped = true; - memset( _outputBuffer, 0, _framesPerBuffer * - channels() * sizeof(float) ); - return paComplete; - } - m_outBufSize = frames; - } - const auto min_len = std::min(_framesPerBuffer, m_outBufSize - m_outBufPos); - - for( fpp_t frame = 0; frame < min_len; ++frame ) - { - for( ch_cnt_t chnl = 0; chnl < channels(); ++chnl ) - { - (_outputBuffer + frame * channels())[chnl] = AudioEngine::clip(m_outBuf[frame][chnl]); - } - } - - _outputBuffer += min_len * channels(); - _framesPerBuffer -= min_len; - m_outBufPos += min_len; - m_outBufPos %= m_outBufSize; - } + audioEngine()->renderNextBufferChunked(reinterpret_cast(_outputBuffer), _framesPerBuffer); return paContinue; } diff --git a/src/core/audio/AudioPulseAudio.cpp b/src/core/audio/AudioPulseAudio.cpp index aa434487154..d7407a23162 100644 --- a/src/core/audio/AudioPulseAudio.cpp +++ b/src/core/audio/AudioPulseAudio.cpp @@ -51,7 +51,6 @@ AudioPulseAudio::AudioPulseAudio( bool & _success_ful, AudioEngine* _audioEngin DEFAULT_CHANNELS, DEFAULT_CHANNELS), _audioEngine), m_s( nullptr ), - m_quit( false ), m_convertEndian( false ) { _success_ful = false; @@ -95,6 +94,7 @@ void AudioPulseAudio::startProcessing() { if( !isRunning() ) { + m_stopped = false; start( QThread::HighPriority ); } } @@ -104,7 +104,7 @@ void AudioPulseAudio::startProcessing() void AudioPulseAudio::stopProcessing() { - m_quit = true; + m_stopped = true; stopProcessingThread( this ); } @@ -160,7 +160,7 @@ static void context_state_callback(pa_context *c, void *userdata) buffer_attr.minreq = (uint32_t)(-1); buffer_attr.fragsize = (uint32_t)(-1); - double latency = (double)( Engine::audioEngine()->framesPerPeriod() ) / (double)_this->sampleRate(); + double latency = static_cast(Engine::audioEngine()->userFramesPerPeriod()) / _this->sampleRate(); // ask PulseAudio for the desired latency (which might not be approved) buffer_attr.tlength = pa_usec_to_bytes( latency * PA_USEC_PER_MSEC, @@ -218,24 +218,12 @@ void AudioPulseAudio::run() if( m_connected ) { int ret = 0; - m_quit = false; - while( m_quit == false - && pa_mainloop_iterate( mainLoop, 1, &ret ) >= 0 ) - { - } + m_stopped = false; + while (!m_stopped && pa_mainloop_iterate(mainLoop, 1, &ret) >= 0) {} pa_stream_disconnect( m_s ); pa_stream_unref( m_s ); } - else - { - const fpp_t fpp = audioEngine()->framesPerPeriod(); - auto temp = new SampleFrame[fpp]; - while( getNextBuffer( temp ) ) - { - } - delete[] temp; - } pa_context_disconnect( context ); pa_context_unref( context ); @@ -248,30 +236,14 @@ void AudioPulseAudio::run() void AudioPulseAudio::streamWriteCallback( pa_stream *s, size_t length ) { - const fpp_t fpp = audioEngine()->framesPerPeriod(); - auto temp = new SampleFrame[fpp]; - auto pcmbuf = (int_sample_t*)pa_xmalloc(fpp * channels() * sizeof(int_sample_t)); + static auto buf = std::vector(audioEngine()->userFramesPerPeriod()); + static auto outbuf = std::vector(buf.size() * channels() * sizeof(int_sample_t)); - size_t fd = 0; - while( fd < length/4 && m_quit == false ) - { - const fpp_t frames = getNextBuffer( temp ); - if( !frames ) - { - m_quit = true; - break; - } - int bytes = convertToS16(temp, frames, pcmbuf, m_convertEndian); - if( bytes > 0 ) - { - pa_stream_write( m_s, pcmbuf, bytes, nullptr, 0, - PA_SEEK_RELATIVE ); - } - fd += frames; - } + if (m_stopped) { return; } - pa_xfree( pcmbuf ); - delete[] temp; + audioEngine()->renderNextBufferChunked(buf.data(), buf.size()); + const auto bytes = convertToS16(buf.data(), buf.size(), outbuf.data(), m_convertEndian); + if (bytes > 0) { pa_stream_write(m_s, outbuf.data(), bytes, nullptr, 0, PA_SEEK_RELATIVE); } } diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 8f533119c8a..f8a474cbcc3 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -43,8 +43,7 @@ constexpr auto PlaybackDeviceSDL = "device"; constexpr auto InputDeviceSDL = "inputdevice"; AudioSdl::AudioSdl( bool & _success_ful, AudioEngine* _audioEngine ) : - AudioDevice( DEFAULT_CHANNELS, _audioEngine ), - m_outBuf(new SampleFrame[audioEngine()->framesPerPeriod()]) + AudioDevice(DEFAULT_CHANNELS, _audioEngine) { _success_ful = false; @@ -63,7 +62,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->userFramesPerPeriod(); m_audioHandle.callback = sdlAudioCallback; m_audioHandle.userdata = this; @@ -130,8 +129,6 @@ AudioSdl::~AudioSdl() SDL_CloseAudioDevice(m_outputDevice); SDL_Quit(); - - delete[] m_outBuf; } @@ -183,32 +180,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) return; } - // SDL2: process float samples - while( _len ) - { - if( m_currentBufferFramePos == 0 ) - { - // frames depend on the sample rate - const fpp_t frames = getNextBuffer( m_outBuf ); - if( !frames ) - { - memset( _buf, 0, _len ); - return; - } - m_currentBufferFramesCount = frames; - - } - const uint min_frames_count = std::min(_len/sizeof(SampleFrame), - m_currentBufferFramesCount - - m_currentBufferFramePos); - - memcpy( _buf, m_outBuf + m_currentBufferFramePos, min_frames_count*sizeof(SampleFrame) ); - _buf += min_frames_count*sizeof(SampleFrame); - _len -= min_frames_count*sizeof(SampleFrame); - m_currentBufferFramePos += min_frames_count; - - m_currentBufferFramePos %= m_currentBufferFramesCount; - } + audioEngine()->renderNextBufferChunked(reinterpret_cast(_buf), _len / sizeof(SampleFrame)); } void AudioSdl::sdlInputAudioCallback(void *_udata, Uint8 *_buf, int _len) { diff --git a/src/core/audio/AudioSndio.cpp b/src/core/audio/AudioSndio.cpp index 95fab473a79..583c4851507 100644 --- a/src/core/audio/AudioSndio.cpp +++ b/src/core/audio/AudioSndio.cpp @@ -74,7 +74,7 @@ AudioSndio::AudioSndio(bool & _success_ful, AudioEngine * _audioEngine) : m_par.bits = 16; m_par.le = SIO_LE_NATIVE; m_par.rate = sampleRate(); - m_par.round = audioEngine()->framesPerPeriod(); + m_par.round = audioEngine()->userFramesPerPeriod(); m_par.appbufsz = m_par.round * 2; if ( (isLittleEndian() && (m_par.le == 0)) || @@ -129,6 +129,7 @@ void AudioSndio::startProcessing() { if( !isRunning() ) { + m_stopped = false; start( QThread::HighPriority ); } } @@ -136,31 +137,23 @@ void AudioSndio::startProcessing() void AudioSndio::stopProcessing() { + m_stopped = true; stopProcessingThread( this ); } void AudioSndio::run() { - SampleFrame* temp = new SampleFrame[audioEngine()->framesPerPeriod()]; - int_sample_t * outbuf = new int_sample_t[audioEngine()->framesPerPeriod() * channels()]; + static auto buf = std::vector(audioEngine()->userFramesPerPeriod()); + static auto outbuf = std::vector(buf.size() * channels()); - while( true ) + while (true) { - const fpp_t frames = getNextBuffer( temp ); - if( !frames ) - { - break; - } - - uint bytes = convertToS16(temp, frames, outbuf, m_convertEndian); - if( sio_write( m_hdl, outbuf, bytes ) != bytes ) - { - break; - } - } + if (m_stopped) { break; } - delete[] temp; - delete[] outbuf; + audioEngine()->renderNextBufferChunked(buf.data(), buf.size()); + const auto bytes = convertToS16(buf.data(), buf.size(), outbuf.data(), m_convertEndian); + if (sio_write(m_hdl, outbuf.data(), outbuf.size()) != static_cast(bytes)) { break; } + } } diff --git a/src/core/audio/AudioSoundIo.cpp b/src/core/audio/AudioSoundIo.cpp index c7fa380e402..5e535765b9f 100644 --- a/src/core/audio/AudioSoundIo.cpp +++ b/src/core/audio/AudioSoundIo.cpp @@ -47,10 +47,7 @@ AudioSoundIo::AudioSoundIo( bool & outSuccessful, AudioEngine * _audioEngine ) : outSuccessful = false; m_soundio = nullptr; m_outstream = nullptr; - m_outBuf = nullptr; m_disconnectErr = 0; - m_outBufFrameIndex = 0; - m_outBufFramesTotal = 0; m_stopped = true; m_outstreamStarted = false; @@ -165,7 +162,7 @@ AudioSoundIo::AudioSoundIo( bool & outSuccessful, AudioEngine * _audioEngine ) : } m_outstream->name = "LMMS"; - m_outstream->software_latency = (double)audioEngine()->framesPerPeriod() / (double)currentSampleRate; + m_outstream->software_latency = static_cast(audioEngine()->userFramesPerPeriod()) / currentSampleRate; m_outstream->userdata = this; m_outstream->write_callback = staticWriteCallback; m_outstream->error_callback = staticErrorCallback; @@ -209,12 +206,6 @@ AudioSoundIo::~AudioSoundIo() void AudioSoundIo::startProcessing() { - m_outBufFrameIndex = 0; - m_outBufFramesTotal = 0; - m_outBufSize = audioEngine()->framesPerPeriod(); - - m_outBuf = new SampleFrame[m_outBufSize]; - if (! m_outstreamStarted) { if (int err = soundio_outstream_start(m_outstream)) @@ -250,12 +241,6 @@ void AudioSoundIo::stopProcessing() soundio_strerror(err)); } } - - if (m_outBuf) - { - delete[] m_outBuf; - m_outBuf = nullptr; - } } void AudioSoundIo::errorCallback(int err) @@ -270,11 +255,9 @@ void AudioSoundIo::underflowCallback() void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax) { - if (m_stopped) {return;} - const struct SoundIoChannelLayout *layout = &m_outstream->layout; - SoundIoChannelArea* areas; - int bytesPerSample = m_outstream->bytes_per_sample; - int framesLeft = frameCountMax; + const auto layout = &m_outstream->layout; + auto areas = static_cast(nullptr); + auto framesLeft = frameCountMax; while (framesLeft > 0) { @@ -285,40 +268,29 @@ void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax) return; } - if (!frameCount) - break; + if (!frameCount) { break; } - if (m_stopped) { for (int channel = 0; channel < layout->channel_count; ++channel) { - memset(areas[channel].ptr, 0, bytesPerSample * frameCount); + memset(areas[channel].ptr, 0, m_outstream->bytes_per_sample * frameCount); areas[channel].ptr += areas[channel].step * frameCount; } continue; } - for (int frame = 0; frame < frameCount; frame += 1) - { - if (m_outBufFrameIndex >= m_outBufFramesTotal) - { - m_outBufFramesTotal = getNextBuffer(m_outBuf); - if (m_outBufFramesTotal == 0) - { - m_stopped = true; - break; - } - m_outBufFrameIndex = 0; - } + auto buf = std::vector(frameCount); + audioEngine()->renderNextBufferChunked(buf.data(), buf.size()); - for (int channel = 0; channel < layout->channel_count; channel += 1) + for (const auto& frame : buf) + { + for (auto channel = 0; channel < layout->channel_count; ++channel) { - float sample = m_outBuf[m_outBufFrameIndex][channel]; - memcpy(areas[channel].ptr, &sample, bytesPerSample); + const auto sample = frame[channel]; + memcpy(areas[channel].ptr, &sample, m_outstream->bytes_per_sample); areas[channel].ptr += areas[channel].step; } - m_outBufFrameIndex += 1; } if (int err = soundio_outstream_end_write(m_outstream))