From f2d68326a7bc30701d4efcd7d65bb1720a43c649 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Tue, 10 Jul 2018 11:13:56 +0900 Subject: [PATCH 1/4] Fix occasional audio interface deadlock (#4450) --- include/AudioJack.h | 2 -- include/AudioPortAudio.h | 1 - include/AudioSoundIo.h | 2 ++ include/fifo_buffer.h | 6 ++++++ src/core/Mixer.cpp | 6 ++++-- src/core/audio/AudioJack.cpp | 4 +--- src/core/audio/AudioPortAudio.cpp | 10 ++-------- src/core/audio/AudioPulseAudio.cpp | 1 + src/core/audio/AudioSdl.cpp | 1 + src/core/audio/AudioSoundIo.cpp | 21 +++++++++++++++++++++ 10 files changed, 38 insertions(+), 16 deletions(-) diff --git a/include/AudioJack.h b/include/AudioJack.h index 60adfc9a5..9bbb3bd48 100644 --- a/include/AudioJack.h +++ b/include/AudioJack.h @@ -37,7 +37,6 @@ #include #include #include -#include #include "AudioDevice.h" #include "AudioDeviceSetupWidget.h" @@ -108,7 +107,6 @@ private: bool m_active; bool m_stopped; - QMutex m_processingMutex; MidiJack *m_midiClient; QVector m_outputPorts; diff --git a/include/AudioPortAudio.h b/include/AudioPortAudio.h index 6a07aad47..e4f27c7e1 100644 --- a/include/AudioPortAudio.h +++ b/include/AudioPortAudio.h @@ -145,7 +145,6 @@ private: int m_outBufSize; bool m_stopped; - QSemaphore m_stopSemaphore; } ; diff --git a/include/AudioSoundIo.h b/include/AudioSoundIo.h index b0192a19e..f743ad676 100644 --- a/include/AudioSoundIo.h +++ b/include/AudioSoundIo.h @@ -109,6 +109,8 @@ private: fpp_t m_outBufFramesTotal; fpp_t m_outBufFrameIndex; + bool m_stopped; + int m_disconnectErr; void onBackendDisconnect(int err); diff --git a/include/fifo_buffer.h b/include/fifo_buffer.h index 39f9867fe..422b48df2 100644 --- a/include/fifo_buffer.h +++ b/include/fifo_buffer.h @@ -66,6 +66,12 @@ public: return( element ); } + void waitUntilRead() + { + m_writer_sem.acquire( m_size ); + m_writer_sem.release( m_size ); + } + bool available() { return( m_reader_sem.available() ); diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index 830d7e6c8..d5baa0a85 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -640,7 +640,7 @@ void Mixer::storeAudioDevice() void Mixer::restoreAudioDevice() { - if( m_oldAudioDev != NULL ) + if( m_oldAudioDev && m_audioDev != m_oldAudioDev ) { stopProcessing(); delete m_audioDev; @@ -648,9 +648,9 @@ void Mixer::restoreAudioDevice() m_audioDev = m_oldAudioDev; emit sampleRateChanged(); - m_oldAudioDev = NULL; startProcessing(); } + m_oldAudioDev = NULL; } @@ -1127,7 +1127,9 @@ void Mixer::fifoWriter::run() write( buffer ); } + // Let audio backend stop processing write( NULL ); + m_fifo->waitUntilRead(); } diff --git a/src/core/audio/AudioJack.cpp b/src/core/audio/AudioJack.cpp index 4d730eed4..bca41356b 100644 --- a/src/core/audio/AudioJack.cpp +++ b/src/core/audio/AudioJack.cpp @@ -201,7 +201,6 @@ bool AudioJack::initJackClient() void AudioJack::startProcessing() { - QMutexLocker m( &m_processingMutex ); m_stopped = false; if( m_active || m_client == NULL ) @@ -254,7 +253,6 @@ void AudioJack::startProcessing() void AudioJack::stopProcessing() { - QMutexLocker m( &m_processingMutex ); m_stopped = true; } @@ -342,7 +340,6 @@ void AudioJack::renamePort( AudioPort * _port ) int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata ) { - QMutexLocker m( &m_processingMutex ); // do midi processing first so that midi input can // add to the following sound processing @@ -406,6 +403,7 @@ int AudioJack::processCallback( jack_nframes_t _nframes, void * _udata ) m_framesDoneInCurBuf = 0; if( !m_framesToDoInCurBuf ) { + m_stopped = true; break; } } diff --git a/src/core/audio/AudioPortAudio.cpp b/src/core/audio/AudioPortAudio.cpp index b14c1e79d..6abb29453 100644 --- a/src/core/audio/AudioPortAudio.cpp +++ b/src/core/audio/AudioPortAudio.cpp @@ -57,8 +57,7 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, Mixer * _mixer ) : m_paStream( NULL ), m_wasPAInitError( false ), m_outBuf( new surroundSampleFrame[mixer()->framesPerPeriod()] ), - m_outBufPos( 0 ), - m_stopSemaphore( 1 ) + m_outBufPos( 0 ) { _success_ful = false; @@ -167,8 +166,6 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, Mixer * _mixer ) : printf( "Input device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( inDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( inDevIdx )->hostApi )->name ); printf( "Output device: '%s' backend: '%s'\n", Pa_GetDeviceInfo( outDevIdx )->name, Pa_GetHostApiInfo( Pa_GetDeviceInfo( outDevIdx )->hostApi )->name ); - m_stopSemaphore.acquire(); - // TODO: debug Mixer::pushInputFrames() //m_supportsCapture = true; @@ -181,7 +178,6 @@ AudioPortAudio::AudioPortAudio( bool & _success_ful, Mixer * _mixer ) : AudioPortAudio::~AudioPortAudio() { stopProcessing(); - m_stopSemaphore.release(); if( !m_wasPAInitError ) { @@ -212,8 +208,7 @@ void AudioPortAudio::stopProcessing() { if( m_paStream && Pa_IsStreamActive( m_paStream ) ) { - m_stopSemaphore.acquire(); - + m_stopped = true; PaError err = Pa_StopStream( m_paStream ); if( err != paNoError ) @@ -283,7 +278,6 @@ int AudioPortAudio::process_callback( if( !frames ) { m_stopped = true; - m_stopSemaphore.release(); memset( _outputBuffer, 0, _framesPerBuffer * channels() * sizeof(float) ); return paComplete; diff --git a/src/core/audio/AudioPulseAudio.cpp b/src/core/audio/AudioPulseAudio.cpp index 23031b10c..20a106ed1 100644 --- a/src/core/audio/AudioPulseAudio.cpp +++ b/src/core/audio/AudioPulseAudio.cpp @@ -103,6 +103,7 @@ void AudioPulseAudio::startProcessing() void AudioPulseAudio::stopProcessing() { + m_quit = true; stopProcessingThread( this ); } diff --git a/src/core/audio/AudioSdl.cpp b/src/core/audio/AudioSdl.cpp index 2b810e913..f513916ba 100644 --- a/src/core/audio/AudioSdl.cpp +++ b/src/core/audio/AudioSdl.cpp @@ -168,6 +168,7 @@ void AudioSdl::sdlAudioCallback( Uint8 * _buf, int _len ) const fpp_t frames = getNextBuffer( m_outBuf ); if( !frames ) { + m_stopped = true; memset( _buf, 0, _len ); return; } diff --git a/src/core/audio/AudioSoundIo.cpp b/src/core/audio/AudioSoundIo.cpp index 46a0315e7..f6c624127 100644 --- a/src/core/audio/AudioSoundIo.cpp +++ b/src/core/audio/AudioSoundIo.cpp @@ -49,6 +49,7 @@ AudioSoundIo::AudioSoundIo( bool & outSuccessful, Mixer * _mixer ) : m_disconnectErr = 0; m_outBufFrameIndex = 0; m_outBufFramesTotal = 0; + m_stopped = true; m_soundio = soundio_create(); if (!m_soundio) @@ -210,15 +211,18 @@ void AudioSoundIo::startProcessing() m_outBuf = new surroundSampleFrame[m_outBufSize]; + m_stopped = false; int err; if ((err = soundio_outstream_start(m_outstream))) { + m_stopped = true; fprintf(stderr, "soundio unable to start stream: %s\n", soundio_strerror(err)); } } void AudioSoundIo::stopProcessing() { + m_stopped = true; if (m_outstream) { soundio_outstream_destroy(m_outstream); @@ -244,6 +248,7 @@ 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; @@ -265,11 +270,27 @@ void AudioSoundIo::writeCallback(int frameCountMin, int frameCountMax) if (!frameCount) break; + + if (m_stopped) + { + for (int channel = 0; channel < layout->channel_count; ++channel) + { + memset(areas[channel].ptr, 0, bytesPerSample * 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; } From 9f64d5214628545dd1692f51812c1b9e82860d75 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Thu, 12 Jul 2018 09:49:02 +0900 Subject: [PATCH 2/4] Always show sample track panning knobs (#4477) Fix hidden sample track panning knobs when using compact track buttons --- src/tracks/SampleTrack.cpp | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/tracks/SampleTrack.cpp b/src/tracks/SampleTrack.cpp index 3c16025a5..63efa4d26 100644 --- a/src/tracks/SampleTrack.cpp +++ b/src/tracks/SampleTrack.cpp @@ -755,15 +755,12 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : m_volumeKnob->setVolumeKnob( true ); m_volumeKnob->setModel( &_t->m_volumeModel ); m_volumeKnob->setHintText( tr( "Channel volume:" ), "%" ); - if( ConfigManager::inst()->value( "ui", - "compacttrackbuttons" ).toInt() ) - { - m_volumeKnob->move( DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT-2*24, 2 ); - } - else - { - m_volumeKnob->move( DEFAULT_SETTINGS_WIDGET_WIDTH-2*24, 2 ); - } + + int settingsWidgetWidth = ConfigManager::inst()-> + value( "ui", "compacttrackbuttons" ).toInt() + ? DEFAULT_SETTINGS_WIDGET_WIDTH_COMPACT + : DEFAULT_SETTINGS_WIDGET_WIDTH; + m_volumeKnob->move( settingsWidgetWidth - 2 * 24, 2 ); m_volumeKnob->setLabel( tr( "VOL" ) ); m_volumeKnob->show(); @@ -771,7 +768,7 @@ SampleTrackView::SampleTrackView( SampleTrack * _t, TrackContainerView* tcv ) : tr( "Panning" ) ); m_panningKnob->setModel( &_t->m_panningModel ); m_panningKnob->setHintText( tr( "Panning:" ), "%" ); - m_panningKnob->move( DEFAULT_SETTINGS_WIDGET_WIDTH-24, 2 ); + m_panningKnob->move( settingsWidgetWidth - 24, 2 ); m_panningKnob->setLabel( tr( "PAN" ) ); m_panningKnob->show(); From 408b72c798cddb6d837cd09d83f3369f9f3b98f1 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Fri, 13 Jul 2018 10:40:24 +0900 Subject: [PATCH 3/4] Use tryLock in audio threads for VST/ZynAddSubFX (#4460) Prevent loading VST or toggling ZynAddSubFX GUI from blocking entire audio processing --- plugins/VstEffect/VstEffect.cpp | 8 +++++--- plugins/vestige/vestige.cpp | 4 +--- plugins/zynaddsubfx/ZynAddSubFx.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/VstEffect/VstEffect.cpp b/plugins/VstEffect/VstEffect.cpp index ea0241a5a..05cc7a070 100644 --- a/plugins/VstEffect/VstEffect.cpp +++ b/plugins/VstEffect/VstEffect.cpp @@ -95,9 +95,11 @@ bool VstEffect::processAudioBuffer( sampleFrame * _buf, const fpp_t _frames ) sampleFrame * buf = new sampleFrame[_frames]; #endif memcpy( buf, _buf, sizeof( sampleFrame ) * _frames ); - m_pluginMutex.lock(); - m_plugin->process( buf, buf ); - m_pluginMutex.unlock(); + if (m_pluginMutex.tryLock()) + { + m_plugin->process( buf, buf ); + m_pluginMutex.unlock(); + } double out_sum = 0.0; const float w = wetLevel(); diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index 9ea053e8e..540c8b5ce 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -359,14 +359,12 @@ void vestigeInstrument::loadFile( const QString & _file ) void vestigeInstrument::play( sampleFrame * _buf ) { - m_pluginMutex.lock(); + if (!m_pluginMutex.tryLock()) {return;} const fpp_t frames = Engine::mixer()->framesPerPeriod(); if( m_plugin == NULL ) { - BufferManager::clear( _buf, frames ); - m_pluginMutex.unlock(); return; } diff --git a/plugins/zynaddsubfx/ZynAddSubFx.cpp b/plugins/zynaddsubfx/ZynAddSubFx.cpp index 8bba1f10f..8c1da751f 100644 --- a/plugins/zynaddsubfx/ZynAddSubFx.cpp +++ b/plugins/zynaddsubfx/ZynAddSubFx.cpp @@ -326,7 +326,7 @@ QString ZynAddSubFxInstrument::nodeName() const void ZynAddSubFxInstrument::play( sampleFrame * _buf ) { - m_pluginMutex.lock(); + if (!m_pluginMutex.tryLock()) {return;} if( m_remotePlugin ) { m_remotePlugin->process( NULL, _buf ); From 45d3359e2114022f875cb28d2a5b9974e826dd09 Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Sun, 15 Jul 2018 14:03:37 +0200 Subject: [PATCH 4/4] Some demo project license fixes (#4481) Add some missing licenses and split out CapDan and Skiessi project licenses to their own files in the corresponding directories. --- data/projects/demos/CapDan/LICENSES.TXT | 15 +++++++++ data/projects/demos/LICENSES.TXT | 40 +++++++----------------- data/projects/demos/Skiessi/LICENSES.TXT | 7 +++++ data/projects/shorties/LICENSES.TXT | 8 +++++ 4 files changed, 42 insertions(+), 28 deletions(-) create mode 100644 data/projects/demos/CapDan/LICENSES.TXT create mode 100644 data/projects/demos/Skiessi/LICENSES.TXT diff --git a/data/projects/demos/CapDan/LICENSES.TXT b/data/projects/demos/CapDan/LICENSES.TXT new file mode 100644 index 000000000..6a640decd --- /dev/null +++ b/data/projects/demos/CapDan/LICENSES.TXT @@ -0,0 +1,15 @@ +* CapDan-ReggaeTry.mmpz + - Artistic 2.0 + - https://lmms.io/lsp/index.php?action=show&file=1369 + +* CapDan-ReggaetonTry.mmpz + - Artistic 2.0 + - https://lmms.io/lsp/index.php?action=show&file=1370 + +* CapDan-TwilightArea-OriginalByAlf42red.mmpz + - CC (by-sa) + - https://lmms.io/lsp/index.php?action=show&file=1439 + +* CapDan-ZeroSumGame-OriginalByZakarra.mmpz + - Artistic 2.0 + - https://lmms.io/lsp/index.php?action=show&file=1565 diff --git a/data/projects/demos/LICENSES.TXT b/data/projects/demos/LICENSES.TXT index c33cc02c8..399d7909f 100644 --- a/data/projects/demos/LICENSES.TXT +++ b/data/projects/demos/LICENSES.TXT @@ -2,22 +2,6 @@ - CC (by-sa) - https://lmms.io/lsp/index.php?action=show&file=819 -* CapDan-ReggaeTry.mmpz - - Artistic 2.0 - - https://lmms.io/lsp/index.php?action=show&file=1369 - -* CapDan-ReggaetonTry.mmpz - - Artistic 2.0 - - https://lmms.io/lsp/index.php?action=show&file=1370 - -* CapDan-TwilightArea-OriginalByAlf42red.mmpz - - CC (by-sa) - - https://lmms.io/lsp/index.php?action=show&file=1439 - -* CapDan-ZeroSumGame-OriginalByZakarra.mmpz - - Artistic 2.0 - - https://lmms.io/lsp/index.php?action=show&file=1565 - * EsoXLB-CPU.mmpz - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=723 @@ -34,6 +18,10 @@ - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=581 +* Jousboxx-BuzzerBeater.mmpz + - CC BY-SA 4.0 + - https://github.com/LMMS/lmms/pull/3482#issuecomment-293609866 + * Momo64-esp.mmpz - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=1534 @@ -50,6 +38,10 @@ - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=1156 +* Popsip-Electric Dancer.mmpz + - Creative Commons (by-nc) + - https://lmms.io/lsp/?action=show&file=5414 + * Root84-Initialize.mmpz - Yellow openmusic - https://lmms.io/lsp/index.php?action=show&file=628 @@ -62,14 +54,6 @@ - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=515 -* Skiessi-C64.mmpz - - CC (by sa) - - https://lmms.io/lsp/index.php?action=show&file=472 - -* Skiessi-Onion.mmpz - - CC (by-sa) - - https://lmms.io/lsp/index.php?action=show&file=405 - * Socceroos-Progress.mmpz - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=1516 @@ -78,6 +62,10 @@ - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=1060 +* Thaledric-Armageddon.mmpz + - Creative Commons (by-nc-sa) + - https://lmms.io/lsp/?action=show&file=1947 + * Thomasso-AxeFromThe80s.mmpz - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=474 @@ -85,7 +73,3 @@ * unfa-Spoken.mmpz - CC (by-nc) - https://lmms.io/lsp/index.php?action=show&file=4929 - -* Jousboxx-BuzzerBeater.mmpz - - CC (by-sa) - - https://lmms.io/lsp/?action=show&file=10488 diff --git a/data/projects/demos/Skiessi/LICENSES.TXT b/data/projects/demos/Skiessi/LICENSES.TXT new file mode 100644 index 000000000..8cb4adc86 --- /dev/null +++ b/data/projects/demos/Skiessi/LICENSES.TXT @@ -0,0 +1,7 @@ +* Skiessi-C64.mmpz + - CC (by sa) + - https://lmms.io/lsp/index.php?action=show&file=472 + +* Skiessi-Onion.mmpz + - CC (by-sa) + - https://lmms.io/lsp/index.php?action=show&file=405 diff --git a/data/projects/shorties/LICENSES.TXT b/data/projects/shorties/LICENSES.TXT index bba2b5547..47969a984 100644 --- a/data/projects/shorties/LICENSES.TXT +++ b/data/projects/shorties/LICENSES.TXT @@ -1,3 +1,11 @@ +* Crunk(Demo).mmp + - Artistic 2.0 + - https://lmms.io/lsp/?action=show&file=4093 + +* DirtyLove.mmpz + - CC-BY-SA + - https://github.com/LMMS/lmms/pull/2727 + * Greshz-CoolSnip.mmpz - Artistic 2.0 - https://lmms.io/lsp/index.php?action=show&file=1170