diff --git a/sdrbase/mainwindow.cpp b/sdrbase/mainwindow.cpp
index 482c99740..a89d506c9 100644
--- a/sdrbase/mainwindow.cpp
+++ b/sdrbase/mainwindow.cpp
@@ -1,1051 +1,1066 @@
-///////////////////////////////////////////////////////////////////////////////////
-// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
-// written by Christian Daniel                                                   //
-//                                                                               //
-// 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 as version 3 of the License, or                  //
-//                                                                               //
-// 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 V3 for more details.                               //
-//                                                                               //
-// You should have received a copy of the GNU General Public License             //
-// along with this program. If not, see .          //
-///////////////////////////////////////////////////////////////////////////////////
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include "mainwindow.h"
-#include "ui_mainwindow.h"
-#include "device/devicesourceapi.h"
-#include "device/devicesinkapi.h"
-#include "audio/audiodeviceinfo.h"
-#include "gui/indicator.h"
-#include "gui/presetitem.h"
-#include "gui/addpresetdialog.h"
-#include "gui/pluginsdialog.h"
-#include "gui/aboutdialog.h"
-#include "gui/rollupwidget.h"
-#include "gui/channelwindow.h"
-#include "gui/audiodialog.h"
-#include "gui/samplingdevicecontrol.h"
-#include "gui/mypositiondialog.h"
-#include "dsp/dspengine.h"
-#include "dsp/spectrumvis.h"
-#include "dsp/dspcommands.h"
-#include "plugin/plugingui.h"
-#include "plugin/pluginapi.h"
-#include "plugin/plugingui.h"
-
-#include "gui/glspectrum.h"
-#include "gui/glspectrumgui.h"
-
-#include 
-#include 
-
-MainWindow::MainWindow(QWidget* parent) :
-	QMainWindow(parent),
-	ui(new Ui::MainWindow),
-	m_masterTabIndex(0),
-	m_settings(),
-	m_dspEngine(DSPEngine::instance()),
-	m_lastEngineState((DSPDeviceSourceEngine::State)-1),
-	m_inputGUI(0),
-	m_sampleRate(0),
-	m_centerFrequency(0),
-	m_sampleFileName(std::string("./test.sdriq"))
-{
-	qDebug() << "MainWindow::MainWindow: start";
-
-	m_settings.setAudioDeviceInfo(&m_audioDeviceInfo);
-
-	ui->setupUi(this);
-	createStatusBar();
-
-	setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
-	setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
-	setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
-	setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
-
-	// work around broken Qt dock widget ordering
-    removeDockWidget(ui->inputViewDock);
-	removeDockWidget(ui->inputSelectDock);
-	removeDockWidget(ui->spectraDisplayDock);
-	removeDockWidget(ui->presetDock);
-	removeDockWidget(ui->channelDock);
-	addDockWidget(Qt::LeftDockWidgetArea, ui->inputSelectDock);
-    addDockWidget(Qt::LeftDockWidgetArea, ui->inputViewDock);
-	addDockWidget(Qt::LeftDockWidgetArea, ui->spectraDisplayDock);
-	addDockWidget(Qt::LeftDockWidgetArea, ui->presetDock);
-	addDockWidget(Qt::RightDockWidgetArea, ui->channelDock);
-
-	ui->inputViewDock->show();
-    ui->inputSelectDock->show();
-	ui->spectraDisplayDock->show();
-	ui->presetDock->show();
-	ui->channelDock->show();
-
-    ui->menu_Window->addAction(ui->inputViewDock->toggleViewAction());
-	ui->menu_Window->addAction(ui->inputSelectDock->toggleViewAction());
-	ui->menu_Window->addAction(ui->spectraDisplayDock->toggleViewAction());
-	ui->menu_Window->addAction(ui->presetDock->toggleViewAction());
-	ui->menu_Window->addAction(ui->channelDock->toggleViewAction());
-
-    ui->tabInputsView->setStyleSheet("QWidget { background: rgb(50,50,50); } "
-            "QToolButton::checked { background: rgb(128,70,0); } "
-            "QComboBox::item:selected { color: rgb(255,140,0); } "
-            "QTabWidget::pane { border: 1px solid #C06900; } "
-            "QTabBar::tab:selected { background: rgb(128,70,0); }");
-    ui->tabInputsSelect->setStyleSheet("QWidget { background: rgb(50,50,50); } "
-            "QToolButton::checked { background: rgb(128,70,0); } "
-            "QComboBox::item:selected { color: rgb(255,140,0); } "
-            "QTabWidget::pane { border: 1px solid #808080; } "
-            "QTabBar::tab:selected { background: rgb(100,100,100); }");
-
-    m_pluginManager = new PluginManager(this);
-    m_pluginManager->loadPlugins();
-
-	connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()), Qt::QueuedConnection);
-
-	connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
-	m_statusTimer.start(1000);
-
-	m_masterTimer.start(50);
-
-    qDebug() << "MainWindow::MainWindow: add the first device...";
-
-    addSourceDevice(); // add the first device
-
-    qDebug() << "MainWindow::MainWindow: load settings...";
-
-	loadSettings();
-
-	qDebug() << "MainWindow::MainWindow: select SampleSource from settings...";
-
-	int sampleSourceIndex = m_settings.getSourceIndex();
-	sampleSourceIndex = m_pluginManager->selectSampleSourceByIndex(sampleSourceIndex, m_deviceUIs.back()->m_deviceSourceAPI);
-
-	if (sampleSourceIndex < 0)
-	{
-	    qCritical("MainWindow::MainWindow: no sample source. Exit");
-	    exit(0);
-	}
-
-    bool sampleSourceSignalsBlocked = m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(true);
-    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->setCurrentIndex(sampleSourceIndex);
-    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(sampleSourceSignalsBlocked);
-
-	qDebug() << "MainWindow::MainWindow: load current preset settings...";
-
-	loadPresetSettings(m_settings.getWorkingPreset(), 0);
-
-	qDebug() << "MainWindow::MainWindow: apply settings...";
-
-	applySettings();
-
-	qDebug() << "MainWindow::MainWindow: update preset controls...";
-
-	updatePresetControls();
-
-	connect(ui->tabInputsView, SIGNAL(currentChanged(int)), this, SLOT(tabInputViewIndexChanged()));
-
-    qDebug() << "MainWindow::MainWindow: end";
-}
-
-MainWindow::~MainWindow()
-{
-    delete m_pluginManager;
-	delete m_dateTimeWidget;
-	delete m_showSystemWidget;
-
-	delete ui;
-}
-
-void MainWindow::addSourceDevice()
-{
-    DSPDeviceSourceEngine *dspDeviceSourceEngine = m_dspEngine->addDeviceSourceEngine();
-    dspDeviceSourceEngine->start();
-
-    uint dspDeviceSourceEngineUID =  dspDeviceSourceEngine->getUID();
-    char uidCStr[16];
-    sprintf(uidCStr, "UID:%d", dspDeviceSourceEngineUID);
-
-    m_deviceUIs.push_back(new DeviceUISet(m_masterTimer));
-    m_deviceUIs.back()->m_deviceSourceEngine = dspDeviceSourceEngine;
-
-    int deviceTabIndex = m_deviceUIs.size()-1;
-    char tabNameCStr[16];
-    sprintf(tabNameCStr, "R%d", deviceTabIndex);
-
-    DeviceSourceAPI *deviceSourceAPI = new DeviceSourceAPI(this, deviceTabIndex, dspDeviceSourceEngine, m_deviceUIs.back()->m_spectrum, m_deviceUIs.back()->m_channelWindow);
-
-    m_deviceUIs.back()->m_deviceSourceAPI = deviceSourceAPI;
-    m_deviceUIs.back()->m_samplingDeviceControl->setDeviceAPI(deviceSourceAPI);
-    m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
-    m_pluginManager->populateRxChannelComboBox(m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector());
-
-    connect(m_deviceUIs.back()->m_samplingDeviceControl->getAddChannelButton(), SIGNAL(clicked(bool)), this, SLOT(on_channel_addClicked(bool)));
-
-    dspDeviceSourceEngine->addSink(m_deviceUIs.back()->m_spectrumVis);
-    ui->tabSpectra->addTab(m_deviceUIs.back()->m_spectrum, tabNameCStr);
-    ui->tabSpectraGUI->addTab(m_deviceUIs.back()->m_spectrumGUI, tabNameCStr);
-    ui->tabChannels->addTab(m_deviceUIs.back()->m_channelWindow, tabNameCStr);
-
-    bool sampleSourceSignalsBlocked = m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(true);
-    m_pluginManager->duplicateLocalSampleSourceDevices(dspDeviceSourceEngineUID);
-    m_pluginManager->fillSampleSourceSelector(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector(), dspDeviceSourceEngineUID);
-
-    connect(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelectionConfirm(), SIGNAL(clicked(bool)), this, SLOT(on_sampleSource_confirmClicked(bool)));
-
-    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(sampleSourceSignalsBlocked);
-    ui->tabInputsSelect->addTab(m_deviceUIs.back()->m_samplingDeviceControl, tabNameCStr);
-    ui->tabInputsSelect->setTabToolTip(deviceTabIndex, QString(uidCStr));
-
-    int sampleSourceIndex = m_pluginManager->selectSampleSourceBySerialOrSequence("sdrangel.samplesource.filesource", "0", 0, m_deviceUIs.back()->m_deviceSourceAPI);
-}
-
-void MainWindow::addSinkDevice()
-{
-    DSPDeviceSinkEngine *dspDeviceSinkEngine = m_dspEngine->addDeviceSinkEngine();
-    dspDeviceSinkEngine->start();
-
-    uint dspDeviceSinkEngineUID =  dspDeviceSinkEngine->getUID();
-    char uidCStr[16];
-    sprintf(uidCStr, "UID:%d", dspDeviceSinkEngineUID);
-
-    m_deviceUIs.push_back(new DeviceUISet(m_masterTimer));
-    m_deviceUIs.back()->m_deviceSourceEngine = 0;
-    m_deviceUIs.back()->m_deviceSinkEngine = dspDeviceSinkEngine;
-
-    int deviceTabIndex = m_deviceUIs.size()-1;
-    char tabNameCStr[16];
-    sprintf(tabNameCStr, "T%d", deviceTabIndex);
-
-    DeviceSinkAPI *deviceSinkAPI = new DeviceSinkAPI(this, deviceTabIndex, dspDeviceSinkEngine, m_deviceUIs.back()->m_spectrum, m_deviceUIs.back()->m_channelWindow);
-
-    m_deviceUIs.back()->m_deviceSourceAPI = 0;
-    m_deviceUIs.back()->m_deviceSinkAPI = deviceSinkAPI;
-    m_deviceUIs.back()->m_samplingDeviceControl->setDeviceAPI(deviceSinkAPI);
-    m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
-    m_pluginManager->populateTxChannelComboBox(m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector());
-
-    connect(m_deviceUIs.back()->m_samplingDeviceControl->getAddChannelButton(), SIGNAL(clicked(bool)), this, SLOT(on_channel_addClicked(bool)));
-
-    dspDeviceSinkEngine->addSpectrumSink(m_deviceUIs.back()->m_spectrumVis);
-    ui->tabSpectra->addTab(m_deviceUIs.back()->m_spectrum, tabNameCStr);
-    ui->tabSpectraGUI->addTab(m_deviceUIs.back()->m_spectrumGUI, tabNameCStr);
-    ui->tabChannels->addTab(m_deviceUIs.back()->m_channelWindow, tabNameCStr);
-
-    bool sampleSourceSignalsBlocked = m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(true);
-    m_pluginManager->duplicateLocalSampleSinkDevices(dspDeviceSinkEngineUID);
-    m_pluginManager->fillSampleSinkSelector(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector(), dspDeviceSinkEngineUID);
-
-    connect(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelectionConfirm(), SIGNAL(clicked(bool)), this, SLOT(on_sampleSink_confirmClicked(bool)));
-
-    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(sampleSourceSignalsBlocked);
-    ui->tabInputsSelect->addTab(m_deviceUIs.back()->m_samplingDeviceControl, tabNameCStr);
-    ui->tabInputsSelect->setTabToolTip(deviceTabIndex, QString(uidCStr));
-
-    int sampleSinkIndex = m_pluginManager->selectSampleSinkBySerialOrSequence("sdrangel.samplesink.filesink", "0", 0, m_deviceUIs.back()->m_deviceSinkAPI);
-}
-
-void MainWindow::removeLastDevice()
-{
-	if (m_deviceUIs.back()->m_deviceSourceEngine) // source tab
-	{
-	    DSPDeviceSourceEngine *lastDeviceEngine = m_deviceUIs.back()->m_deviceSourceEngine;
-	    lastDeviceEngine->stopAcquistion();
-	    lastDeviceEngine->removeSink(m_deviceUIs.back()->m_spectrumVis);
-
-	    ui->tabSpectraGUI->removeTab(ui->tabSpectraGUI->count() - 1);
-	    ui->tabSpectra->removeTab(ui->tabSpectra->count() - 1);
-
-	    m_deviceUIs.back()->m_deviceSourceAPI->freeAll();
-        m_deviceUIs.back()->m_deviceSourceAPI->clearBuddiesLists(); // remove old API from buddies lists
-
-	    ui->tabChannels->removeTab(ui->tabChannels->count() - 1);
-
-	    ui->tabInputsSelect->removeTab(ui->tabInputsSelect->count() - 1);
-
-	    m_deviceWidgetTabs.removeLast();m_pluginManager->loadPlugins();
-	    ui->tabInputsView->clear();
-
-	    for (int i = 0; i < m_deviceWidgetTabs.size(); i++)
-	    {
-	        qDebug("MainWindow::removeLastDevice: adding back tab for %s", m_deviceWidgetTabs[i].displayName.toStdString().c_str());
-	        ui->tabInputsView->addTab(m_deviceWidgetTabs[i].gui, m_deviceWidgetTabs[i].tabName);
-	        ui->tabInputsView->setTabToolTip(i, m_deviceWidgetTabs[i].displayName);
-	    }
-
-	    delete m_deviceUIs.back();
-
-	    lastDeviceEngine->stop();
-	    m_dspEngine->removeLastDeviceSourceEngine();
-	}
-	else if (m_deviceUIs.back()->m_deviceSinkEngine) // sink tab
-	{
-	    DSPDeviceSinkEngine *lastDeviceEngine = m_deviceUIs.back()->m_deviceSinkEngine;
-	    lastDeviceEngine->stopGeneration();
-	    lastDeviceEngine->removeSpectrumSink(m_deviceUIs.back()->m_spectrumVis);
-
-	    ui->tabSpectraGUI->removeTab(ui->tabSpectraGUI->count() - 1);
-	    ui->tabSpectra->removeTab(ui->tabSpectra->count() - 1);
-
-	    m_deviceUIs.back()->m_deviceSinkAPI->freeAll();
-        m_deviceUIs.back()->m_deviceSinkAPI->clearBuddiesLists(); // remove old API from buddies lists
-
-	    ui->tabChannels->removeTab(ui->tabChannels->count() - 1);
-
-	    ui->tabInputsSelect->removeTab(ui->tabInputsSelect->count() - 1);
-
-	    m_deviceWidgetTabs.removeLast();
-	    ui->tabInputsView->clear();
-
-	    for (int i = 0; i < m_deviceWidgetTabs.size(); i++)
-	    {
-	        qDebug("MainWindow::removeLastDevice: adding back tab for %s", m_deviceWidgetTabs[i].displayName.toStdString().c_str());
-	        ui->tabInputsView->addTab(m_deviceWidgetTabs[i].gui, m_deviceWidgetTabs[i].tabName);
-	        ui->tabInputsView->setTabToolTip(i, m_deviceWidgetTabs[i].displayName);
-	    }
-
-	    delete m_deviceUIs.back();
-
-	    lastDeviceEngine->stop();
-	    m_dspEngine->removeLastDeviceSinkEngine();
-	}
-
-    m_deviceUIs.pop_back();
-}
-
-void MainWindow::addChannelRollup(int deviceTabIndex, QWidget* widget)
-{
-    if (deviceTabIndex < ui->tabInputsView->count())
-    {
-        DeviceUISet *deviceUI = m_deviceUIs[deviceTabIndex];
-        deviceUI->m_channelWindow->addRollupWidget(widget);
-        ui->channelDock->show();
-        ui->channelDock->raise();
-    }
-}
-
-void MainWindow::addViewAction(QAction* action)
-{
-	ui->menu_Window->addAction(action);
-}
-
-void MainWindow::setDeviceGUI(int deviceTabIndex, QWidget* gui, const QString& deviceDisplayName, bool sourceDevice)
-{
-    char tabNameCStr[16];
-
-    if (sourceDevice)
-    {
-        sprintf(tabNameCStr, "R%d", deviceTabIndex);
-    }
-    else
-    {
-        sprintf(tabNameCStr, "T%d", deviceTabIndex);
-    }
-
-    qDebug("MainWindow::setDeviceGUI: insert %s tab at %d", sourceDevice ? "Rx" : "Tx", deviceTabIndex);
-
-    if (deviceTabIndex < m_deviceWidgetTabs.size())
-    {
-        m_deviceWidgetTabs[deviceTabIndex] = {gui, deviceDisplayName, QString(tabNameCStr)};
-    }
-    else
-    {
-        m_deviceWidgetTabs.append({gui, deviceDisplayName, QString(tabNameCStr)});
-    }
-
-    ui->tabInputsView->clear();
-
-    for (int i = 0; i < m_deviceWidgetTabs.size(); i++)
-    {
-        qDebug("MainWindow::setDeviceGUI: adding tab for %s", m_deviceWidgetTabs[i].displayName.toStdString().c_str());
-        ui->tabInputsView->addTab(m_deviceWidgetTabs[i].gui, m_deviceWidgetTabs[i].tabName);
-        ui->tabInputsView->setTabToolTip(i, m_deviceWidgetTabs[i].displayName);
-    }
-
-    ui->tabInputsView->setCurrentIndex(deviceTabIndex);
-}
-
-void MainWindow::loadSettings()
-{
-	qDebug() << "MainWindow::loadSettings";
-
-    m_settings.load();
-    m_settings.sortPresets();
-
-    for(int i = 0; i < m_settings.getPresetCount(); ++i)
-    {
-    	addPresetToTree(m_settings.getPreset(i));
-    }
-}
-
-void MainWindow::loadPresetSettings(const Preset* preset, int tabIndex)
-{
-	qDebug("MainWindow::loadPresetSettings: preset [%s | %s]",
-		qPrintable(preset->getGroup()),
-		qPrintable(preset->getDescription()));
-
-	if (tabIndex >= 0)
-	{
-        DeviceUISet *deviceUI = m_deviceUIs[tabIndex];
-
-        if (deviceUI->m_deviceSourceEngine) // source device
-        {
-            deviceUI->m_spectrumGUI->deserialize(preset->getSpectrumConfig());
-            deviceUI->m_deviceSourceAPI->loadSourceSettings(preset);
-            deviceUI->m_deviceSourceAPI->loadChannelSettings(preset, &(m_pluginManager->m_pluginAPI));
-        }
-        else if (deviceUI->m_deviceSinkEngine) // sink device
-        {
-            deviceUI->m_spectrumGUI->deserialize(preset->getSpectrumConfig());
-            deviceUI->m_deviceSinkAPI->loadSinkSettings(preset);
-            deviceUI->m_deviceSinkAPI->loadChannelSettings(preset, &(m_pluginManager->m_pluginAPI));
-        }
-	}
-
-	// has to be last step
-	restoreState(preset->getLayout());
-}
-
-void MainWindow::savePresetSettings(Preset* preset, int tabIndex)
-{
-	qDebug("MainWindow::savePresetSettings: preset [%s | %s]",
-		qPrintable(preset->getGroup()),
-		qPrintable(preset->getDescription()));
-
-    // Save from currently selected source tab
-    //int currentSourceTabIndex = ui->tabInputsView->currentIndex();
-    DeviceUISet *deviceUI = m_deviceUIs[tabIndex];
-
-    if (deviceUI->m_deviceSourceEngine) // source device
-    {
-        preset->setSpectrumConfig(deviceUI->m_spectrumGUI->serialize());
-        preset->clearChannels();
-        deviceUI->m_deviceSourceAPI->saveChannelSettings(preset);
-        deviceUI->m_deviceSourceAPI->saveSourceSettings(preset);
-    }
-    else if (deviceUI->m_deviceSinkEngine) // sink device
-    {
-        preset->setSpectrumConfig(deviceUI->m_spectrumGUI->serialize());
-        preset->clearChannels();
-        preset->setSourcePreset(false);
-        deviceUI->m_deviceSinkAPI->saveChannelSettings(preset);
-        deviceUI->m_deviceSinkAPI->saveSinkSettings(preset);
-    }
-
-    preset->setLayout(saveState());
-}
-
-void MainWindow::createStatusBar()
-{
-    QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR);
-#if QT_VERSION >= 0x050400
-    m_showSystemWidget = new QLabel("SDRangel v3.3.4 " + qtVersionStr + QSysInfo::prettyProductName(), this);
-#else
-    m_showSystemWidget = new QLabel("SDRangel v3.3.4 " + qtVersionStr, this);
-#endif
-    statusBar()->addPermanentWidget(m_showSystemWidget);
-
-	m_dateTimeWidget = new QLabel(tr("Date"), this);
-	m_dateTimeWidget->setToolTip(tr("Current date/time"));
-	statusBar()->addPermanentWidget(m_dateTimeWidget);
-}
-
-void MainWindow::closeEvent(QCloseEvent*)
-{
-}
-
-void MainWindow::updatePresetControls()
-{
-	ui->presetTree->resizeColumnToContents(0);
-
-	if(ui->presetTree->currentItem() != 0)
-	{
-		ui->presetDelete->setEnabled(true);
-		ui->presetLoad->setEnabled(true);
-	}
-	else
-	{
-		ui->presetDelete->setEnabled(false);
-		ui->presetLoad->setEnabled(false);
-	}
-}
-
-QTreeWidgetItem* MainWindow::addPresetToTree(const Preset* preset)
-{
-	QTreeWidgetItem* group = 0;
-
-	for(int i = 0; i < ui->presetTree->topLevelItemCount(); i++)
-	{
-		if(ui->presetTree->topLevelItem(i)->text(0) == preset->getGroup())
-		{
-			group = ui->presetTree->topLevelItem(i);
-			break;
-		}
-	}
-
-	if(group == 0)
-	{
-		QStringList sl;
-		sl.append(preset->getGroup());
-		group = new QTreeWidgetItem(ui->presetTree, sl, PGroup);
-		group->setFirstColumnSpanned(true);
-		group->setExpanded(true);
-		ui->presetTree->sortByColumn(0, Qt::AscendingOrder);
-	}
-
-	QStringList sl;
-	sl.append(QString("%1").arg(preset->getCenterFrequency() / 1e6f, 0, 'f', 3)); // frequency column
-	sl.append(QString("%1").arg(preset->isSourcePreset() ? 'R' : 'T'));           // mode column
-	sl.append(preset->getDescription());                                          // description column
-	PresetItem* item = new PresetItem(group, sl, preset->getCenterFrequency(), PItem);
-	item->setTextAlignment(0, Qt::AlignRight);
-	item->setData(0, Qt::UserRole, qVariantFromValue(preset));
-	ui->presetTree->resizeColumnToContents(0); // Resize frequency column to minimum
-    ui->presetTree->resizeColumnToContents(1); // Resize mode column to minimum
-
-	updatePresetControls();
-	return item;
-}
-
-void MainWindow::applySettings()
-{
-}
-
-void MainWindow::handleMessages()
-{
-	Message* message;
-
-	while ((message = m_inputMessageQueue.pop()) != 0)
-	{
-		qDebug("MainWindow::handleMessages: message: %s", message->getIdentifier());
-		delete message;
-	}
-}
-
-void MainWindow::on_action_View_Fullscreen_toggled(bool checked)
-{
-	if(checked)
-		showFullScreen();
-	else showNormal();
-}
-
-void MainWindow::on_presetSave_clicked()
-{
-	QStringList groups;
-	QString group;
-	QString description = "";
-	for(int i = 0; i < ui->presetTree->topLevelItemCount(); i++)
-		groups.append(ui->presetTree->topLevelItem(i)->text(0));
-
-	QTreeWidgetItem* item = ui->presetTree->currentItem();
-	if(item != 0) {
-		if(item->type() == PGroup)
-			group = item->text(0);
-		else if(item->type() == PItem) {
-			group = item->parent()->text(0);
-			description = item->text(0);
-		}
-	}
-
-	AddPresetDialog dlg(groups, group, this);
-
-	if (description.length() > 0) {
-		dlg.setDescription(description);
-	}
-
-	if(dlg.exec() == QDialog::Accepted) {
-		Preset* preset = m_settings.newPreset(dlg.group(), dlg.description());
-		savePresetSettings(preset, ui->tabInputsView->currentIndex());
-
-		ui->presetTree->setCurrentItem(addPresetToTree(preset));
-	}
-}
-
-void MainWindow::on_presetUpdate_clicked()
-{
-	QTreeWidgetItem* item = ui->presetTree->currentItem();
-
-	if(item != 0) {
-		if(item->type() == PItem) {
-			const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
-			if (preset != 0) {
-				Preset* preset_mod = const_cast(preset);
-				savePresetSettings(preset_mod, ui->tabInputsView->currentIndex());
-			}
-		}
-	}
-}
-
-void MainWindow::on_presetExport_clicked()
-{
-	QTreeWidgetItem* item = ui->presetTree->currentItem();
-
-	if(item != 0) {
-		if(item->type() == PItem)
-		{
-			const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
-			QString base64Str = preset->serialize().toBase64();
-			QString fileName = QFileDialog::getSaveFileName(this,
-			    tr("Open preset export file"), ".", tr("Preset export files (*.prex)"));
-
-			if (fileName != "")
-			{
-				QFileInfo fileInfo(fileName);
-
-				if (fileInfo.suffix() != "prex") {
-					fileName += ".prex";
-				}
-
-				QFile exportFile(fileName);
-
-				if (exportFile.open(QIODevice::WriteOnly | QIODevice::Text))
-				{
-					QTextStream outstream(&exportFile);
-					outstream << base64Str;
-					exportFile.close();
-				}
-				else
-				{
-			    	QMessageBox::information(this, tr("Message"), tr("Cannot open file for writing"));
-				}
-			}
-		}
-	}
-}
-
-void MainWindow::on_presetImport_clicked()
-{
-	QTreeWidgetItem* item = ui->presetTree->currentItem();
-
-	if(item != 0)
-	{
-		QString group;
-
-		if (item->type() == PGroup)	{
-			group = item->text(0);
-		} else if (item->type() == PItem) {
-			group = item->parent()->text(0);
-		} else {
-			return;
-		}
-
-		QString fileName = QFileDialog::getOpenFileName(this,
-		    tr("Open preset export file"), ".", tr("Preset export files (*.prex)"));
-
-		if (fileName != "")
-		{
-			QFile exportFile(fileName);
-
-			if (exportFile.open(QIODevice::ReadOnly | QIODevice::Text))
-			{
-				QByteArray base64Str;
-				QTextStream instream(&exportFile);
-				instream >> base64Str;
-				exportFile.close();
-
-				Preset* preset = m_settings.newPreset("", "");
-				preset->deserialize(QByteArray::fromBase64(base64Str));
-				preset->setGroup(group); // override with current group
-
-				ui->presetTree->setCurrentItem(addPresetToTree(preset));
-			}
-			else
-			{
-				QMessageBox::information(this, tr("Message"), tr("Cannot open file for reading"));
-			}
-		}
-	}
-}
-
-void MainWindow::on_settingsSave_clicked()
-{
-    savePresetSettings(m_settings.getWorkingPreset(), ui->tabInputsView->currentIndex());
-    m_settings.save();
-}
-
-void MainWindow::on_presetLoad_clicked()
-{
-	qDebug() << "MainWindow::on_presetLoad_clicked";
-
-	QTreeWidgetItem* item = ui->presetTree->currentItem();
-
-	if(item == 0)
-	{
-		qDebug("MainWindow::on_presetLoad_clicked: item null");
-		updatePresetControls();
-		return;
-	}
-
-	const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
-
-	if(preset == 0)
-	{
-		qDebug("MainWindow::on_presetLoad_clicked: preset null");
-		return;
-	}
-
-	loadPresetSettings(preset, ui->tabInputsView->currentIndex());
-	applySettings();
-}
-
-void MainWindow::on_presetDelete_clicked()
-{
-	QTreeWidgetItem* item = ui->presetTree->currentItem();
-	if(item == 0) {
-		updatePresetControls();
-		return;
-	}
-	const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
-	if(preset == 0)
-		return;
-
-	if(QMessageBox::question(this, tr("Delete Preset"), tr("Do you want to delete preset '%1'?").arg(preset->getDescription()), QMessageBox::No | QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
-		delete item;
-		m_settings.deletePreset(preset);
-	}
-}
-
-void MainWindow::on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
-{
-	updatePresetControls();
-}
-
-void MainWindow::on_presetTree_itemActivated(QTreeWidgetItem *item, int column)
-{
-	on_presetLoad_clicked();
-}
-
-void MainWindow::on_action_Loaded_Plugins_triggered()
-{
-    PluginsDialog pluginsDialog(m_pluginManager, this);
-    pluginsDialog.exec();
-}
-
-void MainWindow::on_action_Audio_triggered()
-{
-	AudioDialog audioDialog(&m_audioDeviceInfo, this);
-	audioDialog.exec();
-	m_dspEngine->setAudioInputVolume(m_audioDeviceInfo.getInputVolume());
-	m_dspEngine->setAudioInputDeviceIndex(m_audioDeviceInfo.getInputDeviceIndex());
-	m_dspEngine->setAudioOutputDeviceIndex(m_audioDeviceInfo.getOutputDeviceIndex());
-}
-
-void MainWindow::on_action_My_Position_triggered()
-{
-	MyPositionDialog myPositionDialog(m_settings, this);
-	myPositionDialog.exec();
-}
-
-void MainWindow::on_action_DV_Serial_triggered(bool checked)
-{
-    m_dspEngine->setDVSerialSupport(checked);
-
-    if (checked)
-    {
-        std::vector deviceNames;
-        m_dspEngine->getDVSerialNames(deviceNames);
-
-        if (deviceNames.size() == 0)
-        {
-            QMessageBox::information(this, tr("Message"), tr("No DV serial devices found"));
-        }
-        else
-        {
-            std::vector::iterator it = deviceNames.begin();
-            std::string deviceNamesStr = "DV Serial devices found: ";
-
-            while (it != deviceNames.end())
-            {
-                if (it != deviceNames.begin()) {
-                    deviceNamesStr += ",";
-                }
-
-                deviceNamesStr += *it;
-                ++it;
-            }
-
-            QMessageBox::information(this, tr("Message"), tr(deviceNamesStr.c_str()));
-        }
-    }
-}
-
-void MainWindow::on_sampleSource_confirmClicked(bool checked)
-{
-    // Do it in the currently selected source tab
-    int currentSourceTabIndex = ui->tabInputsSelect->currentIndex();
-
-    if (currentSourceTabIndex >= 0)
-    {
-        qDebug("MainWindow::on_sampleSource_confirmClicked: tab at %d", currentSourceTabIndex);
-        DeviceUISet *deviceUI = m_deviceUIs[currentSourceTabIndex];
-        deviceUI->m_deviceSourceAPI->saveSourceSettings(m_settings.getWorkingPreset()); // save old API settings
-        int selectedComboIndex = deviceUI->m_samplingDeviceControl->getDeviceSelector()->currentIndex();
-        void *devicePtr = deviceUI->m_samplingDeviceControl->getDeviceSelector()->itemData(selectedComboIndex).value();
-        deviceUI->m_deviceSourceAPI->stopAcquisition();
-        deviceUI->m_deviceSourceAPI->clearBuddiesLists(); // clear old API buddies lists
-        m_pluginManager->selectSampleSourceByDevice(devicePtr, deviceUI->m_deviceSourceAPI); // sets the new API
-        deviceUI->m_deviceSourceAPI->loadSourceSettings(m_settings.getWorkingPreset()); // load new API settings
-
-        // add to buddies list
-        std::vector::iterator it = m_deviceUIs.begin();
-        for (; it != m_deviceUIs.end(); ++it)
-        {
-            if (*it != deviceUI) // do not add to itself
-            {
-                if ((*it)->m_deviceSourceEngine) // it is a source device
-                {
-                    if ((deviceUI->m_deviceSourceAPI->getHardwareId() == (*it)->m_deviceSourceAPI->getHardwareId()) &&
-                        (deviceUI->m_deviceSourceAPI->getSampleSourceSerial() == (*it)->m_deviceSourceAPI->getSampleSourceSerial()))
-                    {
-                        (*it)->m_deviceSourceAPI->addSourceBuddy(deviceUI->m_deviceSourceAPI);
-                    }
-                }
-
-                if ((*it)->m_deviceSinkEngine) // it is a sink device
-                {
-                    if ((deviceUI->m_deviceSourceAPI->getHardwareId() == (*it)->m_deviceSinkAPI->getHardwareId()) &&
-                        (deviceUI->m_deviceSourceAPI->getSampleSourceSerial() == (*it)->m_deviceSinkAPI->getSampleSinkSerial()))
-                    {
-                        (*it)->m_deviceSinkAPI->addSourceBuddy(deviceUI->m_deviceSourceAPI);
-                    }
-                }
-            }
-        }
-
-        if (currentSourceTabIndex == 0)
-        {
-            m_settings.setSourceIndex(deviceUI->m_samplingDeviceControl->getDeviceSelector()->currentIndex());
-        }
-    }
-}
-
-void MainWindow::on_sampleSink_confirmClicked(bool checked)
-{
-    // Do it in the currently selected source tab
-    int currentSinkTabIndex = ui->tabInputsSelect->currentIndex();
-
-    if (currentSinkTabIndex >= 0)
-    {
-        qDebug("MainWindow::on_sampleSink_confirmClicked: tab at %d", currentSinkTabIndex);
-        DeviceUISet *deviceUI = m_deviceUIs[currentSinkTabIndex];
-        deviceUI->m_deviceSinkAPI->saveSinkSettings(m_settings.getWorkingPreset()); // save old API settings
-        int selectedComboIndex = deviceUI->m_samplingDeviceControl->getDeviceSelector()->currentIndex();
-        void *devicePtr = deviceUI->m_samplingDeviceControl->getDeviceSelector()->itemData(selectedComboIndex).value();
-        deviceUI->m_deviceSinkAPI->stopGeneration();
-        deviceUI->m_deviceSinkAPI->clearBuddiesLists(); // remove old API from buddies lists
-        m_pluginManager->selectSampleSinkByDevice(devicePtr, deviceUI->m_deviceSinkAPI); // sets the new API
-        deviceUI->m_deviceSinkAPI->loadSinkSettings(m_settings.getWorkingPreset()); // load new API settings
-
-        // add to buddies list
-        std::vector::iterator it = m_deviceUIs.begin();
-        for (; it != m_deviceUIs.end(); ++it)
-        {
-            if (*it != deviceUI) // do not add to itself
-            {
-                if ((*it)->m_deviceSourceEngine) // it is a source device
-                {
-                    if ((deviceUI->m_deviceSinkAPI->getHardwareId() == (*it)->m_deviceSourceAPI->getHardwareId()) &&
-                        (deviceUI->m_deviceSinkAPI->getSampleSinkSerial() == (*it)->m_deviceSourceAPI->getSampleSourceSerial()))
-                    {
-                        (*it)->m_deviceSourceAPI->addSinkBuddy(deviceUI->m_deviceSinkAPI);
-                    }
-                }
-
-                if ((*it)->m_deviceSinkEngine) // it is a sink device
-                {
-                    if ((deviceUI->m_deviceSinkAPI->getHardwareId() == (*it)->m_deviceSinkAPI->getHardwareId()) &&
-                        (deviceUI->m_deviceSinkAPI->getSampleSinkSerial() == (*it)->m_deviceSinkAPI->getSampleSinkSerial()))
-                    {
-                        (*it)->m_deviceSinkAPI->addSinkBuddy(deviceUI->m_deviceSinkAPI);
-                    }
-                }
-            }
-        }
-    }
-}
-
-void MainWindow::on_channel_addClicked(bool checked)
-{
-    // Do it in the currently selected source tab
-    int currentSourceTabIndex = ui->tabInputsSelect->currentIndex();
-
-    if (currentSourceTabIndex >= 0)
-    {
-        DeviceUISet *deviceUI = m_deviceUIs[currentSourceTabIndex];
-
-        if (deviceUI->m_deviceSourceEngine) // source device => Rx channels
-        {
-            m_pluginManager->createRxChannelInstance(deviceUI->m_samplingDeviceControl->getChannelSelector()->currentIndex(), deviceUI->m_deviceSourceAPI);
-        }
-        else if (deviceUI->m_deviceSinkEngine) // sink device => Tx channels
-        {
-            uint32_t nbSources = deviceUI->m_deviceSinkAPI->getNumberOfSources();
-
-            if (nbSources > 0) {
-                QMessageBox::information(this, tr("Message"), tr("%1 channel(s) already in use. Multiple transmission channels is experimental. You may experience performance problems").arg(nbSources));
-            }
-
-            m_pluginManager->createTxChannelInstance(deviceUI->m_samplingDeviceControl->getChannelSelector()->currentIndex(), deviceUI->m_deviceSinkAPI);
-        }
-    }
-
-}
-
-void MainWindow::on_action_About_triggered()
-{
-	AboutDialog dlg(this);
-	dlg.exec();
-}
-
-void MainWindow::on_action_addSourceDevice_triggered()
-{
-    addSourceDevice();
-}
-
-void MainWindow::on_action_addSinkDevice_triggered()
-{
-    addSinkDevice();
-}
-
-void MainWindow::on_action_removeLastDevice_triggered()
-{
-    if (m_deviceUIs.size() > 1)
-    {
-        removeLastDevice();
-    }
-}
-
-void MainWindow::on_action_reloadDevices_triggered()
-{
-    // all devices must be stopped
-    std::vector::iterator it = m_deviceUIs.begin();
-    for (; it != m_deviceUIs.end(); ++it)
-    {
-        if ((*it)->m_deviceSourceEngine) // it is a source device
-        {
-            if ((*it)->m_deviceSourceEngine->state() == DSPDeviceSourceEngine::StRunning)
-            {
-                QMessageBox::information(this, tr("Message"), tr("Stop all devices for reload to take effect"));
-                return;
-            }
-        }
-
-        if ((*it)->m_deviceSinkEngine) // it is a sink device
-        {
-            if ((*it)->m_deviceSinkEngine->state() == DSPDeviceSinkEngine::StRunning)
-            {
-                QMessageBox::information(this, tr("Message"), tr("Stop all devices for reload to take effect"));
-                return;
-            }
-        }
-    }
-
-    // re-scan devices
-    m_pluginManager->updateSampleSourceDevices();
-    m_pluginManager->updateSampleSinkDevices();
-
-    // re-populate device selectors keeping the same selection
-    it = m_deviceUIs.begin();
-    for (; it != m_deviceUIs.end(); ++it)
-    {
-        if ((*it)->m_deviceSourceEngine) // it is a source device
-        {
-            QComboBox *deviceSelectorComboBox = (*it)->m_samplingDeviceControl->getDeviceSelector();
-            bool sampleSourceSignalsBlocked = deviceSelectorComboBox->blockSignals(true);
-            m_pluginManager->fillSampleSourceSelector(deviceSelectorComboBox, (*it)->m_deviceSourceEngine->getUID());
-            int newIndex = m_pluginManager->getSampleSourceSelectorIndex(deviceSelectorComboBox, (*it)->m_deviceSourceAPI);
-            deviceSelectorComboBox->setCurrentIndex(newIndex);
-            deviceSelectorComboBox->blockSignals(sampleSourceSignalsBlocked);
-        }
-
-        if ((*it)->m_deviceSinkEngine) // it is a sink device
-        {
-            QComboBox *deviceSelectorComboBox = (*it)->m_samplingDeviceControl->getDeviceSelector();
-            bool sampleSinkSignalsBlocked = deviceSelectorComboBox->blockSignals(true);
-            m_pluginManager->fillSampleSinkSelector(deviceSelectorComboBox, (*it)->m_deviceSinkEngine->getUID());
-            int newIndex = m_pluginManager->getSampleSinkSelectorIndex(deviceSelectorComboBox, (*it)->m_deviceSinkAPI);
-            deviceSelectorComboBox->setCurrentIndex(newIndex);
-            deviceSelectorComboBox->blockSignals(sampleSinkSignalsBlocked);
-        }
-    }
-}
-
-void MainWindow::on_action_Exit_triggered()
-{
-    savePresetSettings(m_settings.getWorkingPreset(), 0);
-    m_settings.save();
-
-    while (m_deviceUIs.size() > 0)
-    {
-        removeLastDevice();
-    }
-}
-
-void MainWindow::tabInputViewIndexChanged()
-{
-    int inputViewIndex = ui->tabInputsView->currentIndex();
-
-    if ((inputViewIndex >= 0) && (m_masterTabIndex >= 0) && (inputViewIndex != m_masterTabIndex))
-    {
-        DeviceUISet *deviceUI = m_deviceUIs[inputViewIndex];
-        DeviceUISet *lastdeviceUI = m_deviceUIs[m_masterTabIndex];
-        lastdeviceUI->m_mainWindowState = saveState();
-        restoreState(deviceUI->m_mainWindowState);
-        m_masterTabIndex = inputViewIndex;
-    }
-
-    ui->tabSpectra->setCurrentIndex(inputViewIndex);
-    ui->tabChannels->setCurrentIndex(inputViewIndex);
-    ui->tabInputsSelect->setCurrentIndex(inputViewIndex);
-    ui->tabSpectraGUI->setCurrentIndex(inputViewIndex);
-}
-
-void MainWindow::updateStatus()
-{
-    m_dateTimeWidget->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss t"));
-}
-
-MainWindow::DeviceUISet::DeviceUISet(QTimer& timer)
-{
-	m_spectrum = new GLSpectrum;
-	m_spectrumVis = new SpectrumVis(m_spectrum);
-	m_spectrum->connectTimer(timer);
-	m_spectrumGUI = new GLSpectrumGUI;
-	m_spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, m_spectrum);
-	m_channelWindow = new ChannelWindow;
-	m_samplingDeviceControl = new SamplingDeviceControl;
-	m_deviceSourceEngine = 0;
-	m_deviceSourceAPI = 0;
-	m_deviceSinkEngine = 0;
-	m_deviceSinkAPI = 0;
-
-	// m_spectrum needs to have its font to be set since it cannot be inherited from the main window
-	QFont font;
-    font.setFamily(QStringLiteral("Sans Serif"));
-    font.setPointSize(9);
-    m_spectrum->setFont(font);
-
-}
-
-MainWindow::DeviceUISet::~DeviceUISet()
-{
-	delete m_samplingDeviceControl;
-	delete m_channelWindow;
-	delete m_spectrumGUI;
-	delete m_spectrumVis;
-	delete m_spectrum;
-}
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2012 maintech GmbH, Otto-Hahn-Str. 15, 97204 Hoechberg, Germany //
+// written by Christian Daniel                                                   //
+//                                                                               //
+// 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 as version 3 of the License, or                  //
+//                                                                               //
+// 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 V3 for more details.                               //
+//                                                                               //
+// You should have received a copy of the GNU General Public License             //
+// along with this program. If not, see .          //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "mainwindow.h"
+#include "ui_mainwindow.h"
+#include "device/devicesourceapi.h"
+#include "device/devicesinkapi.h"
+#include "audio/audiodeviceinfo.h"
+#include "gui/indicator.h"
+#include "gui/presetitem.h"
+#include "gui/addpresetdialog.h"
+#include "gui/pluginsdialog.h"
+#include "gui/aboutdialog.h"
+#include "gui/rollupwidget.h"
+#include "gui/channelwindow.h"
+#include "gui/audiodialog.h"
+#include "gui/samplingdevicecontrol.h"
+#include "gui/mypositiondialog.h"
+#include "dsp/dspengine.h"
+#include "dsp/spectrumvis.h"
+#include "dsp/dspcommands.h"
+#include "plugin/plugingui.h"
+#include "plugin/pluginapi.h"
+#include "plugin/plugingui.h"
+
+#include "gui/glspectrum.h"
+#include "gui/glspectrumgui.h"
+
+#include 
+#include 
+
+MainWindow::MainWindow(QWidget* parent) :
+	QMainWindow(parent),
+	ui(new Ui::MainWindow),
+	m_masterTabIndex(0),
+	m_settings(),
+	m_dspEngine(DSPEngine::instance()),
+	m_lastEngineState((DSPDeviceSourceEngine::State)-1),
+	m_inputGUI(0),
+	m_sampleRate(0),
+	m_centerFrequency(0),
+	m_sampleFileName(std::string("./test.sdriq"))
+{
+	qDebug() << "MainWindow::MainWindow: start";
+
+	m_settings.setAudioDeviceInfo(&m_audioDeviceInfo);
+
+	ui->setupUi(this);
+	createStatusBar();
+
+	setCorner(Qt::TopLeftCorner, Qt::LeftDockWidgetArea);
+	setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
+	setCorner(Qt::TopRightCorner, Qt::RightDockWidgetArea);
+	setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
+
+	// work around broken Qt dock widget ordering
+    removeDockWidget(ui->inputViewDock);
+	removeDockWidget(ui->inputSelectDock);
+	removeDockWidget(ui->spectraDisplayDock);
+	removeDockWidget(ui->presetDock);
+	removeDockWidget(ui->channelDock);
+	addDockWidget(Qt::LeftDockWidgetArea, ui->inputSelectDock);
+    addDockWidget(Qt::LeftDockWidgetArea, ui->inputViewDock);
+	addDockWidget(Qt::LeftDockWidgetArea, ui->spectraDisplayDock);
+	addDockWidget(Qt::LeftDockWidgetArea, ui->presetDock);
+	addDockWidget(Qt::RightDockWidgetArea, ui->channelDock);
+
+	ui->inputViewDock->show();
+    ui->inputSelectDock->show();
+	ui->spectraDisplayDock->show();
+	ui->presetDock->show();
+	ui->channelDock->show();
+
+    ui->menu_Window->addAction(ui->inputViewDock->toggleViewAction());
+	ui->menu_Window->addAction(ui->inputSelectDock->toggleViewAction());
+	ui->menu_Window->addAction(ui->spectraDisplayDock->toggleViewAction());
+	ui->menu_Window->addAction(ui->presetDock->toggleViewAction());
+	ui->menu_Window->addAction(ui->channelDock->toggleViewAction());
+
+    ui->tabInputsView->setStyleSheet("QWidget { background: rgb(50,50,50); } "
+            "QToolButton::checked { background: rgb(128,70,0); } "
+            "QComboBox::item:selected { color: rgb(255,140,0); } "
+            "QTabWidget::pane { border: 1px solid #C06900; } "
+            "QTabBar::tab:selected { background: rgb(128,70,0); }");
+    ui->tabInputsSelect->setStyleSheet("QWidget { background: rgb(50,50,50); } "
+            "QToolButton::checked { background: rgb(128,70,0); } "
+            "QComboBox::item:selected { color: rgb(255,140,0); } "
+            "QTabWidget::pane { border: 1px solid #808080; } "
+            "QTabBar::tab:selected { background: rgb(100,100,100); }");
+
+    m_pluginManager = new PluginManager(this);
+    m_pluginManager->loadPlugins();
+
+	connect(&m_inputMessageQueue, SIGNAL(messageEnqueued()), this, SLOT(handleMessages()), Qt::QueuedConnection);
+
+	connect(&m_statusTimer, SIGNAL(timeout()), this, SLOT(updateStatus()));
+	m_statusTimer.start(1000);
+
+	m_masterTimer.start(50);
+
+    qDebug() << "MainWindow::MainWindow: add the first device...";
+
+    addSourceDevice(); // add the first device
+
+    qDebug() << "MainWindow::MainWindow: load settings...";
+
+	loadSettings();
+
+	qDebug() << "MainWindow::MainWindow: select SampleSource from settings...";
+
+	int sampleSourceIndex = m_settings.getSourceIndex();
+	sampleSourceIndex = m_pluginManager->selectSampleSourceByIndex(sampleSourceIndex, m_deviceUIs.back()->m_deviceSourceAPI);
+
+	if (sampleSourceIndex < 0)
+	{
+	    qCritical("MainWindow::MainWindow: no sample source. Exit");
+	    exit(0);
+	}
+
+    bool sampleSourceSignalsBlocked = m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(true);
+    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->setCurrentIndex(sampleSourceIndex);
+    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(sampleSourceSignalsBlocked);
+
+	qDebug() << "MainWindow::MainWindow: load current preset settings...";
+
+	loadPresetSettings(m_settings.getWorkingPreset(), 0);
+
+	qDebug() << "MainWindow::MainWindow: apply settings...";
+
+	applySettings();
+
+	qDebug() << "MainWindow::MainWindow: update preset controls...";
+
+	updatePresetControls();
+
+	connect(ui->tabInputsView, SIGNAL(currentChanged(int)), this, SLOT(tabInputViewIndexChanged()));
+
+    qDebug() << "MainWindow::MainWindow: end";
+}
+
+MainWindow::~MainWindow()
+{
+    delete m_pluginManager;
+	delete m_dateTimeWidget;
+	delete m_showSystemWidget;
+
+	delete ui;
+}
+
+void MainWindow::addSourceDevice()
+{
+    DSPDeviceSourceEngine *dspDeviceSourceEngine = m_dspEngine->addDeviceSourceEngine();
+    dspDeviceSourceEngine->start();
+
+    uint dspDeviceSourceEngineUID =  dspDeviceSourceEngine->getUID();
+    char uidCStr[16];
+    sprintf(uidCStr, "UID:%d", dspDeviceSourceEngineUID);
+
+    m_deviceUIs.push_back(new DeviceUISet(m_masterTimer));
+    m_deviceUIs.back()->m_deviceSourceEngine = dspDeviceSourceEngine;
+
+    int deviceTabIndex = m_deviceUIs.size()-1;
+    char tabNameCStr[16];
+    sprintf(tabNameCStr, "R%d", deviceTabIndex);
+
+    DeviceSourceAPI *deviceSourceAPI = new DeviceSourceAPI(this, deviceTabIndex, dspDeviceSourceEngine, m_deviceUIs.back()->m_spectrum, m_deviceUIs.back()->m_channelWindow);
+
+    m_deviceUIs.back()->m_deviceSourceAPI = deviceSourceAPI;
+    m_deviceUIs.back()->m_samplingDeviceControl->setDeviceAPI(deviceSourceAPI);
+    m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
+    m_pluginManager->populateRxChannelComboBox(m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector());
+
+    connect(m_deviceUIs.back()->m_samplingDeviceControl->getAddChannelButton(), SIGNAL(clicked(bool)), this, SLOT(on_channel_addClicked(bool)));
+
+    dspDeviceSourceEngine->addSink(m_deviceUIs.back()->m_spectrumVis);
+    ui->tabSpectra->addTab(m_deviceUIs.back()->m_spectrum, tabNameCStr);
+    ui->tabSpectraGUI->addTab(m_deviceUIs.back()->m_spectrumGUI, tabNameCStr);
+    ui->tabChannels->addTab(m_deviceUIs.back()->m_channelWindow, tabNameCStr);
+
+    bool sampleSourceSignalsBlocked = m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(true);
+    m_pluginManager->duplicateLocalSampleSourceDevices(dspDeviceSourceEngineUID);
+    m_pluginManager->fillSampleSourceSelector(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector(), dspDeviceSourceEngineUID);
+
+    connect(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelectionConfirm(), SIGNAL(clicked(bool)), this, SLOT(on_sampleSource_confirmClicked(bool)));
+
+    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(sampleSourceSignalsBlocked);
+    ui->tabInputsSelect->addTab(m_deviceUIs.back()->m_samplingDeviceControl, tabNameCStr);
+    ui->tabInputsSelect->setTabToolTip(deviceTabIndex, QString(uidCStr));
+
+    int sampleSourceIndex = m_pluginManager->selectSampleSourceBySerialOrSequence("sdrangel.samplesource.filesource", "0", 0, m_deviceUIs.back()->m_deviceSourceAPI);
+}
+
+void MainWindow::addSinkDevice()
+{
+    DSPDeviceSinkEngine *dspDeviceSinkEngine = m_dspEngine->addDeviceSinkEngine();
+    dspDeviceSinkEngine->start();
+
+    uint dspDeviceSinkEngineUID =  dspDeviceSinkEngine->getUID();
+    char uidCStr[16];
+    sprintf(uidCStr, "UID:%d", dspDeviceSinkEngineUID);
+
+    m_deviceUIs.push_back(new DeviceUISet(m_masterTimer));
+    m_deviceUIs.back()->m_deviceSourceEngine = 0;
+    m_deviceUIs.back()->m_deviceSinkEngine = dspDeviceSinkEngine;
+
+    int deviceTabIndex = m_deviceUIs.size()-1;
+    char tabNameCStr[16];
+    sprintf(tabNameCStr, "T%d", deviceTabIndex);
+
+    DeviceSinkAPI *deviceSinkAPI = new DeviceSinkAPI(this, deviceTabIndex, dspDeviceSinkEngine, m_deviceUIs.back()->m_spectrum, m_deviceUIs.back()->m_channelWindow);
+
+    m_deviceUIs.back()->m_deviceSourceAPI = 0;
+    m_deviceUIs.back()->m_deviceSinkAPI = deviceSinkAPI;
+    m_deviceUIs.back()->m_samplingDeviceControl->setDeviceAPI(deviceSinkAPI);
+    m_deviceUIs.back()->m_samplingDeviceControl->setPluginManager(m_pluginManager);
+    m_pluginManager->populateTxChannelComboBox(m_deviceUIs.back()->m_samplingDeviceControl->getChannelSelector());
+
+    connect(m_deviceUIs.back()->m_samplingDeviceControl->getAddChannelButton(), SIGNAL(clicked(bool)), this, SLOT(on_channel_addClicked(bool)));
+
+    dspDeviceSinkEngine->addSpectrumSink(m_deviceUIs.back()->m_spectrumVis);
+    ui->tabSpectra->addTab(m_deviceUIs.back()->m_spectrum, tabNameCStr);
+    ui->tabSpectraGUI->addTab(m_deviceUIs.back()->m_spectrumGUI, tabNameCStr);
+    ui->tabChannels->addTab(m_deviceUIs.back()->m_channelWindow, tabNameCStr);
+
+    bool sampleSourceSignalsBlocked = m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(true);
+    m_pluginManager->duplicateLocalSampleSinkDevices(dspDeviceSinkEngineUID);
+    m_pluginManager->fillSampleSinkSelector(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector(), dspDeviceSinkEngineUID);
+
+    connect(m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelectionConfirm(), SIGNAL(clicked(bool)), this, SLOT(on_sampleSink_confirmClicked(bool)));
+
+    m_deviceUIs.back()->m_samplingDeviceControl->getDeviceSelector()->blockSignals(sampleSourceSignalsBlocked);
+    ui->tabInputsSelect->addTab(m_deviceUIs.back()->m_samplingDeviceControl, tabNameCStr);
+    ui->tabInputsSelect->setTabToolTip(deviceTabIndex, QString(uidCStr));
+
+    int sampleSinkIndex = m_pluginManager->selectSampleSinkBySerialOrSequence("sdrangel.samplesink.filesink", "0", 0, m_deviceUIs.back()->m_deviceSinkAPI);
+}
+
+void MainWindow::removeLastDevice()
+{
+	if (m_deviceUIs.back()->m_deviceSourceEngine) // source tab
+	{
+	    DSPDeviceSourceEngine *lastDeviceEngine = m_deviceUIs.back()->m_deviceSourceEngine;
+	    lastDeviceEngine->stopAcquistion();
+	    lastDeviceEngine->removeSink(m_deviceUIs.back()->m_spectrumVis);
+
+	    ui->tabSpectraGUI->removeTab(ui->tabSpectraGUI->count() - 1);
+	    ui->tabSpectra->removeTab(ui->tabSpectra->count() - 1);
+
+	    m_deviceUIs.back()->m_deviceSourceAPI->freeAll();
+        m_deviceUIs.back()->m_deviceSourceAPI->clearBuddiesLists(); // remove old API from buddies lists
+
+	    ui->tabChannels->removeTab(ui->tabChannels->count() - 1);
+
+	    ui->tabInputsSelect->removeTab(ui->tabInputsSelect->count() - 1);
+
+	    m_deviceWidgetTabs.removeLast();m_pluginManager->loadPlugins();
+	    ui->tabInputsView->clear();
+
+	    for (int i = 0; i < m_deviceWidgetTabs.size(); i++)
+	    {
+	        qDebug("MainWindow::removeLastDevice: adding back tab for %s", m_deviceWidgetTabs[i].displayName.toStdString().c_str());
+	        ui->tabInputsView->addTab(m_deviceWidgetTabs[i].gui, m_deviceWidgetTabs[i].tabName);
+	        ui->tabInputsView->setTabToolTip(i, m_deviceWidgetTabs[i].displayName);
+	    }
+
+	    delete m_deviceUIs.back();
+
+	    lastDeviceEngine->stop();
+	    m_dspEngine->removeLastDeviceSourceEngine();
+	}
+	else if (m_deviceUIs.back()->m_deviceSinkEngine) // sink tab
+	{
+	    DSPDeviceSinkEngine *lastDeviceEngine = m_deviceUIs.back()->m_deviceSinkEngine;
+	    lastDeviceEngine->stopGeneration();
+	    lastDeviceEngine->removeSpectrumSink(m_deviceUIs.back()->m_spectrumVis);
+
+	    ui->tabSpectraGUI->removeTab(ui->tabSpectraGUI->count() - 1);
+	    ui->tabSpectra->removeTab(ui->tabSpectra->count() - 1);
+
+	    m_deviceUIs.back()->m_deviceSinkAPI->freeAll();
+        m_deviceUIs.back()->m_deviceSinkAPI->clearBuddiesLists(); // remove old API from buddies lists
+
+	    ui->tabChannels->removeTab(ui->tabChannels->count() - 1);
+
+	    ui->tabInputsSelect->removeTab(ui->tabInputsSelect->count() - 1);
+
+	    m_deviceWidgetTabs.removeLast();
+	    ui->tabInputsView->clear();
+
+	    for (int i = 0; i < m_deviceWidgetTabs.size(); i++)
+	    {
+	        qDebug("MainWindow::removeLastDevice: adding back tab for %s", m_deviceWidgetTabs[i].displayName.toStdString().c_str());
+	        ui->tabInputsView->addTab(m_deviceWidgetTabs[i].gui, m_deviceWidgetTabs[i].tabName);
+	        ui->tabInputsView->setTabToolTip(i, m_deviceWidgetTabs[i].displayName);
+	    }
+
+	    delete m_deviceUIs.back();
+
+	    lastDeviceEngine->stop();
+	    m_dspEngine->removeLastDeviceSinkEngine();
+	}
+
+    m_deviceUIs.pop_back();
+}
+
+void MainWindow::addChannelRollup(int deviceTabIndex, QWidget* widget)
+{
+    if (deviceTabIndex < ui->tabInputsView->count())
+    {
+        DeviceUISet *deviceUI = m_deviceUIs[deviceTabIndex];
+        deviceUI->m_channelWindow->addRollupWidget(widget);
+        ui->channelDock->show();
+        ui->channelDock->raise();
+    }
+}
+
+void MainWindow::addViewAction(QAction* action)
+{
+	ui->menu_Window->addAction(action);
+}
+
+void MainWindow::setDeviceGUI(int deviceTabIndex, QWidget* gui, const QString& deviceDisplayName, bool sourceDevice)
+{
+    char tabNameCStr[16];
+
+    if (sourceDevice)
+    {
+        sprintf(tabNameCStr, "R%d", deviceTabIndex);
+    }
+    else
+    {
+        sprintf(tabNameCStr, "T%d", deviceTabIndex);
+    }
+
+    qDebug("MainWindow::setDeviceGUI: insert %s tab at %d", sourceDevice ? "Rx" : "Tx", deviceTabIndex);
+
+    if (deviceTabIndex < m_deviceWidgetTabs.size())
+    {
+        m_deviceWidgetTabs[deviceTabIndex] = {gui, deviceDisplayName, QString(tabNameCStr)};
+    }
+    else
+    {
+        m_deviceWidgetTabs.append({gui, deviceDisplayName, QString(tabNameCStr)});
+    }
+
+    ui->tabInputsView->clear();
+
+    for (int i = 0; i < m_deviceWidgetTabs.size(); i++)
+    {
+        qDebug("MainWindow::setDeviceGUI: adding tab for %s", m_deviceWidgetTabs[i].displayName.toStdString().c_str());
+        ui->tabInputsView->addTab(m_deviceWidgetTabs[i].gui, m_deviceWidgetTabs[i].tabName);
+        ui->tabInputsView->setTabToolTip(i, m_deviceWidgetTabs[i].displayName);
+    }
+
+    ui->tabInputsView->setCurrentIndex(deviceTabIndex);
+}
+
+void MainWindow::loadSettings()
+{
+	qDebug() << "MainWindow::loadSettings";
+
+    m_settings.load();
+    m_settings.sortPresets();
+
+    for(int i = 0; i < m_settings.getPresetCount(); ++i)
+    {
+    	addPresetToTree(m_settings.getPreset(i));
+    }
+}
+
+void MainWindow::loadPresetSettings(const Preset* preset, int tabIndex)
+{
+	qDebug("MainWindow::loadPresetSettings: preset [%s | %s]",
+		qPrintable(preset->getGroup()),
+		qPrintable(preset->getDescription()));
+
+	if (tabIndex >= 0)
+	{
+        DeviceUISet *deviceUI = m_deviceUIs[tabIndex];
+
+        if (deviceUI->m_deviceSourceEngine) // source device
+        {
+            deviceUI->m_spectrumGUI->deserialize(preset->getSpectrumConfig());
+            deviceUI->m_deviceSourceAPI->loadSourceSettings(preset);
+            deviceUI->m_deviceSourceAPI->loadChannelSettings(preset, &(m_pluginManager->m_pluginAPI));
+        }
+        else if (deviceUI->m_deviceSinkEngine) // sink device
+        {
+            deviceUI->m_spectrumGUI->deserialize(preset->getSpectrumConfig());
+            deviceUI->m_deviceSinkAPI->loadSinkSettings(preset);
+            deviceUI->m_deviceSinkAPI->loadChannelSettings(preset, &(m_pluginManager->m_pluginAPI));
+        }
+	}
+
+	// has to be last step
+	restoreState(preset->getLayout());
+}
+
+void MainWindow::savePresetSettings(Preset* preset, int tabIndex)
+{
+	qDebug("MainWindow::savePresetSettings: preset [%s | %s]",
+		qPrintable(preset->getGroup()),
+		qPrintable(preset->getDescription()));
+
+    // Save from currently selected source tab
+    //int currentSourceTabIndex = ui->tabInputsView->currentIndex();
+    DeviceUISet *deviceUI = m_deviceUIs[tabIndex];
+
+    if (deviceUI->m_deviceSourceEngine) // source device
+    {
+        preset->setSpectrumConfig(deviceUI->m_spectrumGUI->serialize());
+        preset->clearChannels();
+        deviceUI->m_deviceSourceAPI->saveChannelSettings(preset);
+        deviceUI->m_deviceSourceAPI->saveSourceSettings(preset);
+    }
+    else if (deviceUI->m_deviceSinkEngine) // sink device
+    {
+        preset->setSpectrumConfig(deviceUI->m_spectrumGUI->serialize());
+        preset->clearChannels();
+        preset->setSourcePreset(false);
+        deviceUI->m_deviceSinkAPI->saveChannelSettings(preset);
+        deviceUI->m_deviceSinkAPI->saveSinkSettings(preset);
+    }
+
+    preset->setLayout(saveState());
+}
+
+void MainWindow::createStatusBar()
+{
+    QString qtVersionStr = QString("Qt %1 ").arg(QT_VERSION_STR);
+#if QT_VERSION >= 0x050400
+    m_showSystemWidget = new QLabel("SDRangel v3.3.4 " + qtVersionStr + QSysInfo::prettyProductName(), this);
+#else
+    m_showSystemWidget = new QLabel("SDRangel v3.3.4 " + qtVersionStr, this);
+#endif
+    statusBar()->addPermanentWidget(m_showSystemWidget);
+
+	m_dateTimeWidget = new QLabel(tr("Date"), this);
+	m_dateTimeWidget->setToolTip(tr("Current date/time"));
+	statusBar()->addPermanentWidget(m_dateTimeWidget);
+}
+
+void MainWindow::closeEvent(QCloseEvent*)
+{
+}
+
+void MainWindow::updatePresetControls()
+{
+	ui->presetTree->resizeColumnToContents(0);
+
+	if(ui->presetTree->currentItem() != 0)
+	{
+		ui->presetDelete->setEnabled(true);
+		ui->presetLoad->setEnabled(true);
+	}
+	else
+	{
+		ui->presetDelete->setEnabled(false);
+		ui->presetLoad->setEnabled(false);
+	}
+}
+
+QTreeWidgetItem* MainWindow::addPresetToTree(const Preset* preset)
+{
+	QTreeWidgetItem* group = 0;
+
+	for(int i = 0; i < ui->presetTree->topLevelItemCount(); i++)
+	{
+		if(ui->presetTree->topLevelItem(i)->text(0) == preset->getGroup())
+		{
+			group = ui->presetTree->topLevelItem(i);
+			break;
+		}
+	}
+
+	if(group == 0)
+	{
+		QStringList sl;
+		sl.append(preset->getGroup());
+		group = new QTreeWidgetItem(ui->presetTree, sl, PGroup);
+		group->setFirstColumnSpanned(true);
+		group->setExpanded(true);
+		ui->presetTree->sortByColumn(0, Qt::AscendingOrder);
+	}
+
+	QStringList sl;
+	sl.append(QString("%1").arg(preset->getCenterFrequency() / 1e6f, 0, 'f', 3)); // frequency column
+	sl.append(QString("%1").arg(preset->isSourcePreset() ? 'R' : 'T'));           // mode column
+	sl.append(preset->getDescription());                                          // description column
+	PresetItem* item = new PresetItem(group, sl, preset->getCenterFrequency(), PItem);
+	item->setTextAlignment(0, Qt::AlignRight);
+	item->setData(0, Qt::UserRole, qVariantFromValue(preset));
+	ui->presetTree->resizeColumnToContents(0); // Resize frequency column to minimum
+    ui->presetTree->resizeColumnToContents(1); // Resize mode column to minimum
+
+	updatePresetControls();
+	return item;
+}
+
+void MainWindow::applySettings()
+{
+}
+
+void MainWindow::handleMessages()
+{
+	Message* message;
+
+	while ((message = m_inputMessageQueue.pop()) != 0)
+	{
+		qDebug("MainWindow::handleMessages: message: %s", message->getIdentifier());
+		delete message;
+	}
+}
+
+void MainWindow::on_action_View_Fullscreen_toggled(bool checked)
+{
+	if(checked)
+		showFullScreen();
+	else showNormal();
+}
+
+void MainWindow::on_presetSave_clicked()
+{
+	QStringList groups;
+	QString group;
+	QString description = "";
+	for(int i = 0; i < ui->presetTree->topLevelItemCount(); i++)
+		groups.append(ui->presetTree->topLevelItem(i)->text(0));
+
+	QTreeWidgetItem* item = ui->presetTree->currentItem();
+	if(item != 0) {
+		if(item->type() == PGroup)
+			group = item->text(0);
+		else if(item->type() == PItem) {
+			group = item->parent()->text(0);
+			description = item->text(0);
+		}
+	}
+
+	AddPresetDialog dlg(groups, group, this);
+
+	if (description.length() > 0) {
+		dlg.setDescription(description);
+	}
+
+	if(dlg.exec() == QDialog::Accepted) {
+		Preset* preset = m_settings.newPreset(dlg.group(), dlg.description());
+		savePresetSettings(preset, ui->tabInputsView->currentIndex());
+
+		ui->presetTree->setCurrentItem(addPresetToTree(preset));
+	}
+}
+
+void MainWindow::on_presetUpdate_clicked()
+{
+	QTreeWidgetItem* item = ui->presetTree->currentItem();
+
+	if(item != 0) {
+		if(item->type() == PItem) {
+			const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
+			if (preset != 0) {
+				Preset* preset_mod = const_cast(preset);
+				savePresetSettings(preset_mod, ui->tabInputsView->currentIndex());
+			}
+		}
+	}
+}
+
+void MainWindow::on_presetExport_clicked()
+{
+	QTreeWidgetItem* item = ui->presetTree->currentItem();
+
+	if(item != 0) {
+		if(item->type() == PItem)
+		{
+			const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
+			QString base64Str = preset->serialize().toBase64();
+			QString fileName = QFileDialog::getSaveFileName(this,
+			    tr("Open preset export file"), ".", tr("Preset export files (*.prex)"));
+
+			if (fileName != "")
+			{
+				QFileInfo fileInfo(fileName);
+
+				if (fileInfo.suffix() != "prex") {
+					fileName += ".prex";
+				}
+
+				QFile exportFile(fileName);
+
+				if (exportFile.open(QIODevice::WriteOnly | QIODevice::Text))
+				{
+					QTextStream outstream(&exportFile);
+					outstream << base64Str;
+					exportFile.close();
+				}
+				else
+				{
+			    	QMessageBox::information(this, tr("Message"), tr("Cannot open file for writing"));
+				}
+			}
+		}
+	}
+}
+
+void MainWindow::on_presetImport_clicked()
+{
+	QTreeWidgetItem* item = ui->presetTree->currentItem();
+
+	if(item != 0)
+	{
+		QString group;
+
+		if (item->type() == PGroup)	{
+			group = item->text(0);
+		} else if (item->type() == PItem) {
+			group = item->parent()->text(0);
+		} else {
+			return;
+		}
+
+		QString fileName = QFileDialog::getOpenFileName(this,
+		    tr("Open preset export file"), ".", tr("Preset export files (*.prex)"));
+
+		if (fileName != "")
+		{
+			QFile exportFile(fileName);
+
+			if (exportFile.open(QIODevice::ReadOnly | QIODevice::Text))
+			{
+				QByteArray base64Str;
+				QTextStream instream(&exportFile);
+				instream >> base64Str;
+				exportFile.close();
+
+				Preset* preset = m_settings.newPreset("", "");
+				preset->deserialize(QByteArray::fromBase64(base64Str));
+				preset->setGroup(group); // override with current group
+
+				ui->presetTree->setCurrentItem(addPresetToTree(preset));
+			}
+			else
+			{
+				QMessageBox::information(this, tr("Message"), tr("Cannot open file for reading"));
+			}
+		}
+	}
+}
+
+void MainWindow::on_settingsSave_clicked()
+{
+    savePresetSettings(m_settings.getWorkingPreset(), ui->tabInputsView->currentIndex());
+    m_settings.save();
+}
+
+void MainWindow::on_presetLoad_clicked()
+{
+	qDebug() << "MainWindow::on_presetLoad_clicked";
+
+	QTreeWidgetItem* item = ui->presetTree->currentItem();
+
+	if(item == 0)
+	{
+		qDebug("MainWindow::on_presetLoad_clicked: item null");
+		updatePresetControls();
+		return;
+	}
+
+	const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
+
+	if(preset == 0)
+	{
+		qDebug("MainWindow::on_presetLoad_clicked: preset null");
+		return;
+	}
+
+	loadPresetSettings(preset, ui->tabInputsView->currentIndex());
+	applySettings();
+}
+
+void MainWindow::on_presetDelete_clicked()
+{
+	QTreeWidgetItem* item = ui->presetTree->currentItem();
+	if(item == 0) {
+		updatePresetControls();
+		return;
+	}
+	const Preset* preset = qvariant_cast(item->data(0, Qt::UserRole));
+	if(preset == 0)
+		return;
+
+	if(QMessageBox::question(this, tr("Delete Preset"), tr("Do you want to delete preset '%1'?").arg(preset->getDescription()), QMessageBox::No | QMessageBox::Yes, QMessageBox::No) == QMessageBox::Yes) {
+		delete item;
+		m_settings.deletePreset(preset);
+	}
+}
+
+void MainWindow::on_presetTree_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
+{
+	updatePresetControls();
+}
+
+void MainWindow::on_presetTree_itemActivated(QTreeWidgetItem *item, int column)
+{
+	on_presetLoad_clicked();
+}
+
+void MainWindow::on_action_Loaded_Plugins_triggered()
+{
+    PluginsDialog pluginsDialog(m_pluginManager, this);
+    pluginsDialog.exec();
+}
+
+void MainWindow::on_action_Audio_triggered()
+{
+	AudioDialog audioDialog(&m_audioDeviceInfo, this);
+	audioDialog.exec();
+	m_dspEngine->setAudioInputVolume(m_audioDeviceInfo.getInputVolume());
+	m_dspEngine->setAudioInputDeviceIndex(m_audioDeviceInfo.getInputDeviceIndex());
+	m_dspEngine->setAudioOutputDeviceIndex(m_audioDeviceInfo.getOutputDeviceIndex());
+}
+
+void MainWindow::on_action_My_Position_triggered()
+{
+	MyPositionDialog myPositionDialog(m_settings, this);
+	myPositionDialog.exec();
+}
+
+void MainWindow::on_action_DV_Serial_triggered(bool checked)
+{
+    m_dspEngine->setDVSerialSupport(checked);
+
+    if (checked)
+    {
+        std::vector deviceNames;
+        m_dspEngine->getDVSerialNames(deviceNames);
+
+        if (deviceNames.size() == 0)
+        {
+            QMessageBox::information(this, tr("Message"), tr("No DV serial devices found"));
+        }
+        else
+        {
+            std::vector::iterator it = deviceNames.begin();
+            std::string deviceNamesStr = "DV Serial devices found: ";
+
+            while (it != deviceNames.end())
+            {
+                if (it != deviceNames.begin()) {
+                    deviceNamesStr += ",";
+                }
+
+                deviceNamesStr += *it;
+                ++it;
+            }
+
+            QMessageBox::information(this, tr("Message"), tr(deviceNamesStr.c_str()));
+        }
+    }
+}
+
+void MainWindow::on_sampleSource_confirmClicked(bool checked)
+{
+    // Do it in the currently selected source tab
+    int currentSourceTabIndex = ui->tabInputsSelect->currentIndex();
+
+    if (currentSourceTabIndex >= 0)
+    {
+        qDebug("MainWindow::on_sampleSource_confirmClicked: tab at %d", currentSourceTabIndex);
+        DeviceUISet *deviceUI = m_deviceUIs[currentSourceTabIndex];
+        deviceUI->m_deviceSourceAPI->saveSourceSettings(m_settings.getWorkingPreset()); // save old API settings
+        int selectedComboIndex = deviceUI->m_samplingDeviceControl->getDeviceSelector()->currentIndex();
+        void *devicePtr = deviceUI->m_samplingDeviceControl->getDeviceSelector()->itemData(selectedComboIndex).value();
+        deviceUI->m_deviceSourceAPI->stopAcquisition();
+
+        // TODO: deviceUI->m_deviceSourceAPI->setSampleSourcePluginGUI(0); // deletes old GUI and input object
+        deviceUI->m_deviceSourceAPI->clearBuddiesLists(); // clear old API buddies lists
+
+        m_pluginManager->selectSampleSourceByDevice(devicePtr, deviceUI->m_deviceSourceAPI); // sets the new API
+
+        // TODO: move up add to buddies list
+
+        // TODO:
+//        // constructs new GUI and input object
+//        QWidget *gui;
+//        PluginManager::SamplingDevice *sampleSourceDevice = (PluginManager::SamplingDevice *) devicePtr;
+//        PluginGUI *pluginGUI = sampleSourceDevice->m_plugin->createSampleSourcePluginGUI(sampleSourceDevice->m_deviceId, &gui, deviceUI->m_deviceSourceAPI);
+//
+//        deviceUI->m_deviceSourceAPI->setSampleSourcePluginGUI(pluginGUI);
+//        deviceUI->m_deviceSourceAPI->setInputGUI(gui, sampleSourceDevice->m_displayName);
+
+        deviceUI->m_deviceSourceAPI->loadSourceSettings(m_settings.getWorkingPreset()); // load new API settings
+
+        // add to buddies list
+        std::vector::iterator it = m_deviceUIs.begin();
+        for (; it != m_deviceUIs.end(); ++it)
+        {
+            if (*it != deviceUI) // do not add to itself
+            {
+                if ((*it)->m_deviceSourceEngine) // it is a source device
+                {
+                    if ((deviceUI->m_deviceSourceAPI->getHardwareId() == (*it)->m_deviceSourceAPI->getHardwareId()) &&
+                        (deviceUI->m_deviceSourceAPI->getSampleSourceSerial() == (*it)->m_deviceSourceAPI->getSampleSourceSerial()))
+                    {
+                        (*it)->m_deviceSourceAPI->addSourceBuddy(deviceUI->m_deviceSourceAPI);
+                    }
+                }
+
+                if ((*it)->m_deviceSinkEngine) // it is a sink device
+                {
+                    if ((deviceUI->m_deviceSourceAPI->getHardwareId() == (*it)->m_deviceSinkAPI->getHardwareId()) &&
+                        (deviceUI->m_deviceSourceAPI->getSampleSourceSerial() == (*it)->m_deviceSinkAPI->getSampleSinkSerial()))
+                    {
+                        (*it)->m_deviceSinkAPI->addSourceBuddy(deviceUI->m_deviceSourceAPI);
+                    }
+                }
+            }
+        }
+
+        if (currentSourceTabIndex == 0)
+        {
+            m_settings.setSourceIndex(deviceUI->m_samplingDeviceControl->getDeviceSelector()->currentIndex());
+        }
+    }
+}
+
+void MainWindow::on_sampleSink_confirmClicked(bool checked)
+{
+    // Do it in the currently selected source tab
+    int currentSinkTabIndex = ui->tabInputsSelect->currentIndex();
+
+    if (currentSinkTabIndex >= 0)
+    {
+        qDebug("MainWindow::on_sampleSink_confirmClicked: tab at %d", currentSinkTabIndex);
+        DeviceUISet *deviceUI = m_deviceUIs[currentSinkTabIndex];
+        deviceUI->m_deviceSinkAPI->saveSinkSettings(m_settings.getWorkingPreset()); // save old API settings
+        int selectedComboIndex = deviceUI->m_samplingDeviceControl->getDeviceSelector()->currentIndex();
+        void *devicePtr = deviceUI->m_samplingDeviceControl->getDeviceSelector()->itemData(selectedComboIndex).value();
+        deviceUI->m_deviceSinkAPI->stopGeneration();
+        deviceUI->m_deviceSinkAPI->clearBuddiesLists(); // remove old API from buddies lists
+        m_pluginManager->selectSampleSinkByDevice(devicePtr, deviceUI->m_deviceSinkAPI); // sets the new API
+        deviceUI->m_deviceSinkAPI->loadSinkSettings(m_settings.getWorkingPreset()); // load new API settings
+
+        // add to buddies list
+        std::vector::iterator it = m_deviceUIs.begin();
+        for (; it != m_deviceUIs.end(); ++it)
+        {
+            if (*it != deviceUI) // do not add to itself
+            {
+                if ((*it)->m_deviceSourceEngine) // it is a source device
+                {
+                    if ((deviceUI->m_deviceSinkAPI->getHardwareId() == (*it)->m_deviceSourceAPI->getHardwareId()) &&
+                        (deviceUI->m_deviceSinkAPI->getSampleSinkSerial() == (*it)->m_deviceSourceAPI->getSampleSourceSerial()))
+                    {
+                        (*it)->m_deviceSourceAPI->addSinkBuddy(deviceUI->m_deviceSinkAPI);
+                    }
+                }
+
+                if ((*it)->m_deviceSinkEngine) // it is a sink device
+                {
+                    if ((deviceUI->m_deviceSinkAPI->getHardwareId() == (*it)->m_deviceSinkAPI->getHardwareId()) &&
+                        (deviceUI->m_deviceSinkAPI->getSampleSinkSerial() == (*it)->m_deviceSinkAPI->getSampleSinkSerial()))
+                    {
+                        (*it)->m_deviceSinkAPI->addSinkBuddy(deviceUI->m_deviceSinkAPI);
+                    }
+                }
+            }
+        }
+    }
+}
+
+void MainWindow::on_channel_addClicked(bool checked)
+{
+    // Do it in the currently selected source tab
+    int currentSourceTabIndex = ui->tabInputsSelect->currentIndex();
+
+    if (currentSourceTabIndex >= 0)
+    {
+        DeviceUISet *deviceUI = m_deviceUIs[currentSourceTabIndex];
+
+        if (deviceUI->m_deviceSourceEngine) // source device => Rx channels
+        {
+            m_pluginManager->createRxChannelInstance(deviceUI->m_samplingDeviceControl->getChannelSelector()->currentIndex(), deviceUI->m_deviceSourceAPI);
+        }
+        else if (deviceUI->m_deviceSinkEngine) // sink device => Tx channels
+        {
+            uint32_t nbSources = deviceUI->m_deviceSinkAPI->getNumberOfSources();
+
+            if (nbSources > 0) {
+                QMessageBox::information(this, tr("Message"), tr("%1 channel(s) already in use. Multiple transmission channels is experimental. You may experience performance problems").arg(nbSources));
+            }
+
+            m_pluginManager->createTxChannelInstance(deviceUI->m_samplingDeviceControl->getChannelSelector()->currentIndex(), deviceUI->m_deviceSinkAPI);
+        }
+    }
+
+}
+
+void MainWindow::on_action_About_triggered()
+{
+	AboutDialog dlg(this);
+	dlg.exec();
+}
+
+void MainWindow::on_action_addSourceDevice_triggered()
+{
+    addSourceDevice();
+}
+
+void MainWindow::on_action_addSinkDevice_triggered()
+{
+    addSinkDevice();
+}
+
+void MainWindow::on_action_removeLastDevice_triggered()
+{
+    if (m_deviceUIs.size() > 1)
+    {
+        removeLastDevice();
+    }
+}
+
+void MainWindow::on_action_reloadDevices_triggered()
+{
+    // all devices must be stopped
+    std::vector::iterator it = m_deviceUIs.begin();
+    for (; it != m_deviceUIs.end(); ++it)
+    {
+        if ((*it)->m_deviceSourceEngine) // it is a source device
+        {
+            if ((*it)->m_deviceSourceEngine->state() == DSPDeviceSourceEngine::StRunning)
+            {
+                QMessageBox::information(this, tr("Message"), tr("Stop all devices for reload to take effect"));
+                return;
+            }
+        }
+
+        if ((*it)->m_deviceSinkEngine) // it is a sink device
+        {
+            if ((*it)->m_deviceSinkEngine->state() == DSPDeviceSinkEngine::StRunning)
+            {
+                QMessageBox::information(this, tr("Message"), tr("Stop all devices for reload to take effect"));
+                return;
+            }
+        }
+    }
+
+    // re-scan devices
+    m_pluginManager->updateSampleSourceDevices();
+    m_pluginManager->updateSampleSinkDevices();
+
+    // re-populate device selectors keeping the same selection
+    it = m_deviceUIs.begin();
+    for (; it != m_deviceUIs.end(); ++it)
+    {
+        if ((*it)->m_deviceSourceEngine) // it is a source device
+        {
+            QComboBox *deviceSelectorComboBox = (*it)->m_samplingDeviceControl->getDeviceSelector();
+            bool sampleSourceSignalsBlocked = deviceSelectorComboBox->blockSignals(true);
+            m_pluginManager->fillSampleSourceSelector(deviceSelectorComboBox, (*it)->m_deviceSourceEngine->getUID());
+            int newIndex = m_pluginManager->getSampleSourceSelectorIndex(deviceSelectorComboBox, (*it)->m_deviceSourceAPI);
+            deviceSelectorComboBox->setCurrentIndex(newIndex);
+            deviceSelectorComboBox->blockSignals(sampleSourceSignalsBlocked);
+        }
+
+        if ((*it)->m_deviceSinkEngine) // it is a sink device
+        {
+            QComboBox *deviceSelectorComboBox = (*it)->m_samplingDeviceControl->getDeviceSelector();
+            bool sampleSinkSignalsBlocked = deviceSelectorComboBox->blockSignals(true);
+            m_pluginManager->fillSampleSinkSelector(deviceSelectorComboBox, (*it)->m_deviceSinkEngine->getUID());
+            int newIndex = m_pluginManager->getSampleSinkSelectorIndex(deviceSelectorComboBox, (*it)->m_deviceSinkAPI);
+            deviceSelectorComboBox->setCurrentIndex(newIndex);
+            deviceSelectorComboBox->blockSignals(sampleSinkSignalsBlocked);
+        }
+    }
+}
+
+void MainWindow::on_action_Exit_triggered()
+{
+    savePresetSettings(m_settings.getWorkingPreset(), 0);
+    m_settings.save();
+
+    while (m_deviceUIs.size() > 0)
+    {
+        removeLastDevice();
+    }
+}
+
+void MainWindow::tabInputViewIndexChanged()
+{
+    int inputViewIndex = ui->tabInputsView->currentIndex();
+
+    if ((inputViewIndex >= 0) && (m_masterTabIndex >= 0) && (inputViewIndex != m_masterTabIndex))
+    {
+        DeviceUISet *deviceUI = m_deviceUIs[inputViewIndex];
+        DeviceUISet *lastdeviceUI = m_deviceUIs[m_masterTabIndex];
+        lastdeviceUI->m_mainWindowState = saveState();
+        restoreState(deviceUI->m_mainWindowState);
+        m_masterTabIndex = inputViewIndex;
+    }
+
+    ui->tabSpectra->setCurrentIndex(inputViewIndex);
+    ui->tabChannels->setCurrentIndex(inputViewIndex);
+    ui->tabInputsSelect->setCurrentIndex(inputViewIndex);
+    ui->tabSpectraGUI->setCurrentIndex(inputViewIndex);
+}
+
+void MainWindow::updateStatus()
+{
+    m_dateTimeWidget->setText(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss t"));
+}
+
+MainWindow::DeviceUISet::DeviceUISet(QTimer& timer)
+{
+	m_spectrum = new GLSpectrum;
+	m_spectrumVis = new SpectrumVis(m_spectrum);
+	m_spectrum->connectTimer(timer);
+	m_spectrumGUI = new GLSpectrumGUI;
+	m_spectrumGUI->setBuddies(m_spectrumVis->getInputMessageQueue(), m_spectrumVis, m_spectrum);
+	m_channelWindow = new ChannelWindow;
+	m_samplingDeviceControl = new SamplingDeviceControl;
+	m_deviceSourceEngine = 0;
+	m_deviceSourceAPI = 0;
+	m_deviceSinkEngine = 0;
+	m_deviceSinkAPI = 0;
+
+	// m_spectrum needs to have its font to be set since it cannot be inherited from the main window
+	QFont font;
+    font.setFamily(QStringLiteral("Sans Serif"));
+    font.setPointSize(9);
+    m_spectrum->setFont(font);
+
+}
+
+MainWindow::DeviceUISet::~DeviceUISet()
+{
+	delete m_samplingDeviceControl;
+	delete m_channelWindow;
+	delete m_spectrumGUI;
+	delete m_spectrumVis;
+	delete m_spectrum;
+}
diff --git a/sdrbase/plugin/pluginmanager.cpp b/sdrbase/plugin/pluginmanager.cpp
index 2b407c577..82753217d 100644
--- a/sdrbase/plugin/pluginmanager.cpp
+++ b/sdrbase/plugin/pluginmanager.cpp
@@ -1,815 +1,819 @@
-///////////////////////////////////////////////////////////////////////////////////
-// Copyright (C) 2016 Edouard Griffiths, F4EXB                                   //
-//                                                                               //
-// 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 as version 3 of the License, or                  //
-//                                                                               //
-// 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 V3 for more details.                               //
-//                                                                               //
-// You should have received a copy of the GNU General Public License             //
-// along with this program. If not, see .          //
-///////////////////////////////////////////////////////////////////////////////////
-
-#include "device/devicesourceapi.h"
-#include "device/devicesinkapi.h"
-#include 
-#include 
-#include 
-#include 
-
-#include "plugin/pluginmanager.h"
-#include "plugin/plugingui.h"
-#include "settings/preset.h"
-#include "mainwindow.h"
-#include "gui/glspectrum.h"
-#include "util/message.h"
-
-#include 
-#include "dsp/dspdevicesourceengine.h"
-#include "dsp/dspdevicesinkengine.h"
-
-const QString PluginManager::m_sdrDaemonHardwareID = "SDRdaemon";
-const QString PluginManager::m_sdrDaemonDeviceTypeID = "sdrangel.samplesource.sdrdaemon";
-const QString PluginManager::m_sdrDaemonFECHardwareID = "SDRdaemonFEC";
-const QString PluginManager::m_sdrDaemonFECDeviceTypeID = "sdrangel.samplesource.sdrdaemonfec";
-const QString PluginManager::m_fileSourceHardwareID = "FileSource";
-const QString PluginManager::m_fileSourceDeviceTypeID = "sdrangel.samplesource.filesource";
-const QString PluginManager::m_fileSinkDeviceTypeID = "sdrangel.samplesink.filesink";
-
-PluginManager::PluginManager(MainWindow* mainWindow, QObject* parent) :
-	QObject(parent),
-	m_pluginAPI(this, mainWindow),
-	m_mainWindow(mainWindow)
-{
-}
-
-PluginManager::~PluginManager()
-{
-//	freeAll();
-}
-
-void PluginManager::loadPlugins()
-{
-	QString applicationDirPath = QApplication::instance()->applicationDirPath();
-	QString applicationLibPath = applicationDirPath + "/../lib";
-	qDebug() << "PluginManager::loadPlugins: " << qPrintable(applicationDirPath) << ", " << qPrintable(applicationLibPath);
-
-	QDir pluginsBinDir = QDir(applicationDirPath);
-	QDir pluginsLibDir = QDir(applicationLibPath);
-
-	loadPlugins(pluginsBinDir);
-	loadPlugins(pluginsLibDir);
-
-	qSort(m_plugins);
-
-	for (Plugins::const_iterator it = m_plugins.begin(); it != m_plugins.end(); ++it)
-	{
-		it->pluginInterface->initPlugin(&m_pluginAPI);
-	}
-
-	updateSampleSourceDevices();
-	updateSampleSinkDevices();
-}
-
-void PluginManager::registerRxChannel(const QString& channelName, PluginInterface* plugin)
-{
-    qDebug() << "PluginManager::registerRxChannel "
-            << plugin->getPluginDescriptor().displayedName.toStdString().c_str()
-            << " with channel name " << channelName;
-
-	m_rxChannelRegistrations.append(PluginAPI::ChannelRegistration(channelName, plugin));
-}
-
-void PluginManager::registerTxChannel(const QString& channelName, PluginInterface* plugin)
-{
-    qDebug() << "PluginManager::registerTxChannel "
-            << plugin->getPluginDescriptor().displayedName.toStdString().c_str()
-            << " with channel name " << channelName;
-
-	m_txChannelRegistrations.append(PluginAPI::ChannelRegistration(channelName, plugin));
-}
-
-void PluginManager::registerSampleSource(const QString& sourceName, PluginInterface* plugin)
-{
-	qDebug() << "PluginManager::registerSampleSource "
-			<< plugin->getPluginDescriptor().displayedName.toStdString().c_str()
-			<< " with source name " << sourceName.toStdString().c_str();
-
-	m_sampleSourceRegistrations.append(SamplingDeviceRegistration(sourceName, plugin));
-}
-
-void PluginManager::registerSampleSink(const QString& sinkName, PluginInterface* plugin)
-{
-	qDebug() << "PluginManager::registerSampleSink "
-			<< plugin->getPluginDescriptor().displayedName.toStdString().c_str()
-			<< " with sink name " << sinkName.toStdString().c_str();
-
-	m_sampleSinkRegistrations.append(SamplingDeviceRegistration(sinkName, plugin));
-}
-
-void PluginManager::updateSampleSourceDevices()
-{
-	m_sampleSourceDevices.clear();
-
-	for(int i = 0; i < m_sampleSourceRegistrations.count(); ++i)
-	{
-		PluginInterface::SamplingDevices ssd = m_sampleSourceRegistrations[i].m_plugin->enumSampleSources();
-
-		for(int j = 0; j < ssd.count(); ++j)
-		{
-			m_sampleSourceDevices.append(SamplingDevice(m_sampleSourceRegistrations[i].m_plugin,
-					ssd[j].displayedName,
-                    ssd[j].hardwareId,
-					ssd[j].id,
-					ssd[j].serial,
-					ssd[j].sequence));
-		}
-	}
-}
-
-void PluginManager::updateSampleSinkDevices()
-{
-	m_sampleSinkDevices.clear();
-
-	for(int i = 0; i < m_sampleSinkRegistrations.count(); ++i)
-	{
-		PluginInterface::SamplingDevices ssd = m_sampleSinkRegistrations[i].m_plugin->enumSampleSinks();
-
-		for(int j = 0; j < ssd.count(); ++j)
-		{
-			m_sampleSinkDevices.append(SamplingDevice(m_sampleSinkRegistrations[i].m_plugin,
-					ssd[j].displayedName,
-					ssd[j].hardwareId,
-                    ssd[j].id,
-					ssd[j].serial,
-					ssd[j].sequence));
-		}
-	}
-}
-
-void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID)
-{
-    if (deviceUID == 0) {
-        return;
-    }
-
-    SamplingDevice *sdrDaemonSSD0 = 0;
-    SamplingDevice *sdrDaemonFECSSD0 = 0;
-    SamplingDevice *fileSourceSSD0 = 0;
-    bool duplicateSDRDaemon = true;
-    bool duplicateSDRDaemonFEC = true;
-    bool duplicateFileSource = true;
-
-    for(int i = 0; i < m_sampleSourceDevices.count(); ++i)
-    {
-        if (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonDeviceTypeID) // SDRdaemon
-        {
-            if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0
-                sdrDaemonSSD0 = &m_sampleSourceDevices[i];
-            }
-            else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there
-                duplicateSDRDaemon = false;
-            }
-        }
-        else if (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonFECDeviceTypeID) // SDRdaemon with FEC
-        {
-            if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0
-                sdrDaemonFECSSD0 = &m_sampleSourceDevices[i];
-            }
-            else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there
-                duplicateSDRDaemonFEC = false;
-            }
-        }
-        else if (m_sampleSourceDevices[i].m_deviceId == m_fileSourceDeviceTypeID) // File Source
-        {
-            if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0
-                fileSourceSSD0 = &m_sampleSourceDevices[i];
-            }
-            else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there
-                duplicateFileSource = false;
-            }
-        }
-    }
-
-    if (sdrDaemonSSD0 && duplicateSDRDaemon) // append item for a new instance
-    {
-        m_sampleSourceDevices.append(
-            SamplingDevice(
-                sdrDaemonSSD0->m_plugin,
-                QString("SDRdaemon[%1]").arg(deviceUID),
-                sdrDaemonSSD0->m_hadrwareId,
-                sdrDaemonSSD0->m_deviceId,
-                sdrDaemonSSD0->m_deviceSerial,
-                deviceUID
-            )
-        );
-    }
-
-    if (sdrDaemonFECSSD0 && duplicateSDRDaemonFEC) // append item for a new instance
-    {
-        m_sampleSourceDevices.append(
-            SamplingDevice(
-                sdrDaemonFECSSD0->m_plugin,
-                QString("SDRdaemonFEC[%1]").arg(deviceUID),
-                sdrDaemonFECSSD0->m_hadrwareId,
-                sdrDaemonFECSSD0->m_deviceId,
-                sdrDaemonFECSSD0->m_deviceSerial,
-                deviceUID
-            )
-        );
-    }
-
-    if (fileSourceSSD0 && duplicateFileSource) // append item for a new instance
-    {
-        m_sampleSourceDevices.append(
-            SamplingDevice(
-                fileSourceSSD0->m_plugin,
-                QString("FileSource[%1]").arg(deviceUID),
-                fileSourceSSD0->m_hadrwareId,
-                fileSourceSSD0->m_deviceId,
-                fileSourceSSD0->m_deviceSerial,
-                deviceUID
-            )
-        );
-    }
-}
-
-void PluginManager::duplicateLocalSampleSinkDevices(uint deviceUID)
-{
-    if (deviceUID == 0) {
-        return;
-    }
-
-    SamplingDevice *fileSinkSSD0 = 0;
-    bool duplicateFileSink = true;
-
-    for(int i = 0; i < m_sampleSinkDevices.count(); ++i)
-    {
-        if (m_sampleSinkDevices[i].m_deviceId == m_fileSinkDeviceTypeID) // File Sink
-        {
-            if (m_sampleSinkDevices[i].m_deviceSequence == 0) { // reference to device 0
-            	fileSinkSSD0 = &m_sampleSinkDevices[i];
-            }
-            else if (m_sampleSinkDevices[i].m_deviceSequence == deviceUID) { // already there
-                duplicateFileSink = false;
-            }
-        }
-    }
-
-    if (fileSinkSSD0 && duplicateFileSink) // append item for a new instance
-    {
-    	m_sampleSinkDevices.append(
-            SamplingDevice(
-            	fileSinkSSD0->m_plugin,
-                QString("FileSink[%1]").arg(deviceUID),
-                fileSinkSSD0->m_hadrwareId,
-				fileSinkSSD0->m_deviceId,
-				fileSinkSSD0->m_deviceSerial,
-                deviceUID
-            )
-        );
-    }
-}
-
-void PluginManager::fillSampleSourceSelector(QComboBox* comboBox, uint deviceUID)
-{
-	comboBox->clear();
-
-	for(int i = 0; i < m_sampleSourceDevices.count(); i++)
-	{
-	    // For "local" devices show only ones that concern this device set
-	    if ((m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonDeviceTypeID)
-	            || (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonFECDeviceTypeID)
-	            || (m_sampleSourceDevices[i].m_deviceId == m_fileSourceDeviceTypeID))
-	    {
-	        if (deviceUID != m_sampleSourceDevices[i].m_deviceSequence) {
-	            continue;
-	        }
-	    }
-
-		comboBox->addItem(m_sampleSourceDevices[i].m_displayName, qVariantFromValue((void *) &m_sampleSourceDevices[i]));
-	}
-}
-
-int PluginManager::getSampleSourceSelectorIndex(QComboBox* comboBox, DeviceSourceAPI *deviceSourceAPI)
-{
-    for (int i = 0; i < comboBox->count(); i++)
-    {
-        SamplingDevice *samplingDevice = (SamplingDevice*) (comboBox->itemData(i)).value();
-
-        if ((samplingDevice->m_deviceId == deviceSourceAPI->getSampleSourceId()) &&
-            (samplingDevice->m_deviceSerial == deviceSourceAPI->getSampleSourceSerial()) &&
-            (samplingDevice->m_deviceSequence == deviceSourceAPI->getSampleSourceSequence()))
-        {
-            return i;
-        }
-    }
-
-    return 0; // default to first item
-}
-
-void PluginManager::fillSampleSinkSelector(QComboBox* comboBox, uint deviceUID)
-{
-	comboBox->clear();
-
-	for(int i = 0; i < m_sampleSinkDevices.count(); i++)
-	{
-	    // For "local" devices show only ones that concern this device set
-	    if (m_sampleSinkDevices[i].m_deviceId == m_fileSinkDeviceTypeID)
-	    {
-	        if (deviceUID != m_sampleSinkDevices[i].m_deviceSequence) {
-	            continue;
-	        }
-	    }
-
-		comboBox->addItem(m_sampleSinkDevices[i].m_displayName, qVariantFromValue((void *) &m_sampleSinkDevices[i]));
-	}
-}
-
-int PluginManager::getSampleSinkSelectorIndex(QComboBox* comboBox, DeviceSinkAPI *deviceSinkAPI)
-{
-    for (int i = 0; i < comboBox->count(); i++)
-    {
-        SamplingDevice *samplingDevice = (SamplingDevice*) (comboBox->itemData(i)).value();
-
-        if ((samplingDevice->m_deviceId == deviceSinkAPI->getSampleSinkId()) &&
-            (samplingDevice->m_deviceSerial == deviceSinkAPI->getSampleSinkSerial()) &&
-            (samplingDevice->m_deviceSequence == deviceSinkAPI->getSampleSinkSequence()))
-        {
-            return i;
-        }
-    }
-
-    return 0; // default to first item
-}
-
-int PluginManager::selectSampleSourceByIndex(int index, DeviceSourceAPI *deviceAPI)
-{
-	qDebug("PluginManager::selectSampleSourceByIndex: index: %d", index);
-
-	if (m_sampleSourceDevices.count() == 0)
-	{
-		return -1;
-	}
-
-	if (index < 0)
-	{
-		return -1;
-	}
-
-	if (index >= m_sampleSourceDevices.count())
-	{
-		index = 0;
-	}
-
-    qDebug() << "PluginManager::selectSampleSourceByIndex: m_sampleSource at index " << index
-            << " hid: " << m_sampleSourceDevices[index].m_hadrwareId.toStdString().c_str()
-            << " id: " << m_sampleSourceDevices[index].m_deviceId.toStdString().c_str()
-            << " ser: " << m_sampleSourceDevices[index].m_deviceSerial.toStdString().c_str()
-            << " seq: " << m_sampleSourceDevices[index].m_deviceSequence;
-
-    deviceAPI->stopAcquisition();
-    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-	QWidget *gui;
-	PluginGUI *pluginGUI = m_sampleSourceDevices[index].m_plugin->createSampleSourcePluginGUI(m_sampleSourceDevices[index].m_deviceId, &gui, deviceAPI);
-
-	//	m_sampleSourcePluginGUI = pluginGUI;
-	deviceAPI->setSampleSourceSequence(m_sampleSourceDevices[index].m_deviceSequence);
-	deviceAPI->setHardwareId(m_sampleSourceDevices[index].m_hadrwareId);
-	deviceAPI->setSampleSourceId(m_sampleSourceDevices[index].m_deviceId);
-	deviceAPI->setSampleSourceSerial(m_sampleSourceDevices[index].m_deviceSerial);
-	deviceAPI->setSampleSourcePluginGUI(pluginGUI);
-	deviceAPI->setInputGUI(gui, m_sampleSourceDevices[index].m_displayName);
-
-	return index;
-}
-
-int PluginManager::selectSampleSinkByIndex(int index, DeviceSinkAPI *deviceAPI)
-{
-	qDebug("PluginManager::selectSampleSinkByIndex: index: %d", index);
-
-	if (m_sampleSinkDevices.count() == 0)
-	{
-		return -1;
-	}
-
-	if (index < 0)
-	{
-		return -1;
-	}
-
-	if (index >= m_sampleSinkDevices.count())
-	{
-		index = 0;
-	}
-
-    qDebug() << "PluginManager::selectSampleSinkByIndex: m_sampleSink at index " << index
-            << " hid: " << m_sampleSinkDevices[index].m_hadrwareId.toStdString().c_str()
-            << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str()
-            << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str()
-            << " seq: " << m_sampleSinkDevices[index].m_deviceSequence;
-
-    deviceAPI->stopGeneration();
-    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-	QWidget *gui;
-	PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI);
-
-	//	m_sampleSourcePluginGUI = pluginGUI;
-	deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence);
-	deviceAPI->setHardwareId(m_sampleSinkDevices[index].m_hadrwareId);
-	deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId);
-	deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial);
-	deviceAPI->setSampleSinkPluginGUI(pluginGUI);
-	deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName);
-
-	return index;
-}
-
-int PluginManager::selectFirstSampleSource(const QString& sourceId, DeviceSourceAPI *deviceAPI)
-{
-	qDebug("PluginManager::selectFirstSampleSource by id: [%s]", qPrintable(sourceId));
-
-	int index = -1;
-
-	for (int i = 0; i < m_sampleSourceDevices.count(); i++)
-	{
-		qDebug("*** %s vs %s", qPrintable(m_sampleSourceDevices[i].m_deviceId), qPrintable(sourceId));
-
-		if(m_sampleSourceDevices[i].m_deviceId == sourceId)
-		{
-			index = i;
-			break;
-		}
-	}
-
-	if(index == -1)
-	{
-		if(m_sampleSourceDevices.count() > 0)
-		{
-			index = 0;
-		}
-		else
-		{
-			return -1;
-		}
-	}
-
-    qDebug() << "PluginManager::selectFirstSampleSource: m_sampleSource at index " << index
-            << " hid: " << m_sampleSourceDevices[index].m_hadrwareId.toStdString().c_str()
-            << " id: " << m_sampleSourceDevices[index].m_deviceId.toStdString().c_str()
-            << " ser: " << m_sampleSourceDevices[index].m_deviceSerial.toStdString().c_str()
-            << " seq: " << m_sampleSourceDevices[index].m_deviceSequence;
-
-    deviceAPI->stopAcquisition();
-    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-    QWidget *gui;
-	PluginGUI *pluginGUI = m_sampleSourceDevices[index].m_plugin->createSampleSourcePluginGUI(m_sampleSourceDevices[index].m_deviceId, &gui, deviceAPI);
-
-	//	m_sampleSourcePluginGUI = pluginGUI;
-    deviceAPI->setSampleSourceSequence(m_sampleSourceDevices[index].m_deviceSequence);
-    deviceAPI->setHardwareId(m_sampleSourceDevices[index].m_hadrwareId);
-    deviceAPI->setSampleSourceId(m_sampleSourceDevices[index].m_deviceId);
-    deviceAPI->setSampleSourceSerial(m_sampleSourceDevices[index].m_deviceSerial);
-    deviceAPI->setSampleSourcePluginGUI(pluginGUI);
-    deviceAPI->setInputGUI(gui, m_sampleSourceDevices[index].m_displayName);
-
-	return index;
-}
-
-int PluginManager::selectFirstSampleSink(const QString& sinkId, DeviceSinkAPI *deviceAPI)
-{
-	qDebug("PluginManager::selectFirstSampleSink by id: [%s]", qPrintable(sinkId));
-
-	int index = -1;
-
-	for (int i = 0; i < m_sampleSinkDevices.count(); i++)
-	{
-		qDebug("*** %s vs %s", qPrintable(m_sampleSinkDevices[i].m_deviceId), qPrintable(sinkId));
-
-		if(m_sampleSinkDevices[i].m_deviceId == sinkId)
-		{
-			index = i;
-			break;
-		}
-	}
-
-	if(index == -1)
-	{
-		if(m_sampleSinkDevices.count() > 0)
-		{
-			index = 0;
-		}
-		else
-		{
-			return -1;
-		}
-	}
-
-    qDebug() << "PluginManager::selectFirstSampleSink: m_sampleSink at index " << index
-            << " hid: " << m_sampleSinkDevices[index].m_hadrwareId.toStdString().c_str()
-            << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str()
-            << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str()
-            << " seq: " << m_sampleSinkDevices[index].m_deviceSequence;
-
-    deviceAPI->stopGeneration();
-    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-    QWidget *gui;
-	PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI);
-
-	//	m_sampleSourcePluginGUI = pluginGUI;
-    deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence);
-    deviceAPI->setHardwareId(m_sampleSinkDevices[index].m_hadrwareId);
-    deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId);
-    deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial);
-    deviceAPI->setSampleSinkPluginGUI(pluginGUI);
-    deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName);
-
-	return index;
-}
-
-int PluginManager::selectSampleSourceBySerialOrSequence(const QString& sourceId, const QString& sourceSerial, int sourceSequence, DeviceSourceAPI *deviceAPI)
-{
-	qDebug("PluginManager::selectSampleSourceBySequence by sequence: id: %s ser: %s seq: %d", qPrintable(sourceId), qPrintable(sourceSerial), sourceSequence);
-
-	int index = -1;
-	int index_matchingSequence = -1;
-	int index_firstOfKind = -1;
-
-	for (int i = 0; i < m_sampleSourceDevices.count(); i++)
-	{
-		if (m_sampleSourceDevices[i].m_deviceId == sourceId)
-		{
-			index_firstOfKind = i;
-
-			if (m_sampleSourceDevices[i].m_deviceSerial == sourceSerial)
-			{
-				index = i; // exact match
-				break;
-			}
-
-			if (m_sampleSourceDevices[i].m_deviceSequence == sourceSequence)
-			{
-				index_matchingSequence = i;
-			}
-		}
-	}
-
-	if(index == -1) // no exact match
-	{
-		if (index_matchingSequence == -1) // no matching sequence
-		{
-			if (index_firstOfKind == -1) // no matching device type
-			{
-				if(m_sampleSourceDevices.count() > 0) // take first if any
-				{
-					index = 0;
-				}
-				else
-				{
-					return -1; // return if no device attached
-				}
-			}
-			else
-			{
-				index = index_firstOfKind; // take first that matches device type
-			}
-		}
-		else
-		{
-			index = index_matchingSequence; // take the one that matches the sequence in the device type
-		}
-	}
-
-    qDebug() << "PluginManager::selectSampleSourceBySequence: m_sampleSource at index " << index
-            << " hid: " << m_sampleSourceDevices[index].m_hadrwareId.toStdString().c_str()
-            << " id: " << m_sampleSourceDevices[index].m_deviceId.toStdString().c_str()
-            << " ser: " << m_sampleSourceDevices[index].m_deviceSerial.toStdString().c_str()
-            << " seq: " << m_sampleSourceDevices[index].m_deviceSequence;
-
-    deviceAPI->stopAcquisition();
-    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-    QWidget *gui;
-	PluginGUI *pluginGUI = m_sampleSourceDevices[index].m_plugin->createSampleSourcePluginGUI(m_sampleSourceDevices[index].m_deviceId, &gui, deviceAPI);
-
-	//	m_sampleSourcePluginGUI = pluginGUI;
-    deviceAPI->setSampleSourceSequence(m_sampleSourceDevices[index].m_deviceSequence);
-    deviceAPI->setHardwareId(m_sampleSourceDevices[index].m_hadrwareId);
-    deviceAPI->setSampleSourceId(m_sampleSourceDevices[index].m_deviceId);
-    deviceAPI->setSampleSourceSerial(m_sampleSourceDevices[index].m_deviceSerial);
-    deviceAPI->setSampleSourcePluginGUI(pluginGUI);
-    deviceAPI->setInputGUI(gui, m_sampleSourceDevices[index].m_displayName);
-
-	return index;
-}
-
-int PluginManager::selectSampleSinkBySerialOrSequence(const QString& sinkId, const QString& sinkSerial, int sinkSequence, DeviceSinkAPI *deviceAPI)
-{
-	qDebug("PluginManager::selectSampleSinkBySerialOrSequence by sequence: id: %s ser: %s seq: %d", qPrintable(sinkId), qPrintable(sinkSerial), sinkSequence);
-
-	int index = -1;
-	int index_matchingSequence = -1;
-	int index_firstOfKind = -1;
-
-	for (int i = 0; i < m_sampleSinkDevices.count(); i++)
-	{
-		if (m_sampleSinkDevices[i].m_deviceId == sinkId)
-		{
-			index_firstOfKind = i;
-
-			if (m_sampleSinkDevices[i].m_deviceSerial == sinkSerial)
-			{
-				index = i; // exact match
-				break;
-			}
-
-			if (m_sampleSinkDevices[i].m_deviceSequence == sinkSequence)
-			{
-				index_matchingSequence = i;
-			}
-		}
-	}
-
-	if(index == -1) // no exact match
-	{
-		if (index_matchingSequence == -1) // no matching sequence
-		{
-			if (index_firstOfKind == -1) // no matching device type
-			{
-				if(m_sampleSinkDevices.count() > 0) // take first if any
-				{
-					index = 0;
-				}
-				else
-				{
-					return -1; // return if no device attached
-				}
-			}
-			else
-			{
-				index = index_firstOfKind; // take first that matches device type
-			}
-		}
-		else
-		{
-			index = index_matchingSequence; // take the one that matches the sequence in the device type
-		}
-	}
-
-    qDebug() << "PluginManager::selectSampleSinkBySerialOrSequence: m_sampleSink at index " << index
-            << " hid: " << m_sampleSinkDevices[index].m_hadrwareId.toStdString().c_str()
-            << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str()
-            << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str()
-            << " seq: " << m_sampleSinkDevices[index].m_deviceSequence;
-
-    deviceAPI->stopGeneration();
-    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-    QWidget *gui;
-	PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI);
-
-	//	m_sampleSourcePluginGUI = pluginGUI;
-    deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence);
-    deviceAPI->setHardwareId(m_sampleSinkDevices[index].m_hadrwareId);
-    deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId);
-    deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial);
-    deviceAPI->setSampleSinkPluginGUI(pluginGUI);
-    deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName);
-
-	return index;
-}
-
-void PluginManager::selectSampleSourceByDevice(void *devicePtr, DeviceSourceAPI *deviceAPI)
-{
-    SamplingDevice *sampleSourceDevice = (SamplingDevice *) devicePtr;
-
-    qDebug() << "PluginManager::selectSampleSourceByDevice: "
-            << " hid: " << sampleSourceDevice->m_hadrwareId.toStdString().c_str()
-            << " id: " << sampleSourceDevice->m_deviceId.toStdString().c_str()
-            << " ser: " << sampleSourceDevice->m_deviceSerial.toStdString().c_str()
-            << " seq: " << sampleSourceDevice->m_deviceSequence;
-
-    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-    QWidget *gui;
-    PluginGUI *pluginGUI = sampleSourceDevice->m_plugin->createSampleSourcePluginGUI(sampleSourceDevice->m_deviceId, &gui, deviceAPI);
-
-    //  m_sampleSourcePluginGUI = pluginGUI;
-    deviceAPI->setSampleSourceSequence(sampleSourceDevice->m_deviceSequence);
-    deviceAPI->setHardwareId(sampleSourceDevice->m_hadrwareId);
-    deviceAPI->setSampleSourceId(sampleSourceDevice->m_deviceId);
-    deviceAPI->setSampleSourceSerial(sampleSourceDevice->m_deviceSerial);
-    deviceAPI->setSampleSourcePluginGUI(pluginGUI);
-    deviceAPI->setInputGUI(gui, sampleSourceDevice->m_displayName);
-}
-
-void PluginManager::selectSampleSinkByDevice(void *devicePtr, DeviceSinkAPI *deviceAPI)
-{
-    SamplingDevice *sampleSinkDevice = (SamplingDevice *) devicePtr;
-
-    qDebug() << "PluginManager::selectSampleSinkByDevice: "
-            << " hid: " << sampleSinkDevice->m_hadrwareId.toStdString().c_str()
-            << " id: " << sampleSinkDevice->m_deviceId.toStdString().c_str()
-            << " ser: " << sampleSinkDevice->m_deviceSerial.toStdString().c_str()
-            << " seq: " << sampleSinkDevice->m_deviceSequence;
-
-    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
-
-    QWidget *gui;
-    PluginGUI *pluginGUI = sampleSinkDevice->m_plugin->createSampleSinkPluginGUI(sampleSinkDevice->m_deviceId, &gui, deviceAPI);
-
-    //  m_sampleSourcePluginGUI = pluginGUI;
-    deviceAPI->setSampleSinkSequence(sampleSinkDevice->m_deviceSequence);
-    deviceAPI->setHardwareId(sampleSinkDevice->m_hadrwareId);
-    deviceAPI->setSampleSinkId(sampleSinkDevice->m_deviceId);
-    deviceAPI->setSampleSinkSerial(sampleSinkDevice->m_deviceSerial);
-    deviceAPI->setSampleSinkPluginGUI(pluginGUI);
-    deviceAPI->setOutputGUI(gui, sampleSinkDevice->m_displayName);
-}
-
-void PluginManager::loadPlugins(const QDir& dir)
-{
-	QDir pluginsDir(dir);
-
-	foreach (QString fileName, pluginsDir.entryList(QDir::Files))
-	{
-        if (fileName.endsWith(".so") || fileName.endsWith(".dll") || fileName.endsWith(".dylib"))
-		{
-			qDebug() << "PluginManager::loadPlugins: fileName: " << qPrintable(fileName);
-
-			QPluginLoader* loader = new QPluginLoader(pluginsDir.absoluteFilePath(fileName));
-			PluginInterface* plugin = qobject_cast(loader->instance());
-
-			if (loader->isLoaded())
-			{
-				qWarning("PluginManager::loadPlugins: loaded plugin %s", qPrintable(fileName));
-			}
-			else
-			{
-				qWarning() << "PluginManager::loadPlugins: " << qPrintable(loader->errorString());
-			}
-
-			if (plugin != 0)
-			{
-				m_plugins.append(Plugin(fileName, loader, plugin));
-			}
-			else
-			{
-				loader->unload();
-			}
-
-			delete loader; // Valgrind memcheck
-		}
-	}
-
-	// recursive calls on subdirectories
-
-	foreach (QString dirName, pluginsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
-	{
-		loadPlugins(pluginsDir.absoluteFilePath(dirName));
-	}
-}
-
-void PluginManager::populateRxChannelComboBox(QComboBox *channels)
-{
-    for(PluginAPI::ChannelRegistrations::iterator it = m_rxChannelRegistrations.begin(); it != m_rxChannelRegistrations.end(); ++it)
-    {
-        const PluginDescriptor& pluginDescipror = it->m_plugin->getPluginDescriptor();
-        channels->addItem(pluginDescipror.displayedName);
-    }
-}
-
-void PluginManager::populateTxChannelComboBox(QComboBox *channels)
-{
-    for(PluginAPI::ChannelRegistrations::iterator it = m_txChannelRegistrations.begin(); it != m_txChannelRegistrations.end(); ++it)
-    {
-        const PluginDescriptor& pluginDescipror = it->m_plugin->getPluginDescriptor();
-        channels->addItem(pluginDescipror.displayedName);
-    }
-}
-
-void PluginManager::createRxChannelInstance(int channelPluginIndex, DeviceSourceAPI *deviceAPI)
-{
-    if (channelPluginIndex < m_rxChannelRegistrations.size())
-    {
-        PluginInterface *pluginInterface = m_rxChannelRegistrations[channelPluginIndex].m_plugin;
-        pluginInterface->createRxChannel(m_rxChannelRegistrations[channelPluginIndex].m_channelName, deviceAPI);
-    }
-}
-
-void PluginManager::createTxChannelInstance(int channelPluginIndex, DeviceSinkAPI *deviceAPI)
-{
-    if (channelPluginIndex < m_txChannelRegistrations.size())
-    {
-        PluginInterface *pluginInterface = m_txChannelRegistrations[channelPluginIndex].m_plugin;
-        pluginInterface->createTxChannel(m_txChannelRegistrations[channelPluginIndex].m_channelName, deviceAPI);
-    }
-}
+///////////////////////////////////////////////////////////////////////////////////
+// Copyright (C) 2016 Edouard Griffiths, F4EXB                                   //
+//                                                                               //
+// 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 as version 3 of the License, or                  //
+//                                                                               //
+// 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 V3 for more details.                               //
+//                                                                               //
+// You should have received a copy of the GNU General Public License             //
+// along with this program. If not, see .          //
+///////////////////////////////////////////////////////////////////////////////////
+
+#include "device/devicesourceapi.h"
+#include "device/devicesinkapi.h"
+#include 
+#include 
+#include 
+#include 
+
+#include "plugin/pluginmanager.h"
+#include "plugin/plugingui.h"
+#include "settings/preset.h"
+#include "mainwindow.h"
+#include "gui/glspectrum.h"
+#include "util/message.h"
+
+#include 
+#include "dsp/dspdevicesourceengine.h"
+#include "dsp/dspdevicesinkengine.h"
+
+const QString PluginManager::m_sdrDaemonHardwareID = "SDRdaemon";
+const QString PluginManager::m_sdrDaemonDeviceTypeID = "sdrangel.samplesource.sdrdaemon";
+const QString PluginManager::m_sdrDaemonFECHardwareID = "SDRdaemonFEC";
+const QString PluginManager::m_sdrDaemonFECDeviceTypeID = "sdrangel.samplesource.sdrdaemonfec";
+const QString PluginManager::m_fileSourceHardwareID = "FileSource";
+const QString PluginManager::m_fileSourceDeviceTypeID = "sdrangel.samplesource.filesource";
+const QString PluginManager::m_fileSinkDeviceTypeID = "sdrangel.samplesink.filesink";
+
+PluginManager::PluginManager(MainWindow* mainWindow, QObject* parent) :
+	QObject(parent),
+	m_pluginAPI(this, mainWindow),
+	m_mainWindow(mainWindow)
+{
+}
+
+PluginManager::~PluginManager()
+{
+//	freeAll();
+}
+
+void PluginManager::loadPlugins()
+{
+	QString applicationDirPath = QApplication::instance()->applicationDirPath();
+	QString applicationLibPath = applicationDirPath + "/../lib";
+	qDebug() << "PluginManager::loadPlugins: " << qPrintable(applicationDirPath) << ", " << qPrintable(applicationLibPath);
+
+	QDir pluginsBinDir = QDir(applicationDirPath);
+	QDir pluginsLibDir = QDir(applicationLibPath);
+
+	loadPlugins(pluginsBinDir);
+	loadPlugins(pluginsLibDir);
+
+	qSort(m_plugins);
+
+	for (Plugins::const_iterator it = m_plugins.begin(); it != m_plugins.end(); ++it)
+	{
+		it->pluginInterface->initPlugin(&m_pluginAPI);
+	}
+
+	updateSampleSourceDevices();
+	updateSampleSinkDevices();
+}
+
+void PluginManager::registerRxChannel(const QString& channelName, PluginInterface* plugin)
+{
+    qDebug() << "PluginManager::registerRxChannel "
+            << plugin->getPluginDescriptor().displayedName.toStdString().c_str()
+            << " with channel name " << channelName;
+
+	m_rxChannelRegistrations.append(PluginAPI::ChannelRegistration(channelName, plugin));
+}
+
+void PluginManager::registerTxChannel(const QString& channelName, PluginInterface* plugin)
+{
+    qDebug() << "PluginManager::registerTxChannel "
+            << plugin->getPluginDescriptor().displayedName.toStdString().c_str()
+            << " with channel name " << channelName;
+
+	m_txChannelRegistrations.append(PluginAPI::ChannelRegistration(channelName, plugin));
+}
+
+void PluginManager::registerSampleSource(const QString& sourceName, PluginInterface* plugin)
+{
+	qDebug() << "PluginManager::registerSampleSource "
+			<< plugin->getPluginDescriptor().displayedName.toStdString().c_str()
+			<< " with source name " << sourceName.toStdString().c_str();
+
+	m_sampleSourceRegistrations.append(SamplingDeviceRegistration(sourceName, plugin));
+}
+
+void PluginManager::registerSampleSink(const QString& sinkName, PluginInterface* plugin)
+{
+	qDebug() << "PluginManager::registerSampleSink "
+			<< plugin->getPluginDescriptor().displayedName.toStdString().c_str()
+			<< " with sink name " << sinkName.toStdString().c_str();
+
+	m_sampleSinkRegistrations.append(SamplingDeviceRegistration(sinkName, plugin));
+}
+
+void PluginManager::updateSampleSourceDevices()
+{
+	m_sampleSourceDevices.clear();
+
+	for(int i = 0; i < m_sampleSourceRegistrations.count(); ++i)
+	{
+		PluginInterface::SamplingDevices ssd = m_sampleSourceRegistrations[i].m_plugin->enumSampleSources();
+
+		for(int j = 0; j < ssd.count(); ++j)
+		{
+			m_sampleSourceDevices.append(SamplingDevice(m_sampleSourceRegistrations[i].m_plugin,
+					ssd[j].displayedName,
+                    ssd[j].hardwareId,
+					ssd[j].id,
+					ssd[j].serial,
+					ssd[j].sequence));
+		}
+	}
+}
+
+void PluginManager::updateSampleSinkDevices()
+{
+	m_sampleSinkDevices.clear();
+
+	for(int i = 0; i < m_sampleSinkRegistrations.count(); ++i)
+	{
+		PluginInterface::SamplingDevices ssd = m_sampleSinkRegistrations[i].m_plugin->enumSampleSinks();
+
+		for(int j = 0; j < ssd.count(); ++j)
+		{
+			m_sampleSinkDevices.append(SamplingDevice(m_sampleSinkRegistrations[i].m_plugin,
+					ssd[j].displayedName,
+					ssd[j].hardwareId,
+                    ssd[j].id,
+					ssd[j].serial,
+					ssd[j].sequence));
+		}
+	}
+}
+
+void PluginManager::duplicateLocalSampleSourceDevices(uint deviceUID)
+{
+    if (deviceUID == 0) {
+        return;
+    }
+
+    SamplingDevice *sdrDaemonSSD0 = 0;
+    SamplingDevice *sdrDaemonFECSSD0 = 0;
+    SamplingDevice *fileSourceSSD0 = 0;
+    bool duplicateSDRDaemon = true;
+    bool duplicateSDRDaemonFEC = true;
+    bool duplicateFileSource = true;
+
+    for(int i = 0; i < m_sampleSourceDevices.count(); ++i)
+    {
+        if (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonDeviceTypeID) // SDRdaemon
+        {
+            if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0
+                sdrDaemonSSD0 = &m_sampleSourceDevices[i];
+            }
+            else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there
+                duplicateSDRDaemon = false;
+            }
+        }
+        else if (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonFECDeviceTypeID) // SDRdaemon with FEC
+        {
+            if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0
+                sdrDaemonFECSSD0 = &m_sampleSourceDevices[i];
+            }
+            else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there
+                duplicateSDRDaemonFEC = false;
+            }
+        }
+        else if (m_sampleSourceDevices[i].m_deviceId == m_fileSourceDeviceTypeID) // File Source
+        {
+            if (m_sampleSourceDevices[i].m_deviceSequence == 0) { // reference to device 0
+                fileSourceSSD0 = &m_sampleSourceDevices[i];
+            }
+            else if (m_sampleSourceDevices[i].m_deviceSequence == deviceUID) { // already there
+                duplicateFileSource = false;
+            }
+        }
+    }
+
+    if (sdrDaemonSSD0 && duplicateSDRDaemon) // append item for a new instance
+    {
+        m_sampleSourceDevices.append(
+            SamplingDevice(
+                sdrDaemonSSD0->m_plugin,
+                QString("SDRdaemon[%1]").arg(deviceUID),
+                sdrDaemonSSD0->m_hadrwareId,
+                sdrDaemonSSD0->m_deviceId,
+                sdrDaemonSSD0->m_deviceSerial,
+                deviceUID
+            )
+        );
+    }
+
+    if (sdrDaemonFECSSD0 && duplicateSDRDaemonFEC) // append item for a new instance
+    {
+        m_sampleSourceDevices.append(
+            SamplingDevice(
+                sdrDaemonFECSSD0->m_plugin,
+                QString("SDRdaemonFEC[%1]").arg(deviceUID),
+                sdrDaemonFECSSD0->m_hadrwareId,
+                sdrDaemonFECSSD0->m_deviceId,
+                sdrDaemonFECSSD0->m_deviceSerial,
+                deviceUID
+            )
+        );
+    }
+
+    if (fileSourceSSD0 && duplicateFileSource) // append item for a new instance
+    {
+        m_sampleSourceDevices.append(
+            SamplingDevice(
+                fileSourceSSD0->m_plugin,
+                QString("FileSource[%1]").arg(deviceUID),
+                fileSourceSSD0->m_hadrwareId,
+                fileSourceSSD0->m_deviceId,
+                fileSourceSSD0->m_deviceSerial,
+                deviceUID
+            )
+        );
+    }
+}
+
+void PluginManager::duplicateLocalSampleSinkDevices(uint deviceUID)
+{
+    if (deviceUID == 0) {
+        return;
+    }
+
+    SamplingDevice *fileSinkSSD0 = 0;
+    bool duplicateFileSink = true;
+
+    for(int i = 0; i < m_sampleSinkDevices.count(); ++i)
+    {
+        if (m_sampleSinkDevices[i].m_deviceId == m_fileSinkDeviceTypeID) // File Sink
+        {
+            if (m_sampleSinkDevices[i].m_deviceSequence == 0) { // reference to device 0
+            	fileSinkSSD0 = &m_sampleSinkDevices[i];
+            }
+            else if (m_sampleSinkDevices[i].m_deviceSequence == deviceUID) { // already there
+                duplicateFileSink = false;
+            }
+        }
+    }
+
+    if (fileSinkSSD0 && duplicateFileSink) // append item for a new instance
+    {
+    	m_sampleSinkDevices.append(
+            SamplingDevice(
+            	fileSinkSSD0->m_plugin,
+                QString("FileSink[%1]").arg(deviceUID),
+                fileSinkSSD0->m_hadrwareId,
+				fileSinkSSD0->m_deviceId,
+				fileSinkSSD0->m_deviceSerial,
+                deviceUID
+            )
+        );
+    }
+}
+
+void PluginManager::fillSampleSourceSelector(QComboBox* comboBox, uint deviceUID)
+{
+	comboBox->clear();
+
+	for(int i = 0; i < m_sampleSourceDevices.count(); i++)
+	{
+	    // For "local" devices show only ones that concern this device set
+	    if ((m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonDeviceTypeID)
+	            || (m_sampleSourceDevices[i].m_deviceId == m_sdrDaemonFECDeviceTypeID)
+	            || (m_sampleSourceDevices[i].m_deviceId == m_fileSourceDeviceTypeID))
+	    {
+	        if (deviceUID != m_sampleSourceDevices[i].m_deviceSequence) {
+	            continue;
+	        }
+	    }
+
+		comboBox->addItem(m_sampleSourceDevices[i].m_displayName, qVariantFromValue((void *) &m_sampleSourceDevices[i]));
+	}
+}
+
+int PluginManager::getSampleSourceSelectorIndex(QComboBox* comboBox, DeviceSourceAPI *deviceSourceAPI)
+{
+    for (int i = 0; i < comboBox->count(); i++)
+    {
+        SamplingDevice *samplingDevice = (SamplingDevice*) (comboBox->itemData(i)).value();
+
+        if ((samplingDevice->m_deviceId == deviceSourceAPI->getSampleSourceId()) &&
+            (samplingDevice->m_deviceSerial == deviceSourceAPI->getSampleSourceSerial()) &&
+            (samplingDevice->m_deviceSequence == deviceSourceAPI->getSampleSourceSequence()))
+        {
+            return i;
+        }
+    }
+
+    return 0; // default to first item
+}
+
+void PluginManager::fillSampleSinkSelector(QComboBox* comboBox, uint deviceUID)
+{
+	comboBox->clear();
+
+	for(int i = 0; i < m_sampleSinkDevices.count(); i++)
+	{
+	    // For "local" devices show only ones that concern this device set
+	    if (m_sampleSinkDevices[i].m_deviceId == m_fileSinkDeviceTypeID)
+	    {
+	        if (deviceUID != m_sampleSinkDevices[i].m_deviceSequence) {
+	            continue;
+	        }
+	    }
+
+		comboBox->addItem(m_sampleSinkDevices[i].m_displayName, qVariantFromValue((void *) &m_sampleSinkDevices[i]));
+	}
+}
+
+int PluginManager::getSampleSinkSelectorIndex(QComboBox* comboBox, DeviceSinkAPI *deviceSinkAPI)
+{
+    for (int i = 0; i < comboBox->count(); i++)
+    {
+        SamplingDevice *samplingDevice = (SamplingDevice*) (comboBox->itemData(i)).value();
+
+        if ((samplingDevice->m_deviceId == deviceSinkAPI->getSampleSinkId()) &&
+            (samplingDevice->m_deviceSerial == deviceSinkAPI->getSampleSinkSerial()) &&
+            (samplingDevice->m_deviceSequence == deviceSinkAPI->getSampleSinkSequence()))
+        {
+            return i;
+        }
+    }
+
+    return 0; // default to first item
+}
+
+int PluginManager::selectSampleSourceByIndex(int index, DeviceSourceAPI *deviceAPI)
+{
+	qDebug("PluginManager::selectSampleSourceByIndex: index: %d", index);
+
+	if (m_sampleSourceDevices.count() == 0)
+	{
+		return -1;
+	}
+
+	if (index < 0)
+	{
+		return -1;
+	}
+
+	if (index >= m_sampleSourceDevices.count())
+	{
+		index = 0;
+	}
+
+    qDebug() << "PluginManager::selectSampleSourceByIndex: m_sampleSource at index " << index
+            << " hid: " << m_sampleSourceDevices[index].m_hadrwareId.toStdString().c_str()
+            << " id: " << m_sampleSourceDevices[index].m_deviceId.toStdString().c_str()
+            << " ser: " << m_sampleSourceDevices[index].m_deviceSerial.toStdString().c_str()
+            << " seq: " << m_sampleSourceDevices[index].m_deviceSequence;
+
+    deviceAPI->stopAcquisition();
+    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+	QWidget *gui;
+	PluginGUI *pluginGUI = m_sampleSourceDevices[index].m_plugin->createSampleSourcePluginGUI(m_sampleSourceDevices[index].m_deviceId, &gui, deviceAPI);
+
+	//	m_sampleSourcePluginGUI = pluginGUI;
+	deviceAPI->setSampleSourceSequence(m_sampleSourceDevices[index].m_deviceSequence);
+	deviceAPI->setHardwareId(m_sampleSourceDevices[index].m_hadrwareId);
+	deviceAPI->setSampleSourceId(m_sampleSourceDevices[index].m_deviceId);
+	deviceAPI->setSampleSourceSerial(m_sampleSourceDevices[index].m_deviceSerial);
+	deviceAPI->setSampleSourcePluginGUI(pluginGUI);
+	deviceAPI->setInputGUI(gui, m_sampleSourceDevices[index].m_displayName);
+
+	return index;
+}
+
+int PluginManager::selectSampleSinkByIndex(int index, DeviceSinkAPI *deviceAPI)
+{
+	qDebug("PluginManager::selectSampleSinkByIndex: index: %d", index);
+
+	if (m_sampleSinkDevices.count() == 0)
+	{
+		return -1;
+	}
+
+	if (index < 0)
+	{
+		return -1;
+	}
+
+	if (index >= m_sampleSinkDevices.count())
+	{
+		index = 0;
+	}
+
+    qDebug() << "PluginManager::selectSampleSinkByIndex: m_sampleSink at index " << index
+            << " hid: " << m_sampleSinkDevices[index].m_hadrwareId.toStdString().c_str()
+            << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str()
+            << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str()
+            << " seq: " << m_sampleSinkDevices[index].m_deviceSequence;
+
+    deviceAPI->stopGeneration();
+    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+	QWidget *gui;
+	PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI);
+
+	//	m_sampleSourcePluginGUI = pluginGUI;
+	deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence);
+	deviceAPI->setHardwareId(m_sampleSinkDevices[index].m_hadrwareId);
+	deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId);
+	deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial);
+	deviceAPI->setSampleSinkPluginGUI(pluginGUI);
+	deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName);
+
+	return index;
+}
+
+int PluginManager::selectFirstSampleSource(const QString& sourceId, DeviceSourceAPI *deviceAPI)
+{
+	qDebug("PluginManager::selectFirstSampleSource by id: [%s]", qPrintable(sourceId));
+
+	int index = -1;
+
+	for (int i = 0; i < m_sampleSourceDevices.count(); i++)
+	{
+		qDebug("*** %s vs %s", qPrintable(m_sampleSourceDevices[i].m_deviceId), qPrintable(sourceId));
+
+		if(m_sampleSourceDevices[i].m_deviceId == sourceId)
+		{
+			index = i;
+			break;
+		}
+	}
+
+	if(index == -1)
+	{
+		if(m_sampleSourceDevices.count() > 0)
+		{
+			index = 0;
+		}
+		else
+		{
+			return -1;
+		}
+	}
+
+    qDebug() << "PluginManager::selectFirstSampleSource: m_sampleSource at index " << index
+            << " hid: " << m_sampleSourceDevices[index].m_hadrwareId.toStdString().c_str()
+            << " id: " << m_sampleSourceDevices[index].m_deviceId.toStdString().c_str()
+            << " ser: " << m_sampleSourceDevices[index].m_deviceSerial.toStdString().c_str()
+            << " seq: " << m_sampleSourceDevices[index].m_deviceSequence;
+
+    deviceAPI->stopAcquisition();
+    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+    QWidget *gui;
+	PluginGUI *pluginGUI = m_sampleSourceDevices[index].m_plugin->createSampleSourcePluginGUI(m_sampleSourceDevices[index].m_deviceId, &gui, deviceAPI);
+
+	//	m_sampleSourcePluginGUI = pluginGUI;
+    deviceAPI->setSampleSourceSequence(m_sampleSourceDevices[index].m_deviceSequence);
+    deviceAPI->setHardwareId(m_sampleSourceDevices[index].m_hadrwareId);
+    deviceAPI->setSampleSourceId(m_sampleSourceDevices[index].m_deviceId);
+    deviceAPI->setSampleSourceSerial(m_sampleSourceDevices[index].m_deviceSerial);
+    deviceAPI->setSampleSourcePluginGUI(pluginGUI);
+    deviceAPI->setInputGUI(gui, m_sampleSourceDevices[index].m_displayName);
+
+	return index;
+}
+
+int PluginManager::selectFirstSampleSink(const QString& sinkId, DeviceSinkAPI *deviceAPI)
+{
+	qDebug("PluginManager::selectFirstSampleSink by id: [%s]", qPrintable(sinkId));
+
+	int index = -1;
+
+	for (int i = 0; i < m_sampleSinkDevices.count(); i++)
+	{
+		qDebug("*** %s vs %s", qPrintable(m_sampleSinkDevices[i].m_deviceId), qPrintable(sinkId));
+
+		if(m_sampleSinkDevices[i].m_deviceId == sinkId)
+		{
+			index = i;
+			break;
+		}
+	}
+
+	if(index == -1)
+	{
+		if(m_sampleSinkDevices.count() > 0)
+		{
+			index = 0;
+		}
+		else
+		{
+			return -1;
+		}
+	}
+
+    qDebug() << "PluginManager::selectFirstSampleSink: m_sampleSink at index " << index
+            << " hid: " << m_sampleSinkDevices[index].m_hadrwareId.toStdString().c_str()
+            << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str()
+            << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str()
+            << " seq: " << m_sampleSinkDevices[index].m_deviceSequence;
+
+    deviceAPI->stopGeneration();
+    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+    QWidget *gui;
+	PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI);
+
+	//	m_sampleSourcePluginGUI = pluginGUI;
+    deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence);
+    deviceAPI->setHardwareId(m_sampleSinkDevices[index].m_hadrwareId);
+    deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId);
+    deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial);
+    deviceAPI->setSampleSinkPluginGUI(pluginGUI);
+    deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName);
+
+	return index;
+}
+
+int PluginManager::selectSampleSourceBySerialOrSequence(const QString& sourceId, const QString& sourceSerial, int sourceSequence, DeviceSourceAPI *deviceAPI)
+{
+	qDebug("PluginManager::selectSampleSourceBySequence by sequence: id: %s ser: %s seq: %d", qPrintable(sourceId), qPrintable(sourceSerial), sourceSequence);
+
+	int index = -1;
+	int index_matchingSequence = -1;
+	int index_firstOfKind = -1;
+
+	for (int i = 0; i < m_sampleSourceDevices.count(); i++)
+	{
+		if (m_sampleSourceDevices[i].m_deviceId == sourceId)
+		{
+			index_firstOfKind = i;
+
+			if (m_sampleSourceDevices[i].m_deviceSerial == sourceSerial)
+			{
+				index = i; // exact match
+				break;
+			}
+
+			if (m_sampleSourceDevices[i].m_deviceSequence == sourceSequence)
+			{
+				index_matchingSequence = i;
+			}
+		}
+	}
+
+	if(index == -1) // no exact match
+	{
+		if (index_matchingSequence == -1) // no matching sequence
+		{
+			if (index_firstOfKind == -1) // no matching device type
+			{
+				if(m_sampleSourceDevices.count() > 0) // take first if any
+				{
+					index = 0;
+				}
+				else
+				{
+					return -1; // return if no device attached
+				}
+			}
+			else
+			{
+				index = index_firstOfKind; // take first that matches device type
+			}
+		}
+		else
+		{
+			index = index_matchingSequence; // take the one that matches the sequence in the device type
+		}
+	}
+
+    qDebug() << "PluginManager::selectSampleSourceBySequence: m_sampleSource at index " << index
+            << " hid: " << m_sampleSourceDevices[index].m_hadrwareId.toStdString().c_str()
+            << " id: " << m_sampleSourceDevices[index].m_deviceId.toStdString().c_str()
+            << " ser: " << m_sampleSourceDevices[index].m_deviceSerial.toStdString().c_str()
+            << " seq: " << m_sampleSourceDevices[index].m_deviceSequence;
+
+    deviceAPI->stopAcquisition();
+    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+    QWidget *gui;
+	PluginGUI *pluginGUI = m_sampleSourceDevices[index].m_plugin->createSampleSourcePluginGUI(m_sampleSourceDevices[index].m_deviceId, &gui, deviceAPI);
+
+	//	m_sampleSourcePluginGUI = pluginGUI;
+    deviceAPI->setSampleSourceSequence(m_sampleSourceDevices[index].m_deviceSequence);
+    deviceAPI->setHardwareId(m_sampleSourceDevices[index].m_hadrwareId);
+    deviceAPI->setSampleSourceId(m_sampleSourceDevices[index].m_deviceId);
+    deviceAPI->setSampleSourceSerial(m_sampleSourceDevices[index].m_deviceSerial);
+    deviceAPI->setSampleSourcePluginGUI(pluginGUI);
+    deviceAPI->setInputGUI(gui, m_sampleSourceDevices[index].m_displayName);
+
+	return index;
+}
+
+int PluginManager::selectSampleSinkBySerialOrSequence(const QString& sinkId, const QString& sinkSerial, int sinkSequence, DeviceSinkAPI *deviceAPI)
+{
+	qDebug("PluginManager::selectSampleSinkBySerialOrSequence by sequence: id: %s ser: %s seq: %d", qPrintable(sinkId), qPrintable(sinkSerial), sinkSequence);
+
+	int index = -1;
+	int index_matchingSequence = -1;
+	int index_firstOfKind = -1;
+
+	for (int i = 0; i < m_sampleSinkDevices.count(); i++)
+	{
+		if (m_sampleSinkDevices[i].m_deviceId == sinkId)
+		{
+			index_firstOfKind = i;
+
+			if (m_sampleSinkDevices[i].m_deviceSerial == sinkSerial)
+			{
+				index = i; // exact match
+				break;
+			}
+
+			if (m_sampleSinkDevices[i].m_deviceSequence == sinkSequence)
+			{
+				index_matchingSequence = i;
+			}
+		}
+	}
+
+	if(index == -1) // no exact match
+	{
+		if (index_matchingSequence == -1) // no matching sequence
+		{
+			if (index_firstOfKind == -1) // no matching device type
+			{
+				if(m_sampleSinkDevices.count() > 0) // take first if any
+				{
+					index = 0;
+				}
+				else
+				{
+					return -1; // return if no device attached
+				}
+			}
+			else
+			{
+				index = index_firstOfKind; // take first that matches device type
+			}
+		}
+		else
+		{
+			index = index_matchingSequence; // take the one that matches the sequence in the device type
+		}
+	}
+
+    qDebug() << "PluginManager::selectSampleSinkBySerialOrSequence: m_sampleSink at index " << index
+            << " hid: " << m_sampleSinkDevices[index].m_hadrwareId.toStdString().c_str()
+            << " id: " << m_sampleSinkDevices[index].m_deviceId.toStdString().c_str()
+            << " ser: " << m_sampleSinkDevices[index].m_deviceSerial.toStdString().c_str()
+            << " seq: " << m_sampleSinkDevices[index].m_deviceSequence;
+
+    deviceAPI->stopGeneration();
+    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+    QWidget *gui;
+	PluginGUI *pluginGUI = m_sampleSinkDevices[index].m_plugin->createSampleSinkPluginGUI(m_sampleSinkDevices[index].m_deviceId, &gui, deviceAPI);
+
+	//	m_sampleSourcePluginGUI = pluginGUI;
+    deviceAPI->setSampleSinkSequence(m_sampleSinkDevices[index].m_deviceSequence);
+    deviceAPI->setHardwareId(m_sampleSinkDevices[index].m_hadrwareId);
+    deviceAPI->setSampleSinkId(m_sampleSinkDevices[index].m_deviceId);
+    deviceAPI->setSampleSinkSerial(m_sampleSinkDevices[index].m_deviceSerial);
+    deviceAPI->setSampleSinkPluginGUI(pluginGUI);
+    deviceAPI->setOutputGUI(gui, m_sampleSinkDevices[index].m_displayName);
+
+	return index;
+}
+
+void PluginManager::selectSampleSourceByDevice(void *devicePtr, DeviceSourceAPI *deviceAPI)
+{
+    SamplingDevice *sampleSourceDevice = (SamplingDevice *) devicePtr;
+
+    qDebug() << "PluginManager::selectSampleSourceByDevice: "
+            << " hid: " << sampleSourceDevice->m_hadrwareId.toStdString().c_str()
+            << " id: " << sampleSourceDevice->m_deviceId.toStdString().c_str()
+            << " ser: " << sampleSourceDevice->m_deviceSerial.toStdString().c_str()
+            << " seq: " << sampleSourceDevice->m_deviceSequence;
+
+    deviceAPI->setSampleSourcePluginGUI(0); // this effectively destroys the previous GUI if it exists // TODO: move out
+
+    //  m_sampleSourcePluginGUI = pluginGUI;
+    deviceAPI->setSampleSourceSequence(sampleSourceDevice->m_deviceSequence);
+    deviceAPI->setHardwareId(sampleSourceDevice->m_hadrwareId);
+    deviceAPI->setSampleSourceId(sampleSourceDevice->m_deviceId);
+    deviceAPI->setSampleSourceSerial(sampleSourceDevice->m_deviceSerial);
+
+    // TOOD: move out the rest
+
+    QWidget *gui;
+    PluginGUI *pluginGUI = sampleSourceDevice->m_plugin->createSampleSourcePluginGUI(sampleSourceDevice->m_deviceId, &gui, deviceAPI);
+
+    deviceAPI->setSampleSourcePluginGUI(pluginGUI);
+    deviceAPI->setInputGUI(gui, sampleSourceDevice->m_displayName);
+}
+
+void PluginManager::selectSampleSinkByDevice(void *devicePtr, DeviceSinkAPI *deviceAPI)
+{
+    SamplingDevice *sampleSinkDevice = (SamplingDevice *) devicePtr;
+
+    qDebug() << "PluginManager::selectSampleSinkByDevice: "
+            << " hid: " << sampleSinkDevice->m_hadrwareId.toStdString().c_str()
+            << " id: " << sampleSinkDevice->m_deviceId.toStdString().c_str()
+            << " ser: " << sampleSinkDevice->m_deviceSerial.toStdString().c_str()
+            << " seq: " << sampleSinkDevice->m_deviceSequence;
+
+    deviceAPI->setSampleSinkPluginGUI(0); // this effectively destroys the previous GUI if it exists
+
+    //  m_sampleSourcePluginGUI = pluginGUI;
+    deviceAPI->setSampleSinkSequence(sampleSinkDevice->m_deviceSequence);
+    deviceAPI->setHardwareId(sampleSinkDevice->m_hadrwareId);
+    deviceAPI->setSampleSinkId(sampleSinkDevice->m_deviceId);
+    deviceAPI->setSampleSinkSerial(sampleSinkDevice->m_deviceSerial);
+
+    QWidget *gui;
+    PluginGUI *pluginGUI = sampleSinkDevice->m_plugin->createSampleSinkPluginGUI(sampleSinkDevice->m_deviceId, &gui, deviceAPI);
+
+    deviceAPI->setSampleSinkPluginGUI(pluginGUI);
+    deviceAPI->setOutputGUI(gui, sampleSinkDevice->m_displayName);
+}
+
+void PluginManager::loadPlugins(const QDir& dir)
+{
+	QDir pluginsDir(dir);
+
+	foreach (QString fileName, pluginsDir.entryList(QDir::Files))
+	{
+        if (fileName.endsWith(".so") || fileName.endsWith(".dll") || fileName.endsWith(".dylib"))
+		{
+			qDebug() << "PluginManager::loadPlugins: fileName: " << qPrintable(fileName);
+
+			QPluginLoader* loader = new QPluginLoader(pluginsDir.absoluteFilePath(fileName));
+			PluginInterface* plugin = qobject_cast(loader->instance());
+
+			if (loader->isLoaded())
+			{
+				qWarning("PluginManager::loadPlugins: loaded plugin %s", qPrintable(fileName));
+			}
+			else
+			{
+				qWarning() << "PluginManager::loadPlugins: " << qPrintable(loader->errorString());
+			}
+
+			if (plugin != 0)
+			{
+				m_plugins.append(Plugin(fileName, loader, plugin));
+			}
+			else
+			{
+				loader->unload();
+			}
+
+			delete loader; // Valgrind memcheck
+		}
+	}
+
+	// recursive calls on subdirectories
+
+	foreach (QString dirName, pluginsDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
+	{
+		loadPlugins(pluginsDir.absoluteFilePath(dirName));
+	}
+}
+
+void PluginManager::populateRxChannelComboBox(QComboBox *channels)
+{
+    for(PluginAPI::ChannelRegistrations::iterator it = m_rxChannelRegistrations.begin(); it != m_rxChannelRegistrations.end(); ++it)
+    {
+        const PluginDescriptor& pluginDescipror = it->m_plugin->getPluginDescriptor();
+        channels->addItem(pluginDescipror.displayedName);
+    }
+}
+
+void PluginManager::populateTxChannelComboBox(QComboBox *channels)
+{
+    for(PluginAPI::ChannelRegistrations::iterator it = m_txChannelRegistrations.begin(); it != m_txChannelRegistrations.end(); ++it)
+    {
+        const PluginDescriptor& pluginDescipror = it->m_plugin->getPluginDescriptor();
+        channels->addItem(pluginDescipror.displayedName);
+    }
+}
+
+void PluginManager::createRxChannelInstance(int channelPluginIndex, DeviceSourceAPI *deviceAPI)
+{
+    if (channelPluginIndex < m_rxChannelRegistrations.size())
+    {
+        PluginInterface *pluginInterface = m_rxChannelRegistrations[channelPluginIndex].m_plugin;
+        pluginInterface->createRxChannel(m_rxChannelRegistrations[channelPluginIndex].m_channelName, deviceAPI);
+    }
+}
+
+void PluginManager::createTxChannelInstance(int channelPluginIndex, DeviceSinkAPI *deviceAPI)
+{
+    if (channelPluginIndex < m_txChannelRegistrations.size())
+    {
+        PluginInterface *pluginInterface = m_txChannelRegistrations[channelPluginIndex].m_plugin;
+        pluginInterface->createTxChannel(m_txChannelRegistrations[channelPluginIndex].m_channelName, deviceAPI);
+    }
+}