qtractor: incorporate latest enhancements

Signed-off-by: Andreas Müller <schnitzeltony@gmail.com>
This commit is contained in:
Andreas Müller
2017-11-11 16:46:39 +01:00
parent 306b27fcb9
commit 910ef450cf
5 changed files with 274 additions and 544 deletions

View File

@@ -1,7 +1,7 @@
From b8ef1130bee18e5a28340c21941d67bd14949b2d Mon Sep 17 00:00:00 2001
From a5275b9facecc8a77cb6c47c1c186b8135fa34f3 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20M=C3=BCller?= <schnitzeltony@googlemail.com>
Date: Sat, 4 Nov 2017 20:41:50 +0100
Subject: [PATCH 2/4] Add qtractorPluginListDocument to save/load plugin-lists
Subject: [PATCH 1/3] Add qtractorPluginListDocument to save/load plugin-lists
to XML
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -11,10 +11,6 @@ For MIDI Import dialog it is necessary to save/load plugin-lists. The easiest
way to do is to reuse the code used when saving/loading sessions. To perform
save/load only on plugin-lists an own document class has to be created.
Upstream-Status: Submitted [1]
[1] https://github.com/rncbc/qtractor/pull/94
Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
---
src/qtractorPluginListDocument.cpp | 54 ++++++++++++++++++++++++++++++++++++++
@@ -140,10 +136,10 @@ index 0000000..57464d7
+
+// end of qtractorPluginListDocument.h
diff --git a/src/src.pro b/src/src.pro
index 5e43fa7..92c0bd8 100644
index b4bd0e3..949bded 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -94,6 +94,7 @@ HEADERS += config.h \
@@ -95,6 +95,7 @@ HEADERS += config.h \
qtractorPlugin.h \
qtractorPluginFactory.h \
qtractorPluginCommand.h \
@@ -151,7 +147,7 @@ index 5e43fa7..92c0bd8 100644
qtractorPluginListView.h \
qtractorPropertyCommand.h \
qtractorRingBuffer.h \
@@ -218,6 +219,7 @@ SOURCES += \
@@ -220,6 +221,7 @@ SOURCES += \
qtractorPlugin.cpp \
qtractorPluginFactory.cpp \
qtractorPluginCommand.cpp \

View File

