--- qsampler/trunk/src/qsamplerMainForm.cpp 2007/11/06 22:12:32 1475 +++ qsampler/trunk/src/qsamplerMainForm.cpp 2010/01/07 18:42:26 2038 @@ -1,8 +1,8 @@ // qsamplerMainForm.cpp // /**************************************************************************** - Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved. - Copyright (C) 2007, Christian Schoenebeck + Copyright (C) 2004-2010, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2007, 2008 Christian Schoenebeck This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License @@ -20,27 +20,9 @@ *****************************************************************************/ +#include "qsamplerAbout.h" #include "qsamplerMainForm.h" -#include -#include -#include -#include -#include -//#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "qsamplerAbout.h" #include "qsamplerOptions.h" #include "qsamplerChannel.h" #include "qsamplerMessages.h" @@ -51,6 +33,37 @@ #include "qsamplerInstrumentListForm.h" #include "qsamplerDeviceForm.h" #include "qsamplerOptionsForm.h" +#include "qsamplerDeviceStatusForm.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#if QT_VERSION < 0x040500 +namespace Qt { +const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000); +#if QT_VERSION < 0x040200 +const WindowFlags CustomizeWindowHint = WindowFlags(0x02000000); +#endif +} +#endif #ifdef HAVE_SIGNAL_H #include @@ -73,6 +86,15 @@ } #endif + +// All winsock apps needs this. +#if defined(WIN32) +static WSADATA _wsaData; +#endif + + +namespace QSampler { + // Timer constant stuff. #define QSAMPLER_TIMER_MSECS 200 @@ -83,75 +105,69 @@ #define QSAMPLER_STATUS_SESSION 3 // Current session modification state. -// All winsock apps needs this. -#if defined(WIN32) -static WSADATA _wsaData; -#endif - - //------------------------------------------------------------------------- -// qsamplerCustomEvent -- specialty for callback comunication. +// CustomEvent -- specialty for callback comunication. #define QSAMPLER_CUSTOM_EVENT QEvent::Type(QEvent::User + 0) -class qsamplerCustomEvent : public QEvent +class CustomEvent : public QEvent { public: - // Constructor. - qsamplerCustomEvent(lscp_event_t event, const char *pchData, int cchData) - : QEvent(QSAMPLER_CUSTOM_EVENT) - { - m_event = event; - m_data.setLatin1(pchData, cchData); - } - - // Accessors. - lscp_event_t event() { return m_event; } - QString& data() { return m_data; } + // Constructor. + CustomEvent(lscp_event_t event, const char *pchData, int cchData) + : QEvent(QSAMPLER_CUSTOM_EVENT) + { + m_event = event; + m_data = QString::fromUtf8(pchData, cchData); + } + + // Accessors. + lscp_event_t event() { return m_event; } + QString& data() { return m_data; } private: - // The proper event type. - lscp_event_t m_event; - // The event data as a string. - QString m_data; + // The proper event type. + lscp_event_t m_event; + // The event data as a string. + QString m_data; }; //------------------------------------------------------------------------- // qsamplerMainForm -- Main window form implementation. -namespace QSampler { - // Kind of singleton reference. MainForm* MainForm::g_pMainForm = NULL; -MainForm::MainForm(QWidget* parent) : QMainWindow(parent) { - ui.setupUi(this); +MainForm::MainForm ( QWidget *pParent ) + : QMainWindow(pParent) +{ + m_ui.setupUi(this); // Pseudo-singleton reference setup. g_pMainForm = this; - // Initialize some pointer references. - m_pOptions = NULL; + // Initialize some pointer references. + m_pOptions = NULL; - // All child forms are to be created later, not earlier than setup. - m_pMessages = NULL; - m_pInstrumentListForm = NULL; - m_pDeviceForm = NULL; + // All child forms are to be created later, not earlier than setup. + m_pMessages = NULL; + m_pInstrumentListForm = NULL; + m_pDeviceForm = NULL; - // We'll start clean. - m_iUntitled = 0; - m_iDirtyCount = 0; + // We'll start clean. + m_iUntitled = 0; + m_iDirtyCount = 0; - m_pServer = NULL; - m_pClient = NULL; + m_pServer = NULL; + m_pClient = NULL; - m_iStartDelay = 0; - m_iTimerDelay = 0; + m_iStartDelay = 0; + m_iTimerDelay = 0; - m_iTimerSlot = 0; + m_iTimerSlot = 0; #ifdef HAVE_SIGNAL_H // Set to ignore any fatal "Broken pipe" signals. @@ -159,293 +175,308 @@ #endif #ifdef CONFIG_VOLUME - // Make some extras into the toolbar... + // Make some extras into the toolbar... const QString& sVolumeText = tr("Master volume"); m_iVolumeChanging = 0; // Volume slider... - ui.channelsToolbar->addSeparator(); - m_pVolumeSlider = new QSlider(Qt::Horizontal, ui.channelsToolbar); - m_pVolumeSlider->setTickmarks(QSlider::Below); + m_ui.channelsToolbar->addSeparator(); + m_pVolumeSlider = new QSlider(Qt::Horizontal, m_ui.channelsToolbar); + m_pVolumeSlider->setTickPosition(QSlider::TicksBothSides); m_pVolumeSlider->setTickInterval(10); m_pVolumeSlider->setPageStep(10); - m_pVolumeSlider->setRange(0, 100); + m_pVolumeSlider->setSingleStep(10); + m_pVolumeSlider->setMinimum(0); + m_pVolumeSlider->setMaximum(100); m_pVolumeSlider->setMaximumHeight(26); m_pVolumeSlider->setMinimumWidth(160); - QToolTip::add(m_pVolumeSlider, sVolumeText); + m_pVolumeSlider->setToolTip(sVolumeText); QObject::connect(m_pVolumeSlider, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); - //ui.channelsToolbar->setHorizontallyStretchable(true); - //ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider); - ui.channelsToolbar->addWidget(m_pVolumeSlider); + //m_ui.channelsToolbar->setHorizontallyStretchable(true); + //m_ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider); + m_ui.channelsToolbar->addWidget(m_pVolumeSlider); // Volume spin-box - ui.channelsToolbar->addSeparator(); - m_pVolumeSpinBox = new QSpinBox(ui.channelsToolbar); + m_ui.channelsToolbar->addSeparator(); + m_pVolumeSpinBox = new QSpinBox(m_ui.channelsToolbar); + m_pVolumeSpinBox->setMaximumHeight(24); m_pVolumeSpinBox->setSuffix(" %"); - m_pVolumeSpinBox->setRange(0, 100); - QToolTip::add(m_pVolumeSpinBox, sVolumeText); + m_pVolumeSpinBox->setMinimum(0); + m_pVolumeSpinBox->setMaximum(100); + m_pVolumeSpinBox->setToolTip(sVolumeText); QObject::connect(m_pVolumeSpinBox, SIGNAL(valueChanged(int)), SLOT(volumeChanged(int))); - ui.channelsToolbar->addWidget(m_pVolumeSpinBox); + m_ui.channelsToolbar->addWidget(m_pVolumeSpinBox); #endif - // Make it an MDI workspace. - m_pWorkspace = new QWorkspace(this); - m_pWorkspace->setScrollBarsEnabled(true); + // Make it an MDI workspace. + m_pWorkspace = new QWorkspace(this); + m_pWorkspace->setScrollBarsEnabled(true); // Set the activation connection. QObject::connect(m_pWorkspace, SIGNAL(windowActivated(QWidget *)), - SLOT(stabilizeForm())); - // Make it shine :-) - setCentralWidget(m_pWorkspace); - - // Create some statusbar labels... - QLabel *pLabel; - // Client status. - pLabel = new QLabel(tr("Connected"), this); - pLabel->setAlignment(Qt::AlignLeft); - pLabel->setMinimumSize(pLabel->sizeHint()); - m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel; - statusBar()->addWidget(pLabel); - // Server address. - pLabel = new QLabel(this); - pLabel->setAlignment(Qt::AlignLeft); - m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel; - statusBar()->addWidget(pLabel, 1); - // Channel title. - pLabel = new QLabel(this); - pLabel->setAlignment(Qt::AlignLeft); - m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel; - statusBar()->addWidget(pLabel, 2); - // Session modification status. - pLabel = new QLabel(tr("MOD"), this); - pLabel->setAlignment(Qt::AlignHCenter); - pLabel->setMinimumSize(pLabel->sizeHint()); - m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel; - statusBar()->addWidget(pLabel); - - // Create the recent files sub-menu. - m_pRecentFilesMenu = new Q3PopupMenu(this); - ui.fileMenu->insertSeparator(4); - ui.fileMenu->insertItem(tr("Recent &Files"), m_pRecentFilesMenu, 0, 5); + SLOT(activateStrip(QWidget *))); + // Make it shine :-) + setCentralWidget(m_pWorkspace); + + // Create some statusbar labels... + QLabel *pLabel; + // Client status. + pLabel = new QLabel(tr("Connected"), this); + pLabel->setAlignment(Qt::AlignLeft); + pLabel->setMinimumSize(pLabel->sizeHint()); + m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel; + statusBar()->addWidget(pLabel); + // Server address. + pLabel = new QLabel(this); + pLabel->setAlignment(Qt::AlignLeft); + m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel; + statusBar()->addWidget(pLabel, 1); + // Channel title. + pLabel = new QLabel(this); + pLabel->setAlignment(Qt::AlignLeft); + m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel; + statusBar()->addWidget(pLabel, 2); + // Session modification status. + pLabel = new QLabel(tr("MOD"), this); + pLabel->setAlignment(Qt::AlignHCenter); + pLabel->setMinimumSize(pLabel->sizeHint()); + m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel; + statusBar()->addWidget(pLabel); #if defined(WIN32) - WSAStartup(MAKEWORD(1, 1), &_wsaData); + WSAStartup(MAKEWORD(1, 1), &_wsaData); #endif - QObject::connect(ui.fileNewAction, - SIGNAL(activated()), + // Some actions surely need those + // shortcuts firmly attached... + addAction(m_ui.viewMenubarAction); + addAction(m_ui.viewToolbarAction); + + QObject::connect(m_ui.fileNewAction, + SIGNAL(triggered()), SLOT(fileNew())); - QObject::connect(ui.fileOpenAction, - SIGNAL(activated()), + QObject::connect(m_ui.fileOpenAction, + SIGNAL(triggered()), SLOT(fileOpen())); - QObject::connect(ui.fileSaveAction, - SIGNAL(activated()), + QObject::connect(m_ui.fileSaveAction, + SIGNAL(triggered()), SLOT(fileSave())); - QObject::connect(ui.fileSaveAsAction, - SIGNAL(activated()), + QObject::connect(m_ui.fileSaveAsAction, + SIGNAL(triggered()), SLOT(fileSaveAs())); - QObject::connect(ui.fileResetAction, - SIGNAL(activated()), + QObject::connect(m_ui.fileResetAction, + SIGNAL(triggered()), SLOT(fileReset())); - QObject::connect(ui.fileRestartAction, - SIGNAL(activated()), + QObject::connect(m_ui.fileRestartAction, + SIGNAL(triggered()), SLOT(fileRestart())); - QObject::connect(ui.fileExitAction, - SIGNAL(activated()), + QObject::connect(m_ui.fileExitAction, + SIGNAL(triggered()), SLOT(fileExit())); - QObject::connect(ui.editAddChannelAction, - SIGNAL(activated()), + QObject::connect(m_ui.editAddChannelAction, + SIGNAL(triggered()), SLOT(editAddChannel())); - QObject::connect(ui.editRemoveChannelAction, - SIGNAL(activated()), + QObject::connect(m_ui.editRemoveChannelAction, + SIGNAL(triggered()), SLOT(editRemoveChannel())); - QObject::connect(ui.editSetupChannelAction, - SIGNAL(activated()), + QObject::connect(m_ui.editSetupChannelAction, + SIGNAL(triggered()), SLOT(editSetupChannel())); - QObject::connect(ui.editEditChannelAction, - SIGNAL(activated()), + QObject::connect(m_ui.editEditChannelAction, + SIGNAL(triggered()), SLOT(editEditChannel())); - QObject::connect(ui.editResetChannelAction, - SIGNAL(activated()), + QObject::connect(m_ui.editResetChannelAction, + SIGNAL(triggered()), SLOT(editResetChannel())); - QObject::connect(ui.editResetAllChannelsAction, - SIGNAL(activated()), + QObject::connect(m_ui.editResetAllChannelsAction, + SIGNAL(triggered()), SLOT(editResetAllChannels())); - QObject::connect(ui.viewMenubarAction, + QObject::connect(m_ui.viewMenubarAction, SIGNAL(toggled(bool)), SLOT(viewMenubar(bool))); - QObject::connect(ui.viewToolbarAction, + QObject::connect(m_ui.viewToolbarAction, SIGNAL(toggled(bool)), SLOT(viewToolbar(bool))); - QObject::connect(ui.viewStatusbarAction, + QObject::connect(m_ui.viewStatusbarAction, SIGNAL(toggled(bool)), SLOT(viewStatusbar(bool))); - QObject::connect(ui.viewMessagesAction, + QObject::connect(m_ui.viewMessagesAction, SIGNAL(toggled(bool)), SLOT(viewMessages(bool))); - QObject::connect(ui.viewInstrumentsAction, - SIGNAL(activated()), + QObject::connect(m_ui.viewInstrumentsAction, + SIGNAL(triggered()), SLOT(viewInstruments())); - QObject::connect(ui.viewDevicesAction, - SIGNAL(activated()), + QObject::connect(m_ui.viewDevicesAction, + SIGNAL(triggered()), SLOT(viewDevices())); - QObject::connect(ui.viewOptionsAction, - SIGNAL(activated()), + QObject::connect(m_ui.viewOptionsAction, + SIGNAL(triggered()), SLOT(viewOptions())); - QObject::connect(ui.channelsArrangeAction, - SIGNAL(activated()), + QObject::connect(m_ui.channelsArrangeAction, + SIGNAL(triggered()), SLOT(channelsArrange())); - QObject::connect(ui.channelsAutoArrangeAction, + QObject::connect(m_ui.channelsAutoArrangeAction, SIGNAL(toggled(bool)), SLOT(channelsAutoArrange(bool))); - QObject::connect(ui.helpAboutAction, - SIGNAL(activated()), + QObject::connect(m_ui.helpAboutAction, + SIGNAL(triggered()), SLOT(helpAbout())); - QObject::connect(ui.helpAboutQtAction, - SIGNAL(activated()), + QObject::connect(m_ui.helpAboutQtAction, + SIGNAL(triggered()), SLOT(helpAboutQt())); + + QObject::connect(m_ui.fileMenu, + SIGNAL(aboutToShow()), + SLOT(updateRecentFilesMenu())); + QObject::connect(m_ui.channelsMenu, + SIGNAL(aboutToShow()), + SLOT(channelsMenuAboutToShow())); } // Destructor. MainForm::~MainForm() { - // Do final processing anyway. - processServerExit(); + // Do final processing anyway. + processServerExit(); #if defined(WIN32) - WSACleanup(); + WSACleanup(); #endif - // Finally drop any widgets around... - if (m_pDeviceForm) - delete m_pDeviceForm; - if (m_pInstrumentListForm) - delete m_pInstrumentListForm; - if (m_pMessages) - delete m_pMessages; - if (m_pWorkspace) - delete m_pWorkspace; - - // Delete status item labels one by one. - if (m_statusItem[QSAMPLER_STATUS_CLIENT]) - delete m_statusItem[QSAMPLER_STATUS_CLIENT]; - if (m_statusItem[QSAMPLER_STATUS_SERVER]) - delete m_statusItem[QSAMPLER_STATUS_SERVER]; - if (m_statusItem[QSAMPLER_STATUS_CHANNEL]) - delete m_statusItem[QSAMPLER_STATUS_CHANNEL]; - if (m_statusItem[QSAMPLER_STATUS_SESSION]) - delete m_statusItem[QSAMPLER_STATUS_SESSION]; + // Finally drop any widgets around... + if (m_pDeviceForm) + delete m_pDeviceForm; + if (m_pInstrumentListForm) + delete m_pInstrumentListForm; + if (m_pMessages) + delete m_pMessages; + if (m_pWorkspace) + delete m_pWorkspace; + + // Delete status item labels one by one. + if (m_statusItem[QSAMPLER_STATUS_CLIENT]) + delete m_statusItem[QSAMPLER_STATUS_CLIENT]; + if (m_statusItem[QSAMPLER_STATUS_SERVER]) + delete m_statusItem[QSAMPLER_STATUS_SERVER]; + if (m_statusItem[QSAMPLER_STATUS_CHANNEL]) + delete m_statusItem[QSAMPLER_STATUS_CHANNEL]; + if (m_statusItem[QSAMPLER_STATUS_SESSION]) + delete m_statusItem[QSAMPLER_STATUS_SESSION]; #ifdef CONFIG_VOLUME delete m_pVolumeSpinBox; delete m_pVolumeSlider; #endif - // Delete recentfiles menu. - if (m_pRecentFilesMenu) - delete m_pRecentFilesMenu; - // Pseudo-singleton reference shut-down. g_pMainForm = NULL; } // Make and set a proper setup options step. -void MainForm::setup ( qsamplerOptions *pOptions ) +void MainForm::setup ( Options *pOptions ) { - // We got options? - m_pOptions = pOptions; + // We got options? + m_pOptions = pOptions; - // What style do we create these forms? - Qt::WFlags wflags = Qt::WStyle_Customize - | Qt::WStyle_NormalBorder - | Qt::WStyle_Title - | Qt::WStyle_SysMenu - | Qt::WStyle_MinMax - | Qt::WType_TopLevel; - if (m_pOptions->bKeepOnTop) - wflags |= Qt::WStyle_Tool; - // Some child forms are to be created right now. - m_pMessages = new qsamplerMessages(this); - m_pDeviceForm = new DeviceForm(this, wflags); + // What style do we create these forms? + Qt::WindowFlags wflags = Qt::Window + | Qt::CustomizeWindowHint + | Qt::WindowTitleHint + | Qt::WindowSystemMenuHint + | Qt::WindowMinMaxButtonsHint + | Qt::WindowCloseButtonHint; + if (m_pOptions->bKeepOnTop) + wflags |= Qt::Tool; + + // Some child forms are to be created right now. + m_pMessages = new Messages(this); + m_pDeviceForm = new DeviceForm(this, wflags); #ifdef CONFIG_MIDI_INSTRUMENT - m_pInstrumentListForm = new InstrumentListForm(this, wflags); - QObject::connect(&m_pInstrumentListForm->model, - SIGNAL(instrumentsChanged()), - SLOT(sessionDirty())); + m_pInstrumentListForm = new InstrumentListForm(this, wflags); #else - viewInstrumentsAction->setEnabled(false); + m_ui.viewInstrumentsAction->setEnabled(false); #endif - // Set message defaults... - updateMessagesFont(); - updateMessagesLimit(); - updateMessagesCapture(); - // Set the visibility signal. + + // Setup messages logging appropriately... + m_pMessages->setLogging( + m_pOptions->bMessagesLog, + m_pOptions->sMessagesLogPath); + + // Set message defaults... + updateMessagesFont(); + updateMessagesLimit(); + updateMessagesCapture(); + // Set the visibility signal. QObject::connect(m_pMessages, SIGNAL(visibilityChanged(bool)), SLOT(stabilizeForm())); - // Initial decorations toggle state. - ui.viewMenubarAction->setOn(m_pOptions->bMenubar); - ui.viewToolbarAction->setOn(m_pOptions->bToolbar); - ui.viewStatusbarAction->setOn(m_pOptions->bStatusbar); - ui.channelsAutoArrangeAction->setOn(m_pOptions->bAutoArrange); - - // Initial decorations visibility state. - viewMenubar(m_pOptions->bMenubar); - viewToolbar(m_pOptions->bToolbar); - viewStatusbar(m_pOptions->bStatusbar); - - addDockWidget(Qt::BottomDockWidgetArea, m_pMessages); - - // Restore whole toolbar & dock windows states. - QString sDockables = m_pOptions->settings().readEntry("/Layout/DockWindowsBase64" , QString::null); - if (!sDockables.isEmpty()) { - restoreState(QByteArray::fromBase64(sDockables.toAscii())); - } - // Try to restore old window positioning and initial visibility. - m_pOptions->loadWidgetGeometry(this); - m_pOptions->loadWidgetGeometry(m_pInstrumentListForm); - m_pOptions->loadWidgetGeometry(m_pDeviceForm); - - // Final startup stabilization... - updateMaxVolume(); - updateRecentFilesMenu(); - stabilizeForm(); + // Initial decorations toggle state. + m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar); + m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar); + m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar); + m_ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange); + + // Initial decorations visibility state. + viewMenubar(m_pOptions->bMenubar); + viewToolbar(m_pOptions->bToolbar); + viewStatusbar(m_pOptions->bStatusbar); + + addDockWidget(Qt::BottomDockWidgetArea, m_pMessages); + + // Restore whole dock windows state. + QByteArray aDockables = m_pOptions->settings().value( + "/Layout/DockWindows").toByteArray(); + if (!aDockables.isEmpty()) { + restoreState(aDockables); + } + + // Try to restore old window positioning and initial visibility. + m_pOptions->loadWidgetGeometry(this); + m_pOptions->loadWidgetGeometry(m_pInstrumentListForm); + m_pOptions->loadWidgetGeometry(m_pDeviceForm); + + // Final startup stabilization... + updateMaxVolume(); + updateRecentFilesMenu(); + stabilizeForm(); - // Make it ready :-) - statusBar()->message(tr("Ready"), 3000); + // Make it ready :-) + statusBar()->showMessage(tr("Ready"), 3000); - // We'll try to start immediately... - startSchedule(0); + // We'll try to start immediately... + startSchedule(0); - // Register the first timer slot. - QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot())); + // Register the first timer slot. + QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot())); } // Window close event handlers. bool MainForm::queryClose (void) { - bool bQueryClose = closeSession(false); + bool bQueryClose = closeSession(false); - // Try to save current general state... - if (m_pOptions) { - // Some windows default fonts is here on demand too. - if (bQueryClose && m_pMessages) - m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); - // Try to save current positioning. - if (bQueryClose) { - // Save decorations state. - m_pOptions->bMenubar = ui.MenuBar->isVisible(); - m_pOptions->bToolbar = (ui.fileToolbar->isVisible() || ui.editToolbar->isVisible() || ui.channelsToolbar->isVisible()); - m_pOptions->bStatusbar = statusBar()->isVisible(); - // Save the dock windows state. - const QString sDockables = saveState().toBase64().data(); - m_pOptions->settings().writeEntry("/Layout/DockWindowsBase64", sDockables); - // And the children, and the main windows state,. + // Try to save current general state... + if (m_pOptions) { + // Some windows default fonts is here on demand too. + if (bQueryClose && m_pMessages) + m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); + // Try to save current positioning. + if (bQueryClose) { + // Save decorations state. + m_pOptions->bMenubar = m_ui.MenuBar->isVisible(); + m_pOptions->bToolbar = (m_ui.fileToolbar->isVisible() + || m_ui.editToolbar->isVisible() + || m_ui.channelsToolbar->isVisible()); + m_pOptions->bStatusbar = statusBar()->isVisible(); + // Save the dock windows state. + const QString sDockables = saveState().toBase64().data(); + m_pOptions->settings().setValue("/Layout/DockWindows", saveState()); + // And the children, and the main windows state,. m_pOptions->saveWidgetGeometry(m_pDeviceForm); m_pOptions->saveWidgetGeometry(m_pInstrumentListForm); m_pOptions->saveWidgetGeometry(this); @@ -454,116 +485,166 @@ m_pInstrumentListForm->close(); if (m_pDeviceForm) m_pDeviceForm->close(); - // Stop client and/or server, gracefully. - stopServer(); - } - } + // Stop client and/or server, gracefully. + stopServer(true /*interactive*/); + } + } - return bQueryClose; + return bQueryClose; } void MainForm::closeEvent ( QCloseEvent *pCloseEvent ) { - if (queryClose()) - pCloseEvent->accept(); - else - pCloseEvent->ignore(); -} - - -// Drag'n'drop file handler. -bool MainForm::decodeDragFiles ( const QMimeSource *pEvent, QStringList& files ) -{ - bool bDecode = false; - - if (Q3TextDrag::canDecode(pEvent)) { - QString sText; - bDecode = Q3TextDrag::decode(pEvent, sText); - if (bDecode) { - files = QStringList::split('\n', sText); - for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) - *iter = QUrl((*iter).stripWhiteSpace().replace(QRegExp("^file:"), QString::null)).path(); - } - } - - return bDecode; + if (queryClose()) { + DeviceStatusForm::deleteAllInstances(); + pCloseEvent->accept(); + } else + pCloseEvent->ignore(); } // Window drag-n-drop event handlers. void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent ) { - QStringList files; - pDragEnterEvent->accept(decodeDragFiles(pDragEnterEvent, files)); + // Accept external drags only... + if (pDragEnterEvent->source() == NULL + && pDragEnterEvent->mimeData()->hasUrls()) { + pDragEnterEvent->accept(); + } else { + pDragEnterEvent->ignore(); + } } void MainForm::dropEvent ( QDropEvent* pDropEvent ) { - QStringList files; - - if (!decodeDragFiles(pDropEvent, files)) - return; + // Accept externally originated drops only... + if (pDropEvent->source()) + return; - for (QStringList::Iterator iter = files.begin(); iter != files.end(); iter++) { - const QString& sPath = *iter; - if (qsamplerChannel::isInstrumentFile(sPath)) { - // Try to create a new channel from instrument file... - qsamplerChannel *pChannel = new qsamplerChannel(); - if (pChannel == NULL) - return; - // Start setting the instrument filename... - pChannel->setInstrument(sPath, 0); - // Before we show it up, may be we'll - // better ask for some initial values? - if (!pChannel->channelSetup(this)) { - delete pChannel; - return; - } - // Finally, give it to a new channel strip... - if (!createChannelStrip(pChannel)) { - delete pChannel; - return; + const QMimeData *pMimeData = pDropEvent->mimeData(); + if (pMimeData->hasUrls()) { + QListIterator iter(pMimeData->urls()); + while (iter.hasNext()) { + const QString& sPath = iter.next().toLocalFile(); + if (Channel::isInstrumentFile(sPath)) { + // Try to create a new channel from instrument file... + Channel *pChannel = new Channel(); + if (pChannel == NULL) + return; + // Start setting the instrument filename... + pChannel->setInstrument(sPath, 0); + // Before we show it up, may be we'll + // better ask for some initial values? + if (!pChannel->channelSetup(this)) { + delete pChannel; + return; + } + // Finally, give it to a new channel strip... + if (!createChannelStrip(pChannel)) { + delete pChannel; + return; + } + // Make that an overall update. + m_iDirtyCount++; + stabilizeForm(); + } // Otherwise, load an usual session file (LSCP script)... + else if (closeSession(true)) { + loadSessionFile(sPath); + break; } - // Make that an overall update. - m_iDirtyCount++; - stabilizeForm(); - } // Otherwise, load an usual session file (LSCP script)... - else if (closeSession(true)) { - loadSessionFile(sPath); - break; } // Make it look responsive...:) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } } + // Custome event handler. void MainForm::customEvent(QEvent* pCustomEvent) { - // For the time being, just pump it to messages. - if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) { - qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent; - if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) { - int iChannelID = pEvent->data().toInt(); - ChannelStrip *pChannelStrip = channelStrip(iChannelID); - if (pChannelStrip) - channelStripChanged(pChannelStrip); - } else { - appendMessagesColor(tr("Notify event: %1 data: %2") - .arg(::lscp_event_to_text(pEvent->event())) - .arg(pEvent->data()), "#996699"); + // For the time being, just pump it to messages. + if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) { + CustomEvent *pEvent = static_cast (pCustomEvent); + switch (pEvent->event()) { + case LSCP_EVENT_CHANNEL_COUNT: + updateAllChannelStrips(true); + break; + case LSCP_EVENT_CHANNEL_INFO: { + int iChannelID = pEvent->data().toInt(); + ChannelStrip *pChannelStrip = channelStrip(iChannelID); + if (pChannelStrip) + channelStripChanged(pChannelStrip); + break; + } + case LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT: + if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); + DeviceStatusForm::onDevicesChanged(); + updateViewMidiDeviceStatusMenu(); + break; + case LSCP_EVENT_MIDI_INPUT_DEVICE_INFO: { + if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); + const int iDeviceID = pEvent->data().section(' ', 0, 0).toInt(); + DeviceStatusForm::onDeviceChanged(iDeviceID); + break; + } + case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT: + if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); + break; + case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO: + if (m_pDeviceForm) m_pDeviceForm->refreshDevices(); + break; + #if CONFIG_EVENT_CHANNEL_MIDI + case LSCP_EVENT_CHANNEL_MIDI: { + const int iChannelID = pEvent->data().section(' ', 0, 0).toInt(); + ChannelStrip *pChannelStrip = channelStrip(iChannelID); + if (pChannelStrip) + pChannelStrip->midiActivityLedOn(); + break; + } + #endif + #if CONFIG_EVENT_DEVICE_MIDI + case LSCP_EVENT_DEVICE_MIDI: { + const int iDeviceID = pEvent->data().section(' ', 0, 0).toInt(); + const int iPortID = pEvent->data().section(' ', 1, 1).toInt(); + DeviceStatusForm *pDeviceStatusForm + = DeviceStatusForm::getInstance(iDeviceID); + if (pDeviceStatusForm) + pDeviceStatusForm->midiArrived(iPortID); + break; + } + #endif + default: + appendMessagesColor(tr("Notify event: %1 data: %2") + .arg(::lscp_event_to_text(pEvent->event())) + .arg(pEvent->data()), "#996699"); } - } + } } + +void MainForm::updateViewMidiDeviceStatusMenu (void) +{ + m_ui.viewMidiDeviceStatusMenu->clear(); + const std::map statusForms + = DeviceStatusForm::getInstances(); + std::map::const_iterator iter + = statusForms.begin(); + for ( ; iter != statusForms.end(); ++iter) { + DeviceStatusForm *pStatusForm = iter->second; + m_ui.viewMidiDeviceStatusMenu->addAction( + pStatusForm->visibleAction()); + } +} + + // Context menu event handler. void MainForm::contextMenuEvent( QContextMenuEvent *pEvent ) { - stabilizeForm(); + stabilizeForm(); - ui.editMenu->exec(pEvent->globalPos()); + m_ui.editMenu->exec(pEvent->globalPos()); } @@ -571,16 +652,16 @@ // qsamplerMainForm -- Brainless public property accessors. // The global options settings property. -qsamplerOptions *MainForm::options (void) +Options *MainForm::options (void) const { - return m_pOptions; + return m_pOptions; } // The LSCP client descriptor property. -lscp_client_t *MainForm::client (void) +lscp_client_t *MainForm::client (void) const { - return m_pClient; + return m_pClient; } @@ -597,201 +678,205 @@ // Format the displayable session filename. QString MainForm::sessionName ( const QString& sFilename ) { - bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath); - QString sSessionName = sFilename; - if (sSessionName.isEmpty()) - sSessionName = tr("Untitled") + QString::number(m_iUntitled); - else if (!bCompletePath) - sSessionName = QFileInfo(sSessionName).fileName(); - return sSessionName; + bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath); + QString sSessionName = sFilename; + if (sSessionName.isEmpty()) + sSessionName = tr("Untitled") + QString::number(m_iUntitled); + else if (!bCompletePath) + sSessionName = QFileInfo(sSessionName).fileName(); + return sSessionName; } // Create a new session file from scratch. bool MainForm::newSession (void) { - // Check if we can do it. - if (!closeSession(true)) - return false; + // Check if we can do it. + if (!closeSession(true)) + return false; // Give us what the server has, right now... updateSession(); - // Ok increment untitled count. - m_iUntitled++; + // Ok increment untitled count. + m_iUntitled++; - // Stabilize form. - m_sFilename = QString::null; - m_iDirtyCount = 0; - appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename))); - stabilizeForm(); + // Stabilize form. + m_sFilename = QString::null; + m_iDirtyCount = 0; + appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename))); + stabilizeForm(); - return true; + return true; } // Open an existing sampler session. bool MainForm::openSession (void) { - if (m_pOptions == NULL) - return false; + if (m_pOptions == NULL) + return false; + + // Ask for the filename to open... + QString sFilename = QFileDialog::getOpenFileName(this, + QSAMPLER_TITLE ": " + tr("Open Session"), // Caption. + m_pOptions->sSessionDir, // Start here. + tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files) + ); + + // Have we cancelled? + if (sFilename.isEmpty()) + return false; - // Ask for the filename to open... - QString sFilename = QFileDialog::getOpenFileName( - m_pOptions->sSessionDir, // Start here. - tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files) - this, 0, // Parent and name (none) - QSAMPLER_TITLE ": " + tr("Open Session") // Caption. - ); - - // Have we cancelled? - if (sFilename.isEmpty()) - return false; - - // Check if we're going to discard safely the current one... - if (!closeSession(true)) - return false; + // Check if we're going to discard safely the current one... + if (!closeSession(true)) + return false; - // Load it right away. - return loadSessionFile(sFilename); + // Load it right away. + return loadSessionFile(sFilename); } // Save current sampler session with another name. bool MainForm::saveSession ( bool bPrompt ) { - if (m_pOptions == NULL) - return false; + if (m_pOptions == NULL) + return false; - QString sFilename = m_sFilename; + QString sFilename = m_sFilename; - // Ask for the file to save, if there's none... - if (bPrompt || sFilename.isEmpty()) { - // If none is given, assume default directory. - if (sFilename.isEmpty()) - sFilename = m_pOptions->sSessionDir; - // Prompt the guy... - sFilename = QFileDialog::getSaveFileName( - sFilename, // Start here. - tr("LSCP Session files") + " (*.lscp)", // Filter (LSCP files) - this, 0, // Parent and name (none) - QSAMPLER_TITLE ": " + tr("Save Session") // Caption. - ); - // Have we cancelled it? - if (sFilename.isEmpty()) - return false; - // Enforce .lscp extension... - if (QFileInfo(sFilename).extension().isEmpty()) - sFilename += ".lscp"; - // Check if already exists... - if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) { - if (QMessageBox::warning(this, + // Ask for the file to save, if there's none... + if (bPrompt || sFilename.isEmpty()) { + // If none is given, assume default directory. + if (sFilename.isEmpty()) + sFilename = m_pOptions->sSessionDir; + // Prompt the guy... + sFilename = QFileDialog::getSaveFileName(this, + QSAMPLER_TITLE ": " + tr("Save Session"), // Caption. + sFilename, // Start here. + tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files) + ); + // Have we cancelled it? + if (sFilename.isEmpty()) + return false; + // Enforce .lscp extension... + if (QFileInfo(sFilename).suffix().isEmpty()) + sFilename += ".lscp"; + // Check if already exists... + if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) { + if (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), - tr("The file already exists:\n\n" - "\"%1\"\n\n" - "Do you want to replace it?") - .arg(sFilename), - tr("Replace"), tr("Cancel")) > 0) - return false; - } - } + tr("The file already exists:\n\n" + "\"%1\"\n\n" + "Do you want to replace it?") + .arg(sFilename), + QMessageBox::Yes | QMessageBox::No) + == QMessageBox::No) + return false; + } + } - // Save it right away. - return saveSessionFile(sFilename); + // Save it right away. + return saveSessionFile(sFilename); } // Close current session. bool MainForm::closeSession ( bool bForce ) { - bool bClose = true; + bool bClose = true; - // Are we dirty enough to prompt it? - if (m_iDirtyCount > 0) { - switch (QMessageBox::warning(this, + // Are we dirty enough to prompt it? + if (m_iDirtyCount > 0) { + switch (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), - tr("The current session has been changed:\n\n" - "\"%1\"\n\n" - "Do you want to save the changes?") - .arg(sessionName(m_sFilename)), - tr("Save"), tr("Discard"), tr("Cancel"))) { - case 0: // Save... - bClose = saveSession(false); - // Fall thru.... - case 1: // Discard - break; - default: // Cancel. - bClose = false; - break; - } - } - - // If we may close it, dot it. - if (bClose) { - // Remove all channel strips from sight... - m_pWorkspace->setUpdatesEnabled(false); - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - if (pChannelStrip) { - qsamplerChannel *pChannel = pChannelStrip->channel(); - if (bForce && pChannel) - pChannel->removeChannel(); - delete pChannelStrip; - } - } - m_pWorkspace->setUpdatesEnabled(true); - // We're now clean, for sure. - m_iDirtyCount = 0; - } + tr("The current session has been changed:\n\n" + "\"%1\"\n\n" + "Do you want to save the changes?") + .arg(sessionName(m_sFilename)), + QMessageBox::Save | + QMessageBox::Discard | + QMessageBox::Cancel)) { + case QMessageBox::Save: + bClose = saveSession(false); + // Fall thru.... + case QMessageBox::Discard: + break; + default: // Cancel. + bClose = false; + break; + } + } + + // If we may close it, dot it. + if (bClose) { + // Remove all channel strips from sight... + m_pWorkspace->setUpdatesEnabled(false); + QWidgetList wlist = m_pWorkspace->windowList(); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + if (pChannelStrip) { + Channel *pChannel = pChannelStrip->channel(); + if (bForce && pChannel) + pChannel->removeChannel(); + delete pChannelStrip; + } + } + m_pWorkspace->setUpdatesEnabled(true); + // We're now clean, for sure. + m_iDirtyCount = 0; + } - return bClose; + return bClose; } // Load a session from specific file path. bool MainForm::loadSessionFile ( const QString& sFilename ) { - if (m_pClient == NULL) - return false; + if (m_pClient == NULL) + return false; - // Open and read from real file. - QFile file(sFilename); - if (!file.open(IO_ReadOnly)) { - appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename)); - return false; - } + // Open and read from real file. + QFile file(sFilename); + if (!file.open(QIODevice::ReadOnly)) { + appendMessagesError( + tr("Could not open \"%1\" session file.\n\nSorry.") + .arg(sFilename)); + return false; + } // Tell the world we'll take some time... QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - // Read the file. + // Read the file. int iLine = 0; - int iErrors = 0; - QTextStream ts(&file); - while (!ts.atEnd()) { - // Read the line. - QString sCommand = ts.readLine().stripWhiteSpace(); + int iErrors = 0; + QTextStream ts(&file); + while (!ts.atEnd()) { + // Read the line. + QString sCommand = ts.readLine().trimmed(); iLine++; - // If not empty, nor a comment, call the server... - if (!sCommand.isEmpty() && sCommand[0] != '#') { + // If not empty, nor a comment, call the server... + if (!sCommand.isEmpty() && sCommand[0] != '#') { // Remember that, no matter what, // all LSCP commands are CR/LF terminated. sCommand += "\r\n"; - if (::lscp_client_query(m_pClient, sCommand.latin1()) != LSCP_OK) { + if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData()) + != LSCP_OK) { appendMessagesColor(QString("%1(%2): %3") .arg(QFileInfo(sFilename).fileName()).arg(iLine) - .arg(sCommand.simplifyWhiteSpace()), "#996633"); + .arg(sCommand.simplified()), "#996633"); appendMessagesClient("lscp_client_query"); iErrors++; } - } - // Try to make it snappy :) - QApplication::processEvents(QEventLoop::ExcludeUserInput); - } + } + // Try to make it snappy :) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } - // Ok. we've read it. - file.close(); + // Ok. we've read it. + file.close(); // Now we'll try to create (update) the whole GUI session. updateSession(); @@ -800,22 +885,25 @@ QApplication::restoreOverrideCursor(); // Have we any errors? - if (iErrors > 0) - appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename)); + if (iErrors > 0) { + appendMessagesError( + tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.") + .arg(sFilename)); + } - // Save as default session directory. - if (m_pOptions) - m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true); + // Save as default session directory. + if (m_pOptions) + m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath(); // We're not dirty anymore, if loaded without errors, m_iDirtyCount = iErrors; - // Stabilize form... - m_sFilename = sFilename; - updateRecentFiles(sFilename); - appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename))); - - // Make that an overall update. - stabilizeForm(); - return true; + // Stabilize form... + m_sFilename = sFilename; + updateRecentFiles(sFilename); + appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename))); + + // Make that an overall update. + stabilizeForm(); + return true; } @@ -831,32 +919,34 @@ return false; } - // Open and write into real file. - QFile file(sFilename); - if (!file.open(IO_WriteOnly | IO_Truncate)) { - appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename)); - return false; - } + // Open and write into real file. + QFile file(sFilename); + if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { + appendMessagesError( + tr("Could not open \"%1\" session file.\n\nSorry.") + .arg(sFilename)); + return false; + } // Tell the world we'll take some time... QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - // Write the file. - int iErrors = 0; - QTextStream ts(&file); - ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl; - ts << "# " << tr("Version") - << ": " QSAMPLER_VERSION << endl; - ts << "# " << tr("Build") - << ": " __DATE__ " " __TIME__ << endl; - ts << "#" << endl; - ts << "# " << tr("File") - << ": " << QFileInfo(sFilename).fileName() << endl; - ts << "# " << tr("Date") - << ": " << QDate::currentDate().toString("MMM dd yyyy") - << " " << QTime::currentTime().toString("hh:mm:ss") << endl; - ts << "#" << endl; - ts << endl; + // Write the file. + int iErrors = 0; + QTextStream ts(&file); + ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl; + ts << "# " << tr("Version") + << ": " QSAMPLER_VERSION << endl; + ts << "# " << tr("Build") + << ": " __DATE__ " " __TIME__ << endl; + ts << "#" << endl; + ts << "# " << tr("File") + << ": " << QFileInfo(sFilename).fileName() << endl; + ts << "# " << tr("Date") + << ": " << QDate::currentDate().toString("MMM dd yyyy") + << " " << QTime::currentTime().toString("hh:mm:ss") << endl; + ts << "#" << endl; + ts << endl; // It is assumed that this new kind of device+session file // will be loaded from a complete initialized server... @@ -866,84 +956,86 @@ // Audio device mapping. QMap audioDeviceMap; - piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio); + piDeviceIDs = Device::getDevices(m_pClient, Device::Audio); for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { ts << endl; - qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]); + Device device(Device::Audio, piDeviceIDs[iDevice]); // Audio device specification... ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName(); - qsamplerDeviceParamMap::ConstIterator deviceParam; + DeviceParamMap::ConstIterator deviceParam; for (deviceParam = device.params().begin(); deviceParam != device.params().end(); ++deviceParam) { - const qsamplerDeviceParam& param = deviceParam.data(); + const DeviceParam& param = deviceParam.value(); if (param.value.isEmpty()) ts << "# "; ts << " " << deviceParam.key() << "='" << param.value << "'"; } ts << endl; // Audio channel parameters... int iPort = 0; - for (qsamplerDevicePort *pPort = device.ports().first(); - pPort; - pPort = device.ports().next(), ++iPort) { - qsamplerDeviceParamMap::ConstIterator portParam; + QListIterator iter(device.ports()); + while (iter.hasNext()) { + DevicePort *pPort = iter.next(); + DeviceParamMap::ConstIterator portParam; for (portParam = pPort->params().begin(); portParam != pPort->params().end(); ++portParam) { - const qsamplerDeviceParam& param = portParam.data(); + const DeviceParam& param = portParam.value(); if (param.fix || param.value.isEmpty()) ts << "# "; ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice << " " << iPort << " " << portParam.key() << "='" << param.value << "'" << endl; } + iPort++; } // Audio device index/id mapping. audioDeviceMap[device.deviceID()] = iDevice; // Try to keep it snappy :) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // MIDI device mapping. QMap midiDeviceMap; - piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi); + piDeviceIDs = Device::getDevices(m_pClient, Device::Midi); for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { ts << endl; - qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]); + Device device(Device::Midi, piDeviceIDs[iDevice]); // MIDI device specification... ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName(); - qsamplerDeviceParamMap::ConstIterator deviceParam; + DeviceParamMap::ConstIterator deviceParam; for (deviceParam = device.params().begin(); deviceParam != device.params().end(); ++deviceParam) { - const qsamplerDeviceParam& param = deviceParam.data(); + const DeviceParam& param = deviceParam.value(); if (param.value.isEmpty()) ts << "# "; ts << " " << deviceParam.key() << "='" << param.value << "'"; } ts << endl; // MIDI port parameters... int iPort = 0; - for (qsamplerDevicePort *pPort = device.ports().first(); - pPort; - pPort = device.ports().next(), ++iPort) { - qsamplerDeviceParamMap::ConstIterator portParam; + QListIterator iter(device.ports()); + while (iter.hasNext()) { + DevicePort *pPort = iter.next(); + DeviceParamMap::ConstIterator portParam; for (portParam = pPort->params().begin(); portParam != pPort->params().end(); ++portParam) { - const qsamplerDeviceParam& param = portParam.data(); + const DeviceParam& param = portParam.value(); if (param.fix || param.value.isEmpty()) ts << "# "; ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice - << " " << iPort << " " << portParam.key() - << "='" << param.value << "'" << endl; + << " " << iPort << " " << portParam.key() + << "='" << param.value << "'" << endl; } + iPort++; } // MIDI device index/id mapping. midiDeviceMap[device.deviceID()] = iDevice; // Try to keep it snappy :) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } ts << endl; @@ -1000,7 +1092,7 @@ iErrors++; } // Try to keep it snappy :) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } ts << endl; // Check for errors... @@ -1019,15 +1111,15 @@ #endif // CONFIG_MIDI_INSTRUMENT // Sampler channel mapping. - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip + QWidgetList wlist = m_pWorkspace->windowList(); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip* pChannelStrip = static_cast (wlist.at(iChannel)); - if (pChannelStrip) { - qsamplerChannel *pChannel = pChannelStrip->channel(); - if (pChannel) { - ts << "# " << tr("Channel") << " " << iChannel << endl; - ts << "ADD CHANNEL" << endl; + if (pChannelStrip) { + Channel *pChannel = pChannelStrip->channel(); + if (pChannel) { + ts << "# " << tr("Channel") << " " << iChannel << endl; + ts << "ADD CHANNEL" << endl; if (audioDeviceMap.isEmpty()) { ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel << " " << pChannel->audioDriver() << endl; @@ -1044,23 +1136,25 @@ } ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel << " " << pChannel->midiPort() << endl; - ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " "; - if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL) - ts << "ALL"; - else - ts << pChannel->midiChannel(); - ts << endl; - ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl; + ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " "; + if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL) + ts << "ALL"; + else + ts << pChannel->midiChannel(); + ts << endl; + ts << "LOAD ENGINE " << pChannel->engineName() + << " " << iChannel << endl; if (pChannel->instrumentStatus() < 100) ts << "# "; - ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " + ts << "LOAD INSTRUMENT NON_MODAL '" + << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannel << endl; - qsamplerChannelRoutingMap::ConstIterator audioRoute; + ChannelRoutingMap::ConstIterator audioRoute; for (audioRoute = pChannel->audioRouting().begin(); audioRoute != pChannel->audioRouting().end(); ++audioRoute) { ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel << " " << audioRoute.key() - << " " << audioRoute.data() << endl; + << " " << audioRoute.value() << endl; } ts << "SET CHANNEL VOLUME " << iChannel << " " << pChannel->volume() << endl; @@ -1110,12 +1204,12 @@ } } #endif - ts << endl; - } - } - // Try to keep it snappy :) - QApplication::processEvents(QEventLoop::ExcludeUserInput); - } + ts << endl; + } + } + // Try to keep it snappy :) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } #ifdef CONFIG_VOLUME ts << "# " << tr("Global volume level") << endl; @@ -1123,37 +1217,41 @@ ts << endl; #endif - // Ok. we've wrote it. - file.close(); + // Ok. we've wrote it. + file.close(); // We're fornerly done. QApplication::restoreOverrideCursor(); - // Have we any errors? - if (iErrors > 0) - appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename)); - - // Save as default session directory. - if (m_pOptions) - m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true); - // We're not dirty anymore. - m_iDirtyCount = 0; - // Stabilize form... - m_sFilename = sFilename; - updateRecentFiles(sFilename); - appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename))); - stabilizeForm(); - return true; + // Have we any errors? + if (iErrors > 0) { + appendMessagesError( + tr("Some settings could not be saved\n" + "to \"%1\" session file.\n\nSorry.") + .arg(sFilename)); + } + + // Save as default session directory. + if (m_pOptions) + m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath(); + // We're not dirty anymore. + m_iDirtyCount = 0; + // Stabilize form... + m_sFilename = sFilename; + updateRecentFiles(sFilename); + appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename))); + stabilizeForm(); + return true; } // Session change receiver slot. void MainForm::sessionDirty (void) { - // Just mark the dirty form. - m_iDirtyCount++; - // and update the form status... - stabilizeForm(); + // Just mark the dirty form. + m_iDirtyCount++; + // and update the form status... + stabilizeForm(); } @@ -1163,68 +1261,75 @@ // Create a new sampler session. void MainForm::fileNew (void) { - // Of course we'll start clean new. - newSession(); + // Of course we'll start clean new. + newSession(); } // Open an existing sampler session. void MainForm::fileOpen (void) { - // Open it right away. - openSession(); + // Open it right away. + openSession(); } // Open a recent file session. -void MainForm::fileOpenRecent ( int iIndex ) +void MainForm::fileOpenRecent (void) { - // Check if we can safely close the current session... - if (m_pOptions && closeSession(true)) { - QString sFilename = m_pOptions->recentFiles[iIndex]; - loadSessionFile(sFilename); - } + // Retrive filename index from action data... + QAction *pAction = qobject_cast (sender()); + if (pAction && m_pOptions) { + int iIndex = pAction->data().toInt(); + if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) { + QString sFilename = m_pOptions->recentFiles[iIndex]; + // Check if we can safely close the current session... + if (!sFilename.isEmpty() && closeSession(true)) + loadSessionFile(sFilename); + } + } } // Save current sampler session. void MainForm::fileSave (void) { - // Save it right away. - saveSession(false); + // Save it right away. + saveSession(false); } // Save current sampler session with another name. void MainForm::fileSaveAs (void) { - // Save it right away, maybe with another name. - saveSession(true); + // Save it right away, maybe with another name. + saveSession(true); } // Reset the sampler instance. void MainForm::fileReset (void) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; - // Ask user whether he/she want's an internal sampler reset... - if (QMessageBox::warning(this, + // Ask user whether he/she want's an internal sampler reset... + if (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), - tr("Resetting the sampler instance will close\n" - "all device and channel configurations.\n\n" - "Please note that this operation may cause\n" - "temporary MIDI and Audio disruption.\n\n" - "Do you want to reset the sampler engine now?"), - tr("Reset"), tr("Cancel")) > 0) - return; + tr("Resetting the sampler instance will close\n" + "all device and channel configurations.\n\n" + "Please note that this operation may cause\n" + "temporary MIDI and Audio disruption.\n\n" + "Do you want to reset the sampler engine now?"), + QMessageBox::Ok | QMessageBox::Cancel) + == QMessageBox::Cancel) + return; // Trye closing the current session, first... if (!closeSession(true)) return; - // Just do the reset, after closing down current session... + // Just do the reset, after closing down current session... // Do the actual sampler reset... if (::lscp_reset_sampler(m_pClient) != LSCP_OK) { appendMessagesClient("lscp_reset_sampler"); @@ -1232,8 +1337,8 @@ return; } - // Log this. - appendMessages(tr("Sampler reset.")); + // Log this. + appendMessages(tr("Sampler reset.")); // Make it a new session... newSession(); @@ -1243,39 +1348,39 @@ // Restart the client/server instance. void MainForm::fileRestart (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - bool bRestart = true; + bool bRestart = true; - // Ask user whether he/she want's a complete restart... - // (if we're currently up and running) - if (bRestart && m_pClient) { - bRestart = (QMessageBox::warning(this, + // Ask user whether he/she want's a complete restart... + // (if we're currently up and running) + if (bRestart && m_pClient) { + bRestart = (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), - tr("New settings will be effective after\n" - "restarting the client/server connection.\n\n" - "Please note that this operation may cause\n" - "temporary MIDI and Audio disruption.\n\n" - "Do you want to restart the connection now?"), - tr("Restart"), tr("Cancel")) == 0); - } - - // Are we still for it? - if (bRestart && closeSession(true)) { - // Stop server, it will force the client too. - stopServer(); - // Reschedule a restart... - startSchedule(m_pOptions->iStartDelay); - } + tr("New settings will be effective after\n" + "restarting the client/server connection.\n\n" + "Please note that this operation may cause\n" + "temporary MIDI and Audio disruption.\n\n" + "Do you want to restart the connection now?"), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok); + } + + // Are we still for it? + if (bRestart && closeSession(true)) { + // Stop server, it will force the client too. + stopServer(); + // Reschedule a restart... + startSchedule(m_pOptions->iStartDelay); + } } // Exit application program. void MainForm::fileExit (void) { - // Go for close the whole thing. - close(); + // Go for close the whole thing. + close(); } @@ -1285,118 +1390,124 @@ // Add a new sampler channel. void MainForm::editAddChannel (void) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; + + // Just create the channel instance... + Channel *pChannel = new Channel(); + if (pChannel == NULL) + return; + + // Before we show it up, may be we'll + // better ask for some initial values? + if (!pChannel->channelSetup(this)) { + delete pChannel; + return; + } - // Just create the channel instance... - qsamplerChannel *pChannel = new qsamplerChannel(); - if (pChannel == NULL) - return; - - // Before we show it up, may be we'll - // better ask for some initial values? - if (!pChannel->channelSetup(this)) { - delete pChannel; - return; - } - - // And give it to the strip (will own the channel instance, if successful). - if (!createChannelStrip(pChannel)) { - delete pChannel; - return; - } - - // Make that an overall update. - m_iDirtyCount++; - stabilizeForm(); + // And give it to the strip... + // (will own the channel instance, if successful). + if (!createChannelStrip(pChannel)) { + delete pChannel; + return; + } + + // Do we auto-arrange? + if (m_pOptions && m_pOptions->bAutoArrange) + channelsArrange(); + + // Make that an overall update. + m_iDirtyCount++; + stabilizeForm(); } // Remove current sampler channel. void MainForm::editRemoveChannel (void) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; + + ChannelStrip* pChannelStrip = activeChannelStrip(); + if (pChannelStrip == NULL) + return; + + Channel *pChannel = pChannelStrip->channel(); + if (pChannel == NULL) + return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) - return; - - qsamplerChannel *pChannel = pChannelStrip->channel(); - if (pChannel == NULL) - return; - - // Prompt user if he/she's sure about this... - if (m_pOptions && m_pOptions->bConfirmRemove) { - if (QMessageBox::warning(this, + // Prompt user if he/she's sure about this... + if (m_pOptions && m_pOptions->bConfirmRemove) { + if (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), - tr("About to remove channel:\n\n" - "%1\n\n" - "Are you sure?") - .arg(pChannelStrip->caption()), - tr("OK"), tr("Cancel")) > 0) - return; - } - - // Remove the existing sampler channel. - if (!pChannel->removeChannel()) - return; - - // Just delete the channel strip. - delete pChannelStrip; - - // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); - - // We'll be dirty, for sure... - m_iDirtyCount++; - stabilizeForm(); + tr("About to remove channel:\n\n" + "%1\n\n" + "Are you sure?") + .arg(pChannelStrip->windowTitle()), + QMessageBox::Ok | QMessageBox::Cancel) + == QMessageBox::Cancel) + return; + } + + // Remove the existing sampler channel. + if (!pChannel->removeChannel()) + return; + + // Just delete the channel strip. + delete pChannelStrip; + + // Do we auto-arrange? + if (m_pOptions && m_pOptions->bAutoArrange) + channelsArrange(); + + // We'll be dirty, for sure... + m_iDirtyCount++; + stabilizeForm(); } // Setup current sampler channel. void MainForm::editSetupChannel (void) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) - return; + ChannelStrip* pChannelStrip = activeChannelStrip(); + if (pChannelStrip == NULL) + return; - // Just invoque the channel strip procedure. - pChannelStrip->channelSetup(); + // Just invoque the channel strip procedure. + pChannelStrip->channelSetup(); } // Edit current sampler channel. void MainForm::editEditChannel (void) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) - return; + ChannelStrip* pChannelStrip = activeChannelStrip(); + if (pChannelStrip == NULL) + return; - // Just invoque the channel strip procedure. - pChannelStrip->channelEdit(); + // Just invoque the channel strip procedure. + pChannelStrip->channelEdit(); } // Reset current sampler channel. void MainForm::editResetChannel (void) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (pChannelStrip == NULL) - return; + ChannelStrip* pChannelStrip = activeChannelStrip(); + if (pChannelStrip == NULL) + return; - // Just invoque the channel strip procedure. - pChannelStrip->channelReset(); + // Just invoque the channel strip procedure. + pChannelStrip->channelReset(); } @@ -1425,45 +1536,45 @@ // Show/hide the main program window menubar. void MainForm::viewMenubar ( bool bOn ) { - if (bOn) - ui.MenuBar->show(); - else - ui.MenuBar->hide(); + if (bOn) + m_ui.MenuBar->show(); + else + m_ui.MenuBar->hide(); } // Show/hide the main program window toolbar. void MainForm::viewToolbar ( bool bOn ) { - if (bOn) { - ui.fileToolbar->show(); - ui.editToolbar->show(); - ui.channelsToolbar->show(); - } else { - ui.fileToolbar->hide(); - ui.editToolbar->hide(); - ui.channelsToolbar->hide(); - } + if (bOn) { + m_ui.fileToolbar->show(); + m_ui.editToolbar->show(); + m_ui.channelsToolbar->show(); + } else { + m_ui.fileToolbar->hide(); + m_ui.editToolbar->hide(); + m_ui.channelsToolbar->hide(); + } } // Show/hide the main program window statusbar. void MainForm::viewStatusbar ( bool bOn ) { - if (bOn) - statusBar()->show(); - else - statusBar()->hide(); + if (bOn) + statusBar()->show(); + else + statusBar()->hide(); } // Show/hide the messages window logger. void MainForm::viewMessages ( bool bOn ) { - if (bOn) - m_pMessages->show(); - else - m_pMessages->hide(); + if (bOn) + m_pMessages->show(); + else + m_pMessages->hide(); } @@ -1480,7 +1591,7 @@ } else { m_pInstrumentListForm->show(); m_pInstrumentListForm->raise(); - m_pInstrumentListForm->setActiveWindow(); + m_pInstrumentListForm->activateWindow(); } } } @@ -1499,7 +1610,7 @@ } else { m_pDeviceForm->show(); m_pDeviceForm->raise(); - m_pDeviceForm->setActiveWindow(); + m_pDeviceForm->activateWindow(); } } } @@ -1508,85 +1619,95 @@ // Show options dialog. void MainForm::viewOptions (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - OptionsForm* pOptionsForm = new OptionsForm(this); - if (pOptionsForm) { - // Check out some initial nullities(tm)... - ChannelStrip* pChannelStrip = activeChannelStrip(); - if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip) - m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString(); - if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages) - m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); - // To track down deferred or immediate changes. - QString sOldServerHost = m_pOptions->sServerHost; - int iOldServerPort = m_pOptions->iServerPort; - int iOldServerTimeout = m_pOptions->iServerTimeout; - bool bOldServerStart = m_pOptions->bServerStart; - QString sOldServerCmdLine = m_pOptions->sServerCmdLine; - QString sOldDisplayFont = m_pOptions->sDisplayFont; - bool bOldDisplayEffect = m_pOptions->bDisplayEffect; - int iOldMaxVolume = m_pOptions->iMaxVolume; - QString sOldMessagesFont = m_pOptions->sMessagesFont; - bool bOldKeepOnTop = m_pOptions->bKeepOnTop; - bool bOldStdoutCapture = m_pOptions->bStdoutCapture; - int bOldMessagesLimit = m_pOptions->bMessagesLimit; - int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines; - bool bOldCompletePath = m_pOptions->bCompletePath; - bool bOldInstrumentNames = m_pOptions->bInstrumentNames; - int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles; - // Load the current setup settings. - pOptionsForm->setup(m_pOptions); - // Show the setup dialog... - if (pOptionsForm->exec()) { - // Warn if something will be only effective on next run. - if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) || - (!bOldStdoutCapture && m_pOptions->bStdoutCapture) || - ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) || - (!bOldKeepOnTop && m_pOptions->bKeepOnTop)) { - QMessageBox::information(this, + OptionsForm* pOptionsForm = new OptionsForm(this); + if (pOptionsForm) { + // Check out some initial nullities(tm)... + ChannelStrip* pChannelStrip = activeChannelStrip(); + if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip) + m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString(); + if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages) + m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString(); + // To track down deferred or immediate changes. + QString sOldServerHost = m_pOptions->sServerHost; + int iOldServerPort = m_pOptions->iServerPort; + int iOldServerTimeout = m_pOptions->iServerTimeout; + bool bOldServerStart = m_pOptions->bServerStart; + QString sOldServerCmdLine = m_pOptions->sServerCmdLine; + bool bOldMessagesLog = m_pOptions->bMessagesLog; + QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath; + QString sOldDisplayFont = m_pOptions->sDisplayFont; + bool bOldDisplayEffect = m_pOptions->bDisplayEffect; + int iOldMaxVolume = m_pOptions->iMaxVolume; + QString sOldMessagesFont = m_pOptions->sMessagesFont; + bool bOldKeepOnTop = m_pOptions->bKeepOnTop; + bool bOldStdoutCapture = m_pOptions->bStdoutCapture; + int bOldMessagesLimit = m_pOptions->bMessagesLimit; + int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines; + bool bOldCompletePath = m_pOptions->bCompletePath; + bool bOldInstrumentNames = m_pOptions->bInstrumentNames; + int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles; + int iOldBaseFontSize = m_pOptions->iBaseFontSize; + // Load the current setup settings. + pOptionsForm->setup(m_pOptions); + // Show the setup dialog... + if (pOptionsForm->exec()) { + // Warn if something will be only effective on next run. + if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) || + (!bOldStdoutCapture && m_pOptions->bStdoutCapture) || + ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) || + (!bOldKeepOnTop && m_pOptions->bKeepOnTop) || + (iOldBaseFontSize != m_pOptions->iBaseFontSize)) { + QMessageBox::information(this, QSAMPLER_TITLE ": " + tr("Information"), - tr("Some settings may be only effective\n" - "next time you start this program."), tr("OK")); - updateMessagesCapture(); - } - // Check wheather something immediate has changed. - if (( bOldCompletePath && !m_pOptions->bCompletePath) || - (!bOldCompletePath && m_pOptions->bCompletePath) || - (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles)) - updateRecentFilesMenu(); - if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) || - (!bOldInstrumentNames && m_pOptions->bInstrumentNames)) - updateInstrumentNames(); - if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) || - (!bOldDisplayEffect && m_pOptions->bDisplayEffect)) - updateDisplayEffect(); - if (sOldDisplayFont != m_pOptions->sDisplayFont) - updateDisplayFont(); - if (iOldMaxVolume != m_pOptions->iMaxVolume) - updateMaxVolume(); - if (sOldMessagesFont != m_pOptions->sMessagesFont) - updateMessagesFont(); - if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) || - (!bOldMessagesLimit && m_pOptions->bMessagesLimit) || - (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines)) - updateMessagesLimit(); - // And now the main thing, whether we'll do client/server recycling? - if ((sOldServerHost != m_pOptions->sServerHost) || - (iOldServerPort != m_pOptions->iServerPort) || - (iOldServerTimeout != m_pOptions->iServerTimeout) || - ( bOldServerStart && !m_pOptions->bServerStart) || - (!bOldServerStart && m_pOptions->bServerStart) || - (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart)) - fileRestart(); - } - // Done. - delete pOptionsForm; - } + tr("Some settings may be only effective\n" + "next time you start this program.")); + updateMessagesCapture(); + } + // Check wheather something immediate has changed. + if (( bOldMessagesLog && !m_pOptions->bMessagesLog) || + (!bOldMessagesLog && m_pOptions->bMessagesLog) || + (sOldMessagesLogPath != m_pOptions->sMessagesLogPath)) + m_pMessages->setLogging( + m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath); + if (( bOldCompletePath && !m_pOptions->bCompletePath) || + (!bOldCompletePath && m_pOptions->bCompletePath) || + (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles)) + updateRecentFilesMenu(); + if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) || + (!bOldInstrumentNames && m_pOptions->bInstrumentNames)) + updateInstrumentNames(); + if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) || + (!bOldDisplayEffect && m_pOptions->bDisplayEffect)) + updateDisplayEffect(); + if (sOldDisplayFont != m_pOptions->sDisplayFont) + updateDisplayFont(); + if (iOldMaxVolume != m_pOptions->iMaxVolume) + updateMaxVolume(); + if (sOldMessagesFont != m_pOptions->sMessagesFont) + updateMessagesFont(); + if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) || + (!bOldMessagesLimit && m_pOptions->bMessagesLimit) || + (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines)) + updateMessagesLimit(); + // And now the main thing, whether we'll do client/server recycling? + if ((sOldServerHost != m_pOptions->sServerHost) || + (iOldServerPort != m_pOptions->iServerPort) || + (iOldServerTimeout != m_pOptions->iServerTimeout) || + ( bOldServerStart && !m_pOptions->bServerStart) || + (!bOldServerStart && m_pOptions->bServerStart) || + (sOldServerCmdLine != m_pOptions->sServerCmdLine + && m_pOptions->bServerStart)) + fileRestart(); + } + // Done. + delete pOptionsForm; + } - // This makes it. - stabilizeForm(); + // This makes it. + stabilizeForm(); } @@ -1596,47 +1717,48 @@ // Arrange channel strips. void MainForm::channelsArrange (void) { - // Full width vertical tiling - QWidgetList wlist = m_pWorkspace->windowList(); - if (wlist.isEmpty()) - return; - - m_pWorkspace->setUpdatesEnabled(false); - int y = 0; - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) { - // Prevent flicker... - pChannelStrip->hide(); - pChannelStrip->showNormal(); - } */ - pChannelStrip->adjustSize(); - int iWidth = m_pWorkspace->width(); - if (iWidth < pChannelStrip->width()) - iWidth = pChannelStrip->width(); - // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height(); - int iHeight = pChannelStrip->parentWidget()->frameGeometry().height(); - pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight); - y += iHeight; - } - m_pWorkspace->setUpdatesEnabled(true); + // Full width vertical tiling + QWidgetList wlist = m_pWorkspace->windowList(); + if (wlist.isEmpty()) + return; - stabilizeForm(); + m_pWorkspace->setUpdatesEnabled(false); + int y = 0; + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) { + // Prevent flicker... + pChannelStrip->hide(); + pChannelStrip->showNormal(); + } */ + pChannelStrip->adjustSize(); + int iWidth = m_pWorkspace->width(); + if (iWidth < pChannelStrip->width()) + iWidth = pChannelStrip->width(); + // int iHeight = pChannelStrip->height() + // + pChannelStrip->parentWidget()->baseSize().height(); + int iHeight = pChannelStrip->parentWidget()->frameGeometry().height(); + pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight); + y += iHeight; + } + m_pWorkspace->setUpdatesEnabled(true); + + stabilizeForm(); } // Auto-arrange channel strips. void MainForm::channelsAutoArrange ( bool bOn ) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - // Toggle the auto-arrange flag. - m_pOptions->bAutoArrange = bOn; + // Toggle the auto-arrange flag. + m_pOptions->bAutoArrange = bOn; - // If on, update whole workspace... - if (m_pOptions->bAutoArrange) - channelsArrange(); + // If on, update whole workspace... + if (m_pOptions->bAutoArrange) + channelsArrange(); } @@ -1646,89 +1768,104 @@ // Show information about the Qt toolkit. void MainForm::helpAboutQt (void) { - QMessageBox::aboutQt(this); + QMessageBox::aboutQt(this); } // Show information about application program. void MainForm::helpAbout (void) { - // Stuff the about box text... - QString sText = "

