From 5e4e536bf0dad4dfa28e8b51b305638fefaee468 Mon Sep 17 00:00:00 2001 From: knittl Date: Sun, 27 Oct 2019 21:17:04 +0100 Subject: [PATCH 01/41] Replace initializer list macros with delegating constructors (#5279) Closes #5278 --- include/LcdWidget.h | 2 +- src/gui/widgets/Knob.cpp | 29 +++++++++++------------------ src/gui/widgets/LcdWidget.cpp | 22 ++++++---------------- src/gui/widgets/LedCheckbox.cpp | 11 ++--------- 4 files changed, 20 insertions(+), 44 deletions(-) diff --git a/include/LcdWidget.h b/include/LcdWidget.h index 89bafd1d169..cf8a7f94654 100644 --- a/include/LcdWidget.h +++ b/include/LcdWidget.h @@ -100,7 +100,7 @@ public slots: int m_numDigits; int m_marginWidth; - void initUi( const QString& name, const QString &style = QString("19green") ); //!< to be called by ctors + void initUi( const QString& name, const QString &style ); //!< to be called by ctors } ; diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 72c6c7f8bac..7b603844951 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -53,35 +53,28 @@ TextFloat * Knob::s_textFloat = NULL; -//! @todo: in C++11, we can use delegating ctors -#define DEFAULT_KNOB_INITIALIZER_LIST \ - QWidget( _parent ), \ - FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ), \ - m_label( "" ), \ - m_knobPixmap( NULL ), \ - m_volumeKnob( false ), \ - m_volumeRatio( 100.0, 0.0, 1000000.0 ), \ - m_buttonPressed( false ), \ - m_angle( -10 ), \ - m_lineWidth( 0 ), \ - m_textColor( 255, 255, 255 ) Knob::Knob( knobTypes _knob_num, QWidget * _parent, const QString & _name ) : - DEFAULT_KNOB_INITIALIZER_LIST, + QWidget( _parent ), + FloatModelView( new FloatModel( 0, 0, 0, 1, NULL, _name, true ), this ), + m_label( "" ), + m_knobPixmap( NULL ), + m_volumeKnob( false ), + m_volumeRatio( 100.0, 0.0, 1000000.0 ), + m_buttonPressed( false ), + m_angle( -10 ), + m_lineWidth( 0 ), + m_textColor( 255, 255, 255 ), m_knobNum( _knob_num ) { initUi( _name ); } Knob::Knob( QWidget * _parent, const QString & _name ) : - DEFAULT_KNOB_INITIALIZER_LIST, - m_knobNum( knobBright_26 ) + Knob( knobBright_26, _parent, _name ) { - initUi( _name ); } -#undef DEFAULT_KNOB_INITIALIZER_LIST - diff --git a/src/gui/widgets/LcdWidget.cpp b/src/gui/widgets/LcdWidget.cpp index 2b85a64ede8..e34e1eb47b3 100644 --- a/src/gui/widgets/LcdWidget.cpp +++ b/src/gui/widgets/LcdWidget.cpp @@ -39,42 +39,32 @@ -//! @todo: in C++11, we can use delegating ctors -#define DEFAULT_LCDWIDGET_INITIALIZER_LIST \ - QWidget( parent ), \ - m_label(), \ - m_textColor( 255, 255, 255 ), \ - m_textShadowColor( 64, 64, 64 ) - LcdWidget::LcdWidget( QWidget* parent, const QString& name ) : - DEFAULT_LCDWIDGET_INITIALIZER_LIST, - m_numDigits( 1 ) + LcdWidget( 1, parent, name ) { - initUi( name ); } LcdWidget::LcdWidget( int numDigits, QWidget* parent, const QString& name ) : - DEFAULT_LCDWIDGET_INITIALIZER_LIST, - m_numDigits( numDigits ) + LcdWidget( numDigits, QString("19green"), parent, name ) { - initUi( name ); } LcdWidget::LcdWidget( int numDigits, const QString& style, QWidget* parent, const QString& name ) : - DEFAULT_LCDWIDGET_INITIALIZER_LIST, + QWidget( parent ), + m_label(), + m_textColor( 255, 255, 255 ), + m_textShadowColor( 64, 64, 64 ), m_numDigits( numDigits ) { initUi( name, style ); } -#undef DEFAULT_LCDWIDGET_INITIALIZER_LIST - diff --git a/src/gui/widgets/LedCheckbox.cpp b/src/gui/widgets/LedCheckbox.cpp index f69ec6719fd..bdb537744f7 100644 --- a/src/gui/widgets/LedCheckbox.cpp +++ b/src/gui/widgets/LedCheckbox.cpp @@ -39,13 +39,9 @@ static const QString names[LedCheckBox::NumColors] = -//! @todo: in C++11, we can use delegating ctors -#define DEFAULT_LEDCHECKBOX_INITIALIZER_LIST \ - AutomatableButton( _parent, _name ) - LedCheckBox::LedCheckBox( const QString & _text, QWidget * _parent, const QString & _name, LedColors _color ) : - DEFAULT_LEDCHECKBOX_INITIALIZER_LIST, + AutomatableButton( _parent, _name ), m_text( _text ) { initUi( _color ); @@ -56,13 +52,10 @@ LedCheckBox::LedCheckBox( const QString & _text, QWidget * _parent, LedCheckBox::LedCheckBox( QWidget * _parent, const QString & _name, LedColors _color ) : - DEFAULT_LEDCHECKBOX_INITIALIZER_LIST + LedCheckBox( QString(), _parent, _name, _color ) { - initUi( _color ); } -#undef DEFAULT_LEDCHECKBOX_INITIALIZER_LIST - LedCheckBox::~LedCheckBox() From 6c865c072da6ba096fe7bf7a9c1e4d1ceedc016f Mon Sep 17 00:00:00 2001 From: Oskar Wallgren Date: Tue, 29 Oct 2019 14:01:05 +0100 Subject: [PATCH 02/41] Piano Roll - Fix retrigger with vol/pan sliders (#5271) --- src/gui/editors/PianoRoll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 7ba01f98346..6c6acf1b05b 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -2175,7 +2175,7 @@ void PianoRoll::mouseMoveEvent( QMouseEvent * me ) m_pattern->instrumentTrack()->processInEvent( evt ); } } - else if( n->isPlaying() ) + else if( n->isPlaying() && !isSelection() ) { // mouse not over this note, stop playing it. m_pattern->instrumentTrack()->pianoModel()->handleKeyRelease( n->key() ); From fd203c3f7b8d2d7126c7dda51e47761d13de4972 Mon Sep 17 00:00:00 2001 From: Cyp Date: Wed, 30 Oct 2019 10:37:50 +0100 Subject: [PATCH 03/41] Fix crash due to calling QWidget::move from a non-GUI thread while exporting tracks. Calling via QMetaObject::invokeMethod should be thread safe. Crash callstack: QWidget::move SongEditor::updatePosition Song::stop Song::stopExport ProjectRenderer::run QThreadPrivate::start --- src/core/Song.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 6bd94a484e2..54f19e1d305 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -685,7 +685,7 @@ void Song::stop() if( gui && gui->songEditor() && ( tl->autoScroll() == TimeLineWidget::AutoScrollEnabled ) ) { - gui->songEditor()->m_editor->updatePosition(0); + QMetaObject::invokeMethod(gui->songEditor()->m_editor, "updatePosition", Qt::AutoConnection, Q_ARG(MidiTime, 0)); } break; @@ -699,7 +699,7 @@ void Song::stop() if( gui && gui->songEditor() && ( tl->autoScroll() == TimeLineWidget::AutoScrollEnabled ) ) { - gui->songEditor()->m_editor->updatePosition( MidiTime(tl->savedPos().getTicks() ) ); + QMetaObject::invokeMethod(gui->songEditor()->m_editor, "updatePosition", Qt::AutoConnection, Q_ARG(MidiTime, tl->savedPos().getTicks())); } tl->savePos( -1 ); } From 55b65527c3858fb82bf465de8786071752146e4d Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Fri, 1 Nov 2019 07:26:38 +0200 Subject: [PATCH 04/41] appimage: move launcher code into launch_lmms.sh. --- cmake/linux/launch_lmms.sh | 24 ++++++++++++++++++++++++ cmake/linux/package_linux.sh.in | 31 +++---------------------------- 2 files changed, 27 insertions(+), 28 deletions(-) create mode 100644 cmake/linux/launch_lmms.sh diff --git a/cmake/linux/launch_lmms.sh b/cmake/linux/launch_lmms.sh new file mode 100644 index 00000000000..4a0eb30e233 --- /dev/null +++ b/cmake/linux/launch_lmms.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +export PATH="$PATH:/sbin" +if which carla > /dev/null 2>&1; then + CARLAPATH="$(which carla)" + CARLAPREFIX="${CARLAPATH%/bin*}" + echo "Carla appears to be installed on this system at $CARLAPREFIX/lib[64]/carla so we'll use it." + export LD_LIBRARY_PATH=$CARLAPREFIX/lib/carla:$CARLAPREFIX/lib64/carla:$LD_LIBRARY_PATH +else + echo "Carla does not appear to be installed. That's OK, please ignore any related library errors." +fi +export LD_LIBRARY_PATH=$DIR/usr/lib/:$DIR/usr/lib/lmms:$LD_LIBRARY_PATH +# Prevent segfault on VirualBox +if lsmod |grep vboxguest > /dev/null 2>&1; then + echo "VirtualBox detected. Forcing libgl software rendering." + export LIBGL_ALWAYS_SOFTWARE=1; +fi +if ldconfig -p | grep libjack.so.0 > /dev/null 2>&1; then + echo "Jack appears to be installed on this system, so we'll use it." +else + echo "Jack does not appear to be installed. That's OK, we'll use a dummy version instead." + export LD_LIBRARY_PATH=$DIR/usr/lib/lmms/optional:$LD_LIBRARY_PATH +fi +QT_X11_NO_NATIVE_MENUBAR=1 $DIR/usr/bin/lmms.real "$@" \ No newline at end of file diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index 7c0e2593b01..cb3764dcb01 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -96,37 +96,12 @@ cp -R /usr/share/stk/rawwaves/ "${APPDIR}usr/share/stk/" # Create a wrapper script which calls the lmms executable mv "${APPDIR}usr/bin/lmms" "${APPDIR}usr/bin/lmms.real" -# shellcheck disable=SC1083 -cat >"${APPDIR}usr/bin/lmms" < /dev/null 2>&1; then - CARLAPATH="\$(which carla)" - CARLAPREFIX="\${CARLAPATH%/bin*}" - echo "Carla appears to be installed on this system at \$CARLAPREFIX/lib[64]/carla so we'll use it." - export LD_LIBRARY_PATH=\$CARLAPREFIX/lib/carla:\$CARLAPREFIX/lib64/carla:\$LD_LIBRARY_PATH -else - echo "Carla does not appear to be installed. That's OK, please ignore any related library errors." -fi -export LD_LIBRARY_PATH=\$DIR/usr/lib/:\$DIR/usr/lib/lmms:\$LD_LIBRARY_PATH -# Prevent segfault on VirualBox -if lsmod |grep vboxguest > /dev/null 2>&1; then - echo "VirtualBox detected. Forcing libgl software rendering." - export LIBGL_ALWAYS_SOFTWARE=1; -fi -if ldconfig -p | grep libjack.so.0 > /dev/null 2>&1; then - echo "Jack appears to be installed on this system, so we'll use it." -else - echo "Jack does not appear to be installed. That's OK, we'll use a dummy version instead." - export LD_LIBRARY_PATH=\$DIR/usr/lib/lmms/optional:\$LD_LIBRARY_PATH -fi -QT_X11_NO_NATIVE_MENUBAR=1 \$DIR/usr/bin/lmms.real "\$@" -EOL + +cp "@CMAKE_CURRENT_SOURCE_DIR@/launch_lmms.sh" "${APPDIR}usr/bin/lmms" chmod +x "${APPDIR}usr/bin/lmms" -# Per https://github.com/probonopd/linuxdeployqt/issues/129 +# Per https://github.com/probonopd/linuxdeployqt/issues/129 unset LD_LIBRARY_PATH # Ensure linuxdeployqt can find shared objects From 02980e610c960eee97104ceefe0c9563cf0d7ec9 Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Fri, 1 Nov 2019 07:28:05 +0200 Subject: [PATCH 05/41] appimage: Use command -v instead of which (sc2230) --- cmake/linux/launch_lmms.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cmake/linux/launch_lmms.sh b/cmake/linux/launch_lmms.sh index 4a0eb30e233..02cebd5a48e 100644 --- a/cmake/linux/launch_lmms.sh +++ b/cmake/linux/launch_lmms.sh @@ -1,8 +1,9 @@ #!/usr/bin/env bash +alias standard_which="command -v" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export PATH="$PATH:/sbin" -if which carla > /dev/null 2>&1; then - CARLAPATH="$(which carla)" +if standard_which carla > /dev/null 2>&1; then + CARLAPATH="$(standard_which carla)" CARLAPREFIX="${CARLAPATH%/bin*}" echo "Carla appears to be installed on this system at $CARLAPREFIX/lib[64]/carla so we'll use it." export LD_LIBRARY_PATH=$CARLAPREFIX/lib/carla:$CARLAPREFIX/lib64/carla:$LD_LIBRARY_PATH From 08c7e8e8ddd8000131a583d4bf88d4f29d20b14d Mon Sep 17 00:00:00 2001 From: Shmuel H Date: Fri, 1 Nov 2019 07:29:56 +0200 Subject: [PATCH 06/41] appimage: Escape $DIR to avoid word-splitting --- cmake/linux/launch_lmms.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/linux/launch_lmms.sh b/cmake/linux/launch_lmms.sh index 02cebd5a48e..e6432aa3a37 100644 --- a/cmake/linux/launch_lmms.sh +++ b/cmake/linux/launch_lmms.sh @@ -22,4 +22,4 @@ else echo "Jack does not appear to be installed. That's OK, we'll use a dummy version instead." export LD_LIBRARY_PATH=$DIR/usr/lib/lmms/optional:$LD_LIBRARY_PATH fi -QT_X11_NO_NATIVE_MENUBAR=1 $DIR/usr/bin/lmms.real "$@" \ No newline at end of file +QT_X11_NO_NATIVE_MENUBAR=1 "$DIR"/usr/bin/lmms.real "$@" \ No newline at end of file From a8d91b10e8dd32157d25caeb97597eb018e9405c Mon Sep 17 00:00:00 2001 From: Kevin Zander Date: Fri, 1 Nov 2019 02:36:54 -0500 Subject: [PATCH 07/41] Fix vertical piano mouse click unresponsiveness `PianoRoll::mouseDoubleClickEvent` wasn't forwarding the event to the base class when not acting on the event. The base class calls `mousePressEvent`. Fixes #3005 --- src/gui/editors/PianoRoll.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 6c6acf1b05b..f6bda682b30 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -1796,6 +1796,10 @@ void PianoRoll::mouseDoubleClickEvent(QMouseEvent * me ) enterValue( &nv ); } } + else + { + QWidget::mouseDoubleClickEvent(me); + } } From cf4bb7b85121d2794e3588886f05c53d8596d558 Mon Sep 17 00:00:00 2001 From: Dominic Clark Date: Sun, 17 Nov 2019 16:09:48 +0000 Subject: [PATCH 08/41] Fix remote plugin crash reading parameters from Grooove plugin (#5300) --- plugins/vst_base/RemoteVstPlugin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index d12ccd88ab1..15a56e8696e 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -1072,7 +1072,7 @@ void RemoteVstPlugin::getParameterDump() for( int i = 0; i < m_plugin->numParams; ++i ) { - char paramName[32]; + char paramName[256]; memset( paramName, 0, sizeof( paramName ) ); pluginDispatch( effGetParamName, i, 0, paramName ); paramName[sizeof(paramName)-1] = 0; From a2e328e3dd8cc33fdafde7ed2dfe99aec4b77f1c Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Fri, 22 Nov 2019 21:26:47 +0900 Subject: [PATCH 09/41] Fix crash on deleting instrument with controller connections on knobs (#5306) Knob::friendlyUpdate() can be called after the model is deleted due to signal-slot connections. Adding a check for the model fixes a crash due to null pointer dereference. --- src/gui/widgets/Knob.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 7b603844951..3932795b73d 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -803,9 +803,9 @@ void Knob::enterValue() void Knob::friendlyUpdate() { - if( model()->controllerConnection() == NULL || + if (model() && (model()->controllerConnection() == NULL || model()->controllerConnection()->getController()->frequentUpdates() == false || - Controller::runningFrames() % (256*4) == 0 ) + Controller::runningFrames() % (256*4) == 0)) { update(); } From 578a9475ecf7b8c529bb7edb86885987aa77642d Mon Sep 17 00:00:00 2001 From: Cyp <48363+Cyp@users.noreply.github.com> Date: Fri, 22 Nov 2019 14:26:00 +0100 Subject: [PATCH 10/41] Fix invalid read in RemotePlugin::RemotePlugin() on opening the ZynAddSubFx GUI. (#5299) Calling .toUtf8().constData() returns a pointer which is invalid at the end of the statement. --- src/core/RemotePlugin.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/core/RemotePlugin.cpp b/src/core/RemotePlugin.cpp index d82bc61af26..f816b75291d 100644 --- a/src/core/RemotePlugin.cpp +++ b/src/core/RemotePlugin.cpp @@ -101,14 +101,14 @@ RemotePlugin::RemotePlugin() : m_socketFile = QDir::tempPath() + QDir::separator() + QUuid::createUuid().toString(); - const char * path = m_socketFile.toUtf8().constData(); - size_t length = strlen( path ); + auto path = m_socketFile.toUtf8(); + size_t length = path.length(); if ( length >= sizeof sa.sun_path ) { length = sizeof sa.sun_path - 1; qWarning( "Socket path too long." ); } - memcpy( sa.sun_path, path, length ); + memcpy(sa.sun_path, path.constData(), length ); sa.sun_path[length] = '\0'; m_server = socket( PF_LOCAL, SOCK_STREAM, 0 ); @@ -116,7 +116,7 @@ RemotePlugin::RemotePlugin() : { qWarning( "Unable to start the server." ); } - remove( path ); + remove(path.constData()); int ret = bind( m_server, (struct sockaddr *) &sa, sizeof sa ); if ( ret == -1 || listen( m_server, 1 ) == -1 ) { From 4bfcc30a71429f06cf5be1baa223c0475d4702e6 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Mon, 23 Dec 2019 17:33:46 +0900 Subject: [PATCH 11/41] MIDI import: fix putting notes before the beginning of a pattern (#5343) --- plugins/MidiImport/MidiImport.cpp | 49 +++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/plugins/MidiImport/MidiImport.cpp b/plugins/MidiImport/MidiImport.cpp index e83ef8c2736..f0c4888da67 100644 --- a/plugins/MidiImport/MidiImport.cpp +++ b/plugins/MidiImport/MidiImport.cpp @@ -215,8 +215,7 @@ class smfMidiChannel p( NULL ), it_inst( NULL ), isSF2( false ), - hasNotes( false ), - lastEnd( 0 ) + hasNotes( false ) { } InstrumentTrack * it; @@ -224,7 +223,6 @@ class smfMidiChannel Instrument * it_inst; bool isSF2; bool hasNotes; - MidiTime lastEnd; QString trackName; smfMidiChannel * create( TrackContainer* tc, QString tn ) @@ -255,9 +253,11 @@ class smfMidiChannel if( trackName != "") { it->setName( tn ); } - lastEnd = 0; // General MIDI default it->pitchRangeModel()->setInitValue( 2 ); + + // Create a default pattern + p = dynamic_cast(it->createTCO(0)); } return this; } @@ -265,16 +265,37 @@ class smfMidiChannel void addNote( Note & n ) { - if( !p || n.pos() > lastEnd + DefaultTicksPerTact ) + if (!p) { - MidiTime pPos = MidiTime( n.pos().getTact(), 0 ); - p = dynamic_cast( it->createTCO( 0 ) ); - p->movePosition( pPos ); + p = dynamic_cast(it->createTCO(0)); } + p->addNote(n, false); hasNotes = true; - lastEnd = n.pos() + n.length(); - n.setPos( n.pos( p->startPosition() ) ); - p->addNote( n, false ); + } + + void splitPatterns() + { + Pattern * newPattern = nullptr; + MidiTime lastEnd(0); + + p->rearrangeAllNotes(); + for (auto n : p->notes()) + { + if (!newPattern || n->pos() > lastEnd + DefaultTicksPerTact) + { + MidiTime pPos = MidiTime(n->pos().getTact(), 0); + newPattern = dynamic_cast(it->createTCO(0)); + newPattern->movePosition(pPos); + } + lastEnd = n->pos() + n->length(); + + Note newNote(*n); + newNote.setPos(n->pos(newPattern->startPosition())); + newPattern->addNote(newNote, false); + } + + delete p; + p = nullptr; } }; @@ -534,7 +555,11 @@ bool MidiImport::readSMF( TrackContainer* tc ) for( int c=0; c < 256; ++c ) { - if( !chs[c].hasNotes && chs[c].it ) + if (chs[c].hasNotes) + { + chs[c].splitPatterns(); + } + else if (chs[c].it) { printf(" Should remove empty track\n"); // must delete trackView first - but where is it? From d849cc179c8e31c9fdbc3a236cd6e2e4ad6383a9 Mon Sep 17 00:00:00 2001 From: Cyp Date: Wed, 23 Oct 2019 16:01:10 +0200 Subject: [PATCH 12/41] Only filter out <>:"/\|?* while exporting tracks. --- include/Track.h | 2 ++ src/core/RenderManager.cpp | 2 +- src/tracks/InstrumentTrack.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/include/Track.h b/include/Track.h index f3b6c5e4cdb..bc9f161a9b3 100644 --- a/include/Track.h +++ b/include/Track.h @@ -72,6 +72,8 @@ const int DEFAULT_TRACK_HEIGHT = 32; const int TCO_BORDER_WIDTH = 2; +char const *const FILENAME_FILTER = "[\\0000-\x1f\"*/:<>?\\\\|\x7f]"; + class TrackContentObject : public Model, public JournallingObject { diff --git a/src/core/RenderManager.cpp b/src/core/RenderManager.cpp index 478aa46e73d..7b9c489e1cc 100644 --- a/src/core/RenderManager.cpp +++ b/src/core/RenderManager.cpp @@ -203,7 +203,7 @@ QString RenderManager::pathForTrack(const Track *track, int num) { QString extension = ProjectRenderer::getFileExtensionFromFormat( m_format ); QString name = track->name(); - name = name.remove(QRegExp("[^a-zA-Z]")); + name = name.remove(QRegExp(FILENAME_FILTER)); name = QString( "%1_%2%3" ).arg( num ).arg( name ).arg( extension ); return QDir(m_outputPath).filePath(name); } diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 98a691a9a42..3f0c59b7d18 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -1615,7 +1615,7 @@ void InstrumentTrackWindow::saveSettingsBtnClicked() sfd.setDirectory( presetRoot + m_track->instrumentName() ); sfd.setFileMode( FileDialog::AnyFile ); QString fname = m_track->name(); - sfd.selectFile( fname.remove(QRegExp("[^a-zA-Z0-9_\\-\\d\\s]")) ); + sfd.selectFile(fname.remove(QRegExp(FILENAME_FILTER))); sfd.setDefaultSuffix( "xpf"); if( sfd.exec() == QDialog::Accepted && From 42f7e262e9d9353671a3920215f8e41658590891 Mon Sep 17 00:00:00 2001 From: Cyp Date: Tue, 29 Oct 2019 16:53:17 +0100 Subject: [PATCH 13/41] Fix scrolling direction in SongEditor due to stuck Ctrl/Shift. --- CMakeLists.txt | 2 +- include/MainWindow.h | 21 ++++++--------------- src/core/Track.cpp | 2 +- src/gui/MainWindow.cpp | 1 + src/gui/editors/SongEditor.cpp | 11 +++++------ src/gui/widgets/Knob.cpp | 2 +- src/gui/widgets/LcdSpinBox.cpp | 2 +- 7 files changed, 16 insertions(+), 25 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d82ace4ae1d..e3c62cb44ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -480,7 +480,7 @@ ENDIF() # Due to a regression in gcc-4.8.X, we need to disable array-bounds check IF (CMAKE_COMPILER_IS_GNUCXX AND ((CMAKE_CXX_COMPILER_VERSION VERSION_EQUAL "4.8.0") OR (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "4.8.0") OR LMMS_BUILD_WIN32)) - SET(WERROR_FLAGS "${WERROR_FLAGS} -Wno-array-bounds") + SET(WERROR_FLAGS "${WERROR_FLAGS} -Wno-array-bounds -Wno-attributes") ENDIF() IF(NOT CMAKE_BUILD_TYPE) diff --git a/include/MainWindow.h b/include/MainWindow.h index 7ba2ac63079..3de847f6375 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -126,21 +126,12 @@ class MainWindow : public QMainWindow void clearKeyModifiers(); - bool isCtrlPressed() - { - return m_keyMods.m_ctrl; - } - + [[deprecated]] // TODO Remove this function, since m_shift can get stuck down. bool isShiftPressed() { return m_keyMods.m_shift; } - bool isAltPressed() - { - return m_keyMods.m_alt; - } - static void saveWidgetState( QWidget * _w, QDomElement & _de ); static void restoreWidgetState( QWidget * _w, const QDomElement & _de ); @@ -176,11 +167,11 @@ public slots: void autoSave(); protected: - virtual void closeEvent( QCloseEvent * _ce ); - virtual void focusOutEvent( QFocusEvent * _fe ); - virtual void keyPressEvent( QKeyEvent * _ke ); - virtual void keyReleaseEvent( QKeyEvent * _ke ); - virtual void timerEvent( QTimerEvent * _ev ); + void closeEvent( QCloseEvent * _ce ) override; + void focusOutEvent( QFocusEvent * _fe ) override; + void keyPressEvent( QKeyEvent * _ke ) override; + void keyReleaseEvent( QKeyEvent * _ke ) override; + void timerEvent( QTimerEvent * _ev ) override; private: diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 7a04ded954d..6a6b0deb133 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -694,7 +694,7 @@ void TrackContentObjectView::mousePressEvent( QMouseEvent * me ) dataFile.toString(), thumbnail, this ); } else if( me->button() == Qt::LeftButton && - /* engine::mainWindow()->isShiftPressed() == false &&*/ + /* (me->modifiers() & Qt::ShiftModifier) &&*/ fixedTCOs() == false ) { m_tco->addJournalCheckPoint(); diff --git a/src/gui/MainWindow.cpp b/src/gui/MainWindow.cpp index 6be2770954f..e6971f96d34 100644 --- a/src/gui/MainWindow.cpp +++ b/src/gui/MainWindow.cpp @@ -1423,6 +1423,7 @@ void MainWindow::sessionCleanup() void MainWindow::focusOutEvent( QFocusEvent * _fe ) { + // TODO Remove this function, since it is apparently never actually called! // when loosing focus we do not receive key-(release!)-events anymore, // so we might miss release-events of one the modifiers we're watching! clearKeyModifiers(); diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 31cb142c074..de661f29e41 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -415,14 +415,13 @@ void SongEditor::setEditModeSelect() void SongEditor::keyPressEvent( QKeyEvent * ke ) { - if( /*_ke->modifiers() & Qt::ShiftModifier*/ - gui->mainWindow()->isShiftPressed() == true && + bool isShiftPressed = ke->modifiers() & Qt::ShiftModifier; + if( isShiftPressed && ( ke->key() == Qt::Key_Insert || ke->key() == Qt::Key_Enter || ke->key() == Qt::Key_Return ) ) { m_song->insertBar(); } - else if(/* _ke->modifiers() & Qt::ShiftModifier &&*/ - gui->mainWindow()->isShiftPressed() == true && + else if( isShiftPressed && ( ke->key() == Qt::Key_Delete || ke->key() == Qt::Key_Backspace ) ) { m_song->removeBar(); @@ -458,7 +457,7 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) void SongEditor::wheelEvent( QWheelEvent * we ) { - if( gui->mainWindow()->isCtrlPressed() == true ) + if( we->modifiers() & Qt::ControlModifier ) { int z = m_zoomingModel->value(); @@ -480,7 +479,7 @@ void SongEditor::wheelEvent( QWheelEvent * we ) // and make sure, all TCO's are resized and relocated realignTracks(); } - else if( gui->mainWindow()->isShiftPressed() == true || we->orientation() == Qt::Horizontal ) + else if( (we->modifiers() & Qt::ShiftModifier) || we->orientation() == Qt::Horizontal ) { m_leftRightScroll->setValue( m_leftRightScroll->value() - we->delta() / 30 ); diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 3932795b73d..e559d120c99 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -601,7 +601,7 @@ void Knob::mousePressEvent( QMouseEvent * _me ) m_buttonPressed = true; } else if( _me->button() == Qt::LeftButton && - gui->mainWindow()->isShiftPressed() == true ) + (_me->modifiers() & Qt::ShiftModifier) ) { new StringPairDrag( "float_value", QString::number( model()->value() ), diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index 7dc21194a87..7102f5f6baa 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -122,7 +122,7 @@ void LcdSpinBox::mouseMoveEvent( QMouseEvent* event ) if( m_mouseMoving ) { int dy = event->globalY() - m_origMousePos.y(); - if( gui->mainWindow()->isShiftPressed() ) + if( event->modifiers() & Qt::ShiftModifier ) dy = qBound( -4, dy/4, 4 ); if( dy > 1 || dy < -1 ) { From 11e5de3a4e03c7739403c8772f11ae85efa6baa5 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Tue, 24 Dec 2019 12:03:17 +0900 Subject: [PATCH 14/41] Debian: add libx11-xcb-dev as an explicit build dependency --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index 0997676c953..910722c032f 100644 --- a/debian/control +++ b/debian/control @@ -27,6 +27,7 @@ Build-Depends: libsoundio-dev, libstk0-dev, libvorbis-dev, + libx11-xcb-dev, libxcb-keysyms1-dev, libxcb-util0-dev, portaudio19-dev, From a9640c88980b54e17df81ca887a1a0eaf87d8236 Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Thu, 26 Dec 2019 18:23:52 +0100 Subject: [PATCH 15/41] Comment-out deprecated attribute It may be valid, but fails our CI --- include/MainWindow.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/MainWindow.h b/include/MainWindow.h index 3de847f6375..d1fe3eb4e21 100644 --- a/include/MainWindow.h +++ b/include/MainWindow.h @@ -126,7 +126,8 @@ class MainWindow : public QMainWindow void clearKeyModifiers(); - [[deprecated]] // TODO Remove this function, since m_shift can get stuck down. + // TODO Remove this function, since m_shift can get stuck down. + // [[deprecated]] bool isShiftPressed() { return m_keyMods.m_shift; From c52682dfb15870745e7a60a9182d1b8c1044d05a Mon Sep 17 00:00:00 2001 From: Dominic Clark Date: Sun, 5 Jan 2020 20:53:54 +0000 Subject: [PATCH 16/41] Fix stuck notes with Helm VSTi --- src/core/NotePlayHandle.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/core/NotePlayHandle.cpp b/src/core/NotePlayHandle.cpp index d628573506f..d1a5843eda5 100644 --- a/src/core/NotePlayHandle.cpp +++ b/src/core/NotePlayHandle.cpp @@ -540,6 +540,15 @@ void NotePlayHandle::processMidiTime( const MidiTime& time ) void NotePlayHandle::resize( const bpm_t _new_tempo ) { + if (origin() == OriginMidiInput || + (origin() == OriginNoteStacking && m_parent->origin() == OriginMidiInput)) + { + // Don't resize notes from MIDI input - they should continue to play + // until the key is released, and their large duration can cause + // overflows in this method. + return; + } + double completed = m_totalFramesPlayed / (double) m_frames; double new_frames = m_origFrames * m_origTempo / (double) _new_tempo; m_frames = (f_cnt_t)new_frames; From fd77c79cdaab5bbaf05dc88f589eca627c3b0147 Mon Sep 17 00:00:00 2001 From: Javier Serrano Polo Date: Fri, 17 Jan 2020 16:55:07 +0100 Subject: [PATCH 17/41] Switch to Xenial build environment (#4813) * Switch to Xenial build environment * Add Carla submodule/weak linking support, related #3963 * Fix Carla detection in AppImage, closes #5369 --- .gitmodules | 3 +++ .travis.yml | 6 +++++- .travis/linux..before_install.sh | 6 ------ .travis/linux..install.sh | 10 ++------- CMakeLists.txt | 3 ++- cmake/linux/launch_lmms.sh | 7 +++---- cmake/linux/package_linux.sh.in | 7 ++++--- cmake/modules/BuildPlugin.cmake | 6 +++++- plugins/carlabase/CMakeLists.txt | 29 +++++++++++++++++++++++++-- plugins/carlabase/DummyCarla.cpp | 12 +++++++++++ plugins/carlabase/carla | 1 + plugins/carlabase/carla.cpp | 3 ++- plugins/carlabase/logo.png | Bin 0 -> 3313 bytes plugins/carlapatchbay/CMakeLists.txt | 4 ++-- plugins/carlarack/CMakeLists.txt | 4 ++-- 15 files changed, 70 insertions(+), 31 deletions(-) create mode 100644 plugins/carlabase/DummyCarla.cpp create mode 160000 plugins/carlabase/carla create mode 100644 plugins/carlabase/logo.png diff --git a/.gitmodules b/.gitmodules index 4abd7ae3e7c..3c0663dd62d 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "src/3rdparty/rpmalloc/rpmalloc"] path = src/3rdparty/rpmalloc/rpmalloc url = https://github.com/rampantpixels/rpmalloc.git +[submodule "plugins/carlabase/carla"] + path = plugins/carlabase/carla + url = https://github.com/falktx/carla diff --git a/.travis.yml b/.travis.yml index 5f8002cb191..396217af8f4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: cpp compiler: gcc -dist: trusty +dist: xenial sudo: required cache: directories: @@ -10,13 +10,17 @@ cache: matrix: include: - env: TARGET_OS=win32 + dist: trusty - env: TARGET_OS=win64 + dist: trusty - os: osx osx_image: xcode8.2 - env: QT5= - env: QT5=True - env: QT5=True TARGET_OS=win32 TARGET_DEPLOY=True + dist: trusty - env: QT5=True TARGET_OS=win64 TARGET_DEPLOY=True + dist: trusty - os: osx osx_image: xcode8.2 env: QT5=True diff --git a/.travis/linux..before_install.sh b/.travis/linux..before_install.sh index 91f86eef2af..8e6d7bb00c7 100644 --- a/.travis/linux..before_install.sh +++ b/.travis/linux..before_install.sh @@ -1,9 +1,3 @@ #!/usr/bin/env bash - -sudo add-apt-repository ppa:beineri/opt-qt592-trusty -y -sudo add-apt-repository ppa:andrewrk/libgroove -y -sudo sed -e "s/trusty/precise/" -i \ - /etc/apt/sources.list.d/andrewrk-libgroove-trusty.list - sudo dpkg --add-architecture i386 sudo apt-get update -qq || true diff --git a/.travis/linux..install.sh b/.travis/linux..install.sh index 3e86eecfe87..72481fc23c8 100644 --- a/.travis/linux..install.sh +++ b/.travis/linux..install.sh @@ -2,7 +2,7 @@ PACKAGES="cmake libsndfile-dev fftw3-dev libvorbis-dev libogg-dev libmp3lame-dev libasound2-dev libjack-jackd2-dev libsdl-dev libsamplerate0-dev libstk0-dev stk - libfluidsynth-dev portaudio19-dev g++-multilib libfltk1.3-dev + libfluidsynth-dev portaudio19-dev g++-multilib libfltk1.3-dev fluid libgig-dev libsoundio-dev" VST_PACKAGES="wine-dev libqt5x11extras5-dev qtbase5-private-dev libxcb-util0-dev libxcb-keysyms1-dev" @@ -11,15 +11,9 @@ VST_PACKAGES="wine-dev libqt5x11extras5-dev qtbase5-private-dev libxcb-util0-dev PACKAGES="$PACKAGES $VST_PACKAGES libjack-jackd2-0" if [ $QT5 ]; then - PACKAGES="$PACKAGES qt59base qt59translations qt59tools" + PACKAGES="$PACKAGES qttools5-dev-tools" else PACKAGES="$PACKAGES libqt4-dev" fi sudo apt-get install -y $PACKAGES - -# kxstudio repo offers Carla; avoid package conflicts (wine, etc) by running last -sudo add-apt-repository -y ppa:kxstudio-debian/libs -sudo add-apt-repository -y ppa:kxstudio-debian/apps -sudo apt-get update -sudo apt-get install -y carla diff --git a/CMakeLists.txt b/CMakeLists.txt index e3c62cb44ad..a84018eac6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -241,7 +241,8 @@ IF(WANT_CARLA) SET(LMMS_HAVE_CARLA TRUE) SET(STATUS_CARLA "OK") ELSE(CARLA_FOUND) - SET(STATUS_CARLA "not found, please install the latest carla") + SET(LMMS_HAVE_WEAKCARLA TRUE) + SET(STATUS_CARLA "OK (weak linking enabled)") ENDIF(CARLA_FOUND) ENDIF(WANT_CARLA) diff --git a/cmake/linux/launch_lmms.sh b/cmake/linux/launch_lmms.sh index e6432aa3a37..198b5711a53 100644 --- a/cmake/linux/launch_lmms.sh +++ b/cmake/linux/launch_lmms.sh @@ -1,9 +1,8 @@ #!/usr/bin/env bash -alias standard_which="command -v" DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" export PATH="$PATH:/sbin" -if standard_which carla > /dev/null 2>&1; then - CARLAPATH="$(standard_which carla)" +if command -v carla > /dev/null 2>&1; then + CARLAPATH="$(command -v carla)" CARLAPREFIX="${CARLAPATH%/bin*}" echo "Carla appears to be installed on this system at $CARLAPREFIX/lib[64]/carla so we'll use it." export LD_LIBRARY_PATH=$CARLAPREFIX/lib/carla:$CARLAPREFIX/lib64/carla:$LD_LIBRARY_PATH @@ -22,4 +21,4 @@ else echo "Jack does not appear to be installed. That's OK, we'll use a dummy version instead." export LD_LIBRARY_PATH=$DIR/usr/lib/lmms/optional:$LD_LIBRARY_PATH fi -QT_X11_NO_NATIVE_MENUBAR=1 "$DIR"/usr/bin/lmms.real "$@" \ No newline at end of file +QT_X11_NO_NATIVE_MENUBAR=1 "$DIR"/usr/bin/lmms.real "$@" diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index cb3764dcb01..8e48c24389d 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -105,7 +105,7 @@ chmod +x "${APPDIR}usr/bin/lmms" unset LD_LIBRARY_PATH # Ensure linuxdeployqt can find shared objects -export LD_LIBRARY_PATH="${APPDIR}usr/lib/lmms/":$LD_LIBRARY_PATH +export LD_LIBRARY_PATH="${APPDIR}usr/lib/lmms/":"${APPDIR}usr/lib/lmms/optional":$LD_LIBRARY_PATH # Handle wine linking if [ -d "@WINE_LIBRARY_FIX@" ]; then @@ -120,7 +120,7 @@ ZYNBIN="${APPDIR}usr/bin/RemoteZynAddSubFx" VSTBIN="${APPDIR}usr/bin/RemoteVstPlugin.exe.so" mv "$ZYNLIB" "$ZYNBIN" -mv "$VSTLIB" "$VSTBIN" +mv "$VSTLIB" "$VSTBIN" || true # Patch the desktop file sed -i 's/.*Exec=.*/Exec=lmms.real/' "$DESKTOPFILE" @@ -146,13 +146,14 @@ success "Bundled and relinked dependencies" # Link to original location so lmms can find them ln -sr "$ZYNBIN" "$ZYNLIB" -ln -sr "$VSTBIN" "$VSTLIB" +ln -sr "$VSTBIN" "$VSTLIB" || true # Remove wine library conflict rm -f "${APPDIR}/usr/lib/libwine.so.1" # Use system-provided carla rm -f "${APPDIR}usr/lib/"libcarla*.so +rm -f "${APPDIR}usr/lib/lmms/optional/"libcarla*.so # Remove bundled jack in LD_LIBRARY_PATH if exists if [ -e "${APPDIR}/usr/lib/libjack.so.0" ]; then diff --git a/cmake/modules/BuildPlugin.cmake b/cmake/modules/BuildPlugin.cmake index 25cca92afbc..f69fafe862f 100644 --- a/cmake/modules/BuildPlugin.cmake +++ b/cmake/modules/BuildPlugin.cmake @@ -70,7 +70,11 @@ MACRO(BUILD_PLUGIN PLUGIN_NAME) TARGET_LINK_LIBRARIES(${PLUGIN_NAME} lmms) ENDIF(LMMS_BUILD_WIN32) - INSTALL(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION "${PLUGIN_DIR}") + IF(LMMS_BUILD_WIN32 AND "${PLUGIN_LINK}" STREQUAL "SHARED") + INSTALL(TARGETS ${PLUGIN_NAME} RUNTIME DESTINATION "${PLUGIN_DIR}") + ELSE() + INSTALL(TARGETS ${PLUGIN_NAME} LIBRARY DESTINATION "${PLUGIN_DIR}") + ENDIF() IF(LMMS_BUILD_APPLE) IF ("${PLUGIN_LINK}" STREQUAL "SHARED") diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt index 4fa81a4916f..722f8463da8 100644 --- a/plugins/carlabase/CMakeLists.txt +++ b/plugins/carlabase/CMakeLists.txt @@ -6,7 +6,29 @@ IF(NOT CMAKE_VERSION VERSION_LESS 3.9) CMAKE_POLICY(SET CMP0068 OLD) ENDIF() -if(LMMS_HAVE_CARLA) +# If Carla was not provided by the system, make a dummy library instead +if(LMMS_HAVE_WEAKCARLA) + # Mimic the Makefile header + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/config.h "") + SET(CARLA_INCLUDE_DIRS + ${CMAKE_CURRENT_SOURCE_DIR}/carla/source + ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/includes + ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/utils + ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/backend + ${CMAKE_CURRENT_BINARY_DIR} + ) + INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) + ADD_LIBRARY(carla_native-plugin MODULE DummyCarla.cpp) + INSTALL(TARGETS carla_native-plugin LIBRARY DESTINATION "${PLUGIN_DIR}/optional") + SET(CARLA_LIBRARIES $) + SET(CARLA_LIBRARY_DIRS $) + # Set parent scope variables so carlarack and carlapatchbay can see them + SET(CARLA_LIBRARIES ${CARLA_LIBRARIES} PARENT_SCOPE) + SET(CARLA_INCLUDE_DIRS ${CARLA_INCLUDE_DIRS} PARENT_SCOPE) + SET(CARLA_LIBRARY_DIRS ${CARLA_LIBRARY_DIRS} PARENT_SCOPE) +endif() + +if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA) INCLUDE(BuildPlugin) INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) LINK_DIRECTORIES(${CARLA_LIBRARY_DIRS}) @@ -17,4 +39,7 @@ if(LMMS_HAVE_CARLA) BUILD_WITH_INSTALL_RPATH TRUE INSTALL_RPATH_USE_LINK_PATH TRUE INSTALL_RPATH "${CARLA_RPATH}") -endif(LMMS_HAVE_CARLA) + IF(LMMS_HAVE_WEAKCARLA) + ADD_DEPENDENCIES(carlabase carla_native-plugin) + ENDIF() +endif() diff --git a/plugins/carlabase/DummyCarla.cpp b/plugins/carlabase/DummyCarla.cpp new file mode 100644 index 00000000000..560e866b7b6 --- /dev/null +++ b/plugins/carlabase/DummyCarla.cpp @@ -0,0 +1,12 @@ +// A dummy Carla interface +#include "CarlaNativePlugin.h" + +const char* carla_get_library_filename() { return nullptr; } +const char* carla_get_library_folder() { return nullptr; } +const NativePluginDescriptor* carla_get_native_rack_plugin() { return nullptr; } +const NativePluginDescriptor* carla_get_native_patchbay_plugin() { return nullptr; } +const NativePluginDescriptor* carla_get_native_patchbay16_plugin() { return nullptr; } +const NativePluginDescriptor* carla_get_native_patchbay32_plugin() { return nullptr; } +const NativePluginDescriptor* carla_get_native_patchbay64_plugin() { return nullptr; } +const NativePluginDescriptor* carla_get_native_patchbay_cv_plugin() { return nullptr; } +CarlaBackend::CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) { return nullptr; } diff --git a/plugins/carlabase/carla b/plugins/carlabase/carla new file mode 160000 index 00000000000..4ac8ff2ef41 --- /dev/null +++ b/plugins/carlabase/carla @@ -0,0 +1 @@ +Subproject commit 4ac8ff2ef412d4ab190d2e285e318b1f339af4ae diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp index b25677f5c5f..0029a6b4298 100644 --- a/plugins/carlabase/carla.cpp +++ b/plugins/carlabase/carla.cpp @@ -438,7 +438,8 @@ 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(); + // TODO: Remove cast; Only needed for Qt4 + fHost.uiParentId = (uintptr_t)window->winId(); else #endif fHost.uiParentId = 0; diff --git a/plugins/carlabase/logo.png b/plugins/carlabase/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..353d5d718d6fef054ff4fed2932f4f45df7f792c GIT binary patch literal 3313 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 literal 0 HcmV?d00001 diff --git a/plugins/carlapatchbay/CMakeLists.txt b/plugins/carlapatchbay/CMakeLists.txt index d9aa6b32102..8e358891649 100644 --- a/plugins/carlapatchbay/CMakeLists.txt +++ b/plugins/carlapatchbay/CMakeLists.txt @@ -1,4 +1,4 @@ -if(LMMS_HAVE_CARLA) +if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA) ADD_DEFINITIONS(-DCARLA_PLUGIN_PATCHBAY -DCARLA_PLUGIN_SYNTH) INCLUDE(BuildPlugin) INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../carlabase") @@ -6,4 +6,4 @@ if(LMMS_HAVE_CARLA) ${CARLA_LIBRARY_DIRS}) LINK_LIBRARIES(carlabase) BUILD_PLUGIN(carlapatchbay carlapatchbay.cpp EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") -endif(LMMS_HAVE_CARLA) +endif() diff --git a/plugins/carlarack/CMakeLists.txt b/plugins/carlarack/CMakeLists.txt index 1834b23715e..5de833dd59f 100644 --- a/plugins/carlarack/CMakeLists.txt +++ b/plugins/carlarack/CMakeLists.txt @@ -1,4 +1,4 @@ -if(LMMS_HAVE_CARLA) +if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA) ADD_DEFINITIONS(-DCARLA_PLUGIN_RACK -DCARLA_PLUGIN_SYNTH) INCLUDE(BuildPlugin) INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS} "${CMAKE_CURRENT_SOURCE_DIR}/../carlabase") @@ -6,4 +6,4 @@ if(LMMS_HAVE_CARLA) ${CARLA_LIBRARY_DIRS}) LINK_LIBRARIES(carlabase) BUILD_PLUGIN(carlarack carlarack.cpp EMBEDDED_RESOURCES "${CMAKE_CURRENT_SOURCE_DIR}/*.png") -endif(LMMS_HAVE_CARLA) +endif() From 427d77966865df2c7dbb495ad8ba528a8cc1be74 Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Sun, 19 Jan 2020 20:33:58 +0100 Subject: [PATCH 18/41] FileBrowser: Add helpful comments --- include/FileBrowser.h | 19 +++++++++++++++++-- src/gui/FileBrowser.cpp | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/include/FileBrowser.h b/include/FileBrowser.h index 03a1070bb9f..742c1a68096 100644 --- a/include/FileBrowser.h +++ b/include/FileBrowser.h @@ -48,6 +48,14 @@ class FileBrowser : public SideBarWidget { Q_OBJECT public: + /** + Create a file browser side bar widget + @param directories '*'-separated list of directories to search for. + If a directory of factory files should be in the list it + must be the last one (for the factory files delimiter to work) + @param filter Filter as used in QDir::match + @param recurse *to be documented* + */ FileBrowser( const QString & directories, const QString & filter, const QString & title, const QPixmap & pm, QWidget * parent, bool dirs_as_items = false, bool recurse = false ); @@ -69,8 +77,8 @@ private slots: QLineEdit * m_filterEdit; - QString m_directories; - QString m_filter; + QString m_directories; //!< Directories to search, split with '*' + QString m_filter; //!< Filter as used in QDir::match() bool m_dirsAsItems; bool m_recurse; @@ -159,7 +167,14 @@ class Directory : public QTreeWidgetItem static QPixmap * s_folderOpenedPixmap; static QPixmap * s_folderLockedPixmap; + //! Directories that lead here + //! Initially, this is just set to the current path of a directory + //! If, however, you have e.g. 'TripleOscillator/xyz' in two of the + //! file browser's search directories 'a' and 'b', this will have two + //! entries 'a/TripleOscillator' and 'b/TripleOscillator' + //! and 'xyz' in the tree widget QStringList m_directories; + //! Filter as used in QDir::match() QString m_filter; int m_dirCount; diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index b661a9fb29e..3cb55fd459c 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -232,6 +232,7 @@ void FileBrowser::addItems(const QString & path ) return; } + // try to add all directories from file system alphabetically into the tree QDir cdir( path ); QStringList files = cdir.entryList( QDir::Dirs, QDir::Name ); for( QStringList::const_iterator it = files.constBegin(); @@ -247,6 +248,7 @@ void FileBrowser::addItems(const QString & path ) m_l->topLevelItem( i ) ); if( d == NULL || cur_file < d->text( 0 ) ) { + // insert before item, we're done Directory *dd = new Directory( cur_file, path, m_filter ); m_l->insertTopLevelItem( i,dd ); @@ -256,6 +258,11 @@ void FileBrowser::addItems(const QString & path ) } else if( cur_file == d->text( 0 ) ) { + // imagine we have subdirs named "TripleOscillator/xyz" in + // two directories from m_directories + // then only add one tree widget for both + // so we don't add a new Directory - we just + // add the path to the current directory d->addDirectory( path ); d->update(); orphan = false; @@ -264,6 +271,8 @@ void FileBrowser::addItems(const QString & path ) } if( orphan ) { + // it has not yet been added yet, so it's (lexically) + // larger than all other dirs => append it at the bottom Directory *d = new Directory( cur_file, path, m_filter ); d->update(); @@ -761,6 +770,7 @@ void Directory::update( void ) if( !childCount() ) { m_dirCount = 0; + // for all paths leading here, add their items for( QStringList::iterator it = m_directories.begin(); it != m_directories.end(); ++it ) { @@ -796,6 +806,7 @@ bool Directory::addItems(const QString & path ) bool added_something = false; + // try to add all directories from file system alphabetically into the tree QStringList files = thisDir.entryList( QDir::Dirs, QDir::Name ); for( QStringList::const_iterator it = files.constBegin(); it != files.constEnd(); ++it ) @@ -810,6 +821,7 @@ bool Directory::addItems(const QString & path ) child( i ) ); if( d == NULL || cur_file < d->text( 0 ) ) { + // insert before item, we're done insertChild( i, new Directory( cur_file, path, m_filter ) ); orphan = false; @@ -818,6 +830,12 @@ bool Directory::addItems(const QString & path ) } else if( cur_file == d->text( 0 ) ) { + // imagine we have top-level subdirs named "TripleOscillator" in + // two directories from FileBrowser::m_directories + // and imagine both have a sub folder named "xyz" + // then only add one tree widget for both + // so we don't add a new Directory - we just + // add the path to the current directory d->addDirectory( path ); orphan = false; break; @@ -825,6 +843,8 @@ bool Directory::addItems(const QString & path ) } if( orphan ) { + // it has not yet been added yet, so it's (lexically) + // larger than all other dirs => append it at the bottom addChild( new Directory( cur_file, path, m_filter ) ); m_dirCount++; From d280b8628d2ac4642bf704d528e5a7ac935015c5 Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Sun, 19 Jan 2020 20:34:48 +0100 Subject: [PATCH 19/41] Fixes #3183: Fix file factory delimeter position --- src/gui/FileBrowser.cpp | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/gui/FileBrowser.cpp b/src/gui/FileBrowser.cpp index 3cb55fd459c..4a3b8e85b0b 100644 --- a/src/gui/FileBrowser.cpp +++ b/src/gui/FileBrowser.cpp @@ -774,18 +774,25 @@ void Directory::update( void ) for( QStringList::iterator it = m_directories.begin(); it != m_directories.end(); ++it ) { - int top_index = childCount(); + int filesBeforeAdd = childCount() - m_dirCount; if( addItems( fullName( *it ) ) && ( *it ).contains( ConfigManager::inst()->dataDir() ) ) { - QTreeWidgetItem * sep = new QTreeWidgetItem; - sep->setText( 0, - FileBrowserTreeWidget::tr( - "--- Factory files ---" ) ); - sep->setIcon( 0, embed::getIconPixmap( - "factory_files" ) ); - insertChild( m_dirCount + top_index, sep ); + // factory file directory is added + // note: those are always added last + int filesNow = childCount() - m_dirCount; + if(filesNow > filesBeforeAdd) // any file appended? + { + QTreeWidgetItem * sep = new QTreeWidgetItem; + sep->setText( 0, + FileBrowserTreeWidget::tr( + "--- Factory files ---" ) ); + sep->setIcon( 0, embed::getIconPixmap( + "factory_files" ) ); + // add delimeter after last file before appending our files + insertChild( filesBeforeAdd + m_dirCount, sep ); + } } } } From aeac24c06d1a839b242d7738e1412f068508cb4a Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Sun, 26 Jan 2020 16:05:47 +0900 Subject: [PATCH 20/41] Fix a muted demo project "Greippi - Krem Kaakkuja (Second Flight Remix)" --- ...- Krem Kaakkuja (Second Flight Remix).mmpz | Bin 46086 -> 46081 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/projects/demos/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz b/data/projects/demos/Greippi - Krem Kaakkuja (Second Flight Remix).mmpz index 6c9f3436920e5a7a7b847b00a2b5a77e881da457..9ea29b34d3f1aaaf6fe86afe1e0bf10a162abe9a 100644 GIT binary patch delta 16596 zcmX~8b6^DN?5dX!&_*0qjB0m++0YmSxKTT$8A)yQ{ zB@Z#)fF#+V^albf>uP`Y3hsyK{A9e$l)J(9BEEg44%k+K7{~dS+{3@oU|gt0$CUj=95^pEJ{qe znS?;BP*&# z_3|TIybIrVl@FE9^H_fz3T29`^>_Bh2GbwsoVMb5QM1sR<3#f3qdF;fD8>l7scY6C z_|yXLuv_{E(_6+22A?V0z*@-{a|qgCGJ2|YUk=xvMwCu{z%uFkp#0!q2nGu7Lb;{i3Oj%q;9`yrZP4F>wB%>&$H-EFlEH_x87nG9 zQ(?uK8{)P$8J`xKn^~t(e{FS9RC86LM62UVE?~j>no#kfURT8O1m%(Cxl(v-R>%k| z4+EHRbcqFSs_^HsqLy;c?A=gpge)sfgf1Ksy+QF|Rub{?!(Y(|EP!f)C2pAZz5_o% zDQhicIxHfK1e7rE38K#SY!>q&=~g!GKjFDa*A~x=JaSB1ySJ!Iu~nd+Imtc|K(C(- znCOJSy|5M$-n5e%FuB9OJy~gCG%fO+ug)7L5sz3X

&K{~^TIix3)kfh;7+h1@bQ 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

rzdyv7L?w) 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 Date: Sat, 8 Feb 2020 01:57:30 -0500 Subject: [PATCH 21/41] =?UTF-8?q?Fix=20handling=20of=20plugin=5Fexport.h?= =?UTF-8?q?=20Fixes=20error:=20definition=20is=20marked=20=E2=80=98dllimpo?= =?UTF-8?q?rt=E2=80=99=20Per=20#4813?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plugins/carlabase/CMakeLists.txt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt index 722f8463da8..26478099638 100644 --- a/plugins/carlabase/CMakeLists.txt +++ b/plugins/carlabase/CMakeLists.txt @@ -8,14 +8,15 @@ ENDIF() # If Carla was not provided by the system, make a dummy library instead if(LMMS_HAVE_WEAKCARLA) - # Mimic the Makefile header - FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/config.h "") + # Mimic the autoconf header + FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/autoconf) + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/autoconf/config.h "") SET(CARLA_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/carla/source ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/includes ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/utils ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/backend - ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_BINARY_DIR}/autoconf ) INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) ADD_LIBRARY(carla_native-plugin MODULE DummyCarla.cpp) From bbb3624399e2683864e34c51f7d5f00968f25685 Mon Sep 17 00:00:00 2001 From: Spekular Date: Sun, 23 Feb 2020 14:01:40 +0100 Subject: [PATCH 22/41] Bias dropped clip position backwards --- src/core/Track.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core/Track.cpp b/src/core/Track.cpp index 5c61dc5abe3..cb430da964c 100644 --- a/src/core/Track.cpp +++ b/src/core/Track.cpp @@ -1620,9 +1620,13 @@ bool TrackContentWidget::pasteSelection( MidiTime tcoPos, QDropEvent * de ) // TODO -- Need to draw the hovericon either way, or ghost the TCOs // onto their final position. + float snapSize = gui->songEditor()->m_editor->getSnapSize(); // All patterns should be offset the same amount as the grabbed pattern + MidiTime offset = MidiTime(tcoPos - grabbedTCOPos); + // Users expect clips to "fall" backwards, so bias the offset + offset = offset - MidiTime::ticksPerBar() * snapSize / 2; // The offset is quantized (rather than the positions) to preserve fine adjustments - int offset = MidiTime(tcoPos - grabbedTCOPos).quantize(gui->songEditor()->m_editor->getSnapSize()); + offset = offset.quantize(snapSize); for( int i = 0; i Date: Sat, 7 Dec 2019 22:31:27 +0100 Subject: [PATCH 23/41] Fix doxygen comment --- include/AutomatableModel.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index cdfdffccf62..73723abb445 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -325,7 +325,7 @@ public slots: DataType m_dataType; - ScaleType m_scaleType; //! scale type, linear by default + ScaleType m_scaleType; //!< scale type, linear by default float m_value; float m_initValue; float m_minValue; From a0f4e50805caa96db254f3aa89cc490248ef6a8a Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Sat, 7 Dec 2019 22:33:37 +0100 Subject: [PATCH 24/41] Fix knobs not updating vals on link (#4904) --- include/AutomatableModel.h | 1 + src/core/AutomatableModel.cpp | 15 ++++++ tests/CMakeLists.txt | 1 + tests/src/core/AutomatableModelTest.cpp | 67 +++++++++++++++++++++++++ 4 files changed, 84 insertions(+) create mode 100644 tests/src/core/AutomatableModelTest.cpp diff --git a/include/AutomatableModel.h b/include/AutomatableModel.h index 73723abb445..46a225189ed 100644 --- a/include/AutomatableModel.h +++ b/include/AutomatableModel.h @@ -220,6 +220,7 @@ class EXPORT AutomatableModel : public Model, public JournallingObject m_centerValue = centerVal; } + //! link @p m1 and @p m2, let @p m1 take the values of @p m2 static void linkModels( AutomatableModel* m1, AutomatableModel* m2 ); static void unlinkModels( AutomatableModel* m1, AutomatableModel* m2 ); diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 5a97c328075..14bb661e9e1 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -443,8 +443,23 @@ void AutomatableModel::unlinkModel( AutomatableModel* model ) void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* model2 ) { + if (!model1->m_linkedModels.contains( model2 ) && model1 != model2) + { + // copy data + model1->m_value = model2->m_value; + if (model1->valueBuffer() && model2->valueBuffer()) + { + std::copy_n(model2->valueBuffer()->data(), + model1->valueBuffer()->length(), + model1->valueBuffer()->data()); + } + // send dataChanged() before linking (because linking will + // connect the two dataChanged() signals) + emit model1->dataChanged(); + // finally: link the models model1->linkModel( model2 ); model2->linkModel( model1 ); + } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 8cbe23858bf..ce0e00f4cd4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -18,6 +18,7 @@ ADD_EXECUTABLE(tests QTestSuite $ + src/core/AutomatableModelTest.cpp src/core/ProjectVersionTest.cpp src/core/RelativePathsTest.cpp diff --git a/tests/src/core/AutomatableModelTest.cpp b/tests/src/core/AutomatableModelTest.cpp new file mode 100644 index 00000000000..5b1363f6cee --- /dev/null +++ b/tests/src/core/AutomatableModelTest.cpp @@ -0,0 +1,67 @@ +/* + * AutomatableModelTest.cpp + * + * Copyright (c) 2020 Johannes Lorenz + * + * 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. + * + */ + +#include "QTestSuite.h" + +#include "AutomatableModel.h" + +class AutomatableModelTest : QTestSuite +{ + Q_OBJECT + + bool m1Changed, m2Changed; + void resetChanged() { m1Changed = m2Changed = false; } + +private slots: // helper slots + void onM1Changed(Model* ) { m1Changed = true; } + void onM2Changed(Model* ) { m2Changed = true; } + +private slots: // tests + void LinkTests() + { + BoolModel m1(false), m2(false); + + QObject::connect(&m1, SIGNAL(dataChanged(Model*)), + this, SLOT(onM1Changed(Model*))); + QObject::connect(&m2, SIGNAL(dataChanged(Model*)), + this, SLOT(onM2Changed(Model*))); + + resetChanged(); + AutomatableModel::linkModels(&m1, &m1); + QVERIFY(!m1Changed); // cannot link to itself + QVERIFY(!m2Changed); + + resetChanged(); + AutomatableModel::linkModels(&m1, &m2); + QVERIFY(m1Changed); // since m1 takes the value of m2 + QVERIFY(!m2Changed); // the second model is the source + + resetChanged(); + AutomatableModel::linkModels(&m1, &m2); + QVERIFY(!m1Changed); // it's already linked + QVERIFY(!m2Changed); + } +} AutomatableModelTests; + +#include "AutomatableModelTest.moc" From 97a6379c6db356bbab4f67af57ae69c5e89f8d1f Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Sat, 7 Dec 2019 22:35:42 +0100 Subject: [PATCH 25/41] Update UI after linking models (#4904) --- src/core/AutomatableModel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 14bb661e9e1..636a05ca99e 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -460,6 +460,7 @@ void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* m model1->linkModel( model2 ); model2->linkModel( model1 ); } + emit model1->dataChanged(); } From 47786865ef4ae3874ba6c26d91bdbbaedc64c6c3 Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Thu, 2 Jan 2020 19:49:02 +0100 Subject: [PATCH 26/41] Document strange bug --- tests/src/core/AutomatableModelTest.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/src/core/AutomatableModelTest.cpp b/tests/src/core/AutomatableModelTest.cpp index 5b1363f6cee..553656f8d3b 100644 --- a/tests/src/core/AutomatableModelTest.cpp +++ b/tests/src/core/AutomatableModelTest.cpp @@ -61,6 +61,20 @@ private slots: // tests AutomatableModel::linkModels(&m1, &m2); QVERIFY(!m1Changed); // it's already linked QVERIFY(!m2Changed); + + resetChanged(); + BoolModel m3(false); + m1.setValue(1.f); + m2.setValue(1.f); + AutomatableModel::linkModels(&m1, &m2); + QVERIFY(m1.value()); + QVERIFY(m2.value()); + QVERIFY(!m3.value()); + AutomatableModel::linkModels(&m2, &m3); // drag m3, drop on m2 + // m2 should take m3's (0) value + // due to a bug(?), this does not happen + QVERIFY(m2.value()); + QVERIFY(!m3.value()); } } AutomatableModelTests; From 94431ea9decdd8d6f9a1c377c1e7ee621cc19bb7 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Sun, 1 Mar 2020 12:03:49 +0900 Subject: [PATCH 27/41] RemoteVstPlugin: fix issues with FXP/FXB files on Windows (#5411) --- plugins/vst_base/RemoteVstPlugin.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/vst_base/RemoteVstPlugin.cpp b/plugins/vst_base/RemoteVstPlugin.cpp index 15a56e8696e..be92126e3f6 100644 --- a/plugins/vst_base/RemoteVstPlugin.cpp +++ b/plugins/vst_base/RemoteVstPlugin.cpp @@ -1286,7 +1286,7 @@ void RemoteVstPlugin::savePreset( const std::string & _file ) if (!isPreset &&!chunky) uIntToFile = (unsigned int) m_plugin->numPrograms; pBank->numPrograms = endian_swap( uIntToFile ); - FILE * stream = F_OPEN_UTF8( _file, "w" ); + FILE * stream = F_OPEN_UTF8( _file, "wb" ); if (!stream) { fprintf( stderr, @@ -1344,7 +1344,7 @@ void RemoteVstPlugin::loadPresetFile( const std::string & _file ) unsigned int * pLen = new unsigned int[ 1 ]; unsigned int len = 0; sBank * pBank = (sBank*) new char[ sizeof( sBank ) ]; - FILE * stream = F_OPEN_UTF8( _file, "r" ); + FILE * stream = F_OPEN_UTF8( _file, "rb" ); if (!stream) { fprintf( stderr, From ab8be73047ecb15026ecd074471b6ca4137bd7cd Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Sun, 8 Mar 2020 08:24:46 +0100 Subject: [PATCH 28/41] Cherry-pick from master commit 4dc26d1 (#5413) --- src/core/Song.cpp | 2 ++ src/gui/editors/PianoRoll.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 54f19e1d305..3285497a8d7 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -75,6 +75,7 @@ Song::Song() : m_oldTicksPerTact( DefaultTicksPerTact ), m_masterVolumeModel( 100, 0, 200, this, tr( "Master volume" ) ), m_masterPitchModel( 0, -12, 12, this, tr( "Master pitch" ) ), + m_nLoadingTrack( 0 ), m_fileName(), m_oldFileName(), m_modified( false ), @@ -85,6 +86,7 @@ Song::Song() : m_renderBetweenMarkers( false ), m_playing( false ), m_paused( false ), + m_savingProject( false ), m_loadingProject( false ), m_isCancelled( false ), m_playMode( Mode_None ), diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index f6bda682b30..92446399530 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -154,6 +154,8 @@ PianoRoll::PianoRoll() : m_zoomingModel(), m_quantizeModel(), m_noteLenModel(), + m_scaleModel(), + m_chordModel(), m_pattern( NULL ), m_currentPosition(), m_recording( false ), From d382d4e08b474a072285ce25478d1edf3150e1f3 Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Sun, 8 Mar 2020 08:47:27 +0100 Subject: [PATCH 29/41] Fix previous commit --- src/core/Song.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/Song.cpp b/src/core/Song.cpp index 3285497a8d7..cffe234502b 100644 --- a/src/core/Song.cpp +++ b/src/core/Song.cpp @@ -86,7 +86,6 @@ Song::Song() : m_renderBetweenMarkers( false ), m_playing( false ), m_paused( false ), - m_savingProject( false ), m_loadingProject( false ), m_isCancelled( false ), m_playMode( Mode_None ), From 2367a62a51ec833e08d6dd342b65b9b1829391d5 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Mon, 23 Mar 2020 15:11:13 +0900 Subject: [PATCH 30/41] Fix crashes and hangs on importing some Hydrogen drum kit songs (#5420) --- plugins/HydrogenImport/HydrogenImport.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/plugins/HydrogenImport/HydrogenImport.cpp b/plugins/HydrogenImport/HydrogenImport.cpp index f86cdffd703..3ca0f2da2fa 100644 --- a/plugins/HydrogenImport/HydrogenImport.cpp +++ b/plugins/HydrogenImport/HydrogenImport.cpp @@ -200,13 +200,19 @@ bool HydrogenImport::readSong() else { unsigned nLayer = 0; - QDomNode layerNode = instrumentNode.firstChildElement( "layer" ); + QDomNode instrumentComponentNode = instrumentNode.firstChildElement("instrumentComponent"); + if (instrumentComponentNode.isNull()) + { + instrumentComponentNode = instrumentNode; + } + + QDomNode layerNode = instrumentComponentNode.firstChildElement( "layer" ); while ( ! layerNode.isNull() ) { if ( nLayer >= MAX_LAYERS ) { - printf( "nLayer >= MAX_LAYERS" ); - continue; + printf("nLayer >= MAX_LAYERS\n"); + break; } QString sFilename = LocalFileMng::readXmlString( layerNode, "filename", "" ); QString sMode = LocalFileMng::readXmlString( layerNode, "smode", "forward" ); From b51079e921c31f2570a8d07d3100a67ad4584123 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Tue, 24 Mar 2020 10:36:50 +0900 Subject: [PATCH 31/41] Use proper synchronization methods on some instrument track operations --- src/tracks/InstrumentTrack.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/tracks/InstrumentTrack.cpp b/src/tracks/InstrumentTrack.cpp index 3f0c59b7d18..7caf8e2fc16 100644 --- a/src/tracks/InstrumentTrack.cpp +++ b/src/tracks/InstrumentTrack.cpp @@ -445,7 +445,7 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH ) } m_midiNotesMutex.unlock(); - lock(); + Engine::mixer()->requestChangeInModel(); // invalidate all NotePlayHandles and PresetPreviewHandles linked to this track m_processHandles.clear(); @@ -455,7 +455,7 @@ void InstrumentTrack::silenceAllNotes( bool removeIPH ) flags |= PlayHandle::TypeInstrumentPlayHandle; } Engine::mixer()->removePlayHandlesOfTypes( this, flags ); - unlock(); + Engine::mixer()->doneChangeInModel(); } @@ -544,11 +544,13 @@ void InstrumentTrack::setName( const QString & _new_name ) void InstrumentTrack::updateBaseNote() { + Engine::mixer()->requestChangeInModel(); for( NotePlayHandleList::Iterator it = m_processHandles.begin(); it != m_processHandles.end(); ++it ) { ( *it )->setFrequencyUpdate(); } + Engine::mixer()->doneChangeInModel(); } From a8df120a58b3fbafe65225893c89f1078eeb1146 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Tue, 24 Mar 2020 10:55:46 +0900 Subject: [PATCH 32/41] STK Mallets: don't silence active notes when switching instruments This also fixes the underlying noise on instrument switches. --- plugins/stk/mallets/mallets.cpp | 16 ++++++++++------ plugins/stk/mallets/mallets.h | 11 +++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/plugins/stk/mallets/mallets.cpp b/plugins/stk/mallets/mallets.cpp index 29b6aeb20c1..22880484fb4 100644 --- a/plugins/stk/mallets/mallets.cpp +++ b/plugins/stk/mallets/mallets.cpp @@ -338,6 +338,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n, Engine::mixer()->processingSampleRate() ); } m.unlock(); + static_cast(_n->m_pluginData)->setPresetIndex(p); } const fpp_t frames = _n->framesLeftForCurrentPeriod(); @@ -345,6 +346,7 @@ void malletsInstrument::playNote( NotePlayHandle * _n, malletsSynth * ps = static_cast( _n->m_pluginData ); ps->setFrequency( freq ); + p = ps->presetIndex(); sample_t add_scale = 0.0f; if( p == 10 && m_isOldVersionModel.value() == true ) @@ -355,9 +357,9 @@ void malletsInstrument::playNote( NotePlayHandle * _n, for( fpp_t frame = offset; frame < frames + offset; ++frame ) { _working_buffer[frame][0] = ps->nextSampleLeft() * - ( m_scalers[m_presetsModel.value()] + add_scale ); + ( m_scalers[p] + add_scale ); _working_buffer[frame][1] = ps->nextSampleRight() * - ( m_scalers[m_presetsModel.value()] + add_scale ); + ( m_scalers[p] + add_scale ); } instrumentTrack()->processAudioBuffer( _working_buffer, frames + offset, _n ); @@ -579,7 +581,6 @@ void malletsInstrumentView::modelChanged() void malletsInstrumentView::changePreset() { malletsInstrument * inst = castModel(); - inst->instrumentTrack()->silenceAllNotes(); int _preset = inst->m_presetsModel.value(); if( _preset < 9 ) @@ -614,7 +615,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch, const StkFloat _control11, const int _control16, const uint8_t _delay, - const sample_rate_t _sample_rate ) + const sample_rate_t _sample_rate ) : + m_presetIndex(0) { try { @@ -664,7 +666,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch, const StkFloat _control11, const StkFloat _control128, const uint8_t _delay, - const sample_rate_t _sample_rate ) + const sample_rate_t _sample_rate ) : + m_presetIndex(0) { try { @@ -712,7 +715,8 @@ malletsSynth::malletsSynth( const StkFloat _pitch, const StkFloat _control64, const StkFloat _control128, const uint8_t _delay, - const sample_rate_t _sample_rate ) + const sample_rate_t _sample_rate ) : + m_presetIndex(0) { try { diff --git a/plugins/stk/mallets/mallets.h b/plugins/stk/mallets/mallets.h index 3928c531c5c..c8f5e7a47bc 100644 --- a/plugins/stk/mallets/mallets.h +++ b/plugins/stk/mallets/mallets.h @@ -120,8 +120,19 @@ class malletsSynth } } + inline int presetIndex() + { + return m_presetIndex; + } + + inline void setPresetIndex(int presetIndex) + { + m_presetIndex = presetIndex; + } + protected: + int m_presetIndex; Instrmnt * m_voice; StkFloat * m_delay; From 656eede6bac47915c7ca974b40c81162d28a28ae Mon Sep 17 00:00:00 2001 From: Johannes Lorenz Date: Wed, 1 Apr 2020 21:22:05 +0200 Subject: [PATCH 33/41] Fix bug made in #5336 This removes a duplicate dataChanged() emit. Thanks to @PhysSong for the hint. --- src/core/AutomatableModel.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/AutomatableModel.cpp b/src/core/AutomatableModel.cpp index 636a05ca99e..14bb661e9e1 100644 --- a/src/core/AutomatableModel.cpp +++ b/src/core/AutomatableModel.cpp @@ -460,7 +460,6 @@ void AutomatableModel::linkModels( AutomatableModel* model1, AutomatableModel* m model1->linkModel( model2 ); model2->linkModel( model1 ); } - emit model1->dataChanged(); } From 8afa2d541276a3e7bfdb7a836b2567a73dd750d9 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Sat, 4 Apr 2020 12:06:35 +0900 Subject: [PATCH 34/41] Fix the linking method for the dummy Carla library --- plugins/carlabase/CMakeLists.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt index 26478099638..5e024da4030 100644 --- a/plugins/carlabase/CMakeLists.txt +++ b/plugins/carlabase/CMakeLists.txt @@ -18,15 +18,15 @@ if(LMMS_HAVE_WEAKCARLA) ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/backend ${CMAKE_CURRENT_BINARY_DIR}/autoconf ) - INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) - ADD_LIBRARY(carla_native-plugin MODULE DummyCarla.cpp) - INSTALL(TARGETS carla_native-plugin LIBRARY DESTINATION "${PLUGIN_DIR}/optional") - SET(CARLA_LIBRARIES $) - SET(CARLA_LIBRARY_DIRS $) + ADD_LIBRARY(carla_native-plugin SHARED DummyCarla.cpp) + TARGET_INCLUDE_DIRECTORIES(carla_native-plugin PUBLIC ${CARLA_INCLUDE_DIRS}) + INSTALL(TARGETS carla_native-plugin + LIBRARY DESTINATION "${PLUGIN_DIR}/optional" + RUNTIME DESTINATION "${PLUGIN_DIR}/optional" + ) + SET(CARLA_LIBRARIES carla_native-plugin) # Set parent scope variables so carlarack and carlapatchbay can see them SET(CARLA_LIBRARIES ${CARLA_LIBRARIES} PARENT_SCOPE) - SET(CARLA_INCLUDE_DIRS ${CARLA_INCLUDE_DIRS} PARENT_SCOPE) - SET(CARLA_LIBRARY_DIRS ${CARLA_LIBRARY_DIRS} PARENT_SCOPE) endif() if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA) From 9c2ccdf3a826f99d4c4f9c3427e9074c64f15a98 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Wed, 25 Mar 2020 14:54:23 +0900 Subject: [PATCH 35/41] Fix some issues in shell scripts spotted by shellcheck --- .travis/script.sh | 2 +- cmake/linux/package_linux.sh.in | 2 +- cmake/msys/extract_debs.sh | 2 ++ cmake/msys/msys_helper.sh | 2 +- 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.travis/script.sh b/.travis/script.sh index b723f5dd0e4..a6d87b37f0d 100755 --- a/.travis/script.sh +++ b/.travis/script.sh @@ -22,7 +22,7 @@ else "$TRAVIS_BUILD_DIR/.travis/$TRAVIS_OS_NAME.$TARGET_OS.script.sh" # Package and upload non-tagged builds - if [ ! -z "$TRAVIS_TAG" ]; then + if [ -n "$TRAVIS_TAG" ]; then # Skip, handled by travis deploy instead exit 0 elif [[ $TARGET_OS == win* ]]; then diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index dcbb6cb5422..adcf9daa2dc 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -108,7 +108,7 @@ chmod +x "${APPDIR}usr/bin/lmms" unset LD_LIBRARY_PATH # Ensure linuxdeployqt can find shared objects -export LD_LIBRARY_PATH="${APPDIR}usr/lib/lmms/":"${APPDIR}usr/lib/lmms/optional":$LD_LIBRARY_PATH +export LD_LIBRARY_PATH="${APPDIR}"usr/lib/lmms/:"${APPDIR}"usr/lib/lmms/optional:"$LD_LIBRARY_PATH" # Handle wine linking if [ -d "@WINE_32_LIBRARY_DIR@" ]; then diff --git a/cmake/msys/extract_debs.sh b/cmake/msys/extract_debs.sh index cb2a868d3e9..939912bb2c3 100644 --- a/cmake/msys/extract_debs.sh +++ b/cmake/msys/extract_debs.sh @@ -1,4 +1,6 @@ #!/bin/bash +set -e + ppa_dir=./ppa/ pushd $ppa_dir diff --git a/cmake/msys/msys_helper.sh b/cmake/msys/msys_helper.sh index 294edd476da..a6a7e6aae38 100644 --- a/cmake/msys/msys_helper.sh +++ b/cmake/msys/msys_helper.sh @@ -68,7 +68,7 @@ stkver="4.5.1" mingw_root="/$(echo "$MSYSTEM"|tr '[:upper:]' '[:lower:]')" info "Downloading and building fltk $fltkver" -if ! which fluid; then +if ! command -v fluid; then wget http://fltk.org/pub/fltk/$fltkver/fltk-$fltkver-source.tar.gz -O "$HOME/fltk-source.tar.gz" tar zxf "$HOME/fltk-source.tar.gz" -C "$HOME/" pushd "$HOME/fltk-$fltkver" From d173f42fecf04ff43878d2f48e6252289c92ddfb Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Thu, 2 Jan 2020 12:32:39 +0900 Subject: [PATCH 36/41] Fix wine detection --- cmake/linux/package_linux.sh.in | 18 ++++++++++-------- cmake/modules/FindWine.cmake | 20 ++++++++++++++------ tests/src/core/AutomatableModelTest.cpp | 12 ++++++------ 3 files changed, 30 insertions(+), 20 deletions(-) diff --git a/cmake/linux/package_linux.sh.in b/cmake/linux/package_linux.sh.in index adcf9daa2dc..a1f9ff8658f 100644 --- a/cmake/linux/package_linux.sh.in +++ b/cmake/linux/package_linux.sh.in @@ -110,14 +110,6 @@ unset LD_LIBRARY_PATH # Ensure linuxdeployqt can find shared objects export LD_LIBRARY_PATH="${APPDIR}"usr/lib/lmms/:"${APPDIR}"usr/lib/lmms/optional:"$LD_LIBRARY_PATH" -# Handle wine linking -if [ -d "@WINE_32_LIBRARY_DIR@" ]; then - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:@WINE_32_LIBRARY_DIRS@ -fi -if [ -d "@WINE_64_LIBRARY_DIR@" ]; then - export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:@WINE_64_LIBRARY_DIRS@ -fi - # Move executables so linuxdeployqt can find them ZYNLIB="${APPDIR}usr/lib/lmms/RemoteZynAddSubFx" VSTLIB32="${APPDIR}usr/lib/lmms/32/RemoteVstPlugin32.exe.so" @@ -131,6 +123,16 @@ mv "$ZYNLIB" "$ZYNBIN" mv "$VSTLIB32" "$VSTBIN32" || true mv "$VSTLIB64" "$VSTBIN64" || true +# Handle wine linking +if [ -d "@WINE_32_LIBRARY_DIR@" ] && \ + ldd "$VSTBIN32" | grep "libwine\.so" | grep "not found"; then + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"@WINE_32_LIBRARY_DIRS@" +fi +if [ -d "@WINE_64_LIBRARY_DIR@" ] && \ + ldd "$VSTBIN64" | grep "libwine\.so" | grep "not found"; then + export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:"@WINE_64_LIBRARY_DIRS@" +fi + # Patch the desktop file sed -i 's/.*Exec=.*/Exec=lmms.real/' "$DESKTOPFILE" diff --git a/cmake/modules/FindWine.cmake b/cmake/modules/FindWine.cmake index 50bf54edbc6..f7f3b0aa647 100644 --- a/cmake/modules/FindWine.cmake +++ b/cmake/modules/FindWine.cmake @@ -11,11 +11,19 @@ MACRO(_findwine_find_flags output expression result) STRING(REPLACE " " ";" WINEBUILD_FLAGS "${output}") FOREACH(FLAG ${WINEBUILD_FLAGS}) IF("${FLAG}" MATCHES "${expression}") - SET(${result} "${FLAG}") + LIST(APPEND ${result} "${FLAG}") ENDIF() ENDFOREACH() ENDMACRO() +MACRO(_regex_replace_foreach EXPRESSION REPLACEMENT RESULT INPUT) + SET(${RESULT} "") + FOREACH(ITEM ${INPUT}) + STRING(REGEX REPLACE "${EXPRESSION}" "${REPLACEMENT}" ITEM "${ITEM}") + LIST(APPEND ${RESULT} "${ITEM}") + ENDFOREACH() +ENDMACRO() + LIST(APPEND CMAKE_PREFIX_PATH /opt/wine-stable /opt/wine-devel /opt/wine-staging /usr/lib/wine/) FIND_PROGRAM(WINE_CXX @@ -31,10 +39,10 @@ IF(WINE_CXX) _findwine_find_flags("${WINEBUILD_OUTPUT_32}" "^-isystem" WINEGCC_INCLUDE_DIR) _findwine_find_flags("${WINEBUILD_OUTPUT_32}" "libwinecrt0\\.a.*" WINECRT_32) _findwine_find_flags("${WINEBUILD_OUTPUT_64}" "libwinecrt0\\.a.*" WINECRT_64) - STRING(REGEX REPLACE "^-isystem" "" WINE_INCLUDE_HINT "${WINEGCC_INCLUDE_DIR}") - STRING(REGEX REPLACE "/wine/windows$" "" WINE_INCLUDE_HINT "${WINE_INCLUDE_HINT}") - STRING(REGEX REPLACE "libwinecrt0\\.a.*" "" WINE_32_LIBRARY_DIR "${WINECRT_32}") - STRING(REGEX REPLACE "libwinecrt0\\.a.*" "" WINE_64_LIBRARY_DIR "${WINECRT_64}") + _regex_replace_foreach("^-isystem" "" WINE_INCLUDE_HINT "${WINEGCC_INCLUDE_DIR}") + _regex_replace_foreach("/wine/windows$" "" WINE_INCLUDE_HINT "${WINE_INCLUDE_HINT}") + STRING(REGEX REPLACE "wine/libwinecrt0\\.a.*" "" WINE_32_LIBRARY_DIR "${WINECRT_32}") + STRING(REGEX REPLACE "wine/libwinecrt0\\.a.*" "" WINE_64_LIBRARY_DIR "${WINECRT_64}") IF(BUGGED_WINEGCC) MESSAGE(WARNING "Your winegcc is unusable due to https://bugs.winehq.org/show_bug.cgi?id=46293,\n @@ -76,7 +84,7 @@ IF(WINE_CXX) ENDIF() FIND_PATH(WINE_INCLUDE_DIR wine/exception.h - HINTS "${WINE_INCLUDE_HINT}" + HINTS ${WINE_INCLUDE_HINT} ) SET(_ARCHITECTURE ${CMAKE_LIBRARY_ARCHITECTURE}) diff --git a/tests/src/core/AutomatableModelTest.cpp b/tests/src/core/AutomatableModelTest.cpp index 6bf9090e113..d84d89db4a6 100644 --- a/tests/src/core/AutomatableModelTest.cpp +++ b/tests/src/core/AutomatableModelTest.cpp @@ -35,8 +35,8 @@ class AutomatableModelTest : QTestSuite void resetChanged() { m1Changed = m2Changed = false; } private slots: // helper slots - void onM1Changed(Model* ) { m1Changed = true; } - void onM2Changed(Model* ) { m2Changed = true; } + void onM1Changed() { m1Changed = true; } + void onM2Changed() { m2Changed = true; } private slots: // tests //! Test that upcast and exact casts work, @@ -62,10 +62,10 @@ private slots: // tests { BoolModel m1(false), m2(false); - QObject::connect(&m1, SIGNAL(dataChanged(Model*)), - this, SLOT(onM1Changed(Model*))); - QObject::connect(&m2, SIGNAL(dataChanged(Model*)), - this, SLOT(onM2Changed(Model*))); + QObject::connect(&m1, SIGNAL(dataChanged()), + this, SLOT(onM1Changed())); + QObject::connect(&m2, SIGNAL(dataChanged()), + this, SLOT(onM2Changed())); resetChanged(); AutomatableModel::linkModels(&m1, &m1); From 7628b253b0a94e0a22ef44e12de0ee72173cbad1 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Wed, 25 Mar 2020 14:46:15 +0900 Subject: [PATCH 37/41] Fix linking issues with the dummy Carla library(especially with MSVC) --- plugins/carlabase/CMakeLists.txt | 14 +++++++++----- plugins/carlabase/CarlaConfig/config.h | 9 +++++++++ plugins/carlabase/DummyCarla.cpp | 19 ++++++++++--------- plugins/carlabase/carla.h | 5 ++--- plugins/carlapatchbay/carlapatchbay.cpp | 1 + plugins/carlarack/carlarack.cpp | 1 + 6 files changed, 32 insertions(+), 17 deletions(-) create mode 100644 plugins/carlabase/CarlaConfig/config.h diff --git a/plugins/carlabase/CMakeLists.txt b/plugins/carlabase/CMakeLists.txt index 7807aebd241..28a1bc88c51 100644 --- a/plugins/carlabase/CMakeLists.txt +++ b/plugins/carlabase/CMakeLists.txt @@ -8,15 +8,11 @@ ENDIF() # If Carla was not provided by the system, make a dummy library instead if(LMMS_HAVE_WEAKCARLA) - # Mimic the autoconf header - FILE(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/autoconf) - FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/autoconf/config.h "") SET(CARLA_INCLUDE_DIRS ${CMAKE_CURRENT_SOURCE_DIR}/carla/source ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/includes ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/utils ${CMAKE_CURRENT_SOURCE_DIR}/carla/source/backend - ${CMAKE_CURRENT_BINARY_DIR}/autoconf ) ADD_LIBRARY(carla_native-plugin SHARED DummyCarla.cpp) TARGET_INCLUDE_DIRECTORIES(carla_native-plugin PUBLIC ${CARLA_INCLUDE_DIRS}) @@ -30,11 +26,19 @@ if(LMMS_HAVE_WEAKCARLA) endif() if(LMMS_HAVE_CARLA OR LMMS_HAVE_WEAKCARLA) + # Mimic the missing "config.h" + SET(CARLA_INCLUDE_DIRS ${CARLA_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/CarlaConfig) + SET(CARLA_INCLUDE_DIRS ${CARLA_INCLUDE_DIRS} PARENT_SCOPE) + INCLUDE(BuildPlugin) INCLUDE_DIRECTORIES(${CARLA_INCLUDE_DIRS}) LINK_DIRECTORIES(${CARLA_LIBRARY_DIRS}) LINK_LIBRARIES(${CARLA_LIBRARIES}) - BUILD_PLUGIN(carlabase carla.cpp carla.h MOCFILES carla.h EMBEDDED_RESOURCES artwork-patchbay.png artwork-rack.png LINK SHARED) + BUILD_PLUGIN(carlabase carla.cpp carla.h + MOCFILES carla.h + EMBEDDED_RESOURCES artwork-patchbay.png artwork-rack.png + EXPORT_BASE_NAME carlabase + LINK SHARED) SET_TARGET_PROPERTIES(carlabase PROPERTIES SKIP_BUILD_RPATH TRUE BUILD_WITH_INSTALL_RPATH TRUE diff --git a/plugins/carlabase/CarlaConfig/config.h b/plugins/carlabase/CarlaConfig/config.h new file mode 100644 index 00000000000..46b3f34649c --- /dev/null +++ b/plugins/carlabase/CarlaConfig/config.h @@ -0,0 +1,9 @@ +// config.h for Carla +#ifndef FOR_CARLA_CONFIG_H +#define FOR_CARLA_CONFIG_H + +#ifdef _MSC_VER +#define HAVE_CPP11_SUPPORT 1 +#endif + +#endif diff --git a/plugins/carlabase/DummyCarla.cpp b/plugins/carlabase/DummyCarla.cpp index 560e866b7b6..8fd9ef6d7e6 100644 --- a/plugins/carlabase/DummyCarla.cpp +++ b/plugins/carlabase/DummyCarla.cpp @@ -1,12 +1,13 @@ // A dummy Carla interface +#define BUILDING_CARLA #include "CarlaNativePlugin.h" -const char* carla_get_library_filename() { return nullptr; } -const char* carla_get_library_folder() { return nullptr; } -const NativePluginDescriptor* carla_get_native_rack_plugin() { return nullptr; } -const NativePluginDescriptor* carla_get_native_patchbay_plugin() { return nullptr; } -const NativePluginDescriptor* carla_get_native_patchbay16_plugin() { return nullptr; } -const NativePluginDescriptor* carla_get_native_patchbay32_plugin() { return nullptr; } -const NativePluginDescriptor* carla_get_native_patchbay64_plugin() { return nullptr; } -const NativePluginDescriptor* carla_get_native_patchbay_cv_plugin() { return nullptr; } -CarlaBackend::CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) { return nullptr; } +CARLA_EXPORT const char* carla_get_library_filename() { return nullptr; } +CARLA_EXPORT const char* carla_get_library_folder() { return nullptr; } +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_rack_plugin() { return nullptr; } +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay_plugin() { return nullptr; } +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay16_plugin() { return nullptr; } +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay32_plugin() { return nullptr; } +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay64_plugin() { return nullptr; } +CARLA_EXPORT const NativePluginDescriptor* carla_get_native_patchbay_cv_plugin() { return nullptr; } +CARLA_EXPORT CarlaBackend::CarlaEngine* carla_get_native_plugin_engine(const NativePluginDescriptor* desc, NativePluginHandle handle) { return nullptr; } diff --git a/plugins/carlabase/carla.h b/plugins/carlabase/carla.h index 393912a509f..2c683add935 100644 --- a/plugins/carlabase/carla.h +++ b/plugins/carlabase/carla.h @@ -26,10 +26,9 @@ #define CARLA_H #include -#include "plugin_export.h" +#include "carlabase_export.h" #include "CarlaNative.h" -#define REAL_BUILD // FIXME this shouldn't be needed #if CARLA_VERSION_HEX >= 0x010911 #include "CarlaNativePlugin.h" #else @@ -48,7 +47,7 @@ class QPushButton; -class PLUGIN_EXPORT CarlaInstrument : public Instrument +class CARLABASE_EXPORT CarlaInstrument : public Instrument { Q_OBJECT diff --git a/plugins/carlapatchbay/carlapatchbay.cpp b/plugins/carlapatchbay/carlapatchbay.cpp index ac00630d44d..ad0c1f6aef5 100644 --- a/plugins/carlapatchbay/carlapatchbay.cpp +++ b/plugins/carlapatchbay/carlapatchbay.cpp @@ -25,6 +25,7 @@ #include "carla.h" #include "embed.h" +#include "plugin_export.h" #include "InstrumentTrack.h" extern "C" diff --git a/plugins/carlarack/carlarack.cpp b/plugins/carlarack/carlarack.cpp index c0a39f9c258..ee2a788354f 100644 --- a/plugins/carlarack/carlarack.cpp +++ b/plugins/carlarack/carlarack.cpp @@ -25,6 +25,7 @@ #include "carla.h" #include "embed.h" +#include "plugin_export.h" #include "InstrumentTrack.h" extern "C" From ebfa883e4d063a32dead4f17550661a777fc6f1a Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Thu, 26 Mar 2020 16:21:29 +0900 Subject: [PATCH 38/41] Carla: fix MSVC compatibility --- plugins/carlabase/carla.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/plugins/carlabase/carla.cpp b/plugins/carlabase/carla.cpp index 669ac800a26..a6faa4d275d 100644 --- a/plugins/carlabase/carla.cpp +++ b/plugins/carlabase/carla.cpp @@ -333,8 +333,14 @@ void CarlaInstrument::play(sampleFrame* workingBuffer) fTimeInfo.bbt.ticksPerBeat = ticksPerBeat; fTimeInfo.bbt.beatsPerMinute = s->getTempo(); +#ifndef _MSC_VER float buf1[bufsize]; float buf2[bufsize]; +#else + float *buf1 = static_cast(_alloca(bufsize * sizeof(float))); + float *buf2 = static_cast(_alloca(bufsize * sizeof(float))); +#endif + float* rBuf[] = { buf1, buf2 }; std::memset(buf1, 0, sizeof(float)*bufsize); std::memset(buf2, 0, sizeof(float)*bufsize); From 924743dd1725a542afbeca017a3d22e2558551ed Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Wed, 25 Mar 2020 15:13:37 +0900 Subject: [PATCH 39/41] Fix submodule fetching from non-default branches with old Git --- cmake/modules/CheckSubmodules.cmake | 24 ++++++------------------ 1 file changed, 6 insertions(+), 18 deletions(-) diff --git a/cmake/modules/CheckSubmodules.cmake b/cmake/modules/CheckSubmodules.cmake index 32a2f995181..f45885cc6fb 100644 --- a/cmake/modules/CheckSubmodules.cmake +++ b/cmake/modules/CheckSubmodules.cmake @@ -100,11 +100,11 @@ ENDFOREACH() # Once called, status is stored in GIT_RESULT respectively. # Note: Git likes to write to stderr. Don't assume stderr is error; Check GIT_RESULT instead. -MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE FULL_CLONE) +MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE NO_DEPTH) FIND_PACKAGE(Git REQUIRED) # Handle missing commits SET(FORCE_REMOTE_FLAG "${FORCE_REMOTE}") - SET(FULL_CLONE_FLAG "${FULL_CLONE}") + SET(NO_DEPTH_FLAG "${NO_DEPTH}") IF(FORCE_REMOTE_FLAG) MESSAGE("-- Adding remote submodulefix to ${SUBMODULE_PATH}") EXECUTE_PROCESS( @@ -115,7 +115,7 @@ MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE FULL_CLONE) OUTPUT_QUIET ERROR_QUIET ) # Recurse - GIT_SUBMODULE(${SUBMODULE_PATH} false false ${FULL_CLONE_FLAG}) + GIT_SUBMODULE(${SUBMODULE_PATH} false false ${NO_DEPTH_FLAG}) ELSEIF(${FORCE_DEINIT}) MESSAGE("-- Resetting ${SUBMODULE_PATH}") EXECUTE_PROCESS( @@ -125,21 +125,15 @@ MACRO(GIT_SUBMODULE SUBMODULE_PATH FORCE_DEINIT FORCE_REMOTE FULL_CLONE) ) MESSAGE("-- Deleting ${CMAKE_SOURCE_DIR}/.git/${SUBMODULE_PATH}") FILE(REMOVE_RECURSE "${CMAKE_SOURCE_DIR}/.git/modules/${SUBMODULE_PATH}") - # Recurse + # Recurse without depth GIT_SUBMODULE(${SUBMODULE_PATH} false false true) ELSE() # Try to use the depth switch - IF(NO_SHALLOW_CLONE OR GIT_VERSION_STRING VERSION_LESS "1.8.4") + IF(NO_SHALLOW_CLONE OR GIT_VERSION_STRING VERSION_LESS "1.8.4" OR NO_DEPTH_FLAG) # Shallow submodules were introduced in 1.8.4 MESSAGE("-- Fetching ${SUBMODULE_PATH}") SET(DEPTH_CMD "") SET(DEPTH_VAL "") - ELSEIF(FULL_CLONE_FLAG) - # Depth doesn't revert easily... It should be "--no-recommend-shallow" - # but it's ignored by nested submodules, use the highest value instead. - MESSAGE("-- Fetching ${SUBMODULE_PATH}") - SET(DEPTH_CMD "--depth") - SET(DEPTH_VAL "2147483647") ELSE() MESSAGE("-- Fetching ${SUBMODULE_PATH} @ --depth ${DEPTH_VALUE}") SET(DEPTH_CMD "--depth") @@ -201,13 +195,7 @@ FOREACH(_submodule ${SUBMODULE_LIST}) BREAK() ELSEIF("${GIT_MESSAGE}" MATCHES "${_phrase}") MESSAGE("-- Retrying ${_submodule} using 'deinit' (attempt ${COUNTED} of ${MAX_ATTEMPTS})...") - IF(COUNTED LESS 2) - SET(FULL_CLONE false) - ELSE() - SET(FULL_CLONE true) - ENDIF() - - GIT_SUBMODULE("${_submodule}" true false ${FULL_CLONE}) + GIT_SUBMODULE("${_submodule}" true false false) BREAK() ENDIF() ENDFOREACH() From 8d908c681ee66636fe99427d5d22760baee0838f Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Thu, 26 Mar 2020 12:52:59 +0900 Subject: [PATCH 40/41] Ensure plugin dependencies are deployed correctly --- cmake/install/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/install/CMakeLists.txt b/cmake/install/CMakeLists.txt index a3a81beebda..e123ae384fe 100644 --- a/cmake/install/CMakeLists.txt +++ b/cmake/install/CMakeLists.txt @@ -31,7 +31,8 @@ IF(LMMS_BUILD_WIN32 OR LMMS_INSTALL_DEPENDENCIES) NAME "plugins" TARGETS ${PLUGINS_BUILT} DESTINATION ${PLUGIN_DEP_DESTINATION} - LIB_DIRS ${LIB_DIRS} "${PLUGIN_DIR}" + LIB_DIRS ${LIB_DIRS} "${PLUGIN_DIR}" "${PLUGIN_DIR}/optional" + SEARCH_PATH "${PLUGIN_DIR}" "${PLUGIN_DIR}/optional" ) ENDIF() From 174630087ef24899dfb52ef2e892c68a7fd7caf2 Mon Sep 17 00:00:00 2001 From: Hyunjin Song Date: Tue, 3 Mar 2020 12:05:04 +0900 Subject: [PATCH 41/41] Use shimmed std::as_const instead of qAsConst --- include/stdshims.h | 22 +++++++++++++++++++++- src/gui/widgets/ControlLayout.cpp | 4 +++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/include/stdshims.h b/include/stdshims.h index 5eee6543cac..c12254e1506 100644 --- a/include/stdshims.h +++ b/include/stdshims.h @@ -5,11 +5,12 @@ #define STDSHIMS_H #include +#include #include #if (__cplusplus >= 201402L || _MSC_VER) #ifndef _MSC_VER -#warning "This file should now be removed! The functions it provides are part of the C++14 standard." +#warning "This part of this file should now be removed! The functions it provides are part of the C++14 standard." #endif using std::make_unique; @@ -30,5 +31,24 @@ std::unique_ptr make_unique(Args&&... args) } #endif +#if (__cplusplus >= 201703L || _MSC_VER >= 1914) +#ifndef _MSC_VER +#warning "This part of this file should now be removed! The functions it provides are part of the C++17 standard." +#endif +using std::as_const; + +#else + +/// Shim for http://en.cppreference.com/w/cpp/utility/as_const +template +constexpr typename std::add_const::type& as_const(T& t) noexcept +{ + return t; +} + +template +void as_const(const T&&) = delete; +#endif + #endif // include guard diff --git a/src/gui/widgets/ControlLayout.cpp b/src/gui/widgets/ControlLayout.cpp index afd4e68e42e..ce2e9e4ef9b 100644 --- a/src/gui/widgets/ControlLayout.cpp +++ b/src/gui/widgets/ControlLayout.cpp @@ -73,6 +73,8 @@ #include "ControlLayout.h" +#include "stdshims.h" + #include #include #include @@ -208,7 +210,7 @@ QSize ControlLayout::minimumSize() const // get maximum height and width for all children. // as Qt will later call heightForWidth, only the width here really matters QSize size; - for (const QLayoutItem *item : qAsConst(m_itemMap)) + for (const QLayoutItem *item : as_const(m_itemMap)) { size = size.expandedTo(item->minimumSize()); }