From a0cbcb6ec4f92b15ede784ffcc078d41ae042d8b Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Sat, 25 Aug 2018 15:29:40 +0900 Subject: [PATCH 01/16] Remove Qt temporary files after loading ZynAddSubFX settings (#4551) --- plugins/zynaddsubfx/ZynAddSubFx.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/zynaddsubfx/ZynAddSubFx.cpp b/plugins/zynaddsubfx/ZynAddSubFx.cpp index adc337542..49a97d35e 100644 --- a/plugins/zynaddsubfx/ZynAddSubFx.cpp +++ b/plugins/zynaddsubfx/ZynAddSubFx.cpp @@ -240,7 +240,6 @@ void ZynAddSubFxInstrument::loadSettings( const QDomElement & _this ) doc.appendChild( doc.importNode( data, true ) ); QTemporaryFile tf; - tf.setAutoRemove( false ); if( tf.open() ) { QByteArray a = doc.toString( 0 ).toUtf8(); From 4bb6586c66fdeb0ef2f84667958d340a8355c5fe Mon Sep 17 00:00:00 2001 From: Tobias Kortkamp Date: Mon, 27 Aug 2018 22:19:23 +0200 Subject: [PATCH 02/16] Allow building with sndio support on more systems than just OpenBSD (#4486) Sndio also supports FreeBSD and Linux. --- CMakeLists.txt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da5be324a..8be2f701f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -56,6 +56,7 @@ OPTION(WANT_MP3LAME "Include MP3/Lame support" ON) OPTION(WANT_OGGVORBIS "Include OGG/Vorbis support" ON) OPTION(WANT_PULSEAUDIO "Include PulseAudio support" ON) OPTION(WANT_PORTAUDIO "Include PortAudio support" ON) +OPTION(WANT_SNDIO "Include sndio support" ON) OPTION(WANT_SOUNDIO "Include libsoundio support" ON) OPTION(WANT_SDL "Include SDL (Simple DirectMedia Layer) support" ON) OPTION(WANT_SF2 "Include SoundFont2 player plugin" ON) @@ -86,6 +87,7 @@ IF(LMMS_BUILD_WIN32) SET(WANT_JACK OFF) SET(WANT_PULSEAUDIO OFF) SET(WANT_PORTAUDIO OFF) + SET(WANT_SNDIO OFF) SET(WANT_SOUNDIO OFF) SET(WANT_WINMM ON) SET(LMMS_HAVE_WINMM TRUE) @@ -428,7 +430,7 @@ IF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD) FIND_PACKAGE(Threads) ENDIF(LMMS_BUILD_LINUX OR LMMS_BUILD_APPLE OR LMMS_BUILD_OPENBSD) -IF(LMMS_BUILD_OPENBSD) +IF(WANT_SNDIO) FIND_PACKAGE(Sndio) IF(SNDIO_FOUND) SET(LMMS_HAVE_SNDIO TRUE) @@ -436,7 +438,7 @@ IF(LMMS_BUILD_OPENBSD) ELSE() SET(STATUS_SNDIO "") ENDIF(SNDIO_FOUND) -ENDIF(LMMS_BUILD_OPENBSD) +ENDIF(WANT_SNDIO) # check for WINE IF(WANT_VST) From 6f32c962b48911564b0443628b4700edb82c37ce Mon Sep 17 00:00:00 2001 From: Lukas W Date: Mon, 3 Sep 2018 12:39:23 +0200 Subject: [PATCH 03/16] Fix invisible editors on project load by validating size (#4502) --- src/gui/MainWindow.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 6ff55f06f..c047bf96c 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -802,7 +802,10 @@ void MainWindow::restoreWidgetState( QWidget * _w, const QDomElement & _de ) // first restore the window, as attempting to resize a maximized window causes graphics glitching _w->setWindowState( _w->windowState() & ~(Qt::WindowMaximized | Qt::WindowMinimized) ); - _w->resize( r.size() ); + // Check isEmpty() to work around corrupt project files with empty size + if ( ! r.size().isEmpty() ) { + _w->resize( r.size() ); + } _w->move( r.topLeft() ); // set the window to its correct minimized/maximized/restored state From de427bbcf8a9dc012afdf1a4e65a5cd1d3dbe466 Mon Sep 17 00:00:00 2001 From: DomClark Date: Tue, 14 Aug 2018 20:04:59 +0100 Subject: [PATCH 04/16] Suspend plugin when changing sample rate/buffer size Some plugins ignore updates to these values if they're changed while the plugin is in a "resumed" state, resulting in incorrect tuning after a change of sample rate. --- plugins/vst_base/RemoteVstPlugin.cpp | 36 ++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 127036cd0..5a73bd10e 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -147,6 +147,7 @@ public: // set given sample-rate for plugin virtual void updateSampleRate() { + SuspendPlugin suspend( this ); pluginDispatch( effSetSampleRate, 0, 0, NULL, (float) sampleRate() ); } @@ -154,9 +155,20 @@ public: // set given buffer-size for plugin virtual void updateBufferSize() { + SuspendPlugin suspend( this ); pluginDispatch( effSetBlockSize, 0, bufferSize() ); } + void setResumed( bool resumed ) + { + m_resumed = resumed; + pluginDispatch( effMainsChanged, 0, resumed ? 1 : 0 ); + } + + inline bool isResumed() const + { + return m_resumed; + } inline bool isInitialized() const { @@ -309,6 +321,24 @@ private: ClosePlugin } ; + struct SuspendPlugin { + SuspendPlugin( RemoteVstPlugin * plugin ) : + m_plugin( plugin ), + m_resumed( plugin->isResumed() ) + { + if( m_resumed ) { m_plugin->setResumed( false ); } + } + + ~SuspendPlugin() + { + if( m_resumed ) { m_plugin->setResumed( true ); } + } + + private: + RemoteVstPlugin * m_plugin; + bool m_resumed; + }; + // callback used by plugin for being able to communicate with it's host static intptr_t hostCallback( AEffect * _effect, int32_t _opcode, int32_t _index, intptr_t _value, @@ -339,6 +369,7 @@ private: int m_windowHeight; bool m_initialized; + bool m_resumed; bool m_processing; @@ -390,6 +421,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) : m_windowWidth( 0 ), m_windowHeight( 0 ), m_initialized( false ), + m_resumed( false ), m_processing( false ), m_messageList(), m_shouldGiveIdle( false ), @@ -470,7 +502,7 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) : RemoteVstPlugin::~RemoteVstPlugin() { destroyEditor(); - pluginDispatch( effMainsChanged, 0, 0 ); + setResumed( false ); pluginDispatch( effClose ); #ifndef USE_QT_SHMEM // detach shared memory segment @@ -648,7 +680,7 @@ void RemoteVstPlugin::init( const std::string & _plugin_file ) pluginDispatch( effSetProgram, 0, 0 ); */ // request rate and blocksize - pluginDispatch( effMainsChanged, 0, 1 ); + setResumed( true ); debugMessage( "creating editor\n" ); initEditor(); From cc2ae66540cdf62a9f6b9d4daf5cb4b82d229fa3 Mon Sep 17 00:00:00 2001 From: DomClark Date: Tue, 14 Aug 2018 20:52:48 +0100 Subject: [PATCH 05/16] Fix hang when updateInOutCount called from processReplacing Ignore requests to change the I/O count from within processReplacing and print a warning instead; the shared memory is in use so it can't be reallocated. Add a special case to return immediately if the I/O count hasn't changed at all; this will prevent spurious warnings when the plugin is only updating the latency and should reduce unnecessary reallocations in general. --- plugins/vst_base/RemoteVstPlugin.cpp | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 5a73bd10e..e0b51381e 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -118,6 +118,7 @@ class RemoteVstPlugin; RemoteVstPlugin * __plugin = NULL; HWND __MessageHwnd = NULL; +DWORD __processingThreadId = 0; @@ -251,7 +252,7 @@ public: } // has to be called as soon as input- or output-count changes - void updateInOutCount(); + int updateInOutCount(); inline void lockShm() { @@ -1438,8 +1439,21 @@ void RemoteVstPlugin::loadChunkFromFile( const std::string & _file, int _len ) -void RemoteVstPlugin::updateInOutCount() +int RemoteVstPlugin::updateInOutCount() { + if( inputCount() == RemotePluginClient::inputCount() && + outputCount() == RemotePluginClient::outputCount() ) + { + return 1; + } + + if( GetCurrentThreadId() == __processingThreadId ) + { + debugMessage( "Plugin requested I/O change from processing " + "thread. Request denied; stability may suffer.\n" ); + return 0; + } + lockShm(); setShmIsValid( false ); @@ -1467,6 +1481,8 @@ void RemoteVstPlugin::updateInOutCount() { m_outputs = new float * [outputCount()]; } + + return 1; } @@ -1611,10 +1627,9 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, return 0; case audioMasterIOChanged: - __plugin->updateInOutCount(); SHOW_CALLBACK( "amc: audioMasterIOChanged\n" ); - // numInputs and/or numOutputs has changed - return 0; + // numInputs, numOutputs, and/or latency has changed + return __plugin->updateInOutCount(); #ifdef OLD_VST_SDK case audioMasterWantMidi: @@ -1897,6 +1912,8 @@ void RemoteVstPlugin::processUIThreadMessages() DWORD WINAPI RemoteVstPlugin::processingThread( LPVOID _param ) { + __processingThreadId = GetCurrentThreadId(); + RemoteVstPlugin * _this = static_cast( _param ); RemotePluginClient::message m; From 2c5cda563b4985659a7408008915f0e4e0f85edb Mon Sep 17 00:00:00 2001 From: DomClark Date: Tue, 14 Aug 2018 21:37:22 +0100 Subject: [PATCH 06/16] Fix kVstTransportChanged flag usage in VST sync Changed according to feedback from AudioBlast. The flag used to be set most of the time, now it is only set when playback starts/stops, looping is toggled, or playback jumps around. --- include/Song.h | 9 +++++++++ include/VstSyncController.h | 6 ++++++ include/VstSyncData.h | 1 + plugins/vst_base/RemoteVstPlugin.cpp | 12 +++++++++++- src/core/Song.cpp | 24 +++++++++++++++++++++--- src/gui/TimeLineWidget.cpp | 1 + 6 files changed, 49 insertions(+), 4 deletions(-) diff --git a/include/Song.h b/include/Song.h index 0ba8a3503..08c99af47 100644 --- a/include/Song.h +++ b/include/Song.h @@ -87,10 +87,19 @@ public: { return m_currentFrame; } + inline void setJumped( const bool jumped ) + { + m_jumped = jumped; + } + inline bool jumped() const + { + return m_jumped; + } TimeLineWidget * m_timeLine; private: float m_currentFrame; + bool m_jumped; } ; diff --git a/include/VstSyncController.h b/include/VstSyncController.h index b969ebbbe..e858f5545 100644 --- a/include/VstSyncController.h +++ b/include/VstSyncController.h @@ -61,6 +61,11 @@ public: m_syncData->isCycle = false; } + void setPlaybackJumped( bool jumped ) + { + m_syncData->m_playbackJumped = jumped; + } + void update(); @@ -79,6 +84,7 @@ private: bool hasSHM; float cycleStart; float cycleEnd; + bool m_playbackJumped; int m_bufferSize; int m_sampleRate; int m_bpm; diff --git a/include/VstSyncData.h b/include/VstSyncData.h index a4c5db80b..d8694f1b2 100644 --- a/include/VstSyncData.h +++ b/include/VstSyncData.h @@ -49,6 +49,7 @@ struct VstSyncData bool hasSHM; float cycleStart; float cycleEnd; + bool m_playbackJumped; int m_bufferSize; int m_sampleRate; int m_bpm; diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index e0b51381e..1e810f0b7 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -396,6 +396,7 @@ private: { float lastppqPos; float m_Timestamp; + int32_t m_lastFlags; } ; in * m_in; @@ -478,12 +479,14 @@ RemoteVstPlugin::RemoteVstPlugin( const char * socketPath ) : m_vstSyncData->ppqPos = 0; m_vstSyncData->isCycle = false; m_vstSyncData->hasSHM = false; + m_vstSyncData->m_playbackJumped = false; m_vstSyncData->m_sampleRate = sampleRate(); } m_in = ( in* ) new char[ sizeof( in ) ]; m_in->lastppqPos = 0; m_in->m_Timestamp = -1; + m_in->m_lastFlags = 0; // process until we have loaded the plugin while( 1 ) @@ -1588,7 +1591,6 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, __plugin->m_in->m_Timestamp ) { _timeInfo.ppqPos = __plugin->m_vstSyncData->ppqPos; - _timeInfo.flags |= kVstTransportChanged; __plugin->m_in->lastppqPos = __plugin->m_vstSyncData->ppqPos; __plugin->m_in->m_Timestamp = __plugin->m_vstSyncData->ppqPos; } @@ -1615,6 +1617,14 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, _timeInfo.flags |= kVstBarsValid; + if( ( _timeInfo.flags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) != + ( __plugin->m_in->m_lastFlags & ( kVstTransportPlaying | kVstTransportCycleActive ) ) + || __plugin->m_vstSyncData->m_playbackJumped ) + { + _timeInfo.flags |= kVstTransportChanged; + } + __plugin->m_in->m_lastFlags = _timeInfo.flags; + #ifdef LMMS_BUILD_WIN64 return (long long) &_timeInfo; #else diff --git a/src/core/Song.cpp b/src/core/Song.cpp index be0c7dddc..217a8752e 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -193,6 +193,8 @@ void Song::savePos() void Song::processNextBuffer() { + m_vstSyncController.setPlaybackJumped( false ); + // if not playing, nothing to do if( m_playing == false ) { @@ -262,10 +264,21 @@ void Song::processNextBuffer() ( tl->loopBegin().getTicks() * 60 * 1000 / 48 ) / getTempo(); m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); + + m_vstSyncController.setAbsolutePosition( + tl->loopBegin().getTicks() ); + m_vstSyncController.setPlaybackJumped( true ); + emit updateSampleTracks(); } } + if( m_playPos[m_playMode].jumped() ) + { + m_vstSyncController.setPlaybackJumped( true ); + m_playPos[m_playMode].setJumped( false ); + } + f_cnt_t framesPlayed = 0; const float framesPerTick = Engine::framesPerTick(); @@ -320,6 +333,7 @@ void Song::processNextBuffer() ( ticks * 60 * 1000 / 48 ) / getTempo(); m_vstSyncController.setAbsolutePosition( ticks ); + m_vstSyncController.setPlaybackJumped( true ); } } m_playPos[m_playMode].setTicks( ticks ); @@ -334,11 +348,14 @@ void Song::processNextBuffer() // beginning of the range if( m_playPos[m_playMode] >= tl->loopEnd() ) { - m_playPos[m_playMode].setTicks( tl->loopBegin().getTicks() ); + ticks = tl->loopBegin().getTicks(); + m_playPos[m_playMode].setTicks( ticks ); m_elapsedMilliSeconds = - ( ( tl->loopBegin().getTicks() ) * 60 * 1000 / 48 ) / - getTempo(); + ( ticks * 60 * 1000 / 48 ) / getTempo(); + + m_vstSyncController.setAbsolutePosition( ticks ); + m_vstSyncController.setPlaybackJumped( true ); } else if( m_playPos[m_playMode] == tl->loopEnd() - 1 ) { @@ -609,6 +626,7 @@ void Song::setPlayPos( tick_t ticks, PlayModes playMode ) getTempo() ); m_playPos[playMode].setTicks( ticks ); m_playPos[playMode].setCurrentFrame( 0.0f ); + m_playPos[playMode].setJumped( true ); // send a signal if playposition changes during playback if( isPlaying() ) diff --git a/src/gui/TimeLineWidget.cpp b/src/gui/TimeLineWidget.cpp index 06b32ff7f..47d9db95e 100644 --- a/src/gui/TimeLineWidget.cpp +++ b/src/gui/TimeLineWidget.cpp @@ -375,6 +375,7 @@ void TimeLineWidget::mouseMoveEvent( QMouseEvent* event ) ( 60 * 1000 / 48 ) ) / Engine::getSong()->getTempo() ); m_pos.setCurrentFrame( 0 ); + m_pos.setJumped( true ); updatePosition(); positionMarkerMoved(); break; From 53dadd57355a893639fbc99dbea3b5e43025c614 Mon Sep 17 00:00:00 2001 From: DomClark Date: Tue, 14 Aug 2018 21:45:59 +0100 Subject: [PATCH 07/16] Fix VST windows resizing a little incorrectly This was fixed for setting the initial size of the window in 8e9f74d, but I missed the resizing case. --- plugins/vst_base/RemoteVstPlugin.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 1e810f0b7..12a27d183 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -1726,6 +1726,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, #endif case audioMasterSizeWindow: + { SHOW_CALLBACK( "amc: audioMasterSizeWindow\n" ); if( __plugin->m_window == 0 ) { @@ -1733,8 +1734,13 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, } __plugin->m_windowWidth = _index; __plugin->m_windowHeight = _value; - SetWindowPos( __plugin->m_window, 0, 0, 0, - _index + 8, _value + 26, + HWND window = __plugin->m_window; + DWORD dwStyle = GetWindowLongPtr( window, GWL_STYLE ); + RECT windowSize = { 0, 0, (int) _index, (int) _value }; + AdjustWindowRect( &windowSize, dwStyle, false ); + SetWindowPos( window, 0, 0, 0, + windowSize.right - windowSize.left, + windowSize.bottom - windowSize.top, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOZORDER ); __plugin->sendMessage( @@ -1742,6 +1748,7 @@ intptr_t RemoteVstPlugin::hostCallback( AEffect * _effect, int32_t _opcode, addInt( __plugin->m_windowWidth ). addInt( __plugin->m_windowHeight ) ); return 1; + } case audioMasterGetSampleRate: SHOW_CALLBACK( "amc: audioMasterGetSampleRate\n" ); From 0ad8527ff7f34f798ba911271ad936ca6964bb0d Mon Sep 17 00:00:00 2001 From: DomClark Date: Tue, 14 Aug 2018 21:58:44 +0100 Subject: [PATCH 08/16] Link RemoteVstPlugin with -mwindows Stops each remote plugin process spawning a console host, and seems more in line with what other hosts do. --- plugins/vst_base/CMakeLists.txt | 2 +- plugins/vst_base/Win64/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/vst_base/CMakeLists.txt b/plugins/vst_base/CMakeLists.txt index 67e52a9ff..5e2b50206 100644 --- a/plugins/vst_base/CMakeLists.txt +++ b/plugins/vst_base/CMakeLists.txt @@ -12,7 +12,7 @@ IF(LMMS_BUILD_WIN32) TARGET_LINK_LIBRARIES(RemoteVstPlugin -lQtCore4) ENDIF() TARGET_LINK_LIBRARIES(RemoteVstPlugin -lpthread -lgdi32 -lws2_32) - SET_TARGET_PROPERTIES(RemoteVstPlugin PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O0") + SET_TARGET_PROPERTIES(RemoteVstPlugin PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O0" LINK_FLAGS "${LINK_FLAGS} -mwindows") ADD_CUSTOM_COMMAND(TARGET RemoteVstPlugin POST_BUILD COMMAND "${STRIP}" "$") INSTALL(TARGETS RemoteVstPlugin RUNTIME DESTINATION "${PLUGIN_DIR}") diff --git a/plugins/vst_base/Win64/CMakeLists.txt b/plugins/vst_base/Win64/CMakeLists.txt index 6a670829c..4895fcbac 100644 --- a/plugins/vst_base/Win64/CMakeLists.txt +++ b/plugins/vst_base/Win64/CMakeLists.txt @@ -11,7 +11,7 @@ ENDIF() TARGET_LINK_LIBRARIES(RemoteVstPlugin32 -l${QTCORE} -lpthread -lgdi32 -lws2_32) ADD_CUSTOM_COMMAND(TARGET RemoteVstPlugin32 POST_BUILD COMMAND "${STRIP}" "$") -SET_TARGET_PROPERTIES(RemoteVstPlugin32 PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O0") +SET_TARGET_PROPERTIES(RemoteVstPlugin32 PROPERTIES COMPILE_FLAGS "${COMPILE_FLAGS} -O0" LINK_FLAGS "${LINK_FLAGS} -mwindows") INSTALL(TARGETS RemoteVstPlugin32 RUNTIME DESTINATION "${PLUGIN_DIR}/32") INSTALL(FILES "${MINGW_PREFIX32}/bin/${QTCORE}.dll" "${MINGW_PREFIX32}/bin/zlib1.dll" "${MINGW_PREFIX32}/${CMAKE_SYSTEM_PROCESSOR32}-w64-mingw32/bin/libwinpthread-1.dll" From 4c7c68f45a3414f355ec2b17ff235943f93bd199 Mon Sep 17 00:00:00 2001 From: justnope Date: Fri, 18 May 2018 21:04:54 +0200 Subject: [PATCH 09/16] Initialise OLE in RemoteVstPlugin Some plugins don't initialise it themselves, expecting it already to be done for them, and so are liable to hang without it (e.g. TX16Wx). Co-authored-by: Hyunjin Song Co-authored-by: Dominic Clark --- plugins/vst_base/CMakeLists.txt | 2 +- plugins/vst_base/RemoteVstPlugin.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/plugins/vst_base/CMakeLists.txt b/plugins/vst_base/CMakeLists.txt index 5e2b50206..84920d9be 100644 --- a/plugins/vst_base/CMakeLists.txt +++ b/plugins/vst_base/CMakeLists.txt @@ -56,7 +56,7 @@ SET(WINE_CXX_ARGS -L${WINE_LIBRARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/RemoteVstPlugin.cpp -std=c++0x - -mwindows -lpthread ${EXTRA_FLAGS} -fno-omit-frame-pointer + -mwindows -lpthread -lole32 ${EXTRA_FLAGS} -fno-omit-frame-pointer ${WINE_BUILD_FLAGS} -o ../RemoteVstPlugin ) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 12a27d183..219a153f5 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -2061,6 +2061,8 @@ int main( int _argc, char * * _argv ) return -1; } + OleInitialize(nullptr); + #ifdef LMMS_BUILD_WIN32 #ifndef __WINPTHREADS_VERSION // (non-portable) initialization of statically linked pthread library @@ -2176,6 +2178,7 @@ int main( int _argc, char * * _argv ) delete __plugin; + OleUninitialize(); #ifdef LMMS_BUILD_WIN32 #ifndef __WINPTHREADS_VERSION From c3db486be0cd404b3d1a93d7976b6b4819b957b6 Mon Sep 17 00:00:00 2001 From: Dominic Clark Date: Fri, 7 Sep 2018 22:02:45 +0100 Subject: [PATCH 10/16] Set VST program first when restoring settings Fixes a bug where some VSTs (e.g. Temper) would have their settings reset on project load, due to using programs as presets. --- plugins/vst_base/VstPlugin.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index 26c789275..157665eb5 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -157,6 +157,11 @@ void VstPlugin::tryLoad( const QString &remoteVstPluginExecutable ) void VstPlugin::loadSettings( const QDomElement & _this ) { + if( _this.hasAttribute( "program" ) ) + { + setProgram( _this.attribute( "program" ).toInt() ); + } + const int num_params = _this.attribute( "numparams" ).toInt(); // if it exists try to load settings chunk if( _this.hasAttribute( "chunk" ) ) @@ -176,11 +181,6 @@ void VstPlugin::loadSettings( const QDomElement & _this ) } setParameterDump( dump ); } - - if( _this.hasAttribute( "program" ) ) - { - setProgram( _this.attribute( "program" ).toInt() ); - } } From f37ca49e6d52886d40858e23acd1d3ed32f97a71 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Wed, 12 Sep 2018 11:02:40 +0900 Subject: [PATCH 11/16] Fix decimal separator handling (#4547) Makes LMMS can handle both periods and commas properly when loading real numbers. --- include/DataFile.h | 19 ------ include/LocaleHelper.h | 67 +++++++++++++++++++ plugins/MidiExport/MidiExport.cpp | 7 +- plugins/VstEffect/VstEffectControls.cpp | 9 +-- plugins/vestige/vestige.cpp | 9 +-- plugins/vst_base/VstPlugin.cpp | 3 +- .../zynaddsubfx/src/Misc/QtXmlWrapper.cpp | 9 +-- src/core/AutomatableModel.cpp | 5 +- src/core/AutomationPattern.cpp | 7 +- src/core/DataFile.cpp | 38 ++--------- src/core/Song.cpp | 4 -- src/gui/widgets/Knob.cpp | 3 +- src/tracks/InstrumentTrack.cpp | 2 - 13 files changed, 101 insertions(+), 81 deletions(-) create mode 100644 include/LocaleHelper.h diff --git a/include/DataFile.h b/include/DataFile.h index 6b6b1a98e..9a420135a 100644 --- a/include/DataFile.h +++ b/include/DataFile.h @@ -84,25 +84,6 @@ public: return m_type; } - // small helper class for adjusting application's locale settings - // when loading or saving floating point values rendered to strings - class LocaleHelper - { - public: - enum Modes - { - ModeLoad, - ModeSave, - ModeCount - }; - typedef Modes Mode; - - LocaleHelper( Mode mode ); - ~LocaleHelper(); - - }; - - private: static Type type( const QString& typeName ); static QString typeName( Type type ); diff --git a/include/LocaleHelper.h b/include/LocaleHelper.h new file mode 100644 index 000000000..c5d9d4c46 --- /dev/null +++ b/include/LocaleHelper.h @@ -0,0 +1,67 @@ +/* + * LocaleHelper.h - compatibility functions for handling decimal separators + * Providing helper functions which handle both periods and commas + * for decimal separators to load old projects correctly + * + * Copyright (c) 2014 Tobias Doerffel + * Copyright (c) 2018 Hyunjin Song + * + * This file is part of LMMS - https://lmms.io + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program (see COPYING); if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + */ + +#ifndef LOCALEHELPER_H +#define LOCALEHELPER_H + +#include + +#include +#include + +namespace LocaleHelper +{ +inline double toDouble(QString str, bool* ok = nullptr) +{ + bool isOkay; + double value; + QLocale c(QLocale::C); + c.setNumberOptions(QLocale::RejectGroupSeparator); + value = c.toDouble(str, &isOkay); + if (!isOkay) + { + QLocale german(QLocale::German); + german.setNumberOptions(QLocale::RejectGroupSeparator); + value = german.toDouble(str, &isOkay); + } + if (ok != nullptr) {*ok = isOkay;} + return value; +} + +inline float toFloat(QString str, bool* ok = nullptr) +{ + double d = toDouble(str, ok); + if (!std::isinf(d) && std::fabs(d) > std::numeric_limits::max()) + { + if (ok != nullptr) {*ok = false;} + return 0.0f; + } + return static_cast(d); +} +} + +#endif // LOCALEHELPER_H diff --git a/plugins/MidiExport/MidiExport.cpp b/plugins/MidiExport/MidiExport.cpp index 1e20e9d40..65eaf4613 100644 --- a/plugins/MidiExport/MidiExport.cpp +++ b/plugins/MidiExport/MidiExport.cpp @@ -36,6 +36,7 @@ #include "TrackContainer.h" #include "BBTrack.h" #include "InstrumentTrack.h" +#include "LocaleHelper.h" extern "C" @@ -133,7 +134,7 @@ bool MidiExport::tryExport(const TrackContainer::TrackList &tracks, { base_pitch += masterPitch; } - base_volume = it.attribute("volume", "100").toDouble()/100.0; + base_volume = LocaleHelper::toDouble(it.attribute("volume", "100"))/100.0; } if (n.nodeName() == "pattern") @@ -204,7 +205,7 @@ bool MidiExport::tryExport(const TrackContainer::TrackList &tracks, { base_pitch += masterPitch; } - base_volume = it.attribute("volume", "100").toDouble() / 100.0; + base_volume = LocaleHelper::toDouble(it.attribute("volume", "100")) / 100.0; } if (n.nodeName() == "pattern") @@ -273,7 +274,7 @@ void MidiExport::writePattern(MidiNoteVector &pat, QDomNode n, // TODO interpret pan="0" fxch="0" pitchrange="1" MidiNote mnote; mnote.pitch = qMax(0, qMin(127, note.attribute("key", "0").toInt() + base_pitch)); - mnote.volume = qMin(qRound(base_volume * note.attribute("vol", "100").toDouble()), 127); + mnote.volume = qMin(qRound(base_volume * LocaleHelper::toDouble(note.attribute("vol", "100"))), 127); mnote.time = base_time + note.attribute("pos", "0").toInt(); mnote.duration = note.attribute("len", "0").toInt(); pat.push_back(mnote); diff --git a/plugins/VstEffect/VstEffectControls.cpp b/plugins/VstEffect/VstEffectControls.cpp index 21d940ddc..e5261d625 100644 --- a/plugins/VstEffect/VstEffectControls.cpp +++ b/plugins/VstEffect/VstEffectControls.cpp @@ -27,6 +27,7 @@ #include "VstEffectControls.h" #include "VstEffect.h" +#include "LocaleHelper.h" #include "MainWindow.h" #include "GuiApplication.h" #include @@ -85,8 +86,8 @@ void VstEffectControls::loadSettings( const QDomElement & _this ) if( !( knobFModel[ i ]->isAutomated() || knobFModel[ i ]->controllerConnection() ) ) { - knobFModel[ i ]->setValue( (s_dumpValues.at( 2 ) ).toFloat() ); - knobFModel[ i ]->setInitValue( (s_dumpValues.at( 2 ) ).toFloat() ); + knobFModel[ i ]->setValue(LocaleHelper::toFloat(s_dumpValues.at(2))); + knobFModel[ i ]->setInitValue(LocaleHelper::toFloat(s_dumpValues.at(2))); } connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); @@ -381,7 +382,7 @@ manageVSTEffectView::manageVSTEffectView( VstEffect * _eff, VstEffectControls * if( !hasKnobModel ) { sprintf( paramStr, "%d", i); - m_vi->knobFModel[ i ] = new FloatModel( ( s_dumpValues.at( 2 ) ).toFloat(), + m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)), 0.0f, 1.0f, 0.01f, _eff, tr( paramStr ) ); } connect( m_vi->knobFModel[ i ], SIGNAL( dataChanged() ), this, @@ -445,7 +446,7 @@ void manageVSTEffectView::syncPlugin( void ) { sprintf( paramStr, "param%d", i ); s_dumpValues = dump[ paramStr ].split( ":" ); - f_value = ( s_dumpValues.at( 2 ) ).toFloat(); + f_value = LocaleHelper::toFloat(s_dumpValues.at(2)); m_vi2->knobFModel[ i ]->setAutomatedValue( f_value ); m_vi2->knobFModel[ i ]->setInitValue( f_value ); } diff --git a/plugins/vestige/vestige.cpp b/plugins/vestige/vestige.cpp index 540c8b5ce..b958e8ddf 100644 --- a/plugins/vestige/vestige.cpp +++ b/plugins/vestige/vestige.cpp @@ -41,6 +41,7 @@ #include "InstrumentPlayHandle.h" #include "InstrumentTrack.h" #include "VstPlugin.h" +#include "LocaleHelper.h" #include "MainWindow.h" #include "Mixer.h" #include "GuiApplication.h" @@ -203,8 +204,8 @@ void vestigeInstrument::loadSettings( const QDomElement & _this ) if( !( knobFModel[ i ]->isAutomated() || knobFModel[ i ]->controllerConnection() ) ) { - knobFModel[ i ]->setValue( ( s_dumpValues.at( 2 )).toFloat() ); - knobFModel[ i ]->setInitValue( ( s_dumpValues.at( 2 )).toFloat() ); + knobFModel[ i ]->setValue(LocaleHelper::toFloat(s_dumpValues.at(2))); + knobFModel[ i ]->setInitValue(LocaleHelper::toFloat(s_dumpValues.at(2))); } connect( knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); @@ -991,7 +992,7 @@ manageVestigeInstrumentView::manageVestigeInstrumentView( Instrument * _instrume if( !hasKnobModel ) { sprintf( paramStr, "%d", i); - m_vi->knobFModel[ i ] = new FloatModel( (s_dumpValues.at( 2 )).toFloat(), + m_vi->knobFModel[ i ] = new FloatModel( LocaleHelper::toFloat(s_dumpValues.at(2)), 0.0f, 1.0f, 0.01f, castModel(), tr( paramStr ) ); } connect( m_vi->knobFModel[i], SIGNAL( dataChanged() ), this, SLOT( setParameter() ) ); @@ -1052,7 +1053,7 @@ void manageVestigeInstrumentView::syncPlugin( void ) { sprintf( paramStr, "param%d", i ); s_dumpValues = dump[ paramStr ].split( ":" ); - f_value = ( s_dumpValues.at( 2 ) ).toFloat(); + f_value = LocaleHelper::toFloat(s_dumpValues.at(2)); m_vi->knobFModel[ i ]->setAutomatedValue( f_value ); m_vi->knobFModel[ i ]->setInitValue( f_value ); } diff --git a/plugins/vst_base/VstPlugin.cpp b/plugins/vst_base/VstPlugin.cpp index 157665eb5..a97802bdc 100644 --- a/plugins/vst_base/VstPlugin.cpp +++ b/plugins/vst_base/VstPlugin.cpp @@ -56,6 +56,7 @@ #include "ConfigManager.h" #include "GuiApplication.h" +#include "LocaleHelper.h" #include "MainWindow.h" #include "Mixer.h" #include "Song.h" @@ -299,7 +300,7 @@ void VstPlugin::setParameterDump( const QMap & _pdump ) { ( *it ).section( ':', 0, 0 ).toInt(), "", - ( *it ).section( ':', 2, -1 ).toFloat() + LocaleHelper::toFloat((*it).section(':', 2, -1)) } ; m.addInt( item.index ); m.addString( item.shortLabel ); diff --git a/plugins/zynaddsubfx/zynaddsubfx/src/Misc/QtXmlWrapper.cpp b/plugins/zynaddsubfx/zynaddsubfx/src/Misc/QtXmlWrapper.cpp index bab513829..d4b6875a0 100644 --- a/plugins/zynaddsubfx/zynaddsubfx/src/Misc/QtXmlWrapper.cpp +++ b/plugins/zynaddsubfx/zynaddsubfx/src/Misc/QtXmlWrapper.cpp @@ -61,6 +61,7 @@ // Include LMMS headers #include "lmmsconfig.h" #include "IoHelper.h" +#include "LocaleHelper.h" struct XmlData @@ -228,14 +229,14 @@ int QtXmlWrapper::dosavefile(const char *filename, void QtXmlWrapper::addpar(const std::string &name, int val) { - d->addparams("par", 2, "name", name.c_str(), "value", stringFrom( - val).c_str()); + d->addparams("par", 2, "name", name.c_str(), "value", + QString::number(val).toLocal8Bit().constData()); } void QtXmlWrapper::addparreal(const std::string &name, float val) { d->addparams("par_real", 2, "name", name.c_str(), "value", - stringFrom(val).c_str()); + QString::number(val, 'f').toLocal8Bit().constData()); } void QtXmlWrapper::addparbool(const std::string &name, int val) @@ -510,7 +511,7 @@ float QtXmlWrapper::getparreal(const char *name, float defaultpar) const return defaultpar; } - return QLocale().toFloat( tmp.attribute( "value" ) ); + return LocaleHelper::toFloat( tmp.attribute( "value" ) ); } float QtXmlWrapper::getparreal(const char *name, diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 0b2a1522b..ba81a5893 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -28,6 +28,7 @@ #include "AutomationPattern.h" #include "ControllerConnection.h" +#include "LocaleHelper.h" #include "Mixer.h" #include "ProjectJournal.h" @@ -183,7 +184,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString& if( node.isElement() ) { changeID( node.toElement().attribute( "id" ).toInt() ); - setValue( node.toElement().attribute( "value" ).toFloat() ); + setValue( LocaleHelper::toFloat( node.toElement().attribute( "value" ) ) ); if( node.toElement().hasAttribute( "scale_type" ) ) { if( node.toElement().attribute( "scale_type" ) == "linear" ) @@ -204,7 +205,7 @@ void AutomatableModel::loadSettings( const QDomElement& element, const QString& if( element.hasAttribute( name ) ) // attribute => read the element's value from the attribute list { - setInitValue( element.attribute( name ).toFloat() ); + setInitValue( LocaleHelper::toFloat( element.attribute( name ) ) ); } else { diff --git a/src/core/AutomationPattern.cpp b/src/core/AutomationPattern.cpp index 32b13f3f4..25da6defb 100644 --- a/src/core/AutomationPattern.cpp +++ b/src/core/AutomationPattern.cpp @@ -28,6 +28,7 @@ #include "AutomationPatternView.h" #include "AutomationTrack.h" +#include "LocaleHelper.h" #include "Note.h" #include "ProjectJournal.h" #include "BBTrackContainer.h" @@ -154,11 +155,11 @@ void AutomationPattern::setProgressionType( void AutomationPattern::setTension( QString _new_tension ) { bool ok; - float nt = _new_tension.toFloat( & ok ); + float nt = LocaleHelper::toFloat(_new_tension, & ok); if( ok && nt > -0.01 && nt < 1.01 ) { - m_tension = _new_tension.toFloat(); + m_tension = nt; } } @@ -595,7 +596,7 @@ void AutomationPattern::loadSettings( const QDomElement & _this ) if( element.tagName() == "time" ) { m_timeMap[element.attribute( "pos" ).toInt()] - = element.attribute( "value" ).toFloat(); + = LocaleHelper::toFloat(element.attribute("value")); } else if( element.tagName() == "object" ) { diff --git a/src/core/DataFile.cpp b/src/core/DataFile.cpp index dc2b1de57..47df25614 100644 --- a/src/core/DataFile.cpp +++ b/src/core/DataFile.cpp @@ -38,6 +38,7 @@ #include "Effect.h" #include "embed.h" #include "GuiApplication.h" +#include "LocaleHelper.h" #include "PluginFactory.h" #include "ProjectVersion.h" #include "SongEditor.h" @@ -65,37 +66,6 @@ DataFile::typeDescStruct -DataFile::LocaleHelper::LocaleHelper( Mode mode ) -{ - switch( mode ) - { - case ModeLoad: - // set a locale for which QString::fromFloat() returns valid values if - // floating point separator is a comma - otherwise we would fail to load - // older projects made by people from various countries due to their - // locale settings - QLocale::setDefault( QLocale::German ); - break; - - case ModeSave: - // set default locale to C so that floating point decimals are rendered to - // strings with periods as decimal point instead of commas in some countries - QLocale::setDefault( QLocale::C ); - - default: break; - } -} - - - -DataFile::LocaleHelper::~LocaleHelper() -{ - // revert to original locale - QLocale::setDefault( QLocale::system() ); -} - - - DataFile::DataFile( Type type ) : QDomDocument( "lmms-project" ), @@ -416,8 +386,8 @@ void DataFile::upgrade_0_2_1_20070501() QDomElement el = list.item( i ).toElement(); if( el.attribute( "vol" ) != "" ) { - el.setAttribute( "vol", el.attribute( - "vol" ).toFloat() * 100.0f ); + el.setAttribute( "vol", LocaleHelper::toFloat( + el.attribute( "vol" ) ) * 100.0f ); } else { @@ -543,7 +513,7 @@ void DataFile::upgrade_0_2_1_20070508() QDomElement el = list.item( i ).toElement(); if( el.hasAttribute( "vol" ) ) { - float value = el.attribute( "vol" ).toFloat(); + float value = LocaleHelper::toFloat( el.attribute( "vol" ) ); value = roundf( value * 0.585786438f ); el.setAttribute( "vol", value ); } diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 217a8752e..1ebc684c1 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -1034,8 +1034,6 @@ void Song::loadProject( const QString & fileName ) clearErrors(); - DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeLoad ); - Engine::mixer()->requestChangeInModel(); // get the header information from the DOM @@ -1191,8 +1189,6 @@ void Song::loadProject( const QString & fileName ) // only save current song as _filename and do nothing else bool Song::saveProjectFile( const QString & filename ) { - DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeSave ); - DataFile dataFile( DataFile::SongProject ); m_tempoModel.saveSettings( dataFile, dataFile.head(), "bpm" ); diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 73ef42758..72c6c7f8b 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -42,6 +42,7 @@ #include "embed.h" #include "gui_templates.h" #include "GuiApplication.h" +#include "LocaleHelper.h" #include "MainWindow.h" #include "ProjectJournal.h" #include "Song.h" @@ -560,7 +561,7 @@ void Knob::dropEvent( QDropEvent * _de ) QString val = StringPairDrag::decodeValue( _de ); if( type == "float_value" ) { - model()->setValue( val.toFloat() ); + model()->setValue( LocaleHelper::toFloat(val) ); _de->accept(); } else if( type == "automatable_model" ) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 90dbf11a6..d5ded0c70 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -1618,8 +1618,6 @@ void InstrumentTrackWindow::saveSettingsBtnClicked() !sfd.selectedFiles().isEmpty() && !sfd.selectedFiles().first().isEmpty() ) { - DataFile::LocaleHelper localeHelper( DataFile::LocaleHelper::ModeSave ); - DataFile dataFile( DataFile::InstrumentTrackSettings ); m_track->setSimpleSerializing(); m_track->saveSettings( dataFile, dataFile.content() ); From a5a13b1256704b136ea60ac475cfae745396c857 Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Wed, 29 Aug 2018 19:35:06 +0200 Subject: [PATCH 12/16] Restructure help * Allow actions (dump, render*, upgrade) without minuses * Restructure help in CLI * Restructure help in man pages --- doc/lmms.1 | 146 +++++++++++++++++----------------------------- src/core/main.cpp | 121 ++++++++++++++++++-------------------- 2 files changed, 109 insertions(+), 158 deletions(-) diff --git a/doc/lmms.1 b/doc/lmms.1 index 41f906ecf..16b1e5284 100644 --- a/doc/lmms.1 +++ b/doc/lmms.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH LMMS 1 "June 15, 2017" +.TH LMMS 1 "September 10, 2018" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -19,125 +19,83 @@ lmms \- software for easy music production .SH SYNOPSIS .B lmms -.RB "[ \--\fBallowroot\fP ]" +.RB "[\fBglobal options...\fP] [\fBaction\fP [\fBaction parameters\fP...]] .br -.B lmms -.RB "[ \--\fBbitrate\fP \fIbitrate\fP ]" -.br -.B lmms -.RB "[ \--\fBconfig\fP \fIconfigfile\fP ]" -.br -.B lmms -.RB "[ \--\fBdump\fP \fIin\fP ]" -.br -.B lmms -.RB "[ \--\fBfloat\fP ]" -.br -.B lmms -.RB "[ \--\fBformat\fP \fIformat\fP ]" -.br -.B lmms -.RB "[ \--\fBgeometry\fP \fIgeometry\fP ]" -.br -.B lmms -.RB "[ \--\fBhelp\fP ]" -.br -.B lmms -.RB "[ \--\interpolation\fP \fImethod\fP ]" -.br -.B lmms -.RB "[ \--\fBimport\fP \fIin\fP [ \-e ] ]" -.br -.B lmms -.RB "[ \--\fBloop\fP ]" -.br -.B lmms -.RB "[ \--\fBmode\fP \fIstereomode\fP ]" -.br -.B lmms -.RB "[ \--\fBoutput\fP \fIpath\fP ]" -.br -.B lmms -.RB "[ \--\fBoversampling\fP \fIvalue\fP ]" -.br -.B lmms -.RB "[ \--\fBprofile\fP \fIout\fP ]" -.br -.B lmms -.RB "[ \--\fBrender\fP \fIfile\fP ] [options]" -.br -.B lmms -.RB "[ \--\fBsamplerate\fP \fIsamplerate\fP ]" -.br -.B lmms -.RB "[ \--\fBupgrade\fP \fIin\fP \fIout\fP ]" -.br -.B lmms -.RB "[ \--\fBversion\fP ]" -.br -.B lmms -.RI "[ file ]" .SH DESCRIPTION .PP .\" TeX users may be more comfortable with the \fB\fP and .\" \fI\fP escape sequences to invode bold face and italics, .\" respectively. .B LMMS -LMMS is a free cross-platform alternative to commercial programs like FL Studio®, which allow you to produce music with your computer. This includes the creation of melodies and beats, the synthesis and mixing of sounds, and arranging of samples. You can have fun with your MIDI-keyboard and much more; all in a user-friendly and modern interface. +is a free cross-platform alternative to commercial programs like FL Studio®, which allow you to produce music with your computer. This includes the creation of melodies and beats, the synthesis and mixing of sounds, and arranging of samples. You can have fun with your MIDI-keyboard and much more; all in a user-friendly and modern interface. LMMS features components such as a Song Editor, a Beat+Bassline Editor, a Piano Roll, an FX Mixer as well as many powerful instruments and effects. -.SH OPTIONS -.IP "\fB\-a, --float\fP -32bit float bit depth -.IP "\fB\-b, --bitrate\fP \fIbitrate\fP -Specify output bitrate in KBit/s (for OGG encoding only), default is 160 +.SH ACTIONS + +.IP " [\fIoptions\fP...] [\fIproject\fP] +Start LMMS in normal GUI mode. +.IP "\fBdump\fP \fIin\fP +Dump XML of compressed (MMPZ) file \fIin\fP. +.IP "\fBrender\fP \fIproject\fP [\fIoptions\fP...] +Render given project file. +.IP "\fBrendertracks\fP \fIproject\fP [\fIoptions\fP...] +Render each track to a different file. +.IP "\fBupgrade\fP \fIin\fP [\fIout\fP] +Upgrade file \fIin\fP and save as \fIout\fP. Standard out is used if no output file is specifed. + +.SH GLOBAL OPTIONS + +.IP "\fB\ --allowroot +Bypass root user startup check (use with caution). .IP "\fB\-c, --config\fP \fIconfigfile\fP -Get the configuration from \fIconfigfile\fP instead of ~/.lmmsrc.xml (default) -.IP "\fB\-d, --dump\fP \fIin\fP -Dump XML of compressed file \fIin\fP (i.e. MMPZ-file) -.IP "\fB\-f, --format\fP \fIformat\fP -Specify format of render-output where \fIformat\fP is either 'wav', 'ogg' or 'mp3'. -.IP "\fB\ --geometry\fP \fIgeometry\fP -Specify the prefered size and position of the main window -.br -\fIgeometry\fP syntax is <\fIxsize\fPx\fIysize\fP+\fIxoffset\fP+\fIyoffset\fP>. -.br -Default: full screen +Get the configuration from \fIconfigfile\fP instead of ~/.lmmsrc.xml (default). .IP "\fB\-h, --help\fP Show usage information and exit. -.IP "\fB\-i, --interpolation\fP \fImethod\fP -Specify interpolation method - possible values are \fIlinear\fP, \fIsincfastest\fP (default), \fIsincmedium\fP, \fIsincbest\fP -.IP "\fB\ --import\fP \fIin\fP \fB\-e\fP -Import MIDI file \fIin\fP +.IP "\fB\-v, --version +Show version information and exit. + +.SH OPTIONS IF NO ACTION IS GIVEN + +.IP "\fB\ --geometry\fP \fIgeometry\fP +Specify the prefered size and position of the main window. .br +\fIgeometry\fP syntax is \fIxsize\fPx\fIysize\fP+\fIxoffset\fP+\fIyoffset\fP. +.br +Default: full screen. +.IP "\fB\ --import\fP \fIin\fP \fB\-e\fP +Import MIDI or Hydrogen file \fIin\fP. +.br + +.SH OPTIONS FOR RENDER AND RENDERTRACKS + +.IP "\fB\-a, --float\fP +Use 32bit float bit depth. +.IP "\fB\-b, --bitrate\fP \fIbitrate\fP +Specify output bitrate in KBit/s (for OGG encoding only), default is 160. +.IP "\fB\-f, --format\fP \fIformat\fP +Specify format of render-output where \fIformat\fP is either 'wav', 'ogg' or 'mp3'. +.IP "\fB\-i, --interpolation\fP \fImethod\fP +Specify interpolation method - possible values are \fIlinear\fP, \fIsincfastest\fP (default), \fIsincmedium\fP, \fIsincbest\fP. + If -e is specified lmms exits after importing the file. .IP "\fB\-l, --loop Render the given file as a loop, i.e. stop rendering at exactly the end of the song. Additional silence or reverb tails at the end of the song are not rendered. .IP "\fB\-m, --mode\fP \fIstereomode\fP Set the stereo mode used for the MP3 export. \fIstereomode\fP can be either 's' (stereo mode), 'j' (joint stereo) or 'm' (mono). If no mode is given 'j' is used as the default. .IP "\fB\-o, --output\fP \fIpath\fP -Render into \fIpath\fP +Render into \fIpath\fP. .br For --render, this is interpreted as a file path. .br For --render-tracks, this is interpreted as a path to an existing directory. -IP "\fB\-p, --profile\fP \fIout\fP -Dump profiling information to file \fIout\fP -.IP "\fB\-r, --render\fP \fIproject-file\fP -Render given file to either a wav\- or ogg\-file. See \fB\-f\fP for details -.IP "\fB\-r, --rendertracks\fP \fIproject-file\fP -Render each track into a separate wav\- or ogg\-file. See \fB\-f\fP for details +.IP "\fB\-p, --profile\fP \fIout\fP +Dump profiling information to file \fIout\fP. .IP "\fB\-s, --samplerate\fP \fIsamplerate\fP -Specify output samplerate in Hz - range is 44100 (default) to 192000 -.IP "\fB\-u, --upgrade\fP \fIin\fP \fIout\fP -Upgrade file \fIin\fP and save as \fIout\fP -.IP "\fB\-v, --version -Show version information and exit. +Specify output samplerate in Hz - range is 44100 (default) to 192000. .IP "\fB\-x, --oversampling\fP \fIvalue\fP -Specify oversampling, possible values: 1, 2 (default), 4, 8 -.IP "\fB\ --allowroot -Bypass root user startup check (use with caution). +Specify oversampling, possible values: 1, 2 (default), 4, 8. + .SH SEE ALSO .BR https://lmms.io/ .BR https://lmms.io/documentation/ diff --git a/src/core/main.cpp b/src/core/main.cpp index fc8dd5de2..721f83479 100644 --- a/src/core/main.cpp +++ b/src/core/main.cpp @@ -113,65 +113,57 @@ void printHelp() { printf( "LMMS %s\n" "Copyright (c) %s\n\n" - "Usage: lmms [ -a ]\n" - " [ -b ]\n" - " [ -c ]\n" - " [ -d ]\n" - " [ -f ]\n" - " [ --geometry ]\n" - " [ -h ]\n" - " [ -i ]\n" - " [ --import [-e]]\n" - " [ -l ]\n" - " [ -m ]\n" - " [ -o ]\n" - " [ -p ]\n" - " [ -r ] [ options ]\n" - " [ -s ]\n" - " [ -u ]\n" - " [ -v ]\n" - " [ -x ]\n" - " [ ]\n\n" - "-a, --float 32bit float bit depth\n" - "-b, --bitrate Specify output bitrate in KBit/s\n" - " Default: 160.\n" - "-c, --config Get the configuration from \n" - "-d, --dump Dump XML of compressed file \n" - "-f, --format Specify format of render-output where\n" - " Format is either 'wav', 'ogg' or 'mp3'.\n" - " --geometry Specify the size and position of the main window\n" - " geometry is .\n" - "-h, --help Show this usage information and exit.\n" - "-i, --interpolation Specify interpolation method\n" - " Possible values:\n" - " - linear\n" - " - sincfastest (default)\n" - " - sincmedium\n" - " - sincbest\n" - " --import [-e] Import MIDI file .\n" - " If -e is specified lmms exits after importing the file.\n" - "-l, --loop Render as a loop\n" - "-m, --mode Stereo mode used for MP3 export\n" - " Possible values: s, j, m\n" - " s: Stereo\n" - " j: Joint Stereo\n" - " m: Mono\n" - " Default: j\n" - "-o, --output Render into \n" - " For --render, provide a file path\n" - " For --rendertracks, provide a directory path\n" - "-p, --profile Dump profiling information to file \n" - "-r, --render Render given project file\n" - " --rendertracks Render each track to a different file\n" - "-s, --samplerate Specify output samplerate in Hz\n" - " Range: 44100 (default) to 192000\n" - "-u, --upgrade [out] Upgrade file and save as \n" - " Standard out is used if no output file is specifed\n" - "-v, --version Show version information and exit.\n" - " --allowroot Bypass root user startup check (use with caution).\n" - "-x, --oversampling Specify oversampling\n" - " Possible values: 1, 2, 4, 8\n" - " Default: 2\n\n", + "Usage: lmms [global options...] [ [action parameters...]]\n\n" + "Actions:\n" + " [options...] [] Start LMMS in normal GUI mode\n" + " dump Dump XML of compressed file \n" + " render [options...] Render given project file\n" + " rendertracks [options...] Render each track to a different file\n" + " upgrade [out] Upgrade file and save as \n" + " Standard out is used if no output file\n" + " is specifed\n" + "\nGlobal options:\n" + " --allowroot Bypass root user startup check (use with\n" + " caution).\n" + " -c, --config Get the configuration from \n" + " -h, --help Show this usage information and exit.\n" + " -v, --version Show version information and exit.\n" + "\nOptions if no action is given:\n" + " --geometry Specify the size and position of\n" + " the main window\n" + " geometry is .\n" + " --import [-e] Import MIDI or Hydrogen file .\n" + " If -e is specified lmms exits after importing the file.\n" + "\nOptions for \"render\" and \"rendertracks\":\n" + " -a, --float Use 32bit float bit depth\n" + " -b, --bitrate Specify output bitrate in KBit/s\n" + " Default: 160.\n" + " -f, --format Specify format of render-output where\n" + " Format is either 'wav', 'flac', 'ogg' or 'mp3'.\n" + " -i, --interpolation Specify interpolation method\n" + " Possible values:\n" + " - linear\n" + " - sincfastest (default)\n" + " - sincmedium\n" + " - sincbest\n" + " -l, --loop Render as a loop\n" + " -m, --mode Stereo mode used for MP3 export\n" + " Possible values: s, j, m\n" + " s: Stereo\n" + " j: Joint Stereo\n" + " m: Mono\n" + " Default: j\n" + " -o, --output Render into \n" + " For \"render\", provide a file path\n" + " For \"rendertracks\", provide a directory path\n" + " If not specified, render will overwrite the input file\n" + " For \"rendertracks\", this might be required\n" + " -p, --profile Dump profiling information to file \n" + " -s, --samplerate Specify output samplerate in Hz\n" + " Range: 44100 (default) to 192000\n" + " -x, --oversampling Specify oversampling\n" + " Possible values: 1, 2, 4, 8\n" + " Default: 2\n\n", LMMS_VERSION, LMMS_PROJECT_COPYRIGHT ); } @@ -224,11 +216,11 @@ int main( int argc, char * * argv ) if( arg == "--help" || arg == "-h" || arg == "--version" || arg == "-v" || - arg == "--render" || arg == "-r" ) + arg == "render" || arg == "--render" || arg == "-r" ) { coreOnly = true; } - else if( arg == "--rendertracks" ) + else if( arg == "rendertracks" || arg == "--rendertracks" ) { coreOnly = true; renderTracks = true; @@ -283,7 +275,7 @@ int main( int argc, char * * argv ) printHelp(); return EXIT_SUCCESS; } - else if( arg == "--upgrade" || arg == "-u" ) + else if( arg == "upgrade" || arg == "--upgrade" || arg == "-u") { ++i; @@ -321,7 +313,7 @@ int main( int argc, char * * argv ) #endif } - else if( arg == "--dump" || arg == "-d" ) + else if( arg == "dump" || arg == "--dump" || arg == "-d" ) { ++i; @@ -340,7 +332,8 @@ int main( int argc, char * * argv ) return EXIT_SUCCESS; } - else if( arg == "--render" || arg == "-r" || arg == "--rendertracks" ) + else if( arg == "render" || arg == "--render" || arg == "-r" || + arg == "rendertracks" || arg == "--rendertracks" ) { ++i; From 3064f03818198bf8881aff644a14b57e500938ed Mon Sep 17 00:00:00 2001 From: Hyunin Song Date: Wed, 6 Jun 2018 09:35:03 +0900 Subject: [PATCH 13/16] Validate audio/MIDI backend when opening setup dialog Original work: #4372 by @justnope --- src/gui/SetupDialog.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/SetupDialog.cpp b/src/gui/SetupDialog.cpp index 5e8f53c5c..23266f153 100644 --- a/src/gui/SetupDialog.cpp +++ b/src/gui/SetupDialog.cpp @@ -833,7 +833,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) : // If no preferred audio device is saved, save the current one QString audioDevName = ConfigManager::inst()->value( "mixer", "audiodev" ); - if( audioDevName.length() == 0 ) + if( m_audioInterfaces->findText(audioDevName) < 0 ) { audioDevName = Engine::mixer()->audioDevName(); ConfigManager::inst()->setValue( @@ -936,7 +936,7 @@ SetupDialog::SetupDialog( ConfigTabs _tab_to_open ) : QString midiDevName = ConfigManager::inst()->value( "mixer", "mididev" ); - if( midiDevName.length() == 0 ) + if( m_midiInterfaces->findText(midiDevName) < 0 ) { midiDevName = Engine::mixer()->midiClientName(); ConfigManager::inst()->setValue( From 91ca660161dbaf5a18d6b1cd2d90328140b99728 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Mon, 13 Aug 2018 15:35:27 +0900 Subject: [PATCH 14/16] Fallback to default audio/MIDI backends if invalid one is set Also shows the setup dialog in case of invalid audio backends --- include/Mixer.h | 3 + src/core/Mixer.cpp | 128 +++++++++++++++++++++++++++++++++++++++++ src/gui/MainWindow.cpp | 4 +- 3 files changed, 134 insertions(+), 1 deletion(-) diff --git a/include/Mixer.h b/include/Mixer.h index 499205892..3063b0f2b 100644 --- a/include/Mixer.h +++ b/include/Mixer.h @@ -308,6 +308,9 @@ public: void requestChangeInModel(); void doneChangeInModel(); + static bool isAudioDevNameValid(QString name); + static bool isMidiDevNameValid(QString name); + signals: void qualitySettingsChanged(); diff --git a/src/core/Mixer.cpp b/src/core/Mixer.cpp index d5baa0a85..67736742d 100644 --- a/src/core/Mixer.cpp +++ b/src/core/Mixer.cpp @@ -829,14 +829,138 @@ void Mixer::runChangesInModel() } } +bool Mixer::isAudioDevNameValid(QString name) +{ +#ifdef LMMS_HAVE_SDL + if (name == AudioSdl::name()) + { + return true; + } +#endif +#ifdef LMMS_HAVE_ALSA + if (name == AudioAlsa::name()) + { + return true; + } +#endif + + +#ifdef LMMS_HAVE_PULSEAUDIO + if (name == AudioPulseAudio::name()) + { + return true; + } +#endif + + +#ifdef LMMS_HAVE_OSS + if (name == AudioOss::name()) + { + return true; + } +#endif + +#ifdef LMMS_HAVE_SNDIO + if (name == AudioSndio::name()) + { + return true; + } +#endif + +#ifdef LMMS_HAVE_JACK + if (name == AudioJack::name()) + { + return true; + } +#endif + + +#ifdef LMMS_HAVE_PORTAUDIO + if (name == AudioPortAudio::name()) + { + return true; + } +#endif + + +#ifdef LMMS_HAVE_SOUNDIO + if (name == AudioSoundIo::name()) + { + return true; + } +#endif + + if (name == AudioDummy::name()) + { + return true; + } + + return false; +} + +bool Mixer::isMidiDevNameValid(QString name) +{ +#ifdef LMMS_HAVE_ALSA + if (name == MidiAlsaSeq::name() || name == MidiAlsaRaw::name()) + { + return true; + } +#endif + +#ifdef LMMS_HAVE_JACK + if (name == MidiJack::name()) + { + return true; + } +#endif + +#ifdef LMMS_HAVE_OSS + if (name == MidiOss::name()) + { + return true; + } +#endif + +#ifdef LMMS_HAVE_SNDIO + if (name == MidiSndio::name()) + { + return true; + } +#endif + +#ifdef LMMS_BUILD_WIN32 + if (name == MidiWinMM::name()) + { + return true; + } +#endif + +#ifdef LMMS_BUILD_APPLE + if (name == MidiApple::name()) + { + return true; + } +#endif + + if (name == MidiDummy::name()) + { + return true; + } + + return false; +} AudioDevice * Mixer::tryAudioDevices() { bool success_ful = false; AudioDevice * dev = NULL; QString dev_name = ConfigManager::inst()->value( "mixer", "audiodev" ); + if( !isAudioDevNameValid( dev_name ) ) + { + dev_name = ""; + } m_audioDevStartFailed = false; @@ -980,6 +1104,10 @@ MidiClient * Mixer::tryMidiClients() { QString client_name = ConfigManager::inst()->value( "mixer", "mididev" ); + if( !isMidiDevNameValid( client_name ) ) + { + client_name = ""; + } #ifdef LMMS_HAVE_ALSA if( client_name == MidiAlsaSeq::name() || client_name == "" ) diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index c047bf96c..fa6958cef 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -590,7 +590,9 @@ void MainWindow::finalize() } // look whether mixer failed to start the audio device selected by the // user and is using AudioDummy as a fallback - else if( Engine::mixer()->audioDevStartFailed() ) + // or the audio device is set to invalid one + else if( Engine::mixer()->audioDevStartFailed() || !Mixer::isAudioDevNameValid( + ConfigManager::inst()->value( "mixer", "audiodev" ) ) ) { // if so, offer the audio settings section of the setup dialog SetupDialog sd( SetupDialog::AudioSettings ); From 153f15f4b4e702fc198611f2bc4a93a7e2e31228 Mon Sep 17 00:00:00 2001 From: Tres Finocchiaro Date: Sat, 15 Sep 2018 09:32:29 -0400 Subject: [PATCH 15/16] Add Carla support for MacOS (#4558) Add Carla support for MacOS --- .gitignore | 1 + .travis/osx..install.sh | 2 +- CMakeLists.txt | 6 +++- cmake/apple/install_apple.sh.in | 41 ++++++++++++++++++++----- cmake/modules/BuildPlugin.cmake | 6 +++- plugins/carlabase/CMakeLists.txt | 8 +++++ plugins/carlabase/carla.cpp | 28 ++++++----------- plugins/carlabase/carla.h | 18 +++++++++-- plugins/carlapatchbay/carlapatchbay.cpp | 4 +-- plugins/carlarack/carlarack.cpp | 4 +-- 10 files changed, 81 insertions(+), 37 deletions(-) diff --git a/.gitignore b/.gitignore index aa4f17ab8..771eba607 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ /build /target .*.sw? +.DS_Store *~ /CMakeLists.txt.user /plugins/zynaddsubfx/zynaddsubfx/ExternalPrograms/Controller/Makefile diff --git a/.travis/osx..install.sh b/.travis/osx..install.sh index 45a6762d1..dfe1df4d1 100644 --- a/.travis/osx..install.sh +++ b/.travis/osx..install.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -PACKAGES="cmake pkgconfig fftw libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio node fltk" +PACKAGES="cmake pkgconfig fftw libogg libvorbis lame libsndfile libsamplerate jack sdl libgig libsoundio stk fluid-synth portaudio node fltk carla" if [ $QT5 ]; then PACKAGES="$PACKAGES qt5" diff --git a/CMakeLists.txt b/CMakeLists.txt index 8be2f701f..452c05c5f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -231,7 +231,11 @@ ENDIF(WANT_TAP) # check for CARLA IF(WANT_CARLA) - PKG_CHECK_MODULES(CARLA carla-standalone>=1.9.5) + PKG_CHECK_MODULES(CARLA carla-native-plugin) + # look for carla under old name + IF(NOT CARLA_FOUND) + PKG_CHECK_MODULES(CARLA carla-standalone>=1.9.5) + ENDIF() IF(CARLA_FOUND) SET(LMMS_HAVE_CARLA TRUE) SET(STATUS_CARLA "OK") diff --git a/cmake/apple/install_apple.sh.in b/cmake/apple/install_apple.sh.in index 057cf5445..259734208 100644 --- a/cmake/apple/install_apple.sh.in +++ b/cmake/apple/install_apple.sh.in @@ -21,14 +21,7 @@ echo -e "$MSG_COLOR\n\nCreating App Bundle \"$APP\"...$COLOR_RESET" # Locate macdeployqt, assume homebrew & Qt5 which macdeployqt > /dev/null 2>&1 if [ $? -ne 0 ]; then - brew --prefix qt55 > /dev/null 2>&1 - if [ $? -eq 0 ]; then - # Prefer Qt 5.5 (QTBUG-53533) - export PATH=$PATH:$(brew --prefix qt55)/bin - else - # Fallback Qt 5.6+ - export PATH=$PATH:$(brew --prefix qt5)/bin - fi + export PATH=$PATH:$(brew --prefix qt)/bin fi # Remove any old .app bundles @@ -71,6 +64,17 @@ install_name_tool -change @rpath/libZynAddSubFxCore.dylib \ @loader_path/../../$zynfmk \ "$APP/Contents/$zynlib" +# Replace @rpath with @loader_path for Carla +# See also plugins/carlabase/CMakeLists.txt +# This MUST be done BEFORE calling macdeployqt +install_name_tool -change @rpath/libcarlabase.dylib \ + @loader_path/libcarlabase.dylib \ + "$APP/Contents/lib/lmms/libcarlapatchbay.so" + +install_name_tool -change @rpath/libcarlabase.dylib \ + @loader_path/libcarlabase.dylib \ + "$APP/Contents/lib/lmms/libcarlarack.so" + # Link lmms binary _executables="${_executables} -executable=$APP/Contents/$zynbin" _executables="${_executables} -executable=$APP/Contents/$zynfmk" @@ -90,6 +94,27 @@ done # Finalize .app macdeployqt "$APP" $_executables +# Carla is a standalone plugin. Remove library, look for it side-by-side LMMS.app +# This MUST be done AFTER calling macdeployqt +# +# For example: +# /Applications/LMMS.app +# /Applications/Carla.app +carlalibs=$(echo "@CARLA_LIBRARIES@"|tr ";" "\n") + +# Loop over all libcarlas, fix linking +for file in "$APP/Contents/lib/lmms/"libcarla*; do + _thisfile="$APP/Contents/lib/lmms/${file##*/}" + for lib in $carlalibs; do + _oldpath="../../Frameworks/lib${lib}.dylib" + _newpath="Carla.app/Contents/MacOS/lib${lib}.dylib" + install_name_tool -change @loader_path/$_oldpath \ + @executable_path/../../../$_newpath \ + "$_thisfile" + rm -f "$APP/Contents/Frameworks/lib${lib}.dylib" + done +done + # Cleanup rm -rf "$APP/Contents/bin" echo -e "\nFinished.\n\n" diff --git a/cmake/modules/BuildPlugin.cmake b/cmake/modules/BuildPlugin.cmake index f1dd95db6..25cca92af 100644 --- a/cmake/modules/BuildPlugin.cmake +++ b/cmake/modules/BuildPlugin.cmake @@ -73,7 +73,11 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME) INSTALL(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION "${PLUGIN_DIR}") IF(LMMS_BUILD_APPLE) - SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES LINK_FLAGS "-bundle_loader \"${CMAKE_BINARY_DIR}/lmms\"") + IF ("${PLUGIN_LINK}" STREQUAL "SHARED") + SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES LINK_FLAGS "-undefined dynamic_lookup") + ELSE() + SET_TARGET_PROPERTIES(${PLUGIN_NAME} PROPERTIES LINK_FLAGS "-bundle_loader \"${CMAKE_BINARY_DIR}/lmms\"") + ENDIF() ADD_DEPENDENCIES(${PLUGIN_NAME} lmms) ENDIF(LMMS_BUILD_APPLE) IF(LMMS_BUILD_WIN32) diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt index 8fdde2ec5..4fa81a491 100644 --- a/plugins/carlabase/CMakeLists.txt +++ b/plugins/carlabase/CMakeLists.txt @@ -1,3 +1,11 @@ +# For MacOS, use "OLD" RPATH install_name behavior +# This can be changed to "NEW" safely if install_apple.sh.in +# is updated to relink libcarlabase.dylib. MacOS 10.8 uses +# cmake 3.9.6, so this can be done at any time. +IF(NOT CMAKE_VERSION VERSION_LESS 3.9) + CMAKE_POLICY(SET CMP0068 OLD) +ENDIF() + if(LMMS_HAVE_CARLA) INCLUDE(BuildPlugin) INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp index 9221ad4f2..b25677f5c 100644 --- a/plugins/carlabase/carla.cpp +++ b/plugins/carlabase/carla.cpp @@ -1,7 +1,7 @@ /* * carla.cpp - Carla for LMMS * - * Copyright (C) 2014 Filipe Coelho + * Copyright (C) 2014-2018 Filipe Coelho * * This file is part of LMMS - https://lmms.io * @@ -24,9 +24,6 @@ #include "carla.h" -#define REAL_BUILD // FIXME this shouldn't be needed -#include "CarlaHost.h" - #include "Engine.h" #include "Song.h" #include "gui_templates.h" @@ -132,14 +129,6 @@ static const char* host_ui_save_file(NativeHostHandle, bool isDir, const char* t // ----------------------------------------------------------------------- -CARLA_EXPORT -const NativePluginDescriptor* carla_get_native_patchbay_plugin(); - -CARLA_EXPORT -const NativePluginDescriptor* carla_get_native_rack_plugin(); - -// ----------------------------------------------------------------------- - CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const Descriptor* const descriptor, const bool isPatchbay) : Instrument(instrumentTrack, descriptor), kIsPatchbay(isPatchbay), @@ -161,8 +150,9 @@ CarlaInstrument::CarlaInstrument(InstrumentTrack* const instrumentTrack, const D path.cdUp(); resourcesPath = path.absolutePath() + "/share/carla/resources"; #elif defined(CARLA_OS_MAC) - // assume standard install location - resourcesPath = "/Applications/Carla.app/Contents/MacOS/resources"; + // parse prefix from dll filename + QDir path = QFileInfo(dllName).dir(); + resourcesPath = path.absolutePath() + "/resources"; #elif defined(CARLA_OS_WIN32) || defined(CARLA_OS_WIN64) // not yet supported #endif @@ -254,7 +244,7 @@ void CarlaInstrument::handleUiClosed() emit uiClosed(); } -intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t index, const intptr_t value, void* const ptr, const float opt) +intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opcode, const int32_t, const intptr_t, void* const, const float) { intptr_t ret = 0; @@ -267,13 +257,10 @@ intptr_t CarlaInstrument::handleDispatcher(const NativeHostDispatcherOpcode opco qApp->processEvents(); break; default: - break; + break; } return ret; - - // unused for now - (void)index; (void)value; (void)ptr; (void)opt; } // ------------------------------------------------------------------- @@ -448,9 +435,12 @@ bool CarlaInstrument::handleMidiEvent(const MidiEvent& event, const MidiTime&, f PluginView* CarlaInstrument::instantiateView(QWidget* parent) { +// Disable plugin focus per https://bugreports.qt.io/browse/QTBUG-30181 +#ifndef CARLA_OS_MAC if (QWidget* const window = parent->window()) fHost.uiParentId = window->winId(); else +#endif fHost.uiParentId = 0; std::free((char*)fHost.uiName); diff --git a/plugins/carlabase/carla.h b/plugins/carlabase/carla.h index 6431e5300..fb54e2271 100644 --- a/plugins/carlabase/carla.h +++ b/plugins/carlabase/carla.h @@ -1,7 +1,7 @@ /* * carla.h - Carla for LMMS * - * Copyright (C) 2014 Filipe Coelho + * Copyright (C) 2014-2018 Filipe Coelho * * This file is part of LMMS - https://lmms.io * @@ -27,7 +27,19 @@ #include -#include "CarlaNative.h" +#define REAL_BUILD // FIXME this shouldn't be needed +#if CARLA_VERSION_HEX >= 0x010911 + #include "CarlaNativePlugin.h" +#else + #include "CarlaBackend.h" + #include "CarlaNative.h" + #include "CarlaUtils.h" + CARLA_EXPORT + const NativePluginDescriptor* carla_get_native_patchbay_plugin(); + + CARLA_EXPORT + const NativePluginDescriptor* carla_get_native_rack_plugin(); +#endif #include "Instrument.h" #include "InstrumentView.h" @@ -44,7 +56,7 @@ public: CarlaInstrument(InstrumentTrack* const instrumentTrack, const Descriptor* const descriptor, const bool isPatchbay); virtual ~CarlaInstrument(); - // CarlaNative functions + // Carla NativeHostDescriptor functions uint32_t handleGetBufferSize() const; double handleGetSampleRate() const; bool handleIsOffline() const; diff --git a/plugins/carlapatchbay/carlapatchbay.cpp b/plugins/carlapatchbay/carlapatchbay.cpp index ae6ca1906..42786d18a 100644 --- a/plugins/carlapatchbay/carlapatchbay.cpp +++ b/plugins/carlapatchbay/carlapatchbay.cpp @@ -1,7 +1,7 @@ /* * carlapatchbay.cpp - Carla for LMMS (Patchbay) * - * Copyright (C) 2014 Filipe Coelho + * Copyright (C) 2014-2018 Filipe Coelho * * This file is part of LMMS - https://lmms.io * @@ -36,7 +36,7 @@ Plugin::Descriptor PLUGIN_EXPORT carlapatchbay_plugin_descriptor = QT_TRANSLATE_NOOP( "pluginBrowser", "Carla Patchbay Instrument" ), "falkTX ", - 0x0195, + CARLA_VERSION_HEX, Plugin::Instrument, new PluginPixmapLoader( "logo" ), NULL, diff --git a/plugins/carlarack/carlarack.cpp b/plugins/carlarack/carlarack.cpp index 0a52c63c5..2149e6604 100644 --- a/plugins/carlarack/carlarack.cpp +++ b/plugins/carlarack/carlarack.cpp @@ -1,7 +1,7 @@ /* * carlarack.cpp - Carla for LMMS (Rack) * - * Copyright (C) 2014 Filipe Coelho + * Copyright (C) 2014-2018 Filipe Coelho * * This file is part of LMMS - https://lmms.io * @@ -36,7 +36,7 @@ Plugin::Descriptor PLUGIN_EXPORT carlarack_plugin_descriptor = QT_TRANSLATE_NOOP( "pluginBrowser", "Carla Rack Instrument" ), "falkTX ", - 0x0195, + CARLA_VERSION_HEX, Plugin::Instrument, new PluginPixmapLoader( "logo" ), NULL, From dd7b0865fbb212e5df178048f5c271d2fbaa5cdf Mon Sep 17 00:00:00 2001 From: Karmo Rosental Date: Mon, 17 Sep 2018 17:49:25 +0300 Subject: [PATCH 16/16] Update UI 60 times per second (#4570) * Update UI 60 times per second * Adjust falloff values --- plugins/Eq/EqFader.h | 6 +++--- plugins/Eq/EqSpectrumView.cpp | 2 +- src/gui/FxMixerView.cpp | 6 +++--- src/gui/MainWindow.cpp | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/Eq/EqFader.h b/plugins/Eq/EqFader.h index 6f9b26615..c588c2b92 100644 --- a/plugins/Eq/EqFader.h +++ b/plugins/Eq/EqFader.h @@ -80,7 +80,7 @@ private slots: { const float opl = getPeak_L(); const float opr = getPeak_R(); - const float fall_off = 1.2; + const float fallOff = 1.07; if( *m_lPeak > opl ) { setPeak_L( *m_lPeak ); @@ -88,7 +88,7 @@ private slots: } else { - setPeak_L( opl/fall_off ); + setPeak_L( opl/fallOff ); } if( *m_rPeak > opr ) @@ -98,7 +98,7 @@ private slots: } else { - setPeak_R( opr/fall_off ); + setPeak_R( opr/fallOff ); } update(); } diff --git a/plugins/Eq/EqSpectrumView.cpp b/plugins/Eq/EqSpectrumView.cpp index d44e01ece..677c896fb 100644 --- a/plugins/Eq/EqSpectrumView.cpp +++ b/plugins/Eq/EqSpectrumView.cpp @@ -224,7 +224,7 @@ void EqSpectrumView::paintEvent(QPaintEvent *event) float peak; m_path.moveTo( 0, height() ); m_peakSum = 0; - float fallOff = 1.2; + const float fallOff = 1.07; for( int x = 0; x < MAX_BANDS; ++x, ++bands ) { peak = ( fh * 2.0 / 3.0 * ( 20 * ( log10( *bands / energy ) ) - LOWER_Y ) / ( - LOWER_Y ) ); diff --git a/src/gui/FxMixerView.cpp b/src/gui/FxMixerView.cpp index 8da1cb4e0..edeaceb54 100644 --- a/src/gui/FxMixerView.cpp +++ b/src/gui/FxMixerView.cpp @@ -579,7 +579,7 @@ void FxMixerView::updateFaders() { const float opl = m_fxChannelViews[i]->m_fader->getPeak_L(); const float opr = m_fxChannelViews[i]->m_fader->getPeak_R(); - const float fall_off = 1.2; + const float fallOff = 1.07; if( m->effectChannel(i)->m_peakLeft > opl ) { m_fxChannelViews[i]->m_fader->setPeak_L( m->effectChannel(i)->m_peakLeft ); @@ -587,7 +587,7 @@ void FxMixerView::updateFaders() } else { - m_fxChannelViews[i]->m_fader->setPeak_L( opl/fall_off ); + m_fxChannelViews[i]->m_fader->setPeak_L( opl/fallOff ); } if( m->effectChannel(i)->m_peakRight > opr ) @@ -597,7 +597,7 @@ void FxMixerView::updateFaders() } else { - m_fxChannelViews[i]->m_fader->setPeak_R( opr/fall_off ); + m_fxChannelViews[i]->m_fader->setPeak_R( opr/fallOff ); } } } diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index fa6958cef..d82d5befe 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -209,7 +209,7 @@ MainWindow::MainWindow() : vbox->addWidget( w ); setCentralWidget( main_widget ); - m_updateTimer.start( 1000 / 20, this ); // 20 fps + m_updateTimer.start( 1000 / 60, this ); // 60 fps if( ConfigManager::inst()->value( "ui", "enableautosave" ).toInt() ) {