\n"; - sText += "" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "
\n"; - sText += "
\n"; - sText += tr("Version") + ": " QSAMPLER_VERSION "
\n"; - sText += "" + tr("Build") + ": " __DATE__ " " __TIME__ "
\n"; + // Stuff the about box text... + QString sText = "

\n"; + sText += "" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "
\n"; + sText += "
\n"; + sText += tr("Version") + ": " QSAMPLER_VERSION "
\n"; + sText += "" + tr("Build") + ": " __DATE__ " " __TIME__ "
\n"; #ifdef CONFIG_DEBUG - sText += ""; - sText += tr("Debugging option enabled."); - sText += "
"; + sText += ""; + sText += tr("Debugging option enabled."); + sText += "
"; #endif #ifndef CONFIG_LIBGIG - sText += ""; - sText += tr("GIG (libgig) file support disabled."); - sText += "
"; + sText += ""; + sText += tr("GIG (libgig) file support disabled."); + sText += "
"; #endif #ifndef CONFIG_INSTRUMENT_NAME - sText += ""; - sText += tr("LSCP (liblscp) instrument_name support disabled."); - sText += "
"; + sText += ""; + sText += tr("LSCP (liblscp) instrument_name support disabled."); + sText += "
"; #endif #ifndef CONFIG_MUTE_SOLO - sText += ""; - sText += tr("Sampler channel Mute/Solo support disabled."); - sText += "
"; + sText += ""; + sText += tr("Sampler channel Mute/Solo support disabled."); + sText += "
"; #endif #ifndef CONFIG_AUDIO_ROUTING - sText += ""; - sText += tr("LSCP (liblscp) audio_routing support disabled."); - sText += "
"; + sText += ""; + sText += tr("LSCP (liblscp) audio_routing support disabled."); + sText += "
"; #endif #ifndef CONFIG_FXSEND - sText += ""; - sText += tr("Sampler channel Effect Sends support disabled."); - sText += "
"; + sText += ""; + sText += tr("Sampler channel Effect Sends support disabled."); + sText += "
"; #endif #ifndef CONFIG_VOLUME - sText += ""; - sText += tr("Global volume support disabled."); - sText += "
"; + sText += ""; + sText += tr("Global volume support disabled."); + sText += "
"; #endif #ifndef CONFIG_MIDI_INSTRUMENT - sText += ""; - sText += tr("MIDI instrument mapping support disabled."); - sText += "
"; + sText += ""; + sText += tr("MIDI instrument mapping support disabled."); + sText += "
"; #endif #ifndef CONFIG_EDIT_INSTRUMENT - sText += ""; - sText += tr("Instrument editing support disabled."); - sText += "
"; -#endif - sText += "
\n"; - sText += tr("Using") + ": "; - sText += ::lscp_client_package(); - sText += " "; - sText += ::lscp_client_version(); + sText += ""; + sText += tr("Instrument editing support disabled."); + sText += "
"; +#endif +#ifndef CONFIG_EVENT_CHANNEL_MIDI + sText += ""; + sText += tr("Channel MIDI event support disabled."); + sText += "
"; +#endif +#ifndef CONFIG_EVENT_DEVICE_MIDI + sText += ""; + sText += tr("Device MIDI event support disabled."); + sText += "
"; +#endif +#ifndef CONFIG_MAX_VOICES + sText += ""; + sText += tr("Runtime max. voices / disk streams support disabled."); + sText += "
"; +#endif + sText += "
\n"; + sText += tr("Using") + ": "; + sText += ::lscp_client_package(); + sText += " "; + sText += ::lscp_client_version(); #ifdef CONFIG_LIBGIG - sText += ", "; - sText += gig::libraryName().c_str(); - sText += " "; - sText += gig::libraryVersion().c_str(); -#endif - sText += "
\n"; - sText += "
\n"; - sText += tr("Website") + ": " QSAMPLER_WEBSITE "
\n"; - sText += "
\n"; - sText += ""; - sText += QSAMPLER_COPYRIGHT "
\n"; - sText += QSAMPLER_COPYRIGHT2 "
\n"; - sText += "
\n"; - sText += tr("This program is free software; you can redistribute it and/or modify it") + "
\n"; - sText += tr("under the terms of the GNU General Public License version 2 or later."); - sText += "
"; - sText += "