@@ -1,248 +0,0 @@
From dad78145c4c427d44ad63caaa15966e8fe5693bf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20M=C3=BCller?= <schnitzeltony@googlemail.com>
Date: Sat, 4 Nov 2017 11:59:47 +0100
Subject: [PATCH 1/4] Make plugin-lists and MIDI-manager-list thread-safe
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
During debugging (PC) and testing (RaspberryPi) the MIDI import dialog, qtractor
crashed several times with segfaults due to inconsistent list state (the MIDI-
manager case was mentioned in [1]). Since adding plugins to MIDI import the
probabilty of these crashes increases because of performing 'dangerous'
operations multiple times.
To avoid this, lock/unlock guards were added under the following consideration:
Keep the locking time as short as possible to reduce the probability of
blocking audio-engine. For the implemetation qtractorSession::lock got a
parameter 'bStabilize' set true by default. If set to false, no events are
performed to avoid plugin-list-view updates with inconsistent data.
Worth to mention: With this modification no more crashes happend.
[1] https://github.com/rncbc/qtractor/issues/91
Upstream-Status: Submitted [2]
[2] https://github.com/rncbc/qtractor/pull/94
Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
---
src/qtractorPlugin.cpp | 40 +++++++++++++++++++++++++++++++++-------
src/qtractorPluginCommand.cpp | 16 ----------------
src/qtractorSession.cpp | 14 +++++++++++---
src/qtractorSession.h | 2 +-
4 files changed, 45 insertions(+), 27 deletions(-)
diff --git a/src/qtractorPlugin.cpp b/src/qtractorPlugin.cpp
index e547381..651f603 100644
--- a/src/qtractorPlugin.cpp
+++ b/src/qtractorPlugin.cpp
@@ -1620,10 +1620,17 @@ void qtractorPluginList::insertPlugin (
// We'll get prepared before plugging it in...
pPlugin->setChannels(m_iChannels);
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (pSession == NULL)
+ return;
+
+ // Do not perform events while locking - list views are not yet updated.
+ pSession->lock(false);
if (pNextPlugin)
insertBefore(pPlugin, pNextPlugin);
else
append(pPlugin);
+ pSession->unlock();
// Now update each observer list-view...
QListIterator<qtractorPluginListView *> iter(m_views);
@@ -1654,13 +1661,15 @@ void qtractorPluginList::movePlugin (
if (pPluginList == NULL)
return;
- // Remove and insert back again...
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (pSession == NULL)
+ return;
+
+ // Do not perform events while locking - list views are not yet updated.
+ pSession->lock(false);
+ // Remove it -> it is no more processed by worker thread.
pPluginList->unlink(pPlugin);
- if (pNextPlugin) {
- insertBefore(pPlugin, pNextPlugin);
- } else {
- append(pPlugin);
- }
+ pSession->unlock();
// DANGER: Gasp, we might be not the same...
if (pPluginList != this) {
@@ -1713,6 +1722,16 @@ void qtractorPluginList::movePlugin (
pListView->setCurrentItem(pNextItem);
}
+ // Views are updated so perform events during lock.
+ pSession->lock();
+ // Insert back again -> processing continues.
+ if (pNextPlugin) {
+ insertBefore(pPlugin, pNextPlugin);
+ } else {
+ append(pPlugin);
+ }
+ pSession->unlock();
+
// update (both) lists for Auto-plugin-deactivation
autoDeactivatePlugins(m_bAutoDeactivated, true);
if (pPluginList != this)
@@ -1723,8 +1742,15 @@ void qtractorPluginList::movePlugin (
// Remove-guarded plugin method.
void qtractorPluginList::removePlugin ( qtractorPlugin *pPlugin )
{
- // Just unlink the plugin from the list...
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (pSession == NULL)
+ return;
+
+ // Views are not touched here so perform events.
+ pSession->lock();
+ // Remove it -> it is no more processed by worker thread.
unlink(pPlugin);
+ pSession->unlock();
if (pPlugin->isActivated())
updateActivated(false);
diff --git a/src/qtractorPluginCommand.cpp b/src/qtractorPluginCommand.cpp
index 10bd717..c4321ca 100644
--- a/src/qtractorPluginCommand.cpp
+++ b/src/qtractorPluginCommand.cpp
@@ -65,8 +65,6 @@ bool qtractorPluginCommand::addPlugins (void)
if (pSession == NULL)
return false;
-// pSession->lock();
-
// Add all listed plugins, in order...
QListIterator<qtractorPlugin *> iter(m_plugins);
while (iter.hasNext()) {
@@ -78,8 +76,6 @@ bool qtractorPluginCommand::addPlugins (void)
// Avoid the disposal of the plugin reference(s).
setAutoDelete(false);
-// pSession->unlock();
-
return true;
}
@@ -91,8 +87,6 @@ bool qtractorPluginCommand::removePlugins (void)
if (pSession == NULL)
return false;
-// pSession->lock();
-
// Unlink all listed plugins, in order...
QListIterator<qtractorPlugin *> iter(m_plugins);
iter.toBack();
@@ -105,8 +99,6 @@ bool qtractorPluginCommand::removePlugins (void)
// Allow the disposal of the plugin reference(s).
setAutoDelete(true);
-// pSession->unlock();
-
return true;
}
@@ -284,8 +276,6 @@ bool qtractorInsertPluginCommand::redo (void)
if (pPluginList == NULL)
return false;
-// pSession->lock();
-
qtractorPlugin *pNextPlugin = pPlugin->next();
// Insert it...
@@ -297,8 +287,6 @@ bool qtractorInsertPluginCommand::redo (void)
// Whether to allow the disposal of the plugin reference.
setAutoDelete(false);
-// pSession->unlock();
-
return true;
}
@@ -317,8 +305,6 @@ bool qtractorInsertPluginCommand::undo (void)
if (pPluginList == NULL)
return false;
-// pSession->lock();
-
qtractorPlugin *pNextPlugin = pPlugin->next();
// Insert it...
@@ -330,8 +316,6 @@ bool qtractorInsertPluginCommand::undo (void)
// Whether to allow the disposal of the plugin reference.
setAutoDelete(true);
-// pSession->unlock();
-
return true;
}
diff --git a/src/qtractorSession.cpp b/src/qtractorSession.cpp
index bc901d6..19e72b3 100644
--- a/src/qtractorSession.cpp
+++ b/src/qtractorSession.cpp
@@ -1250,13 +1250,17 @@ void qtractorSession::release (void)
}
-void qtractorSession::lock (void)
+void qtractorSession::lock (bool bStabilize)
{
// Wind up as pending lock...
if (ATOMIC_INC(&m_locks) == 1) {
// Get lost for a while...
- while (!acquire())
- stabilize();
+ while (!acquire()) {
+ if (bStabilize)
+ stabilize();
+ else
+ QThread::yieldCurrentThread();
+ }
}
}
@@ -1901,12 +1905,16 @@ void qtractorSession::resetAllMidiControllers ( bool bForceImmediate )
// MIDI manager list accessors.
void qtractorSession::addMidiManager ( qtractorMidiManager *pMidiManager )
{
+ lock();
m_midiManagers.append(pMidiManager);
+ unlock();
}
void qtractorSession::removeMidiManager ( qtractorMidiManager *pMidiManager )
{
+ lock();
m_midiManagers.remove(pMidiManager);
+ unlock();
}
diff --git a/src/qtractorSession.h b/src/qtractorSession.h
index 151096e..821fa5b 100644
--- a/src/qtractorSession.h
+++ b/src/qtractorSession.h
@@ -229,7 +229,7 @@ public:
// Session RT-safe pseudo-locking primitives.
bool acquire();
void release();
- void lock();
+ void lock(bool bStabilize = false);
void unlock();
// Re-entrancy check.
--
2.9.5

View File

@@ -1,7 +1,7 @@
From e509eef8b5653796acb44bdd187db6574ed39da8 Mon Sep 17 00:00:00 2001
From 093a9a2af41222116dc7525dc3050842134d47c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20M=C3=BCller?= <schnitzeltony@googlemail.com>
Date: Sun, 5 Nov 2017 00:58:28 +0100
Subject: [PATCH 3/4] qtractorImportTrackCommand: extend to accept
Subject: [PATCH 2/3] qtractorImportTrackCommand: extend to accept
qtractorEditTrackCommand
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
@@ -17,10 +17,6 @@ are performed.
qtractorImportTrackCommand to avoid useless forward declarations. This makes
the diff a bit human-unreadable.
Upstream-Status: Submitted [1]
[1] https://github.com/rncbc/qtractor/pull/94
Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
---
src/qtractorTrackCommand.cpp | 15 +++++++++----

View File

@@ -1,18 +1,16 @@
From b48b25af8979c40e58c263338446cd419db4016a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20M=C3=BCller?= <schnitzeltony@googlemail.com>
Date: Sun, 5 Nov 2017 01:14:49 +0100
Subject: [PATCH 4/4] Optionally enhance MIDI import
From 19a97a228e1af0adcb2cc565920a14646215d638 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Andreas=20M=C3=BCller?= <schnitzeltony@gmail.com>
Date: Thu, 9 Nov 2017 22:08:14 +0100
Subject: [PATCH 3/3] Add MIDI import options to create ready-to-play sessions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In the 'MIDI' section of settings, the following can be set to get a ready to
play MIDI import:
In the 'MIDI' section of settings, a dialog can be opened to set up the
following:
* Plugins can be set. Each track imported gets the plugins with settings set in
dialog.
* Bank used for instruments and drums can be set. When using plugins using
soundfonts it is useful to set instrument bank to 0 and drum bank to 128.
* Plugins: Each track imported gets the plugins with settings made in dialog.
* MIDI-bank used can be set seperately selected for instruments and drums.
* Names of created tracks can be aligned:
* MIDI filename: This is the same naming scheme as it was before this patch
* Track n: Tracks ar named 'Track n' where 'n' is an incrementing number.
@@ -21,28 +19,25 @@ play MIDI import:
especially on small monitors where large areas of patch section in track
header are usually hidden.
Upstream-Status: Submitted [1]
[1] https://github.com/rncbc/qtractor/pull/94
Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
Signed-off-by: Andreas Müller <schnitzeltony@gmail.com>
---
src/qtractorMainForm.cpp | 14 +-
src/qtractorMidiImportExtender.cpp | 372 ++++++++++++++++++++++++
src/qtractorMidiImportExtender.h | 102 +++++++
src/qtractorMidiImportForm.cpp | 568 +++++++++++++++++++++++++++++++++++++
src/qtractorMidiImportForm.h | 119 ++++++++
src/qtractorMidiImportForm.ui | 396 ++++++++++++++++++++++++++
src/qtractorMidiImportExtender.cpp | 398 ++++++++++++++++++++++++++++
src/qtractorMidiImportExtender.h | 100 +++++++
src/qtractorMidiImportForm.cpp | 519 +++++++++++++++++++++++++++++++++++++
src/qtractorMidiImportForm.h | 110 ++++++++
src/qtractorMidiImportForm.ui | 396 ++++++++++++++++++++++++++++
src/qtractorOptions.cpp | 16 +-
src/qtractorOptions.h | 9 +
src/qtractorOptionsForm.cpp | 35 +++
src/qtractorOptionsForm.h | 5 +
src/qtractorOptionsForm.ui | 21 +-
src/qtractorSession.cpp | 2 +
src/qtractorTracks.cpp | 47 ++-
src/qtractorTrackList.cpp | 8 +-
src/qtractorTracks.cpp | 47 +++-
src/qtractorTracks.h | 4 +-
src/src.pro | 5 +
15 files changed, 1702 insertions(+), 13 deletions(-)
16 files changed, 1674 insertions(+), 15 deletions(-)
create mode 100644 src/qtractorMidiImportExtender.cpp
create mode 100644 src/qtractorMidiImportExtender.h
create mode 100644 src/qtractorMidiImportForm.cpp
@@ -50,10 +45,10 @@ Signed-off-by: Andreas Müller <schnitzeltony@googlemail.com>
create mode 100644 src/qtractorMidiImportForm.ui
diff --git a/src/qtractorMainForm.cpp b/src/qtractorMainForm.cpp
index 0fbb649..d2d5aa6 100644
index d7d16ba..30ed26f 100644
--- a/src/qtractorMainForm.cpp
+++ b/src/qtractorMainForm.cpp
@@ -75,6 +75,8 @@
@@ -76,6 +76,8 @@
#include "qtractorMidiEditorForm.h"
#include "qtractorMidiEditor.h"
@@ -62,7 +57,7 @@ index 0fbb649..d2d5aa6 100644
#include "qtractorTrackCommand.h"
#include "qtractorCurveCommand.h"
@@ -3786,9 +3788,15 @@ void qtractorMainForm::trackImportMidi (void)
@@ -3833,9 +3835,15 @@ void qtractorMainForm::trackImportMidi (void)
if (m_pTracks) {
const unsigned long iClipStart = m_pSession->editHead();
qtractorTrack *pTrack = m_pTracks->currentTrack();
@@ -83,10 +78,10 @@ index 0fbb649..d2d5aa6 100644
diff --git a/src/qtractorMidiImportExtender.cpp b/src/qtractorMidiImportExtender.cpp
new file mode 100644
index 0000000..875f94c
index 0000000..431e9d7
--- /dev/null
+++ b/src/qtractorMidiImportExtender.cpp
@@ -0,0 +1,372 @@
@@ -0,0 +1,398 @@
+// qtractorMidiImportExtender.cpp
+//
+/****************************************************************************
@@ -119,19 +114,28 @@ index 0000000..875f94c
+#include "qtractorTrackCommand.h"
+#include "QDomDocument"
+
+// It is not a good idea to delete plugins within a session. To avoid
+// deletion, the plugins are kept in static m_pPluginList. As soon
+// as an object of qtractorMidiImportExtender is created, a plugin-list
+// is created to. It is either deleted by:
+// * closing session which calls qtractorMidiImportExtender::clearPluginList
+// * on import / first track: After moving plugins to target track, plugin
+// list is empty and can be deleted
+//----------------------------------------------------------------------
+// class qtractorMidiImportExtender -- MIDI import extender class.
+//
+
+//
+// It is not a good idea to delete plugins: At least DSSI plugins supporting
+// run_multiple_synths interface get confused and cause crashes when deleting.
+//
+// To avoid deletion of plugins the plugins are kept in static m_pPluginList
+// which is created as soon as pluginList() is called (typically by settings
+// dialog).
+// At MIDI import process the plugins in plugin list are reused by moving to
+// first track generated to avoid wasting resources.
+//
+
+
+// Pointer to singleton plugin list for display.
+qtractorPluginList *qtractorMidiImportExtender::m_pPluginList = NULL;
+
+
+// Constructor.
+qtractorMidiImportExtender::qtractorMidiImportExtender() :
+ m_pPluginDomDocument(NULL), m_pPluginListDocument(NULL),
+ m_iTrackNumber(0)
+qtractorMidiImportExtender::qtractorMidiImportExtender()
+{
+ // Get global session object
+ qtractorSession *pSession = qtractorSession::getInstance();
@@ -142,57 +146,36 @@ index 0000000..875f94c
+ if (!pOptions)
+ return;
+
+ // Create and fill plugin-lists if when called first time in session
+ if (!m_pPluginList) {
+ m_pPluginList = new qtractorPluginList(0, 0);
+
+ // Restore plugin-list from persistant options.
+ if (!pOptions->sMidiImportPlugins.isEmpty()) {
+ QDomDocument domDocument("qtractorMidiImport");
+ if (domDocument.setContent(pOptions->sMidiImportPlugins)) {
+ qtractorPluginListDocument pluginListDocument(&domDocument, m_pPluginList);
+ // Get root element and check for proper taq name.
+ QDomElement elem = domDocument.documentElement();
+ if (elem.tagName() == "PluginList")
+ m_pPluginList->loadElement(&pluginListDocument, &elem);
+ }
+ }
+ // Output bus gets to be the first available output bus (master).
+ qtractorAudioBus *pAudioBus = NULL;
+ qtractorAudioEngine *pAudioEngine = pSession->audioEngine();
+ for (qtractorBus *pBus = (pAudioEngine->buses()).first();
+ pBus; pBus = pBus->next()) {
+ if (pBus->busMode() & qtractorBus::Output) {
+ pAudioBus = static_cast<qtractorAudioBus *> (pBus);
+ break;
+ }
+ }
+
+ // Plugin-List needs one or more channels - just to allow adding plugins.
+ if (pAudioBus)
+ m_pPluginList->setChannels(pAudioBus->channels(),
+ qtractorPluginList::Midi);
+ else
+ m_pPluginList->setChannels(1, qtractorPluginList::Midi);
+ }
+
+ // Keep a shadow copy of settings.
+ m_tExtendedSettings.sMidiImportInstInst = pOptions->sMidiImportInstInst;
+ m_tExtendedSettings.sMidiImportDrumInst = pOptions->sMidiImportDrumInst;
+ m_tExtendedSettings.iMidiImportInstBank = pOptions->iMidiImportInstBank;
+ m_tExtendedSettings.iMidiImportDrumBank = pOptions->iMidiImportDrumBank;
+ m_tExtendedSettings.eMidiImportTrackNameType = (TrackNameType) pOptions->iMidiImportTrackName;
+ if (!pOptions->sMidiImportPlugins.isEmpty()) {
+ m_extendedSettings.pPluginDomDocument = new QDomDocument("qtractorMidiImport");
+ m_extendedSettings.pPluginDomDocument->setContent(pOptions->sMidiImportPlugins);
+ } else
+ m_extendedSettings.pPluginDomDocument = NULL;
+ m_extendedSettings.sMidiImportInstInst = pOptions->sMidiImportInstInst;
+ m_extendedSettings.sMidiImportDrumInst = pOptions->sMidiImportDrumInst;
+ m_extendedSettings.iMidiImportInstBank = pOptions->iMidiImportInstBank;
+ m_extendedSettings.iMidiImportDrumBank = pOptions->iMidiImportDrumBank;
+ m_extendedSettings.eMidiImportTrackNameType = (TrackNameType) pOptions->iMidiImportTrackName;
+
+ // Get reference of the last command before dialog.
+ m_pLastCommand = NULL;
+ m_pLastUndoCommand = NULL;
+ qtractorCommandList *pCommands = pSession->commands();
+ m_pLastCommand = pCommands->lastCommand();
+ if (pCommands)
+ m_pLastUndoCommand = pCommands->lastCommand();
+
+ // Setup track number here. When setting track name, imported tracks are
+ // already created.
+ m_iTrackNumber = pSession->tracks().count();
+}
+
+
+// Destructor.
+qtractorMidiImportExtender::~qtractorMidiImportExtender()
+{
+ // cleanup document
+ if (m_extendedSettings.pPluginDomDocument)
+ delete m_extendedSettings.pPluginDomDocument;
+}
+
+
@@ -204,60 +187,100 @@ index 0000000..875f94c
+ if (!pOptions)
+ return;
+
+ // Xmlize plugin list and staore in options
+ // Xmlize plugin list and store in options
+ pluginListToDocument();
+ QString strPluginListXML;
+ if (m_pPluginDomDocument)
+ if (m_extendedSettings.pPluginDomDocument)
+ // Store as XML string without whitespaces.
+ strPluginListXML = m_pPluginDomDocument->toString(-1);
+ strPluginListXML = m_extendedSettings.pPluginDomDocument->toString(-1);
+ pOptions->sMidiImportPlugins = strPluginListXML;
+
+ // Store other options
+ pOptions->sMidiImportInstInst = m_tExtendedSettings.sMidiImportInstInst;
+ pOptions->sMidiImportDrumInst = m_tExtendedSettings.sMidiImportDrumInst;
+ pOptions->iMidiImportInstBank = m_tExtendedSettings.iMidiImportInstBank;
+ pOptions->iMidiImportDrumBank = m_tExtendedSettings.iMidiImportDrumBank;
+ pOptions->iMidiImportTrackName = (int)m_tExtendedSettings.eMidiImportTrackNameType;
+ pOptions->sMidiImportInstInst = m_extendedSettings.sMidiImportInstInst;
+ pOptions->sMidiImportDrumInst = m_extendedSettings.sMidiImportDrumInst;
+ pOptions->iMidiImportInstBank = m_extendedSettings.iMidiImportInstBank;
+ pOptions->iMidiImportDrumBank = m_extendedSettings.iMidiImportDrumBank;
+ pOptions->iMidiImportTrackName = (int)m_extendedSettings.eMidiImportTrackNameType;
+}
+
+
+// Undo commands done since creation.
+// Undo commands done since creation (for CANCEL on dialog).
+void qtractorMidiImportExtender::backoutCommandList()
+{
+ // Backout all commands made in this dialog-session.
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (pSession)
+ pSession->commands()->backout(m_pLastCommand);
+ pSession->commands()->backout(m_pLastUndoCommand);
+}
+
+
+// Restore command list to the point of creation.
+// Restore undo command list to the point of creation without performing
+// plugin list actions. Do this to avoid commands added to undo menu (for OK
+// on dialogs).
+void qtractorMidiImportExtender::restoreCommandList()
+{
+ // Avoid inconsistent execution of undo menu entries for actions done
+ // within dialog.
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (pSession) {
+ qtractorCommandList *pCommands = pSession->commands();
+ // Remove all commands without execution - tested: command-list keeps
+ // Remove all commands without execution - tested: command list keeps
+ // them with proper auto-delete so they are cleaned up properly on
+ // session close.
+ for (qtractorCommand *pCurrLastCommand = pCommands->lastCommand();
+ pCurrLastCommand != m_pLastCommand;
+ pCurrLastCommand != m_pLastUndoCommand;
+ pCurrLastCommand = pCommands->lastCommand())
+ pCommands->removeLastCommand();
+ }
+}
+
+
+// Accessor to plugin list.
+// Accessor/creator for plugin list.
+qtractorPluginList *qtractorMidiImportExtender::pluginList()
+{
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (!pSession)
+ return NULL;
+
+ // Create plugin list.
+ if (!m_pPluginList) {
+ // Create plugin list.
+ m_pPluginList = new qtractorPluginList(0, qtractorPluginList::Midi);
+ // Create plugins from document.
+ if (m_extendedSettings.pPluginDomDocument) {
+ qtractorPluginListDocument pluginListDocument(
+ m_extendedSettings.pPluginDomDocument,
+ m_pPluginList);
+ // Get root element and check for proper taq name.
+ QDomElement elem = m_extendedSettings.pPluginDomDocument->documentElement();
+ if (elem.tagName() == "PluginList") {
+ pluginListDocument.loadElement(&elem);
+ }
+ }
+ // Plugin list needs channels set > 0. Otherwise all entries in
+ // plugin selection dialog are disabled. Try same channel count as
+ // master output audio bus. That is default connection for imported
+ // tracks.
+ qtractorAudioBus *pAudioBus = NULL;
+ qtractorAudioEngine *pAudioEngine = pSession->audioEngine();
+ for (qtractorBus *pBus = (pAudioEngine->buses()).first();
+ pBus; pBus = pBus->next()) {
+ if (pBus->busMode() & qtractorBus::Output) {
+ pAudioBus = static_cast<qtractorAudioBus *> (pBus);
+ break;
+ }
+ }
+ if (pAudioBus)
+ m_pPluginList->setChannels(pAudioBus->channels(),
+ qtractorPluginList::Midi);
+ else
+ // Use reasonable fallback channel count.
+ m_pPluginList->setChannels(2, qtractorPluginList::Midi);
+ }
+
+ return m_pPluginList;
+}
+
+
+// Clear singleton plugin-list and delete plugins
+// Clear singleton plugin list and delete plugins
+void qtractorMidiImportExtender::clearPluginList()
+{
+ if (m_pPluginList) {
@@ -266,53 +289,51 @@ index 0000000..875f94c
+ }
+}
+
+// Add plugins to track and return a track-edit-command for setting bank
+
+// Add plugins to track and return a track-edit-command for setting midi-bank.
+qtractorEditTrackCommand *qtractorMidiImportExtender::modifyBareTrackAndGetEditCommand(
+ qtractorTrack *pTrack)
+{
+ // Bail out if something is seriously wrong.
+ // Bail out if something is wrong.
+ if (!pTrack)
+ return NULL;
+ qtractorPluginList *pTargetList = pTrack->pluginList();
+ if (!pTargetList)
+ return NULL;
+
+ // Add plugins
+ // Add plugins.
+
+ // Take plugins for first track from plugin-list.
+ // Take plugins for first track from plugin list.
+ if (m_pPluginList) {
+ // First ensure we have a valid document for further tracks
+ pluginListToDocument();
+
+ // Move plugins to target.
+ while (m_pPluginList->count())
+ pTargetList->movePlugin(m_pPluginList->first(), NULL);
+
+ // Remove list: It is empty and no more required
+ // Plugin list is empty now so it can be removed.
+ clearPluginList();
+ }
+
+ // all further are cloned by our document - if there is one.
+ else if (m_pPluginListDocument) {
+ // All further are cloned by our document - if there is one.
+ else if (m_extendedSettings.pPluginDomDocument) {
+ // Get root element and check for proper taq name.
+ QDomElement elem = m_pPluginDomDocument->documentElement();
+ if (elem.tagName() == "PluginList")
+ pTargetList->loadElement(m_pPluginListDocument, &elem);
+ QDomElement elem =
+ m_extendedSettings.pPluginDomDocument->documentElement();
+ if (elem.tagName() == "PluginList") {
+ qtractorPluginListDocument pluginListDocument(
+ m_extendedSettings.pPluginDomDocument, pTargetList);
+ pluginListDocument.loadElement(&elem);
+ }
+ }
+
+
+ // Set bank.
+ // Set MIDI bank.
+ bool bTrackChanged = false;
+ bool bIsDrumTrack = pTrack->midiChannel() == 9;
+ int iBankNew = bIsDrumTrack ?
+ m_tExtendedSettings.iMidiImportDrumBank :
+ m_tExtendedSettings.iMidiImportInstBank;
+
+ bool bTrackChanged = false;
+ m_extendedSettings.iMidiImportDrumBank :
+ m_extendedSettings.iMidiImportInstBank;
+ qtractorTrack::Properties &properties = pTrack->properties();
+ if (iBankNew >= 0) {
+ properties.midiBank = iBankNew;
+ // By default midiBankSelMethod is -1. If we don't set it here bank
+ // change is not sent to instrument.
+ // By default midiBankSelMethod is -1. If not set it here, bank change
+ // is not send to instrument.
+ properties.midiBankSelMethod = 0;
+ bTrackChanged = true;
+ // Special case for drum-tracks: Some MIDI files out in the wild do not
@@ -329,15 +350,17 @@ index 0000000..875f94c
+}
+
+
+// Set instrument and track-name. Track must be 'complete' (have an output bus).
+bool qtractorMidiImportExtender::modifyFinishedTrack(qtractorTrack *pTrack)
+{
+ // Bail out if something seriously is wrong.
+ // Bail out if something is wrong.
+ if (!pTrack)
+ return false;
+ qtractorSession *pSession = qtractorSession::getInstance();
+ if (!pSession)
+ return false;
+
+ // Some helpers...
+ bool bTrackChanged = false;
+ int iMidiChannel = pTrack->midiChannel();
+ bool bIsDrumTrack = pTrack->midiChannel() == 9;
@@ -352,8 +375,8 @@ index 0000000..875f94c
+ if (patch.prog >= 0) {
+ // Set instrument.
+ QString strInstrumentNew = bIsDrumTrack ?
+ m_tExtendedSettings.sMidiImportDrumInst :
+ m_tExtendedSettings.sMidiImportInstInst;
+ m_extendedSettings.sMidiImportDrumInst :
+ m_extendedSettings.sMidiImportInstInst;
+
+ // Update patch if necessary.
+ if (!strInstrumentNew.isEmpty()) {
@@ -370,50 +393,54 @@ index 0000000..875f94c
+
+ // Set track name.
+ QString sTrackName;
+ switch (m_tExtendedSettings.eMidiImportTrackNameType) {
+ case Midifile:
+ // Default: no modification
+ break;
+ case Track: {
+ // Set names only for tracks making music after import
+ if (pTrack->midiBank() < 0 || pTrack->midiProg() < 0)
+ // Set names only for tracks making noise after import. This indicates
+ // immediately that such track is special or broken or...
+ if (pTrack->midiBank() >= 0 && pTrack->midiProg() >= 0) {
+ // Set track name based upon type set up.
+ switch (m_extendedSettings.eMidiImportTrackNameType) {
+ case Midifile:
+ // MIDI filename is default: no modification.
+ break;
+ sTrackName = pSession->uniqueTrackName(
+ QString("Track %1").arg(++m_iTrackNumber));
+ break;
+ }
+ case PatchName:
+ // Instrument track.
+ if (!bIsDrumTrack) {
+ // Other bail out checks...
+ if (pTrack->midiBank() < 0 || pTrack->midiProg() < 0)
+ break;
+ qtractorPluginList *pPluginList = pTrack->pluginList();
+ if (!pPluginList)
+ break;
+ qtractorMidiManager *pMidiManager = pPluginList->midiManager();
+ if (!pMidiManager)
+ break;
+ case Track: {
+ sTrackName = pSession->uniqueTrackName(
+ QString("Track %1").arg(++m_iTrackNumber));
+ break;
+ }
+ case PatchName:
+ // Instrument track.
+ if (!bIsDrumTrack) {
+ // Collect what's necessary to get patch name.
+ qtractorPluginList *pPluginList = pTrack->pluginList();
+ if (!pPluginList)
+ break;
+
+ const qtractorMidiManager::Instruments& list
+ = pMidiManager->instruments();
+ QString sInstrumentName = m_tExtendedSettings.sMidiImportInstInst;
+ if (!list.contains(sInstrumentName))
+ break;
+ qtractorMidiManager *pMidiManager = pPluginList->midiManager();
+ if (!pMidiManager)
+ break;
+
+ // Banks reference...
+ const qtractorMidiManager::Banks& banks
+ = list[sInstrumentName];
+ if (banks.contains(pTrack->midiBank())) {
+ const qtractorMidiManager::Instruments& list
+ = pMidiManager->instruments();
+ QString sInstrumentName = m_extendedSettings.sMidiImportInstInst;
+ if (!list.contains(sInstrumentName))
+ break;
+
+ const qtractorMidiManager::Banks& banks
+ = list[sInstrumentName];
+ if (!banks.contains(pTrack->midiBank()))
+ break;
+
+ // A patch name was found!
+ const qtractorMidiManager::Progs& progs = banks[pTrack->midiBank()].progs;
+ sTrackName = progs[pTrack->midiProg()];
+ }
+
+ // Drum track's name is fixed - patch names are not really useful at drums.
+ else
+ sTrackName = QObject::tr("Drums");
+ break;
+ }
+ // Drum track.
+ else
+ sTrackName = QObject::tr("Drums");
+ break;
+ }
+ // Let name overrides cause effect.
+ if (!sTrackName.isEmpty()) {
+ pSession->releaseTrackName(pTrack);
+ pTrack->setTrackName(sTrackName);
@@ -428,43 +455,37 @@ index 0000000..875f94c
+// Accessor to exteneded settings.
+qtractorMidiImportExtender::exportExtensionsData *qtractorMidiImportExtender::exportExtensions()
+{
+ return &m_tExtendedSettings;
+ return &m_extendedSettings;
+}
+
+// Xmlize plugin List
+
+// Xmlize plugin list.
+void qtractorMidiImportExtender::pluginListToDocument()
+{
+ // remove old plugin-list settings
+ if (m_pPluginDomDocument) {
+ delete m_pPluginDomDocument;
+ m_pPluginDomDocument = NULL;
+ }
+ if (m_pPluginListDocument) {
+ delete m_pPluginListDocument;
+ m_pPluginListDocument = NULL;
+ // Remove old plugin list document.
+ if (m_extendedSettings.pPluginDomDocument) {
+ delete m_extendedSettings.pPluginDomDocument;
+ m_extendedSettings.pPluginDomDocument = NULL;
+ }
+
+ // Xmlize plugin-list for options and cloning.
+ if (m_pPluginList->count()) {
+ m_pPluginDomDocument = new QDomDocument("qtractorMidiImport");
+ m_pPluginListDocument = new qtractorPluginListDocument(m_pPluginDomDocument, m_pPluginList);
+
+ // Save plugin settings to document.
+ QDomElement elem = m_pPluginDomDocument->createElement("PluginList");
+ m_pPluginList->saveElement(m_pPluginListDocument, &elem);
+ m_pPluginDomDocument->appendChild(elem);
+ if (m_pPluginList && m_pPluginList->count()) {
+ // Save plugin settings to new document.
+ m_extendedSettings.pPluginDomDocument = new QDomDocument("qtractorMidiImport");
+ qtractorPluginListDocument pluginListDocument(m_extendedSettings.pPluginDomDocument, m_pPluginList);
+ QDomElement elem = m_extendedSettings.pPluginDomDocument->createElement("PluginList");
+ m_pPluginList->saveElement(&pluginListDocument, &elem);
+ m_extendedSettings.pPluginDomDocument->appendChild(elem);
+ }
+}
+
+
+
+// end of qtractorMidiImportExtender.cpp
diff --git a/src/qtractorMidiImportExtender.h b/src/qtractorMidiImportExtender.h
new file mode 100644
index 0000000..e5a1c87
index 0000000..b507602
--- /dev/null
+++ b/src/qtractorMidiImportExtender.h
@@ -0,0 +1,102 @@
@@ -0,0 +1,100 @@
+// qtractorMidiImportExtender.h
+//
+/****************************************************************************
@@ -510,14 +531,14 @@ index 0000000..e5a1c87
+
+ // Save all settings to global options.
+ void saveSettings();
+ // Undo commands done since creation.
+ // Undo plugin list commands done since creation.
+ void backoutCommandList();
+ // Restore command list to the point of creation.
+ // Restore plugin list command list to the point of creation.
+ void restoreCommandList();
+
+ // Accessor to plugin list.
+ // Accessor/creator for plugin list.
+ qtractorPluginList *pluginList();
+ // Clear singleton plugin-list.
+ // Clear singleton plugin list - do only call on session close!!!
+ static void clearPluginList();
+
+ // Methods used during import.
@@ -527,8 +548,10 @@ index 0000000..e5a1c87
+ // Track name set types.
+ typedef enum { Midifile, Track, PatchName } TrackNameType;
+
+ // All extended settings except plugin list
+ // Declare all extended settings for MIDI import.
+ typedef struct{
+ // Plugin list.
+ QDomDocument *pPluginDomDocument;
+ // Instruments to set.
+ QString sMidiImportInstInst;
+ QString sMidiImportDrumInst;
@@ -547,21 +570,17 @@ index 0000000..e5a1c87
+ // XMLize plugin List
+ void pluginListToDocument();
+
+ // pointer to singleton plugin-list
+ // Pointer to singleton plugin list for display.
+ static qtractorPluginList *m_pPluginList;
+
+ // Plugin list settings keeper.
+ QDomDocument *m_pPluginDomDocument;
+ qtractorPluginListDocument *m_pPluginListDocument;
+
+ // Counter for 'Track n' name-type
+ int m_iTrackNumber;
+
+ // All settings except plugin list.
+ exportExtensionsData m_tExtendedSettings;
+ // Settings member.
+ exportExtensionsData m_extendedSettings;
+
+ // Keep last command for backout / restore.
+ qtractorCommand *m_pLastCommand;
+ qtractorCommand *m_pLastUndoCommand;
+
+ // Track number for 'Track n' naming type.
+ int m_iTrackNumber;
+};
+
+#endif // __qtractorMidiImportExtender_h
@@ -569,10 +588,10 @@ index 0000000..e5a1c87
+// end of qtractorMidiImportExtender.h
diff --git a/src/qtractorMidiImportForm.cpp b/src/qtractorMidiImportForm.cpp
new file mode 100644
index 0000000..39ab05c
index 0000000..30a6e86
--- /dev/null
+++ b/src/qtractorMidiImportForm.cpp
@@ -0,0 +1,568 @@
@@ -0,0 +1,519 @@
+// qtractorMidiListView.cpp
+//
+/****************************************************************************
@@ -605,35 +624,6 @@ index 0000000..39ab05c
+#include "qtractorInstrument.h"
+#include "QPushButton"
+
+//----------------------------------------------------------------------------
+// qtractorMidiImportForm::MidiProgramObserver -- Local dedicated observer.
+
+class qtractorMidiImportForm::MidiProgramObserver : public qtractorObserver
+{
+public:
+
+ // Constructor.
+ MidiProgramObserver(qtractorMidiImportForm *pMidiImportForm, qtractorSubject *pSubject)
+ : qtractorObserver(pSubject), m_pMidiImportForm(pMidiImportForm) {}
+
+protected:
+
+ // Update feedback.
+ void update(bool bUpdate)
+ {
+ if (bUpdate) {
+ const int iValue = int(value());
+ const int iBank = (iValue >> 7) & 0x3fff;
+ m_pMidiImportForm->setMidiProgram(iBank);
+ }
+ }
+
+private:
+
+ // Members.
+ qtractorMidiImportForm *m_pMidiImportForm;
+};
+
+
+//----------------------------------------------------------------------
+// class qtractorMidiImportForm -- UI wrapper form.
@@ -644,8 +634,7 @@ index 0000000..39ab05c
+qtractorMidiImportForm::qtractorMidiImportForm(qtractorMidiImportExtender *pMidiImportExtender,
+ QWidget *pParent, Qt::WindowFlags wflags )
+ : QDialog(pParent, wflags),
+ m_pMidiImportExtender(pMidiImportExtender),
+ m_pMidiProgramObserver(NULL), m_iDirtySetup(0)
+ m_pMidiImportExtender(pMidiImportExtender), m_iDirtySetup(0)
+{
+
+ // Get global session object.
@@ -653,7 +642,7 @@ index 0000000..39ab05c
+ if (!pSession)
+ return;
+
+ // Get plugin-list to work with.
+ // Get plugin list to display.
+ qtractorPluginList *pPluginList = m_pMidiImportExtender->pluginList();
+ if (!pPluginList)
+ return;
@@ -673,12 +662,6 @@ index 0000000..39ab05c
+ m_ui.PluginListView->setPluginList(pPluginList);
+ m_ui.PluginListView->refresh();
+
+ // Setup Observer for the instrument bank combobox.
+ if ( pPluginList->midiProgramSubject()) {
+ m_pMidiProgramObserver = new MidiProgramObserver(this,
+ pPluginList->midiProgramSubject());
+ }
+
+ // Fill Instrument / bank comboboxes.
+ updateInstruments();
+
@@ -762,9 +745,6 @@ index 0000000..39ab05c
+// Destructor.
+qtractorMidiImportForm::~qtractorMidiImportForm()
+{
+ // Do final cleanup
+ delete m_pMidiProgramObserver;
+
+}
+
+
@@ -857,7 +837,7 @@ index 0000000..39ab05c
+}
+
+
+// Plugin-list add plugin.
+// Plugin list: add plugin.
+void qtractorMidiImportForm::addPlugin()
+{
+ m_ui.PluginListView->addPlugin();
@@ -865,7 +845,7 @@ index 0000000..39ab05c
+}
+
+
+// Plugin-list remove plugin.
+// Plugin list: remove plugin.
+void qtractorMidiImportForm::removePlugin()
+{
+ m_ui.PluginListView->removePlugin();
@@ -873,7 +853,7 @@ index 0000000..39ab05c
+}
+
+
+// Plugin-list move plugin up.
+// Plugin list: move plugin up.
+void qtractorMidiImportForm::moveUpPlugin()
+{
+ m_ui.PluginListView->moveUpPlugin();
@@ -881,7 +861,7 @@ index 0000000..39ab05c
+}
+
+
+// Plugin-list move plugin down.
+// Plugin list: move plugin down.
+void qtractorMidiImportForm::moveDownPlugin()
+{
+ m_ui.PluginListView->moveDownPlugin();
@@ -1125,28 +1105,18 @@ index 0000000..39ab05c
+ pPlugin->closeForm();
+ }
+
+ // Unlink plugin-list from view.
+ // Unlink plugin list from view.
+ m_ui.PluginListView->setPluginList(NULL);
+}
+
+
+// MIDI bank/program settlers.
+void qtractorMidiImportForm::setMidiProgram ( int iBank )
+{
+ QString sInstrumentName;
+ if (m_ui.InstInstComboBox->currentIndex() > 0)
+ sInstrumentName = m_ui.InstInstComboBox->currentText();
+ updateBanks(sInstrumentName, iBank, Instruments);
+}
+
+
+// end of qtractorMidiImportForm.cpp
diff --git a/src/qtractorMidiImportForm.h b/src/qtractorMidiImportForm.h
new file mode 100644
index 0000000..e36ac79
index 0000000..fde1d32
--- /dev/null
+++ b/src/qtractorMidiImportForm.h
@@ -0,0 +1,119 @@
@@ -0,0 +1,110 @@
+// qtractorMidiImportForm.h
+//
+/****************************************************************************
@@ -1193,9 +1163,6 @@ index 0000000..e36ac79
+ // Destructor.
+ virtual ~qtractorMidiImportForm();
+
+ // MIDI observer callback
+ void setMidiProgram(int iBank);
+
+protected slots:
+
+ void accept();
@@ -1245,12 +1212,6 @@ index 0000000..e36ac79
+ // Keep last command for backout / restore.
+ qtractorCommand *m_pLastCommand;
+
+ // MIDI bank/program observer.
+ class MidiProgramObserver;
+
+ // Observer to catch instument bank change
+ MidiProgramObserver *m_pMidiProgramObserver;
+
+ // Button group around name-type radios
+ QButtonGroup* m_groupNameRadios;
+
@@ -1730,7 +1691,7 @@ index ca8aad0..1822b63 100644
int iMetroChannel;
int iMetroBarNote;
diff --git a/src/qtractorOptionsForm.cpp b/src/qtractorOptionsForm.cpp
index 99072a1..f33dcb6 100644
index f15a3a7..39b5f7e 100644
--- a/src/qtractorOptionsForm.cpp
+++ b/src/qtractorOptionsForm.cpp
@@ -36,6 +36,8 @@
@@ -1784,7 +1745,7 @@ index 99072a1..f33dcb6 100644
// Save/commit to disk.
m_pOptions->saveOptions();
+ // Remove plugin-list commands from undo-menu.
+ // Remove plugin list commands from undo menu.
+ if (m_pMidiImportExtender)
+ m_pMidiImportExtender->restoreCommandList();
+
@@ -1796,7 +1757,7 @@ index 99072a1..f33dcb6 100644
return;
case QMessageBox::Discard:
+ // In case Midi-Import dialog was closed with OK but changes
+ // shall be discarded, the plugin-list changes must be discarded
+ // shall be discarded, the plugin list's changes must be discarded
+ // too.
+ if (m_pMidiImportExtender)
+ m_pMidiImportExtender->backoutCommandList();
@@ -1894,7 +1855,7 @@ index ab60726..ff62036 100644
<widget class="QLabel" name="MidiCaptureQuantizeTextLabel">
<property name="font">
diff --git a/src/qtractorSession.cpp b/src/qtractorSession.cpp
index 19e72b3..f4415b2 100644
index c080215..9d71fc5 100644
--- a/src/qtractorSession.cpp
+++ b/src/qtractorSession.cpp
@@ -33,6 +33,7 @@
@@ -1913,8 +1874,34 @@ index 19e72b3..f4415b2 100644
m_iSessionStart = 0;
m_iSessionEnd = 0;
diff --git a/src/qtractorTrackList.cpp b/src/qtractorTrackList.cpp
index 0b710eb..7a99060 100644
--- a/src/qtractorTrackList.cpp
+++ b/src/qtractorTrackList.cpp
@@ -46,6 +46,7 @@
#include "qtractorMidiMonitor.h"
#include "qtractorAudioMeter.h"
#include "qtractorMidiMeter.h"
+#include "qtractorMidiImportExtender.h"
#include "qtractorOptions.h"
@@ -1596,8 +1597,11 @@ void qtractorTrackList::dropEvent ( QDropEvent *pDropEvent )
const unsigned long iClipStart = (pSession ? pSession->editHead() : 0);
qtractorTrack *pAfterTrack = currentTrack();
- if (!midi_files.isEmpty())
- m_pTracks->addMidiTracks(midi_files, iClipStart, pAfterTrack);
+ if (!midi_files.isEmpty()) {
+ qtractorMidiImportExtender midiImportExtenter;
+ m_pTracks->addMidiTracks(
+ midi_files, iClipStart, pAfterTrack, &midiImportExtenter);
+ }
if (!audio_files.isEmpty())
m_pTracks->addAudioTracks(audio_files, iClipStart, pAfterTrack);
diff --git a/src/qtractorTracks.cpp b/src/qtractorTracks.cpp
index 2d2ff6a..86fec14 100644
index 9b9c4c4..06405ea 100644
--- a/src/qtractorTracks.cpp
+++ b/src/qtractorTracks.cpp
@@ -61,9 +61,12 @@
@@ -1971,7 +1958,7 @@ index 2d2ff6a..86fec14 100644
- ++iUpdate;
+ // Enhanced dialog: do modifications on bare track
+ if (pMidiImportExtender)
+ pImportTrackCommand->addTrackEditCommand(
+ pImportTrackCommand->addTrackEditCommand(
+ pMidiImportExtender->modifyBareTrackAndGetEditCommand(pTrack));
// Don't forget to add this one to local repository.
if (pMainForm)
@@ -1996,7 +1983,7 @@ index 2d2ff6a..86fec14 100644
// Put it in the form of an undoable command...
bResult = pSession->execute(pImportTrackCommand);
+ // Tracks are complete now: instrument and track-name (based on
+ // program-name are depending on instrument) can be set.
+ // patch name are depending on instrument) can be set.
+ if (bResult && pMidiImportExtender) {
+ bool bModified = false;
+ QListIterator<qtractorTrack *> iter(addedTracks);
@@ -2049,19 +2036,19 @@ index 2d9fa48..dbe60de 100644
unsigned long iClipStart, qtractorTrack *pAfterTrack = NULL);
diff --git a/src/src.pro b/src/src.pro
index 92c0bd8..e87382f 100644
index 949bded..3f9a394 100644
--- a/src/src.pro
+++ b/src/src.pro
@@ -45,6 +45,8 @@ HEADERS += config.h \
qtractorFileList.h \
@@ -46,6 +46,8 @@ HEADERS += config.h \
qtractorFileListView.h \
qtractorFiles.h \
qtractorFileSystem.h \
+ qtractorMidiImportExtender.h \
+ qtractorMidiImportForm.h \
qtractorInsertPlugin.h \
qtractorInstrument.h \
qtractorInstrumentMenu.h \
@@ -202,6 +204,8 @@ SOURCES += \
@@ -204,6 +206,8 @@ SOURCES += \
qtractorMidiEventList.cpp \
qtractorMidiFile.cpp \
qtractorMidiFileTempo.cpp \
@@ -2070,7 +2057,7 @@ index 92c0bd8..e87382f 100644
qtractorMidiListView.cpp \
qtractorMidiManager.cpp \
qtractorMidiMeter.cpp \
@@ -276,6 +280,7 @@ FORMS += \
@@ -278,6 +282,7 @@ FORMS += \
qtractorMidiControlForm.ui \
qtractorMidiControlObserverForm.ui \
qtractorMidiEditorForm.ui \

View File

@@ -23,12 +23,11 @@ SRC_URI = " \
file://0002-do-nor-try-run-for-float-sse-detection.patch \
file://0003-do-nor-try-run-for-suil-libs-detection.patch \
file://0004-Add-ARM-NEON-acceleration-for-time-stretch-not-yet-t.patch \
file://0005-Make-plugin-lists-and-MIDI-manager-list-thread-safe.patch \
file://0006-Add-qtractorPluginListDocument-to-save-load-plugin-l.patch \
file://0007-qtractorImportTrackCommand-extend-to-accept-qtractor.patch \
file://0008-Optionally-enhance-MIDI-import.patch \
file://0005-Add-qtractorPluginListDocument-to-save-load-plugin-l.patch \
file://0006-qtractorImportTrackCommand-extend-to-accept-qtractor.patch \
file://0007-Add-MIDI-import-options-to-create-ready-to-play-sess.patch \
"
SRCREV = "1152ce6c8e64c76e5fadff59ca9e84aa6a647a9a"
SRCREV = "3de003e171a605e7fb4dab761f3943727d8cad05"
PV = "0.8.4+git${SRCPV}"
S = "${WORKDIR}/git"