\n"; + sText += ", "; + sText += gig::libraryName().c_str(); + sText += " "; + sText += gig::libraryVersion().c_str(); +#endif + sText += "
\n"; + sText += "
\n"; + sText += tr("Website") + ": " QSAMPLER_WEBSITE "
\n"; + sText += "
\n"; + sText += ""; + sText += QSAMPLER_COPYRIGHT "
\n"; + sText += QSAMPLER_COPYRIGHT2 "
\n"; + sText += "
\n"; + sText += tr("This program is free software; you can redistribute it and/or modify it") + "
\n"; + sText += tr("under the terms of the GNU General Public License version 2 or later."); + sText += "
"; + sText += "

\n"; - QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText); + QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText); } @@ -1737,72 +1874,76 @@ void MainForm::stabilizeForm (void) { - // Update the main application caption... - QString sSessionName = sessionName(m_sFilename); - if (m_iDirtyCount > 0) - sSessionName += " *"; - setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName)); - - // Update the main menu state... - ChannelStrip* pChannelStrip = activeChannelStrip(); - bool bHasClient = (m_pOptions != NULL && m_pClient != NULL); - bool bHasChannel = (bHasClient && pChannelStrip != NULL); - ui.fileNewAction->setEnabled(bHasClient); - ui.fileOpenAction->setEnabled(bHasClient); - ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0); - ui.fileSaveAsAction->setEnabled(bHasClient); - ui.fileResetAction->setEnabled(bHasClient); - ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL); - ui.editAddChannelAction->setEnabled(bHasClient); - ui.editRemoveChannelAction->setEnabled(bHasChannel); - ui.editSetupChannelAction->setEnabled(bHasChannel); + // Update the main application caption... + QString sSessionName = sessionName(m_sFilename); + if (m_iDirtyCount > 0) + sSessionName += " *"; + setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName)); + + // Update the main menu state... + ChannelStrip *pChannelStrip = activeChannelStrip(); + bool bHasClient = (m_pOptions != NULL && m_pClient != NULL); + bool bHasChannel = (bHasClient && pChannelStrip != NULL); + bool bHasChannels = (bHasClient && m_pWorkspace->windowList().count() > 0); + m_ui.fileNewAction->setEnabled(bHasClient); + m_ui.fileOpenAction->setEnabled(bHasClient); + m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0); + m_ui.fileSaveAsAction->setEnabled(bHasClient); + m_ui.fileResetAction->setEnabled(bHasClient); + m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL); + m_ui.editAddChannelAction->setEnabled(bHasClient); + m_ui.editRemoveChannelAction->setEnabled(bHasChannel); + m_ui.editSetupChannelAction->setEnabled(bHasChannel); #ifdef CONFIG_EDIT_INSTRUMENT - ui.editEditChannelAction->setEnabled(bHasChannel); + m_ui.editEditChannelAction->setEnabled(bHasChannel); #else - ui.editEditChannelAction->setEnabled(false); + m_ui.editEditChannelAction->setEnabled(false); #endif - ui.editResetChannelAction->setEnabled(bHasChannel); - ui.editResetAllChannelsAction->setEnabled(bHasChannel); - ui.viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible()); + m_ui.editResetChannelAction->setEnabled(bHasChannel); + m_ui.editResetAllChannelsAction->setEnabled(bHasChannels); + m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible()); #ifdef CONFIG_MIDI_INSTRUMENT - ui.viewInstrumentsAction->setOn(m_pInstrumentListForm + m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm && m_pInstrumentListForm->isVisible()); - ui.viewInstrumentsAction->setEnabled(bHasClient); + m_ui.viewInstrumentsAction->setEnabled(bHasClient); #else - ui.viewInstrumentsAction->setEnabled(false); + m_ui.viewInstrumentsAction->setEnabled(false); #endif - ui.viewDevicesAction->setOn(m_pDeviceForm + m_ui.viewDevicesAction->setChecked(m_pDeviceForm && m_pDeviceForm->isVisible()); - ui.viewDevicesAction->setEnabled(bHasClient); - ui.channelsArrangeAction->setEnabled(bHasChannel); + m_ui.viewDevicesAction->setEnabled(bHasClient); + m_ui.viewMidiDeviceStatusMenu->setEnabled( + DeviceStatusForm::getInstances().size() > 0); + m_ui.channelsArrangeAction->setEnabled(bHasChannels); #ifdef CONFIG_VOLUME // Toolbar widgets are also affected... - m_pVolumeSlider->setEnabled(bHasClient); - m_pVolumeSpinBox->setEnabled(bHasClient); + m_pVolumeSlider->setEnabled(bHasClient); + m_pVolumeSpinBox->setEnabled(bHasClient); #endif - // Client/Server status... - if (bHasClient) { - m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected")); - m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort)); - } else { - m_statusItem[QSAMPLER_STATUS_CLIENT]->clear(); - m_statusItem[QSAMPLER_STATUS_SERVER]->clear(); - } - // Channel status... - if (bHasChannel) - m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption()); - else - m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear(); - // Session status... - if (m_iDirtyCount > 0) - m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD")); - else - m_statusItem[QSAMPLER_STATUS_SESSION]->clear(); + // Client/Server status... + if (bHasClient) { + m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected")); + m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + + ':' + QString::number(m_pOptions->iServerPort)); + } else { + m_statusItem[QSAMPLER_STATUS_CLIENT]->clear(); + m_statusItem[QSAMPLER_STATUS_SERVER]->clear(); + } + // Channel status... + if (bHasChannel) + m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle()); + else + m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear(); + // Session status... + if (m_iDirtyCount > 0) + m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD")); + else + m_statusItem[QSAMPLER_STATUS_SESSION]->clear(); - // Recent files menu. - m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0); + // Recent files menu. + m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0); } @@ -1842,15 +1983,15 @@ void MainForm::channelStripChanged(ChannelStrip* pChannelStrip) { // Add this strip to the changed list... - if (m_changedStrips.containsRef(pChannelStrip) == 0) { + if (!m_changedStrips.contains(pChannelStrip)) { m_changedStrips.append(pChannelStrip); pChannelStrip->resetErrorCount(); } - // Just mark the dirty form. - m_iDirtyCount++; - // and update the form status... - stabilizeForm(); + // Just mark the dirty form. + m_iDirtyCount++; + // and update the form status... + stabilizeForm(); } @@ -1870,17 +2011,34 @@ if (iMaps < 0) appendMessagesClient("lscp_get_midi_instrument_maps"); else if (iMaps < 1) { - ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1()); - ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1()); + ::lscp_add_midi_instrument_map(m_pClient, + tr("Chromatic").toUtf8().constData()); + ::lscp_add_midi_instrument_map(m_pClient, + tr("Drum Kits").toUtf8().constData()); } #endif + updateAllChannelStrips(false); + + // Do we auto-arrange? + if (m_pOptions && m_pOptions->bAutoArrange) + channelsArrange(); + + // Remember to refresh devices and instruments... + if (m_pInstrumentListForm) + m_pInstrumentListForm->refreshInstruments(); + if (m_pDeviceForm) + m_pDeviceForm->refreshDevices(); +} + +void MainForm::updateAllChannelStrips(bool bRemoveDeadStrips) { // Retrieve the current channel list. int *piChannelIDs = ::lscp_list_channels(m_pClient); if (piChannelIDs == NULL) { if (::lscp_client_get_errno(m_pClient)) { appendMessagesClient("lscp_list_channels"); - appendMessagesError(tr("Could not get current list of channels.\n\nSorry.")); + appendMessagesError( + tr("Could not get current list of channels.\n\nSorry.")); } } else { // Try to (re)create each channel. @@ -1888,161 +2046,167 @@ for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) { // Check if theres already a channel strip for this one... if (!channelStrip(piChannelIDs[iChannel])) - createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel])); + createChannelStrip(new Channel(piChannelIDs[iChannel])); + } + + // Do we auto-arrange? + if (m_pOptions && m_pOptions->bAutoArrange) + channelsArrange(); + + stabilizeForm(); + + // remove dead channel strips + if (bRemoveDeadStrips) { + for (int i = 0; channelStripAt(i); ++i) { + ChannelStrip* pChannelStrip = channelStripAt(i); + bool bExists = false; + for (int j = 0; piChannelIDs[j] >= 0; ++j) { + if (!pChannelStrip->channel()) break; + if (piChannelIDs[j] == pChannelStrip->channel()->channelID()) { + // strip exists, don't touch it + bExists = true; + break; + } + } + if (!bExists) destroyChannelStrip(pChannelStrip); + } } m_pWorkspace->setUpdatesEnabled(true); } - - // Do we auto-arrange? - if (m_pOptions && m_pOptions->bAutoArrange) - channelsArrange(); - - // Remember to refresh devices and instruments... - if (m_pInstrumentListForm) - m_pInstrumentListForm->refreshInstruments(); - if (m_pDeviceForm) - m_pDeviceForm->refreshDevices(); } - // Update the recent files list and menu. void MainForm::updateRecentFiles ( const QString& sFilename ) { - if (m_pOptions == NULL) - return; - - // Remove from list if already there (avoid duplicates) - QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename); - if (iter != m_pOptions->recentFiles.end()) - m_pOptions->recentFiles.remove(iter); - // Put it to front... - m_pOptions->recentFiles.push_front(sFilename); + if (m_pOptions == NULL) + return; - // May update the menu. - updateRecentFilesMenu(); + // Remove from list if already there (avoid duplicates) + int iIndex = m_pOptions->recentFiles.indexOf(sFilename); + if (iIndex >= 0) + m_pOptions->recentFiles.removeAt(iIndex); + // Put it to front... + m_pOptions->recentFiles.push_front(sFilename); } // Update the recent files list and menu. void MainForm::updateRecentFilesMenu (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; + + // Time to keep the list under limits. + int iRecentFiles = m_pOptions->recentFiles.count(); + while (iRecentFiles > m_pOptions->iMaxRecentFiles) { + m_pOptions->recentFiles.pop_back(); + iRecentFiles--; + } - // Time to keep the list under limits. - int iRecentFiles = m_pOptions->recentFiles.count(); - while (iRecentFiles > m_pOptions->iMaxRecentFiles) { - m_pOptions->recentFiles.pop_back(); - iRecentFiles--; - } - - // rebuild the recent files menu... - m_pRecentFilesMenu->clear(); - for (int i = 0; i < iRecentFiles; i++) { - const QString& sFilename = m_pOptions->recentFiles[i]; - if (QFileInfo(sFilename).exists()) { - m_pRecentFilesMenu->insertItem(QString("&%1 %2") - .arg(i + 1).arg(sessionName(sFilename)), - this, SLOT(fileOpenRecent(int)), 0, i); - } - } + // Rebuild the recent files menu... + m_ui.fileOpenRecentMenu->clear(); + for (int i = 0; i < iRecentFiles; i++) { + const QString& sFilename = m_pOptions->recentFiles[i]; + if (QFileInfo(sFilename).exists()) { + QAction *pAction = m_ui.fileOpenRecentMenu->addAction( + QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)), + this, SLOT(fileOpenRecent())); + pAction->setData(i); + } + } } // Force update of the channels instrument names mode. void MainForm::updateInstrumentNames (void) { - // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); - if (wlist.isEmpty()) - return; - - m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel); - if (pChannelStrip) - pChannelStrip->updateInstrumentName(true); - } - m_pWorkspace->setUpdatesEnabled(true); + // Full channel list update... + QWidgetList wlist = m_pWorkspace->windowList(); + if (wlist.isEmpty()) + return; + + m_pWorkspace->setUpdatesEnabled(false); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel); + if (pChannelStrip) + pChannelStrip->updateInstrumentName(true); + } + m_pWorkspace->setUpdatesEnabled(true); } // Force update of the channels display font. void MainForm::updateDisplayFont (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; + + // Check if display font is legal. + if (m_pOptions->sDisplayFont.isEmpty()) + return; + // Realize it. + QFont font; + if (!font.fromString(m_pOptions->sDisplayFont)) + return; + + // Full channel list update... + QWidgetList wlist = m_pWorkspace->windowList(); + if (wlist.isEmpty()) + return; - // Check if display font is legal. - if (m_pOptions->sDisplayFont.isEmpty()) - return; - // Realize it. - QFont font; - if (!font.fromString(m_pOptions->sDisplayFont)) - return; - - // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); - if (wlist.isEmpty()) - return; - - m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - if (pChannelStrip) - pChannelStrip->setDisplayFont(font); - } - m_pWorkspace->setUpdatesEnabled(true); + m_pWorkspace->setUpdatesEnabled(false); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + if (pChannelStrip) + pChannelStrip->setDisplayFont(font); + } + m_pWorkspace->setUpdatesEnabled(true); } // Update channel strips background effect. void MainForm::updateDisplayEffect (void) { - QPixmap pm; - if (m_pOptions->bDisplayEffect) - pm = QPixmap(":/qsampler/pixmaps/displaybg1.png"); - - // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); - if (wlist.isEmpty()) - return; - - m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - if (pChannelStrip) - pChannelStrip->setDisplayBackground(pm); - } - m_pWorkspace->setUpdatesEnabled(true); + // Full channel list update... + QWidgetList wlist = m_pWorkspace->windowList(); + if (wlist.isEmpty()) + return; + + m_pWorkspace->setUpdatesEnabled(false); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + if (pChannelStrip) + pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); + } + m_pWorkspace->setUpdatesEnabled(true); } // Force update of the channels maximum volume setting. void MainForm::updateMaxVolume (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; #ifdef CONFIG_VOLUME m_iVolumeChanging++; - m_pVolumeSlider->setMaxValue(m_pOptions->iMaxVolume); - m_pVolumeSpinBox->setMaxValue(m_pOptions->iMaxVolume); + m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume); + m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume); m_iVolumeChanging--; #endif - // Full channel list update... - QWidgetList wlist = m_pWorkspace->windowList(); - if (wlist.isEmpty()) - return; - - m_pWorkspace->setUpdatesEnabled(false); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - if (pChannelStrip) - pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); - } - m_pWorkspace->setUpdatesEnabled(true); + // Full channel list update... + QWidgetList wlist = m_pWorkspace->windowList(); + if (wlist.isEmpty()) + return; + + m_pWorkspace->setUpdatesEnabled(false); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + if (pChannelStrip) + pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); + } + m_pWorkspace->setUpdatesEnabled(true); } @@ -2052,93 +2216,93 @@ // Messages output methods. void MainForm::appendMessages( const QString& s ) { - if (m_pMessages) - m_pMessages->appendMessages(s); + if (m_pMessages) + m_pMessages->appendMessages(s); - statusBar()->message(s, 3000); + statusBar()->showMessage(s, 3000); } void MainForm::appendMessagesColor( const QString& s, const QString& c ) { - if (m_pMessages) - m_pMessages->appendMessagesColor(s, c); + if (m_pMessages) + m_pMessages->appendMessagesColor(s, c); - statusBar()->message(s, 3000); + statusBar()->showMessage(s, 3000); } void MainForm::appendMessagesText( const QString& s ) { - if (m_pMessages) - m_pMessages->appendMessagesText(s); + if (m_pMessages) + m_pMessages->appendMessagesText(s); } void MainForm::appendMessagesError( const QString& s ) { - if (m_pMessages) - m_pMessages->show(); + if (m_pMessages) + m_pMessages->show(); - appendMessagesColor(s.simplified(), "#ff0000"); + appendMessagesColor(s.simplified(), "#ff0000"); // Make it look responsive...:) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - QMessageBox::critical(this, - QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel")); + QMessageBox::critical(this, + QSAMPLER_TITLE ": " + tr("Error"), s, QMessageBox::Cancel); } // This is a special message format, just for client results. void MainForm::appendMessagesClient( const QString& s ) { - if (m_pClient == NULL) - return; + if (m_pClient == NULL) + return; - appendMessagesColor(s + QString(": %1 (errno=%2)") - .arg(::lscp_client_get_result(m_pClient)) - .arg(::lscp_client_get_errno(m_pClient)), "#996666"); + appendMessagesColor(s + QString(": %1 (errno=%2)") + .arg(::lscp_client_get_result(m_pClient)) + .arg(::lscp_client_get_errno(m_pClient)), "#996666"); // Make it look responsive...:) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // Force update of the messages font. void MainForm::updateMessagesFont (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) { - QFont font; - if (font.fromString(m_pOptions->sMessagesFont)) - m_pMessages->setMessagesFont(font); - } + if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) { + QFont font; + if (font.fromString(m_pOptions->sMessagesFont)) + m_pMessages->setMessagesFont(font); + } } // Update messages window line limit. void MainForm::updateMessagesLimit (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - if (m_pMessages) { - if (m_pOptions->bMessagesLimit) - m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines); - else - m_pMessages->setMessagesLimit(-1); - } + if (m_pMessages) { + if (m_pOptions->bMessagesLimit) + m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines); + else + m_pMessages->setMessagesLimit(-1); + } } // Enablement of the messages capture feature. void MainForm::updateMessagesCapture (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - if (m_pMessages) - m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture); + if (m_pMessages) + m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture); } @@ -2146,81 +2310,79 @@ // qsamplerMainForm -- MDI channel strip management. // The channel strip creation executive. -ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel) +ChannelStrip* MainForm::createChannelStrip ( Channel *pChannel ) { - if (m_pClient == NULL || pChannel == NULL) - return NULL; + if (m_pClient == NULL || pChannel == NULL) + return NULL; - // Prepare for auto-arrange? - ChannelStrip* pChannelStrip = NULL; - int y = 0; - if (m_pOptions && m_pOptions->bAutoArrange) { - QWidgetList wlist = m_pWorkspace->windowList(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - pChannelStrip = (ChannelStrip *) wlist.at(iChannel); - if (pChannelStrip) { - // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height(); - y += pChannelStrip->parentWidget()->frameGeometry().height(); - } - } - } + // Add a new channel itema... + ChannelStrip *pChannelStrip = new ChannelStrip(); + if (pChannelStrip == NULL) + return NULL; + + // Set some initial channel strip options... + if (m_pOptions) { + // Background display effect... + pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); + // We'll need a display font. + QFont font; + if (font.fromString(m_pOptions->sDisplayFont)) + pChannelStrip->setDisplayFont(font); + // Maximum allowed volume setting. + pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); + } - // Add a new channel itema... - pChannelStrip = new ChannelStrip(); - if (pChannelStrip == NULL) - return NULL; + // Add it to workspace... + m_pWorkspace->addWindow(pChannelStrip, Qt::FramelessWindowHint); - m_pWorkspace->addWindow(pChannelStrip, Qt::Tool); + // Actual channel strip setup... + pChannelStrip->setup(pChannel); - // Actual channel strip setup... - pChannelStrip->setup(pChannel); QObject::connect(pChannelStrip, SIGNAL(channelChanged(ChannelStrip*)), SLOT(channelStripChanged(ChannelStrip*))); - // Set some initial aesthetic options... - if (m_pOptions) { - // Background display effect... - pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect); - // We'll need a display font. - QFont font; - if (font.fromString(m_pOptions->sDisplayFont)) - pChannelStrip->setDisplayFont(font); - // Maximum allowed volume setting. - pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume); - } - - // Now we show up us to the world. - pChannelStrip->show(); - // Only then, we'll auto-arrange... - if (m_pOptions && m_pOptions->bAutoArrange) { - int iWidth = m_pWorkspace->width(); - // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height(); - int iHeight = pChannelStrip->parentWidget()->frameGeometry().height(); pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight); - } + + // Now we show up us to the world. + pChannelStrip->show(); // This is pretty new, so we'll watch for it closely. channelStripChanged(pChannelStrip); - // Return our successful reference... - return pChannelStrip; + // Return our successful reference... + return pChannelStrip; } +void MainForm::destroyChannelStrip(ChannelStrip* pChannelStrip) { + // Just delete the channel strip. + delete pChannelStrip; + + // Do we auto-arrange? + if (m_pOptions && m_pOptions->bAutoArrange) + channelsArrange(); + + stabilizeForm(); +} // Retrieve the active channel strip. ChannelStrip* MainForm::activeChannelStrip (void) { - return (ChannelStrip*) m_pWorkspace->activeWindow(); + return static_cast (m_pWorkspace->activeWindow()); } // Retrieve a channel strip by index. ChannelStrip* MainForm::channelStripAt ( int iChannel ) { - QWidgetList wlist = m_pWorkspace->windowList(); - if (wlist.isEmpty()) - return NULL; + if (!m_pWorkspace) return NULL; - return (ChannelStrip*) wlist.at(iChannel); + QWidgetList wlist = m_pWorkspace->windowList(); + if (wlist.isEmpty()) + return NULL; + + if (iChannel < 0 || iChannel >= wlist.size()) + return NULL; + + return dynamic_cast (wlist.at(iChannel)); } @@ -2232,9 +2394,10 @@ return NULL; for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); + ChannelStrip* pChannelStrip + = static_cast (wlist.at(iChannel)); if (pChannelStrip) { - qsamplerChannel *pChannel = pChannelStrip->channel(); + Channel *pChannel = pChannelStrip->channel(); if (pChannel && pChannel->channelID() == iChannelID) return pChannelStrip; } @@ -2248,32 +2411,42 @@ // Construct the windows menu. void MainForm::channelsMenuAboutToShow (void) { - ui.channelsMenu->clear(); - ui.channelsArrangeAction->addTo(ui.channelsMenu); - ui.channelsAutoArrangeAction->addTo(ui.channelsMenu); - - QWidgetList wlist = m_pWorkspace->windowList(); - if (!wlist.isEmpty()) { - ui.channelsMenu->insertSeparator(); - for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { - ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel); - if (pChannelStrip) { - int iItemID = ui.channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int))); - ui.channelsMenu->setItemParameter(iItemID, iChannel); - ui.channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip); - } - } - } + m_ui.channelsMenu->clear(); + m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction); + m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction); + + QWidgetList wlist = m_pWorkspace->windowList(); + if (!wlist.isEmpty()) { + m_ui.channelsMenu->addSeparator(); + for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { + ChannelStrip* pChannelStrip + = static_cast (wlist.at(iChannel)); + if (pChannelStrip) { + QAction *pAction = m_ui.channelsMenu->addAction( + pChannelStrip->windowTitle(), + this, SLOT(channelsMenuActivated())); + pAction->setCheckable(true); + pAction->setChecked(activeChannelStrip() == pChannelStrip); + pAction->setData(iChannel); + } + } + } } // Windows menu activation slot -void MainForm::channelsMenuActivated ( int iChannel ) +void MainForm::channelsMenuActivated (void) { - ChannelStrip* pChannelStrip = channelStripAt(iChannel); - if (pChannelStrip) - pChannelStrip->showNormal(); - pChannelStrip->setFocus(); + // Retrive channel index from action data... + QAction *pAction = qobject_cast (sender()); + if (pAction == NULL) + return; + + ChannelStrip* pChannelStrip = channelStripAt(pAction->data().toInt()); + if (pChannelStrip) { + pChannelStrip->showNormal(); + pChannelStrip->setFocus(); + } } @@ -2283,43 +2456,45 @@ // Set the pseudo-timer delay schedule. void MainForm::startSchedule ( int iStartDelay ) { - m_iStartDelay = 1 + (iStartDelay * 1000); - m_iTimerDelay = 0; + m_iStartDelay = 1 + (iStartDelay * 1000); + m_iTimerDelay = 0; } // Suspend the pseudo-timer delay schedule. void MainForm::stopSchedule (void) { - m_iStartDelay = 0; - m_iTimerDelay = 0; + m_iStartDelay = 0; + m_iTimerDelay = 0; } // Timer slot funtion. void MainForm::timerSlot (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - // Is it the first shot on server start after a few delay? - if (m_iTimerDelay < m_iStartDelay) { - m_iTimerDelay += QSAMPLER_TIMER_MSECS; - if (m_iTimerDelay >= m_iStartDelay) { - // If we cannot start it now, maybe a lil'mo'later ;) - if (!startClient()) { - m_iStartDelay += m_iTimerDelay; - m_iTimerDelay = 0; - } - } - } + // Is it the first shot on server start after a few delay? + if (m_iTimerDelay < m_iStartDelay) { + m_iTimerDelay += QSAMPLER_TIMER_MSECS; + if (m_iTimerDelay >= m_iStartDelay) { + // If we cannot start it now, maybe a lil'mo'later ;) + if (!startClient()) { + m_iStartDelay += m_iTimerDelay; + m_iTimerDelay = 0; + } + } + } if (m_pClient) { // Update the channel information for each pending strip... - if (m_changedStrips.count() > 0) { - for (ChannelStrip* pChannelStrip = m_changedStrips.first(); - pChannelStrip; pChannelStrip = m_changedStrips.next()) { - // If successfull, remove from pending list... - if (pChannelStrip->updateChannelInfo()) - m_changedStrips.remove(pChannelStrip); + QListIterator iter(m_changedStrips); + while (iter.hasNext()) { + ChannelStrip *pChannelStrip = iter.next(); + // If successfull, remove from pending list... + if (pChannelStrip->updateChannelInfo()) { + int iChannelStrip = m_changedStrips.indexOf(pChannelStrip); + if (iChannelStrip >= 0) + m_changedStrips.removeAt(iChannelStrip); } } // Refresh each channel usage, on each period... @@ -2340,8 +2515,8 @@ } } - // Register the next timer slot. - QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot())); + // Register the next timer slot. + QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot())); } @@ -2351,136 +2526,164 @@ // Start linuxsampler server... void MainForm::startServer (void) { - if (m_pOptions == NULL) - return; + if (m_pOptions == NULL) + return; - // Aren't already a client, are we? - if (!m_pOptions->bServerStart || m_pClient) - return; - - // Is the server process instance still here? - if (m_pServer) { - switch (QMessageBox::warning(this, + // Aren't already a client, are we? + if (!m_pOptions->bServerStart || m_pClient) + return; + + // Is the server process instance still here? + if (m_pServer) { + if (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), - tr("Could not start the LinuxSampler server.\n\n" - "Maybe it ss already started."), - tr("Stop"), tr("Kill"), tr("Cancel"))) { - case 0: - m_pServer->terminate(); - break; - case 1: - m_pServer->kill(); - break; - } - return; - } - - // Reset our timer counters... - stopSchedule(); - - // OK. Let's build the startup process... - m_pServer = new QProcess(this); - - // Setup stdout/stderr capture... - // if (m_pOptions->bStdoutCapture) { - //m_pServer->setProcessChannelMode( - // QProcess::StandardOutput); + tr("Could not start the LinuxSampler server.\n\n" + "Maybe it is already started."), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { + m_pServer->terminate(); + m_pServer->kill(); + } + return; + } + + // Reset our timer counters... + stopSchedule(); + + // Verify we have something to start with... + if (m_pOptions->sServerCmdLine.isEmpty()) + return; + + // OK. Let's build the startup process... + m_pServer = new QProcess(); + bForceServerStop = true; + + // Setup stdout/stderr capture... +// if (m_pOptions->bStdoutCapture) { +#if QT_VERSION >= 0x040200 + m_pServer->setProcessChannelMode(QProcess::ForwardedChannels); +#endif QObject::connect(m_pServer, SIGNAL(readyReadStandardOutput()), SLOT(readServerStdout())); QObject::connect(m_pServer, SIGNAL(readyReadStandardError()), SLOT(readServerStdout())); - // } +// } + // The unforgiveable signal communication... QObject::connect(m_pServer, - SIGNAL(finished(int,QProcess::ExitStatus)), + SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processServerExit())); - // Build process arguments... - QStringList serverCmdLine = QStringList::split(' ', m_pOptions->sServerCmdLine); - - appendMessages(tr("Server is starting...")); - appendMessagesColor(m_pOptions->sServerCmdLine, "#990099"); - - - - const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString(); - const QStringList args = serverCmdLine.mid(1); - - // Go jack, go... - m_pServer->start(prog, args); - if (!m_pServer->waitForStarted()) { - appendMessagesError(tr("Could not start server.\n\nSorry.")); - processServerExit(); - return; - } - - // Show startup results... - appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->pid())); + // Build process arguments... + QStringList args = m_pOptions->sServerCmdLine.split(' '); + QString sCommand = args[0]; + args.removeAt(0); + + appendMessages(tr("Server is starting...")); + appendMessagesColor(m_pOptions->sServerCmdLine, "#990099"); + + // Go linuxsampler, go... + m_pServer->start(sCommand, args); + if (!m_pServer->waitForStarted()) { + appendMessagesError(tr("Could not start server.\n\nSorry.")); + processServerExit(); + return; + } - // Reset (yet again) the timer counters, - // but this time is deferred as the user opted. - startSchedule(m_pOptions->iStartDelay); - stabilizeForm(); + // Show startup results... + appendMessages( + tr("Server was started with PID=%1.").arg((long) m_pServer->pid())); + + // Reset (yet again) the timer counters, + // but this time is deferred as the user opted. + startSchedule(m_pOptions->iStartDelay); + stabilizeForm(); } // Stop linuxsampler server... -void MainForm::stopServer (void) +void MainForm::stopServer (bool bInteractive) { - // Stop client code. - stopClient(); + // Stop client code. + stopClient(); - // And try to stop server. - if (m_pServer) { - appendMessages(tr("Server is stopping...")); - if (m_pServer->state() == QProcess::Running) - m_pServer->terminate(); - } - - // Give it some time to terminate gracefully and stabilize... - QTime t; - t.start(); - while (t.elapsed() < QSAMPLER_TIMER_MSECS) - QApplication::processEvents(QEventLoop::ExcludeUserInput); + if (m_pServer && bInteractive) { + if (QMessageBox::question(this, + QSAMPLER_TITLE ": " + tr("The backend's fate ..."), + tr("You have the option to keep the sampler backend (LinuxSampler)\n" + "running in the background. The sampler would continue to work\n" + "according to your current sampler session and you could alter the\n" + "sampler session at any time by relaunching QSampler.\n\n" + "Do you want LinuxSampler to stop?"), + QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + { + bForceServerStop = false; + } + } - // Do final processing anyway. - processServerExit(); + // And try to stop server. + if (m_pServer && bForceServerStop) { + appendMessages(tr("Server is stopping...")); + if (m_pServer->state() == QProcess::Running) { +#if defined(WIN32) + // Try harder... + m_pServer->kill(); +#else + // Try softly... + m_pServer->terminate(); +#endif + } + } // Do final processing anyway. + else processServerExit(); + + // Give it some time to terminate gracefully and stabilize... + QTime t; + t.start(); + while (t.elapsed() < QSAMPLER_TIMER_MSECS) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // Stdout handler... void MainForm::readServerStdout (void) { - if (m_pMessages) - m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput()); + if (m_pMessages) + m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput()); } // Linuxsampler server cleanup. void MainForm::processServerExit (void) { - // Force client code cleanup. - stopClient(); + // Force client code cleanup. + stopClient(); - // Flush anything that maybe pending... - if (m_pMessages) - m_pMessages->flushStdoutBuffer(); - - if (m_pServer) { - // Force final server shutdown... - appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus())); - m_pServer->terminate(); - if (!m_pServer->waitForFinished(2000)) - m_pServer->kill(); - // Destroy it. - delete m_pServer; - m_pServer = NULL; - } + // Flush anything that maybe pending... + if (m_pMessages) + m_pMessages->flushStdoutBuffer(); + + if (m_pServer && bForceServerStop) { + if (m_pServer->state() != QProcess::NotRunning) { + appendMessages(tr("Server is being forced...")); + // Force final server shutdown... + m_pServer->kill(); + // Give it some time to terminate gracefully and stabilize... + QTime t; + t.start(); + while (t.elapsed() < QSAMPLER_TIMER_MSECS) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } + // Force final server shutdown... + appendMessages( + tr("Server was stopped with exit status %1.") + .arg(m_pServer->exitStatus())); + delete m_pServer; + m_pServer = NULL; + } - // Again, make status visible stable. - stabilizeForm(); + // Again, make status visible stable. + stabilizeForm(); } @@ -2488,126 +2691,187 @@ // qsamplerMainForm -- Client stuff. // The LSCP client callback procedure. -lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData ) +lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, + lscp_event_t event, const char *pchData, int cchData, void *pvData ) { - MainForm* pMainForm = (MainForm *) pvData; - if (pMainForm == NULL) - return LSCP_FAILED; - - // ATTN: DO NOT EVER call any GUI code here, - // as this is run under some other thread context. - // A custom event must be posted here... - QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData)); + MainForm* pMainForm = (MainForm *) pvData; + if (pMainForm == NULL) + return LSCP_FAILED; + + // ATTN: DO NOT EVER call any GUI code here, + // as this is run under some other thread context. + // A custom event must be posted here... + QApplication::postEvent(pMainForm, + new CustomEvent(event, pchData, cchData)); - return LSCP_OK; + return LSCP_OK; } // Start our almighty client... bool MainForm::startClient (void) { - // Have it a setup? - if (m_pOptions == NULL) - return false; - - // Aren't we already started, are we? - if (m_pClient) - return true; - - // Log prepare here. - appendMessages(tr("Client connecting...")); - - // Create the client handle... - m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this); - if (m_pClient == NULL) { - // Is this the first try? - // maybe we need to start a local server... - if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart) - appendMessagesError(tr("Could not connect to server as client.\n\nSorry.")); - else - startServer(); - // This is always a failure. - stabilizeForm(); - return false; - } - // Just set receive timeout value, blindly. - ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout); - appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient))); + // Have it a setup? + if (m_pOptions == NULL) + return false; + + // Aren't we already started, are we? + if (m_pClient) + return true; + + // Log prepare here. + appendMessages(tr("Client connecting...")); + + // Create the client handle... + m_pClient = ::lscp_client_create( + m_pOptions->sServerHost.toUtf8().constData(), + m_pOptions->iServerPort, qsampler_client_callback, this); + if (m_pClient == NULL) { + // Is this the first try? + // maybe we need to start a local server... + if ((m_pServer && m_pServer->state() == QProcess::Running) + || !m_pOptions->bServerStart) { + appendMessagesError( + tr("Could not connect to server as client.\n\nSorry.")); + } else { + startServer(); + } + // This is always a failure. + stabilizeForm(); + return false; + } + // Just set receive timeout value, blindly. + ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout); + appendMessages( + tr("Client receive timeout is set to %1 msec.") + .arg(::lscp_client_get_timeout(m_pClient))); // Subscribe to channel info change notifications... + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)"); if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK) - appendMessagesClient("lscp_client_subscribe"); + appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)"); - // We may stop scheduling around. - stopSchedule(); + DeviceStatusForm::onDevicesChanged(); // initialize + updateViewMidiDeviceStatusMenu(); + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)"); + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)"); + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)"); + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)"); + +#if CONFIG_EVENT_CHANNEL_MIDI + // Subscribe to channel MIDI data notifications... + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)"); +#endif + +#if CONFIG_EVENT_DEVICE_MIDI + // Subscribe to channel MIDI data notifications... + if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK) + appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)"); +#endif + + // We may stop scheduling around. + stopSchedule(); - // We'll accept drops from now on... - setAcceptDrops(true); + // We'll accept drops from now on... + setAcceptDrops(true); - // Log success here. - appendMessages(tr("Client connected.")); + // Log success here. + appendMessages(tr("Client connected.")); // Hard-notify instrumnet and device configuration forms, // if visible, that we're ready... if (m_pInstrumentListForm) - m_pInstrumentListForm->refreshInstruments(); + m_pInstrumentListForm->refreshInstruments(); if (m_pDeviceForm) - m_pDeviceForm->refreshDevices(); + m_pDeviceForm->refreshDevices(); + + // Is any session pending to be loaded? + if (!m_pOptions->sSessionFile.isEmpty()) { + // Just load the prabably startup session... + if (loadSessionFile(m_pOptions->sSessionFile)) { + m_pOptions->sSessionFile = QString::null; + return true; + } + } - // Is any session pending to be loaded? - if (!m_pOptions->sSessionFile.isEmpty()) { - // Just load the prabably startup session... - if (loadSessionFile(m_pOptions->sSessionFile)) { - m_pOptions->sSessionFile = QString::null; - return true; - } - } + // send the current / loaded fine tuning settings to the sampler + m_pOptions->sendFineTuningSettings(); - // Make a new session - return newSession(); + // Make a new session + return newSession(); } // Stop client... void MainForm::stopClient (void) { - if (m_pClient == NULL) - return; - - // Log prepare here. - appendMessages(tr("Client disconnecting...")); + if (m_pClient == NULL) + return; - // Clear timer counters... - stopSchedule(); + // Log prepare here. + appendMessages(tr("Client disconnecting...")); - // We'll reject drops from now on... - setAcceptDrops(false); + // Clear timer counters... + stopSchedule(); - // Force any channel strips around, but - // but avoid removing the corresponding - // channels from the back-end server. - m_iDirtyCount = 0; - closeSession(false); + // We'll reject drops from now on... + setAcceptDrops(false); - // Close us as a client... + // Force any channel strips around, but + // but avoid removing the corresponding + // channels from the back-end server. + m_iDirtyCount = 0; + closeSession(false); + + // Close us as a client... +#if CONFIG_EVENT_DEVICE_MIDI + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI); +#endif +#if CONFIG_EVENT_CHANNEL_MIDI + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI); +#endif + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO); + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT); + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO); + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT); ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO); - ::lscp_client_destroy(m_pClient); - m_pClient = NULL; + ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT); + ::lscp_client_destroy(m_pClient); + m_pClient = NULL; // Hard-notify instrumnet and device configuration forms, // if visible, that we're running out... if (m_pInstrumentListForm) - m_pInstrumentListForm->refreshInstruments(); + m_pInstrumentListForm->refreshInstruments(); if (m_pDeviceForm) - m_pDeviceForm->refreshDevices(); + m_pDeviceForm->refreshDevices(); - // Log final here. - appendMessages(tr("Client disconnected.")); + // Log final here. + appendMessages(tr("Client disconnected.")); - // Make visible status. - stabilizeForm(); + // Make visible status. + stabilizeForm(); } + +// Channel strip activation/selection. +void MainForm::activateStrip ( QWidget *pWidget ) +{ + ChannelStrip *pChannelStrip + = static_cast (pWidget); + if (pChannelStrip) + pChannelStrip->setSelected(true); + + stabilizeForm(); +} + + } // namespace QSampler