/[svn]/qsampler/trunk/src/qsamplerMainForm.cpp
ViewVC logotype

Diff of /qsampler/trunk/src/qsamplerMainForm.cpp

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1507 by capela, Wed Nov 21 23:22:18 2007 UTC revision 3837 by capela, Tue Dec 1 17:46:41 2020 UTC
# Line 1  Line 1 
1  // qsamplerMainForm.cpp  // qsamplerMainForm.cpp
2  //  //
3  /****************************************************************************  /****************************************************************************
4     Copyright (C) 2004-2007, rncbc aka Rui Nuno Capela. All rights reserved.     Copyright (C) 2004-2020, rncbc aka Rui Nuno Capela. All rights reserved.
5     Copyright (C) 2007, Christian Schoenebeck     Copyright (C) 2007-2019 Christian Schoenebeck
6    
7     This program is free software; you can redistribute it and/or     This program is free software; you can redistribute it and/or
8     modify it under the terms of the GNU General Public License     modify it under the terms of the GNU General Public License
# Line 20  Line 20 
20    
21  *****************************************************************************/  *****************************************************************************/
22    
23    #include "qsamplerAbout.h"
24  #include "qsamplerMainForm.h"  #include "qsamplerMainForm.h"
25    
 #include "qsamplerAbout.h"  
26  #include "qsamplerOptions.h"  #include "qsamplerOptions.h"
27  #include "qsamplerChannel.h"  #include "qsamplerChannel.h"
28  #include "qsamplerMessages.h"  #include "qsamplerMessages.h"
# Line 33  Line 33 
33  #include "qsamplerInstrumentListForm.h"  #include "qsamplerInstrumentListForm.h"
34  #include "qsamplerDeviceForm.h"  #include "qsamplerDeviceForm.h"
35  #include "qsamplerOptionsForm.h"  #include "qsamplerOptionsForm.h"
36    #include "qsamplerDeviceStatusForm.h"
37    
38    #include "qsamplerPaletteForm.h"
39    
40    #include <QStyleFactory>
41    
42    #include <QMdiArea>
43    #include <QMdiSubWindow>
44    
45  #include <QApplication>  #include <QApplication>
 #include <QWorkspace>  
46  #include <QProcess>  #include <QProcess>
47  #include <QMessageBox>  #include <QMessageBox>
48    
 #include <QRegExp>  
49  #include <QTextStream>  #include <QTextStream>
50  #include <QFileDialog>  #include <QFileDialog>
51  #include <QFileInfo>  #include <QFileInfo>
# Line 55  Line 61 
61  #include <QTimer>  #include <QTimer>
62  #include <QDateTime>  #include <QDateTime>
63    
64    #include <QElapsedTimer>
65    
66  #ifdef HAVE_SIGNAL_H  #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
67  #include <signal.h>  #include <QMimeData>
68    #endif
69    
70    #if QT_VERSION < QT_VERSION_CHECK(4, 5, 0)
71    namespace Qt {
72    const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000);
73    }
74  #endif  #endif
75    
76  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
77  #include <gig.h>  #include <gig.h>
78  #endif  #endif
79    
80    // Deprecated QTextStreamFunctions/Qt namespaces workaround.
81    #if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)
82    #define endl    Qt::endl
83    #endif
84    
85  // Needed for lroundf()  // Needed for lroundf()
86  #include <math.h>  #include <math.h>
87    
# Line 77  static inline long lroundf ( float x ) Line 95  static inline long lroundf ( float x )
95  }  }
96  #endif  #endif
97    
98    
99    // All winsock apps needs this.
100    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
101    static WSADATA _wsaData;
102    #undef HAVE_SIGNAL_H
103    #endif
104    
105    
106    //-------------------------------------------------------------------------
107    // LADISH Level 1 support stuff.
108    
109    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
110    
111    #include <QSocketNotifier>
112    
113    #include <unistd.h>
114    #include <sys/types.h>
115    #include <sys/socket.h>
116    #include <signal.h>
117    
118    // File descriptor for SIGUSR1 notifier.
119    static int g_fdSigusr1[2] = { -1, -1 };
120    
121    // Unix SIGUSR1 signal handler.
122    static void qsampler_sigusr1_handler ( int /* signo */ )
123    {
124            char c = 1;
125    
126            (::write(g_fdSigusr1[0], &c, sizeof(c)) > 0);
127    }
128    
129    // File descriptor for SIGTERM notifier.
130    static int g_fdSigterm[2] = { -1, -1 };
131    
132    // Unix SIGTERM signal handler.
133    static void qsampler_sigterm_handler ( int /* signo */ )
134    {
135            char c = 1;
136    
137            (::write(g_fdSigterm[0], &c, sizeof(c)) > 0);
138    }
139    
140    #endif  // HAVE_SIGNAL_H
141    
142    
143    //-------------------------------------------------------------------------
144    // QSampler -- namespace
145    
146    
147    namespace QSampler {
148    
149  // Timer constant stuff.  // Timer constant stuff.
150  #define QSAMPLER_TIMER_MSECS    200  #define QSAMPLER_TIMER_MSECS    200
151    
# Line 87  static inline long lroundf ( float x ) Line 156  static inline long lroundf ( float x )
156  #define QSAMPLER_STATUS_SESSION 3       // Current session modification state.  #define QSAMPLER_STATUS_SESSION 3       // Current session modification state.
157    
158    
159  // All winsock apps needs this.  // Specialties for thread-callback comunication.
160  #if defined(WIN32)  #define QSAMPLER_LSCP_EVENT   QEvent::Type(QEvent::User + 1)
 static WSADATA _wsaData;  
 #endif  
161    
162    
163  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
164  // qsamplerCustomEvent -- specialty for callback comunication.  // QSampler::LscpEvent -- specialty for LSCP callback comunication.
   
 #define QSAMPLER_CUSTOM_EVENT   QEvent::Type(QEvent::User + 0)  
165    
166  class qsamplerCustomEvent : public QEvent  class LscpEvent : public QEvent
167  {  {
168  public:  public:
169    
170      // Constructor.          // Constructor.
171      qsamplerCustomEvent(lscp_event_t event, const char *pchData, int cchData)          LscpEvent(lscp_event_t event, const char *pchData, int cchData)
172          : QEvent(QSAMPLER_CUSTOM_EVENT)                  : QEvent(QSAMPLER_LSCP_EVENT)
173      {          {
174          m_event = event;                  m_event = event;
175          m_data  = QString::fromUtf8(pchData, cchData);                  m_data  = QString::fromUtf8(pchData, cchData);
176      }          }
177    
178      // Accessors.          // Accessors.
179      lscp_event_t event() { return m_event; }          lscp_event_t  event() { return m_event; }
180      QString&     data()  { return m_data;  }          const QString& data() { return m_data;  }
181    
182  private:  private:
183    
184      // The proper event type.          // The proper event type.
185      lscp_event_t m_event;          lscp_event_t m_event;
186      // The event data as a string.          // The event data as a string.
187      QString      m_data;          QString      m_data;
188  };  };
189    
190    
191  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
192  // qsamplerMainForm -- Main window form implementation.  // QSampler::Workspace -- Main window workspace (MDI Area) decl.
193    
194  namespace QSampler {  class Workspace : public QMdiArea
195    {
196    public:
197    
198            Workspace(MainForm *pMainForm) : QMdiArea(pMainForm) {}
199    
200    protected:
201    
202            void resizeEvent(QResizeEvent *)
203            {
204                    MainForm *pMainForm = static_cast<MainForm *> (parentWidget());
205                    if (pMainForm)
206                            pMainForm->channelsArrangeAuto();
207            }
208    };
209    
210    
211    //-------------------------------------------------------------------------
212    // QSampler::MainForm -- Main window form implementation.
213    
214  // Kind of singleton reference.  // Kind of singleton reference.
215  MainForm* MainForm::g_pMainForm = NULL;  MainForm *MainForm::g_pMainForm = nullptr;
216    
217  MainForm::MainForm(QWidget* parent) : QMainWindow(parent) {  MainForm::MainForm ( QWidget *pParent )
218      ui.setupUi(this);          : QMainWindow(pParent)
219    {
220            m_ui.setupUi(this);
221    
222          // Pseudo-singleton reference setup.          // Pseudo-singleton reference setup.
223          g_pMainForm = this;          g_pMainForm = this;
224    
225      // Initialize some pointer references.          // Initialize some pointer references.
226      m_pOptions = NULL;          m_pOptions = nullptr;
227    
228            // All child forms are to be created later, not earlier than setup.
229            m_pMessages = nullptr;
230            m_pInstrumentListForm = nullptr;
231            m_pDeviceForm = nullptr;
232    
233      // All child forms are to be created later, not earlier than setup.          // We'll start clean.
234      m_pMessages = NULL;          m_iUntitled   = 0;
235      m_pInstrumentListForm = NULL;          m_iDirtySetup = 0;
236      m_pDeviceForm = NULL;          m_iDirtyCount = 0;
237    
238      // We'll start clean.          m_pServer = nullptr;
239      m_iUntitled   = 0;          m_pClient = nullptr;
     m_iDirtyCount = 0;  
240    
241      m_pServer = NULL;          m_iStartDelay = 0;
242      m_pClient = NULL;          m_iTimerDelay = 0;
243    
244      m_iStartDelay = 0;          m_iTimerSlot = 0;
     m_iTimerDelay = 0;  
245    
246      m_iTimerSlot = 0;  #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
247    
 #ifdef HAVE_SIGNAL_H  
248          // Set to ignore any fatal "Broken pipe" signals.          // Set to ignore any fatal "Broken pipe" signals.
249          ::signal(SIGPIPE, SIG_IGN);          ::signal(SIGPIPE, SIG_IGN);
250  #endif  
251            // LADISH Level 1 suport.
252    
253            // Initialize file descriptors for SIGUSR1 socket notifier.
254            ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigusr1);
255            m_pSigusr1Notifier
256                    = new QSocketNotifier(g_fdSigusr1[1], QSocketNotifier::Read, this);
257    
258            QObject::connect(m_pSigusr1Notifier,
259                    SIGNAL(activated(int)),
260                    SLOT(handle_sigusr1()));
261    
262            // Install SIGUSR1 signal handler.
263            struct sigaction sigusr1;
264            sigusr1.sa_handler = qsampler_sigusr1_handler;
265            sigemptyset(&sigusr1.sa_mask);
266            sigusr1.sa_flags = 0;
267            sigusr1.sa_flags |= SA_RESTART;
268            ::sigaction(SIGUSR1, &sigusr1, nullptr);
269    
270            // Initialize file descriptors for SIGTERM socket notifier.
271            ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigterm);
272            m_pSigtermNotifier
273                    = new QSocketNotifier(g_fdSigterm[1], QSocketNotifier::Read, this);
274    
275            QObject::connect(m_pSigtermNotifier,
276                    SIGNAL(activated(int)),
277                    SLOT(handle_sigterm()));
278    
279            // Install SIGTERM signal handler.
280            struct sigaction sigterm;
281            sigterm.sa_handler = qsampler_sigterm_handler;
282            sigemptyset(&sigterm.sa_mask);
283            sigterm.sa_flags = 0;
284            sigterm.sa_flags |= SA_RESTART;
285            ::sigaction(SIGTERM, &sigterm, nullptr);
286            ::sigaction(SIGQUIT, &sigterm, nullptr);
287    
288            // Ignore SIGHUP/SIGINT signals.
289            ::signal(SIGHUP, SIG_IGN);
290            ::signal(SIGINT, SIG_IGN);
291    
292    #else   // HAVE_SIGNAL_H
293    
294            m_pSigusr1Notifier = nullptr;
295            m_pSigtermNotifier = nullptr;
296            
297    #endif  // !HAVE_SIGNAL_H
298    
299  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
300      // Make some extras into the toolbar...          // Make some extras into the toolbar...
301          const QString& sVolumeText = tr("Master volume");          const QString& sVolumeText = tr("Master volume");
302          m_iVolumeChanging = 0;          m_iVolumeChanging = 0;
303          // Volume slider...          // Volume slider...
304          ui.channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
305          m_pVolumeSlider = new QSlider(Qt::Horizontal, ui.channelsToolbar);          m_pVolumeSlider = new QSlider(Qt::Horizontal, m_ui.channelsToolbar);
306          m_pVolumeSlider->setTickPosition(QSlider::TicksBelow);          m_pVolumeSlider->setTickPosition(QSlider::TicksBothSides);
307          m_pVolumeSlider->setTickInterval(10);          m_pVolumeSlider->setTickInterval(10);
308          m_pVolumeSlider->setPageStep(10);          m_pVolumeSlider->setPageStep(10);
309          m_pVolumeSlider->setSingleStep(10);          m_pVolumeSlider->setSingleStep(10);
# Line 181  MainForm::MainForm(QWidget* parent) : QM Line 315  MainForm::MainForm(QWidget* parent) : QM
315          QObject::connect(m_pVolumeSlider,          QObject::connect(m_pVolumeSlider,
316                  SIGNAL(valueChanged(int)),                  SIGNAL(valueChanged(int)),
317                  SLOT(volumeChanged(int)));                  SLOT(volumeChanged(int)));
318          //ui.channelsToolbar->setHorizontallyStretchable(true);          m_ui.channelsToolbar->addWidget(m_pVolumeSlider);
         //ui.channelsToolbar->setStretchableWidget(m_pVolumeSlider);  
     ui.channelsToolbar->addWidget(m_pVolumeSlider);  
319          // Volume spin-box          // Volume spin-box
320          ui.channelsToolbar->addSeparator();          m_ui.channelsToolbar->addSeparator();
321          m_pVolumeSpinBox = new QSpinBox(ui.channelsToolbar);          m_pVolumeSpinBox = new QSpinBox(m_ui.channelsToolbar);
322          m_pVolumeSpinBox->setSuffix(" %");          m_pVolumeSpinBox->setSuffix(" %");
323          m_pVolumeSpinBox->setMinimum(0);          m_pVolumeSpinBox->setMinimum(0);
324          m_pVolumeSpinBox->setMaximum(100);          m_pVolumeSpinBox->setMaximum(100);
# Line 194  MainForm::MainForm(QWidget* parent) : QM Line 326  MainForm::MainForm(QWidget* parent) : QM
326          QObject::connect(m_pVolumeSpinBox,          QObject::connect(m_pVolumeSpinBox,
327                  SIGNAL(valueChanged(int)),                  SIGNAL(valueChanged(int)),
328                  SLOT(volumeChanged(int)));                  SLOT(volumeChanged(int)));
329      ui.channelsToolbar->addWidget(m_pVolumeSpinBox);          m_ui.channelsToolbar->addWidget(m_pVolumeSpinBox);
330  #endif  #endif
331    
332      // Make it an MDI workspace.          // Make it an MDI workspace.
333      m_pWorkspace = new QWorkspace(this);          m_pWorkspace = new Workspace(this);
334      m_pWorkspace->setScrollBarsEnabled(true);          m_pWorkspace->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
335            m_pWorkspace->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
336          // Set the activation connection.          // Set the activation connection.
337          QObject::connect(m_pWorkspace,          QObject::connect(m_pWorkspace,
338                  SIGNAL(windowActivated(QWidget *)),                  SIGNAL(subWindowActivated(QMdiSubWindow *)),
339                  SLOT(stabilizeForm()));                  SLOT(activateStrip(QMdiSubWindow *)));
340      // Make it shine :-)          // Make it shine :-)
341      setCentralWidget(m_pWorkspace);          setCentralWidget(m_pWorkspace);
342    
343            // Create some statusbar labels...
344            QLabel *pLabel;
345            // Client status.
346            pLabel = new QLabel(tr("Connected"), this);
347            pLabel->setAlignment(Qt::AlignLeft);
348            pLabel->setMinimumSize(pLabel->sizeHint());
349            m_statusItem[QSAMPLER_STATUS_CLIENT] = pLabel;
350            statusBar()->addWidget(pLabel);
351            // Server address.
352            pLabel = new QLabel(this);
353            pLabel->setAlignment(Qt::AlignLeft);
354            m_statusItem[QSAMPLER_STATUS_SERVER] = pLabel;
355            statusBar()->addWidget(pLabel, 1);
356            // Channel title.
357            pLabel = new QLabel(this);
358            pLabel->setAlignment(Qt::AlignLeft);
359            m_statusItem[QSAMPLER_STATUS_CHANNEL] = pLabel;
360            statusBar()->addWidget(pLabel, 2);
361            // Session modification status.
362            pLabel = new QLabel(tr("MOD"), this);
363            pLabel->setAlignment(Qt::AlignHCenter);
364            pLabel->setMinimumSize(pLabel->sizeHint());
365            m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel;
366            statusBar()->addWidget(pLabel);
367    
368    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
369            WSAStartup(MAKEWORD(1, 1), &_wsaData);
370    #endif
371    
372            // Some actions surely need those
373            // shortcuts firmly attached...
374            addAction(m_ui.viewMenubarAction);
375            addAction(m_ui.viewToolbarAction);
376    
377      // Create some statusbar labels...          QObject::connect(m_ui.fileNewAction,
     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);  
 #endif  
   
         QObject::connect(ui.fileNewAction,  
378                  SIGNAL(triggered()),                  SIGNAL(triggered()),
379                  SLOT(fileNew()));                  SLOT(fileNew()));
380          QObject::connect(ui.fileOpenAction,          QObject::connect(m_ui.fileOpenAction,
381                  SIGNAL(triggered()),                  SIGNAL(triggered()),
382                  SLOT(fileOpen()));                  SLOT(fileOpen()));
383          QObject::connect(ui.fileSaveAction,          QObject::connect(m_ui.fileSaveAction,
384                  SIGNAL(triggered()),                  SIGNAL(triggered()),
385                  SLOT(fileSave()));                  SLOT(fileSave()));
386          QObject::connect(ui.fileSaveAsAction,          QObject::connect(m_ui.fileSaveAsAction,
387                  SIGNAL(triggered()),                  SIGNAL(triggered()),
388                  SLOT(fileSaveAs()));                  SLOT(fileSaveAs()));
389          QObject::connect(ui.fileResetAction,          QObject::connect(m_ui.fileResetAction,
390                  SIGNAL(triggered()),                  SIGNAL(triggered()),
391                  SLOT(fileReset()));                  SLOT(fileReset()));
392          QObject::connect(ui.fileRestartAction,          QObject::connect(m_ui.fileRestartAction,
393                  SIGNAL(triggered()),                  SIGNAL(triggered()),
394                  SLOT(fileRestart()));                  SLOT(fileRestart()));
395          QObject::connect(ui.fileExitAction,          QObject::connect(m_ui.fileExitAction,
396                  SIGNAL(triggered()),                  SIGNAL(triggered()),
397                  SLOT(fileExit()));                  SLOT(fileExit()));
398          QObject::connect(ui.editAddChannelAction,          QObject::connect(m_ui.editAddChannelAction,
399                  SIGNAL(triggered()),                  SIGNAL(triggered()),
400                  SLOT(editAddChannel()));                  SLOT(editAddChannel()));
401          QObject::connect(ui.editRemoveChannelAction,          QObject::connect(m_ui.editRemoveChannelAction,
402                  SIGNAL(triggered()),                  SIGNAL(triggered()),
403                  SLOT(editRemoveChannel()));                  SLOT(editRemoveChannel()));
404          QObject::connect(ui.editSetupChannelAction,          QObject::connect(m_ui.editSetupChannelAction,
405                  SIGNAL(triggered()),                  SIGNAL(triggered()),
406                  SLOT(editSetupChannel()));                  SLOT(editSetupChannel()));
407          QObject::connect(ui.editEditChannelAction,          QObject::connect(m_ui.editEditChannelAction,
408                  SIGNAL(triggered()),                  SIGNAL(triggered()),
409                  SLOT(editEditChannel()));                  SLOT(editEditChannel()));
410          QObject::connect(ui.editResetChannelAction,          QObject::connect(m_ui.editResetChannelAction,
411                  SIGNAL(triggered()),                  SIGNAL(triggered()),
412                  SLOT(editResetChannel()));                  SLOT(editResetChannel()));
413          QObject::connect(ui.editResetAllChannelsAction,          QObject::connect(m_ui.editResetAllChannelsAction,
414                  SIGNAL(triggered()),                  SIGNAL(triggered()),
415                  SLOT(editResetAllChannels()));                  SLOT(editResetAllChannels()));
416          QObject::connect(ui.viewMenubarAction,          QObject::connect(m_ui.viewMenubarAction,
417                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
418                  SLOT(viewMenubar(bool)));                  SLOT(viewMenubar(bool)));
419          QObject::connect(ui.viewToolbarAction,          QObject::connect(m_ui.viewToolbarAction,
420                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
421                  SLOT(viewToolbar(bool)));                  SLOT(viewToolbar(bool)));
422          QObject::connect(ui.viewStatusbarAction,          QObject::connect(m_ui.viewStatusbarAction,
423                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
424                  SLOT(viewStatusbar(bool)));                  SLOT(viewStatusbar(bool)));
425          QObject::connect(ui.viewMessagesAction,          QObject::connect(m_ui.viewMessagesAction,
426                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
427                  SLOT(viewMessages(bool)));                  SLOT(viewMessages(bool)));
428          QObject::connect(ui.viewInstrumentsAction,          QObject::connect(m_ui.viewInstrumentsAction,
429                  SIGNAL(triggered()),                  SIGNAL(triggered()),
430                  SLOT(viewInstruments()));                  SLOT(viewInstruments()));
431          QObject::connect(ui.viewDevicesAction,          QObject::connect(m_ui.viewDevicesAction,
432                  SIGNAL(triggered()),                  SIGNAL(triggered()),
433                  SLOT(viewDevices()));                  SLOT(viewDevices()));
434          QObject::connect(ui.viewOptionsAction,          QObject::connect(m_ui.viewOptionsAction,
435                  SIGNAL(triggered()),                  SIGNAL(triggered()),
436                  SLOT(viewOptions()));                  SLOT(viewOptions()));
437          QObject::connect(ui.channelsArrangeAction,          QObject::connect(m_ui.channelsArrangeAction,
438                  SIGNAL(triggered()),                  SIGNAL(triggered()),
439                  SLOT(channelsArrange()));                  SLOT(channelsArrange()));
440          QObject::connect(ui.channelsAutoArrangeAction,          QObject::connect(m_ui.channelsAutoArrangeAction,
441                  SIGNAL(toggled(bool)),                  SIGNAL(toggled(bool)),
442                  SLOT(channelsAutoArrange(bool)));                  SLOT(channelsAutoArrange(bool)));
443          QObject::connect(ui.helpAboutAction,          QObject::connect(m_ui.helpAboutAction,
444                  SIGNAL(triggered()),                  SIGNAL(triggered()),
445                  SLOT(helpAbout()));                  SLOT(helpAbout()));
446          QObject::connect(ui.helpAboutQtAction,          QObject::connect(m_ui.helpAboutQtAction,
447                  SIGNAL(triggered()),                  SIGNAL(triggered()),
448                  SLOT(helpAboutQt()));                  SLOT(helpAboutQt()));
449    
450          QObject::connect(ui.fileMenu,          QObject::connect(m_ui.fileMenu,
451                  SIGNAL(aboutToShow()),                  SIGNAL(aboutToShow()),
452                  SLOT(updateRecentFilesMenu()));                  SLOT(updateRecentFilesMenu()));
453          QObject::connect(ui.channelsMenu,          QObject::connect(m_ui.channelsMenu,
454                  SIGNAL(aboutToShow()),                  SIGNAL(aboutToShow()),
455                  SLOT(channelsMenuAboutToShow()));                  SLOT(channelsMenuAboutToShow()));
456    #ifdef CONFIG_VOLUME
457            QObject::connect(m_ui.channelsToolbar,
458                    SIGNAL(orientationChanged(Qt::Orientation)),
459                    SLOT(channelsToolbarOrientation(Qt::Orientation)));
460    #endif
461  }  }
462    
463  // Destructor.  // Destructor.
464  MainForm::~MainForm()  MainForm::~MainForm()
465  {  {
466      // Do final processing anyway.          // Do final processing anyway.
467      processServerExit();          processServerExit();
468    
469    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
470            WSACleanup();
471    #endif
472    
473  #if defined(WIN32)  #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
474      WSACleanup();          if (m_pSigusr1Notifier)
475                    delete m_pSigusr1Notifier;
476            if (m_pSigtermNotifier)
477                    delete m_pSigtermNotifier;
478  #endif  #endif
479    
480      // Finally drop any widgets around...          // Finally drop any widgets around...
481      if (m_pDeviceForm)          if (m_pDeviceForm)
482          delete m_pDeviceForm;                  delete m_pDeviceForm;
483      if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
484          delete m_pInstrumentListForm;                  delete m_pInstrumentListForm;
485      if (m_pMessages)          if (m_pMessages)
486          delete m_pMessages;                  delete m_pMessages;
487      if (m_pWorkspace)          if (m_pWorkspace)
488          delete m_pWorkspace;                  delete m_pWorkspace;
489    
490      // Delete status item labels one by one.          // Delete status item labels one by one.
491      if (m_statusItem[QSAMPLER_STATUS_CLIENT])          if (m_statusItem[QSAMPLER_STATUS_CLIENT])
492          delete m_statusItem[QSAMPLER_STATUS_CLIENT];                  delete m_statusItem[QSAMPLER_STATUS_CLIENT];
493      if (m_statusItem[QSAMPLER_STATUS_SERVER])          if (m_statusItem[QSAMPLER_STATUS_SERVER])
494          delete m_statusItem[QSAMPLER_STATUS_SERVER];                  delete m_statusItem[QSAMPLER_STATUS_SERVER];
495      if (m_statusItem[QSAMPLER_STATUS_CHANNEL])          if (m_statusItem[QSAMPLER_STATUS_CHANNEL])
496          delete m_statusItem[QSAMPLER_STATUS_CHANNEL];                  delete m_statusItem[QSAMPLER_STATUS_CHANNEL];
497      if (m_statusItem[QSAMPLER_STATUS_SESSION])          if (m_statusItem[QSAMPLER_STATUS_SESSION])
498          delete m_statusItem[QSAMPLER_STATUS_SESSION];                  delete m_statusItem[QSAMPLER_STATUS_SESSION];
499    
500  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
501          delete m_pVolumeSpinBox;          delete m_pVolumeSpinBox;
# Line 353  MainForm::~MainForm() Line 503  MainForm::~MainForm()
503  #endif  #endif
504    
505          // Pseudo-singleton reference shut-down.          // Pseudo-singleton reference shut-down.
506          g_pMainForm = NULL;          g_pMainForm = nullptr;
507  }  }
508    
509    
510  // Make and set a proper setup options step.  // Make and set a proper setup options step.
511  void MainForm::setup ( qsamplerOptions *pOptions )  void MainForm::setup ( Options *pOptions )
512  {  {
513      // We got options?          // We got options?
514      m_pOptions = pOptions;          m_pOptions = pOptions;
515    
516      // What style do we create these forms?          // What style do we create these forms?
517          Qt::WindowFlags wflags = Qt::Window          Qt::WindowFlags wflags = Qt::Window
 #if QT_VERSION >= 0x040200  
518                  | Qt::CustomizeWindowHint                  | Qt::CustomizeWindowHint
 #endif  
519                  | Qt::WindowTitleHint                  | Qt::WindowTitleHint
520                  | Qt::WindowSystemMenuHint                  | Qt::WindowSystemMenuHint
521                  | Qt::WindowMinMaxButtonsHint;                  | Qt::WindowMinMaxButtonsHint
522                    | Qt::WindowCloseButtonHint;
523          if (m_pOptions->bKeepOnTop)          if (m_pOptions->bKeepOnTop)
524                  wflags |= Qt::Tool;                  wflags |= Qt::Tool;
525      // Some child forms are to be created right now.  
526      m_pMessages = new qsamplerMessages(this);          // Some child forms are to be created right now.
527      m_pDeviceForm = new DeviceForm(this, wflags);          m_pMessages = new Messages(this);
528            m_pDeviceForm = new DeviceForm(this, wflags);
529  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
530      m_pInstrumentListForm = new InstrumentListForm(this, wflags);          m_pInstrumentListForm = new InstrumentListForm(this, wflags);
         QObject::connect(&m_pInstrumentListForm->model,  
                 SIGNAL(instrumentsChanged()),  
                 SLOT(sessionDirty()));  
531  #else  #else
532          viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
533  #endif  #endif
534      // Set message defaults...  
535      updateMessagesFont();          // Setup messages logging appropriately...
536      updateMessagesLimit();          m_pMessages->setLogging(
537      updateMessagesCapture();                  m_pOptions->bMessagesLog,
538      // Set the visibility signal.                  m_pOptions->sMessagesLogPath);
539    
540            // Set message defaults...
541            updateMessagesFont();
542            updateMessagesLimit();
543            updateMessagesCapture();
544    
545            // Set the visibility signal.
546          QObject::connect(m_pMessages,          QObject::connect(m_pMessages,
547                  SIGNAL(visibilityChanged(bool)),                  SIGNAL(visibilityChanged(bool)),
548                  SLOT(stabilizeForm()));                  SLOT(stabilizeForm()));
549    
550      // Initial decorations toggle state.          // Initial decorations toggle state.
551      ui.viewMenubarAction->setChecked(m_pOptions->bMenubar);          m_ui.viewMenubarAction->setChecked(m_pOptions->bMenubar);
552      ui.viewToolbarAction->setChecked(m_pOptions->bToolbar);          m_ui.viewToolbarAction->setChecked(m_pOptions->bToolbar);
553      ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar);          m_ui.viewStatusbarAction->setChecked(m_pOptions->bStatusbar);
554      ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange);          m_ui.channelsAutoArrangeAction->setChecked(m_pOptions->bAutoArrange);
555    
556      // Initial decorations visibility state.          // Initial decorations visibility state.
557      viewMenubar(m_pOptions->bMenubar);          viewMenubar(m_pOptions->bMenubar);
558      viewToolbar(m_pOptions->bToolbar);          viewToolbar(m_pOptions->bToolbar);
559      viewStatusbar(m_pOptions->bStatusbar);          viewStatusbar(m_pOptions->bStatusbar);
560    
561      addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);          addDockWidget(Qt::BottomDockWidgetArea, m_pMessages);
562    
563          // Restore whole dock windows state.          // Restore whole dock windows state.
564          QByteArray aDockables = m_pOptions->settings().value(          QByteArray aDockables = m_pOptions->settings().value(
# Line 413  void MainForm::setup ( qsamplerOptions * Line 567  void MainForm::setup ( qsamplerOptions *
567                  restoreState(aDockables);                  restoreState(aDockables);
568          }          }
569    
570      // Try to restore old window positioning and initial visibility.          // Try to restore old window positioning and initial visibility.
571      m_pOptions->loadWidgetGeometry(this);          m_pOptions->loadWidgetGeometry(this, true);
572      m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);          m_pOptions->loadWidgetGeometry(m_pInstrumentListForm);
573      m_pOptions->loadWidgetGeometry(m_pDeviceForm);          m_pOptions->loadWidgetGeometry(m_pDeviceForm);
574    
575      // Final startup stabilization...          // Final startup stabilization...
576      updateMaxVolume();          updateMaxVolume();
577      updateRecentFilesMenu();          updateRecentFilesMenu();
578      stabilizeForm();          stabilizeForm();
579    
580      // Make it ready :-)          // Make it ready :-)
581      statusBar()->showMessage(tr("Ready"), 3000);          statusBar()->showMessage(tr("Ready"), 3000);
582    
583      // We'll try to start immediately...          // We'll try to start immediately...
584      startSchedule(0);          startSchedule(0);
585    
586      // Register the first timer slot.          // Register the first timer slot.
587      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
588  }  }
589    
590    
591  // Window close event handlers.  // Window close event handlers.
592  bool MainForm::queryClose (void)  bool MainForm::queryClose (void)
593  {  {
594      bool bQueryClose = closeSession(false);          bool bQueryClose = closeSession(false);
595    
596      // Try to save current general state...          // Try to save current general state...
597      if (m_pOptions) {          if (m_pOptions) {
598          // Some windows default fonts is here on demand too.                  // Some windows default fonts is here on demand too.
599          if (bQueryClose && m_pMessages)                  if (bQueryClose && m_pMessages)
600              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
601          // Try to save current positioning.                  // Try to save current positioning.
602          if (bQueryClose) {                  if (bQueryClose) {
603              // Save decorations state.                          // Save decorations state.
604              m_pOptions->bMenubar = ui.MenuBar->isVisible();                          m_pOptions->bMenubar = m_ui.MenuBar->isVisible();
605              m_pOptions->bToolbar = (ui.fileToolbar->isVisible() || ui.editToolbar->isVisible() || ui.channelsToolbar->isVisible());                          m_pOptions->bToolbar = (m_ui.fileToolbar->isVisible()
606              m_pOptions->bStatusbar = statusBar()->isVisible();                                  || m_ui.editToolbar->isVisible()
607              // Save the dock windows state.                                  || m_ui.channelsToolbar->isVisible());
608              const QString sDockables = saveState().toBase64().data();                          m_pOptions->bStatusbar = statusBar()->isVisible();
609                            // Save the dock windows state.
610                          m_pOptions->settings().setValue("/Layout/DockWindows", saveState());                          m_pOptions->settings().setValue("/Layout/DockWindows", saveState());
611              // And the children, and the main windows state,.                          // And the children, and the main windows state,.
612                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);                          m_pOptions->saveWidgetGeometry(m_pDeviceForm);
613                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);                          m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
614                          m_pOptions->saveWidgetGeometry(this);                          m_pOptions->saveWidgetGeometry(this, true);
615                          // Close popup widgets.                          // Close popup widgets.
616                          if (m_pInstrumentListForm)                          if (m_pInstrumentListForm)
617                                  m_pInstrumentListForm->close();                                  m_pInstrumentListForm->close();
618                          if (m_pDeviceForm)                          if (m_pDeviceForm)
619                                  m_pDeviceForm->close();                                  m_pDeviceForm->close();
620              // Stop client and/or server, gracefully.                          // Stop client and/or server, gracefully.
621              stopServer();                          stopServer(true /*interactive*/);
622          }                  }
623      }          }
624    
625      return bQueryClose;          return bQueryClose;
626  }  }
627    
628    
629  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )  void MainForm::closeEvent ( QCloseEvent *pCloseEvent )
630  {  {
631      if (queryClose())          if (queryClose()) {
632          pCloseEvent->accept();                  DeviceStatusForm::deleteAllInstances();
633      else                  pCloseEvent->accept();
634          pCloseEvent->ignore();          } else
635                    pCloseEvent->ignore();
636  }  }
637    
638    
# Line 484  void MainForm::closeEvent ( QCloseEvent Line 640  void MainForm::closeEvent ( QCloseEvent
640  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )  void MainForm::dragEnterEvent ( QDragEnterEvent* pDragEnterEvent )
641  {  {
642          // Accept external drags only...          // Accept external drags only...
643          if (pDragEnterEvent->source() == NULL          if (pDragEnterEvent->source() == nullptr
644                  && pDragEnterEvent->mimeData()->hasUrls()) {                  && pDragEnterEvent->mimeData()->hasUrls()) {
645                  pDragEnterEvent->accept();                  pDragEnterEvent->accept();
646          } else {          } else {
# Line 493  void MainForm::dragEnterEvent ( QDragEnt Line 649  void MainForm::dragEnterEvent ( QDragEnt
649  }  }
650    
651    
652  void MainForm::dropEvent ( QDropEvent* pDropEvent )  void MainForm::dropEvent ( QDropEvent *pDropEvent )
653  {  {
654          // Accept externally originated drops only...          // Accept externally originated drops only...
655          if (pDropEvent->source())          if (pDropEvent->source())
# Line 504  void MainForm::dropEvent ( QDropEvent* p Line 660  void MainForm::dropEvent ( QDropEvent* p
660                  QListIterator<QUrl> iter(pMimeData->urls());                  QListIterator<QUrl> iter(pMimeData->urls());
661                  while (iter.hasNext()) {                  while (iter.hasNext()) {
662                          const QString& sPath = iter.next().toLocalFile();                          const QString& sPath = iter.next().toLocalFile();
663                          if (qsamplerChannel::isInstrumentFile(sPath)) {                  //      if (Channel::isDlsInstrumentFile(sPath)) {
664                            if (QFileInfo(sPath).exists()) {
665                                  // Try to create a new channel from instrument file...                                  // Try to create a new channel from instrument file...
666                                  qsamplerChannel *pChannel = new qsamplerChannel();                                  Channel *pChannel = new Channel();
667                                  if (pChannel == NULL)                                  if (pChannel == nullptr)
668                                          return;                                          return;
669                                  // Start setting the instrument filename...                                  // Start setting the instrument filename...
670                                  pChannel->setInstrument(sPath, 0);                                  pChannel->setInstrument(sPath, 0);
# Line 538  void MainForm::dropEvent ( QDropEvent* p Line 695  void MainForm::dropEvent ( QDropEvent* p
695    
696    
697  // Custome event handler.  // Custome event handler.
698  void MainForm::customEvent(QEvent* pCustomEvent)  void MainForm::customEvent ( QEvent* pEvent )
699  {  {
700      // For the time being, just pump it to messages.          // For the time being, just pump it to messages.
701      if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) {          if (pEvent->type() == QSAMPLER_LSCP_EVENT) {
702          qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent;                  LscpEvent *pLscpEvent = static_cast<LscpEvent *> (pEvent);
703                  if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) {                  switch (pLscpEvent->event()) {
704                          int iChannelID = pEvent->data().toInt();                          case LSCP_EVENT_CHANNEL_COUNT:
705                          ChannelStrip *pChannelStrip = channelStrip(iChannelID);                                  updateAllChannelStrips(true);
706                          if (pChannelStrip)                                  break;
707                                  channelStripChanged(pChannelStrip);                          case LSCP_EVENT_CHANNEL_INFO: {
708                  } else {                                  const int iChannelID = pLscpEvent->data().toInt();
709                          appendMessagesColor(tr("Notify event: %1 data: %2")                                  ChannelStrip *pChannelStrip = channelStrip(iChannelID);
710                                  .arg(::lscp_event_to_text(pEvent->event()))                                  if (pChannelStrip)
711                                  .arg(pEvent->data()), "#996699");                                          channelStripChanged(pChannelStrip);
712                                    break;
713                            }
714                            case LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT:
715                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
716                                    DeviceStatusForm::onDevicesChanged();
717                                    updateViewMidiDeviceStatusMenu();
718                                    break;
719                            case LSCP_EVENT_MIDI_INPUT_DEVICE_INFO: {
720                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
721                                    const int iDeviceID = pLscpEvent->data().section(' ', 0, 0).toInt();
722                                    DeviceStatusForm::onDeviceChanged(iDeviceID);
723                                    break;
724                            }
725                            case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT:
726                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
727                                    break;
728                            case LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO:
729                                    if (m_pDeviceForm) m_pDeviceForm->refreshDevices();
730                                    break;
731                    #if CONFIG_EVENT_CHANNEL_MIDI
732                            case LSCP_EVENT_CHANNEL_MIDI: {
733                                    const int iChannelID = pLscpEvent->data().section(' ', 0, 0).toInt();
734                                    ChannelStrip *pChannelStrip = channelStrip(iChannelID);
735                                    if (pChannelStrip)
736                                            pChannelStrip->midiActivityLedOn();
737                                    break;
738                            }
739                    #endif
740                    #if CONFIG_EVENT_DEVICE_MIDI
741                            case LSCP_EVENT_DEVICE_MIDI: {
742                                    const int iDeviceID = pLscpEvent->data().section(' ', 0, 0).toInt();
743                                    const int iPortID   = pLscpEvent->data().section(' ', 1, 1).toInt();
744                                    DeviceStatusForm *pDeviceStatusForm
745                                            = DeviceStatusForm::getInstance(iDeviceID);
746                                    if (pDeviceStatusForm)
747                                            pDeviceStatusForm->midiArrived(iPortID);
748                                    break;
749                            }
750                    #endif
751                            default:
752                                    appendMessagesColor(tr("LSCP Event: %1 data: %2")
753                                            .arg(::lscp_event_to_text(pLscpEvent->event()))
754                                            .arg(pLscpEvent->data()), "#996699");
755                  }                  }
756      }          }
757    }
758    
759    
760    // LADISH Level 1 -- SIGUSR1 signal handler.
761    void MainForm::handle_sigusr1 (void)
762    {
763    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
764    
765            char c;
766    
767            if (::read(g_fdSigusr1[1], &c, sizeof(c)) > 0)
768                    saveSession(false);
769    
770    #endif
771  }  }
772    
773    
774    void MainForm::handle_sigterm (void)
775    {
776    #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
777    
778            char c;
779    
780            if (::read(g_fdSigterm[1], &c, sizeof(c)) > 0)
781                    close();
782    
783    #endif
784    }
785    
786    
787    void MainForm::updateViewMidiDeviceStatusMenu (void)
788    {
789            m_ui.viewMidiDeviceStatusMenu->clear();
790            const std::map<int, DeviceStatusForm *> statusForms
791                    = DeviceStatusForm::getInstances();
792            std::map<int, DeviceStatusForm *>::const_iterator iter
793                    = statusForms.begin();
794            for ( ; iter != statusForms.end(); ++iter) {
795                    DeviceStatusForm *pStatusForm = iter->second;
796                    m_ui.viewMidiDeviceStatusMenu->addAction(
797                            pStatusForm->visibleAction());
798            }
799    }
800    
801    
802  // Context menu event handler.  // Context menu event handler.
803  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )  void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )
804  {  {
805      stabilizeForm();          stabilizeForm();
806    
807      ui.editMenu->exec(pEvent->globalPos());          m_ui.editMenu->exec(pEvent->globalPos());
808  }  }
809    
810    
811  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
812  // qsamplerMainForm -- Brainless public property accessors.  // QSampler::MainForm -- Brainless public property accessors.
813    
814  // The global options settings property.  // The global options settings property.
815  qsamplerOptions *MainForm::options (void)  Options *MainForm::options (void) const
816  {  {
817      return m_pOptions;          return m_pOptions;
818  }  }
819    
820    
821  // The LSCP client descriptor property.  // The LSCP client descriptor property.
822  lscp_client_t *MainForm::client (void)  lscp_client_t *MainForm::client (void) const
823  {  {
824      return m_pClient;          return m_pClient;
825  }  }
826    
827    
# Line 590  MainForm *MainForm::getInstance (void) Line 833  MainForm *MainForm::getInstance (void)
833    
834    
835  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
836  // qsamplerMainForm -- Session file stuff.  // QSampler::MainForm -- Session file stuff.
837    
838  // Format the displayable session filename.  // Format the displayable session filename.
839  QString MainForm::sessionName ( const QString& sFilename )  QString MainForm::sessionName ( const QString& sFilename )
840  {  {
841      bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);          const bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
842      QString sSessionName = sFilename;          QString sSessionName = sFilename;
843      if (sSessionName.isEmpty())          if (sSessionName.isEmpty())
844          sSessionName = tr("Untitled") + QString::number(m_iUntitled);                  sSessionName = tr("Untitled") + QString::number(m_iUntitled);
845      else if (!bCompletePath)          else if (!bCompletePath)
846          sSessionName = QFileInfo(sSessionName).fileName();                  sSessionName = QFileInfo(sSessionName).fileName();
847      return sSessionName;          return sSessionName;
848  }  }
849    
850    
851  // Create a new session file from scratch.  // Create a new session file from scratch.
852  bool MainForm::newSession (void)  bool MainForm::newSession (void)
853  {  {
854      // Check if we can do it.          // Check if we can do it.
855      if (!closeSession(true))          if (!closeSession(true))
856          return false;                  return false;
857    
858          // Give us what the server has, right now...          // Give us what the server has, right now...
859          updateSession();          updateSession();
860    
861      // Ok increment untitled count.          // Ok increment untitled count.
862      m_iUntitled++;          m_iUntitled++;
863    
864      // Stabilize form.          // Stabilize form.
865      m_sFilename = QString::null;          m_sFilename = QString();
866      m_iDirtyCount = 0;          m_iDirtyCount = 0;
867      appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
868      stabilizeForm();          stabilizeForm();
869    
870      return true;          return true;
871  }  }
872    
873    
874  // Open an existing sampler session.  // Open an existing sampler session.
875  bool MainForm::openSession (void)  bool MainForm::openSession (void)
876  {  {
877      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
878          return false;                  return false;
879    
880      // Ask for the filename to open...          // Ask for the filename to open...
881          QString sFilename = QFileDialog::getOpenFileName(this,          QString sFilename = QFileDialog::getOpenFileName(this,
882                  QSAMPLER_TITLE ": " + tr("Open Session"), // Caption.                  tr("Open Session"),                       // Caption.
883                  m_pOptions->sSessionDir,                  // Start here.                  m_pOptions->sSessionDir,                  // Start here.
884                  tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)                  tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
885          );          );
886    
887      // Have we cancelled?          // Have we cancelled?
888      if (sFilename.isEmpty())          if (sFilename.isEmpty())
889          return false;                  return false;
890    
891      // Check if we're going to discard safely the current one...          // Check if we're going to discard safely the current one...
892      if (!closeSession(true))          if (!closeSession(true))
893          return false;                  return false;
894    
895      // Load it right away.          // Load it right away.
896      return loadSessionFile(sFilename);          return loadSessionFile(sFilename);
897  }  }
898    
899    
900  // Save current sampler session with another name.  // Save current sampler session with another name.
901  bool MainForm::saveSession ( bool bPrompt )  bool MainForm::saveSession ( bool bPrompt )
902  {  {
903      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
904          return false;                  return false;
905    
906      QString sFilename = m_sFilename;          QString sFilename = m_sFilename;
907    
908      // Ask for the file to save, if there's none...          // Ask for the file to save, if there's none...
909      if (bPrompt || sFilename.isEmpty()) {          if (bPrompt || sFilename.isEmpty()) {
910          // If none is given, assume default directory.                  // If none is given, assume default directory.
911          if (sFilename.isEmpty())                  if (sFilename.isEmpty())
912              sFilename = m_pOptions->sSessionDir;                          sFilename = m_pOptions->sSessionDir;
913          // Prompt the guy...                  // Prompt the guy...
914                  sFilename = QFileDialog::getSaveFileName(this,                  sFilename = QFileDialog::getSaveFileName(this,
915                          QSAMPLER_TITLE ": " + tr("Save Session"), // Caption.                          tr("Save Session"),                       // Caption.
916                          sFilename,                                // Start here.                          sFilename,                                // Start here.
917                          tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)                          tr("LSCP Session files") + " (*.lscp)"    // Filter (LSCP files)
918                  );                  );
919          // Have we cancelled it?                  // Have we cancelled it?
920          if (sFilename.isEmpty())                  if (sFilename.isEmpty())
921              return false;                          return false;
922          // Enforce .lscp extension...                  // Enforce .lscp extension...
923          if (QFileInfo(sFilename).suffix().isEmpty())                  if (QFileInfo(sFilename).suffix().isEmpty())
924              sFilename += ".lscp";                          sFilename += ".lscp";
925          // Check if already exists...          #if 0
926          if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {                  // Check if already exists...
927              if (QMessageBox::warning(this,                  if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
928                                  QSAMPLER_TITLE ": " + tr("Warning"),                          if (QMessageBox::warning(this,
929                  tr("The file already exists:\n\n"                                  tr("Warning"),
930                     "\"%1\"\n\n"                                  tr("The file already exists:\n\n"
931                     "Do you want to replace it?")                                  "\"%1\"\n\n"
932                     .arg(sFilename),                                  "Do you want to replace it?")
933                  tr("Replace"), tr("Cancel")) > 0)                                  .arg(sFilename),
934                  return false;                                  QMessageBox::Yes | QMessageBox::No)
935          }                                  == QMessageBox::No)
936      }                                  return false;
937                    }
938            #endif
939            }
940    
941      // Save it right away.          // Save it right away.
942      return saveSessionFile(sFilename);          return saveSessionFile(sFilename);
943  }  }
944    
945    
946  // Close current session.  // Close current session.
947  bool MainForm::closeSession ( bool bForce )  bool MainForm::closeSession ( bool bForce )
948  {  {
949      bool bClose = true;          bool bClose = true;
950    
951      // Are we dirty enough to prompt it?          // Are we dirty enough to prompt it?
952      if (m_iDirtyCount > 0) {          if (m_iDirtyCount > 0) {
953          switch (QMessageBox::warning(this,                  switch (QMessageBox::warning(this,
954                          QSAMPLER_TITLE ": " + tr("Warning"),                          tr("Warning"),
955              tr("The current session has been changed:\n\n"                          tr("The current session has been changed:\n\n"
956              "\"%1\"\n\n"                          "\"%1\"\n\n"
957              "Do you want to save the changes?")                          "Do you want to save the changes?")
958              .arg(sessionName(m_sFilename)),                          .arg(sessionName(m_sFilename)),
959              tr("Save"), tr("Discard"), tr("Cancel"))) {                          QMessageBox::Save |
960          case 0:     // Save...                          QMessageBox::Discard |
961              bClose = saveSession(false);                          QMessageBox::Cancel)) {
962              // Fall thru....                  case QMessageBox::Save:
963          case 1:     // Discard                          bClose = saveSession(false);
964              break;                          // Fall thru....
965          default:    // Cancel.                  case QMessageBox::Discard:
966              bClose = false;                          break;
967              break;                  default:    // Cancel.
968          }                          bClose = false;
969      }                          break;
970                    }
971      // 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;  
     }  
972    
973      return bClose;          // If we may close it, dot it.
974            if (bClose) {
975                    // Remove all channel strips from sight...
976                    m_pWorkspace->setUpdatesEnabled(false);
977                    const QList<QMdiSubWindow *>& wlist
978                            = m_pWorkspace->subWindowList();
979                    foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
980                            ChannelStrip *pChannelStrip
981                                    = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
982                            if (pChannelStrip) {
983                                    Channel *pChannel = pChannelStrip->channel();
984                                    if (bForce && pChannel)
985                                            pChannel->removeChannel();
986                                    delete pChannelStrip;
987                            }
988                            delete pMdiSubWindow;
989                    }
990                    m_pWorkspace->setUpdatesEnabled(true);
991                    // We're now clean, for sure.
992                    m_iDirtyCount = 0;
993            }
994    
995            return bClose;
996  }  }
997    
998    
999  // Load a session from specific file path.  // Load a session from specific file path.
1000  bool MainForm::loadSessionFile ( const QString& sFilename )  bool MainForm::loadSessionFile ( const QString& sFilename )
1001  {  {
1002      if (m_pClient == NULL)          if (m_pClient == nullptr)
1003          return false;                  return false;
1004    
1005      // Open and read from real file.          // Open and read from real file.
1006      QFile file(sFilename);          QFile file(sFilename);
1007      if (!file.open(QIODevice::ReadOnly)) {          if (!file.open(QIODevice::ReadOnly)) {
1008          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1009          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
1010      }                          .arg(sFilename));
1011                    return false;
1012            }
1013    
1014          // Tell the world we'll take some time...          // Tell the world we'll take some time...
1015          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1016    
1017      // Read the file.          // Read the file.
1018          int iLine = 0;          int iLine = 0;
1019      int iErrors = 0;          int iErrors = 0;
1020      QTextStream ts(&file);          QTextStream ts(&file);
1021      while (!ts.atEnd()) {          while (!ts.atEnd()) {
1022          // Read the line.                  // Read the line.
1023          QString sCommand = ts.readLine().trimmed();                  QString sCommand = ts.readLine().trimmed();
1024                  iLine++;                  iLine++;
1025          // If not empty, nor a comment, call the server...                  // If not empty, nor a comment, call the server...
1026          if (!sCommand.isEmpty() && sCommand[0] != '#') {                  if (!sCommand.isEmpty() && sCommand[0] != '#') {
1027                          // Remember that, no matter what,                          // Remember that, no matter what,
1028                          // all LSCP commands are CR/LF terminated.                          // all LSCP commands are CR/LF terminated.
1029                          sCommand += "\r\n";                          sCommand += "\r\n";
# Line 782  bool MainForm::loadSessionFile ( const Q Line 1035  bool MainForm::loadSessionFile ( const Q
1035                                  appendMessagesClient("lscp_client_query");                                  appendMessagesClient("lscp_client_query");
1036                                  iErrors++;                                  iErrors++;
1037                          }                          }
1038          }                  }
1039          // Try to make it snappy :)                  // Try to make it snappy :)
1040          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1041      }          }
1042    
1043      // Ok. we've read it.          // Ok. we've read it.
1044      file.close();          file.close();
1045    
1046          // Now we'll try to create (update) the whole GUI session.          // Now we'll try to create (update) the whole GUI session.
1047          updateSession();          updateSession();
# Line 797  bool MainForm::loadSessionFile ( const Q Line 1050  bool MainForm::loadSessionFile ( const Q
1050          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1051    
1052          // Have we any errors?          // Have we any errors?
1053          if (iErrors > 0)          if (iErrors > 0) {
1054                  appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));                  appendMessagesError(
1055                            tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.")
1056                            .arg(sFilename));
1057            }
1058    
1059      // Save as default session directory.          // Save as default session directory.
1060      if (m_pOptions)          if (m_pOptions)
1061          m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1062          // We're not dirty anymore, if loaded without errors,          // We're not dirty anymore, if loaded without errors,
1063          m_iDirtyCount = iErrors;          m_iDirtyCount = iErrors;
1064      // Stabilize form...          // Stabilize form...
1065      m_sFilename = sFilename;          m_sFilename = sFilename;
1066      updateRecentFiles(sFilename);          updateRecentFiles(sFilename);
1067      appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));          appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
1068    
1069      // Make that an overall update.          // Make that an overall update.
1070      stabilizeForm();          stabilizeForm();
1071      return true;          return true;
1072  }  }
1073    
1074    
1075  // Save current session to specific file path.  // Save current session to specific file path.
1076  bool MainForm::saveSessionFile ( const QString& sFilename )  bool MainForm::saveSessionFile ( const QString& sFilename )
1077  {  {
1078          if (m_pClient == NULL)          if (m_pClient == nullptr)
1079                  return false;                  return false;
1080    
1081          // Check whether server is apparently OK...          // Check whether server is apparently OK...
# Line 828  bool MainForm::saveSessionFile ( const Q Line 1084  bool MainForm::saveSessionFile ( const Q
1084                  return false;                  return false;
1085          }          }
1086    
1087      // Open and write into real file.          // Open and write into real file.
1088      QFile file(sFilename);          QFile file(sFilename);
1089      if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {          if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1090          appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1091          return false;                          tr("Could not open \"%1\" session file.\n\nSorry.")
1092      }                          .arg(sFilename));
1093                    return false;
1094            }
1095    
1096          // Tell the world we'll take some time...          // Tell the world we'll take some time...
1097          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));          QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1098    
1099      // Write the file.          // Write the file.
1100      int  iErrors = 0;          int iErrors = 0;
1101      QTextStream ts(&file);          QTextStream ts(&file);
1102      ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;          ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
1103      ts << "# " << tr("Version")          ts << "# " << tr("Version") << ": " CONFIG_BUILD_VERSION << endl;
1104         << ": " QSAMPLER_VERSION << endl;  //      ts << "# " << tr("Build") << ": " CONFIG_BUILD_DATE << endl;
1105      ts << "# " << tr("Build")          ts << "#"  << endl;
1106         << ": " __DATE__ " " __TIME__ << endl;          ts << "# " << tr("File")
1107      ts << "#"  << endl;          << ": " << QFileInfo(sFilename).fileName() << endl;
1108      ts << "# " << tr("File")          ts << "# " << tr("Date")
1109         << ": " << QFileInfo(sFilename).fileName() << endl;          << ": " << QDate::currentDate().toString("MMM dd yyyy")
1110      ts << "# " << tr("Date")          << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;
1111         << ": " << QDate::currentDate().toString("MMM dd yyyy")          ts << "#"  << endl;
1112         << " "  << QTime::currentTime().toString("hh:mm:ss") << endl;          ts << endl;
     ts << "#"  << endl;  
     ts << endl;  
1113    
1114          // It is assumed that this new kind of device+session file          // It is assumed that this new kind of device+session file
1115          // will be loaded from a complete initialized server...          // will be loaded from a complete initialized server...
1116          int *piDeviceIDs;          int *piDeviceIDs;
1117          int  iDevice;          int  i, iDevice;
1118          ts << "RESET" << endl;          ts << "RESET" << endl;
1119    
1120          // Audio device mapping.          // Audio device mapping.
1121          QMap<int, int> audioDeviceMap;          QMap<int, int> audioDeviceMap; iDevice = 0;
1122          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);          piDeviceIDs = Device::getDevices(m_pClient, Device::Audio);
1123          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) {
1124                  ts << endl;                  Device device(Device::Audio, piDeviceIDs[i]);
1125                  qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]);                  // Avoid plug-in driver devices...
1126                    if (device.driverName().toUpper() == "PLUGIN")
1127                            continue;
1128                  // Audio device specification...                  // Audio device specification...
1129                    ts << endl;
1130                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
1131                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
1132                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();                  ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
1133                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
1134                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
1135                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
1136                                          ++deviceParam) {                                          ++deviceParam) {
1137                          const qsamplerDeviceParam& param = deviceParam.value();                          const DeviceParam& param = deviceParam.value();
1138                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
1139                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1140                  }                  }
1141                  ts << endl;                  ts << endl;
1142                  // Audio channel parameters...                  // Audio channel parameters...
1143                  int iPort = 0;                  int iPort = 0;
1144                  QListIterator<qsamplerDevicePort *> iter(device.ports());                  QListIterator<DevicePort *> iter(device.ports());
1145                  while (iter.hasNext()) {                  while (iter.hasNext()) {
1146                          qsamplerDevicePort *pPort = iter.next();                          DevicePort *pPort = iter.next();
1147                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1148                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1149                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1150                                                  ++portParam) {                                                  ++portParam) {
1151                                  const qsamplerDeviceParam& param = portParam.value();                                  const DeviceParam& param = portParam.value();
1152                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1153                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice                                  ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
1154                                          << " " << iPort << " " << portParam.key()                                          << " " << iPort << " " << portParam.key()
# Line 898  bool MainForm::saveSessionFile ( const Q Line 1157  bool MainForm::saveSessionFile ( const Q
1157                          iPort++;                          iPort++;
1158                  }                  }
1159                  // Audio device index/id mapping.                  // Audio device index/id mapping.
1160                  audioDeviceMap[device.deviceID()] = iDevice;                  audioDeviceMap.insert(device.deviceID(), iDevice++);
1161                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1162                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1163          }          }
1164    
1165          // MIDI device mapping.          // MIDI device mapping.
1166          QMap<int, int> midiDeviceMap;          QMap<int, int> midiDeviceMap; iDevice = 0;
1167          piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);          piDeviceIDs = Device::getDevices(m_pClient, Device::Midi);
1168          for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {          for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) {
1169                  ts << endl;                  Device device(Device::Midi, piDeviceIDs[i]);
1170                  qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]);                  // Avoid plug-in driver devices...
1171                    if (device.driverName().toUpper() == "PLUGIN")
1172                            continue;
1173                  // MIDI device specification...                  // MIDI device specification...
1174                    ts << endl;
1175                  ts << "# " << device.deviceTypeName() << " " << device.driverName()                  ts << "# " << device.deviceTypeName() << " " << device.driverName()
1176                          << " " << tr("Device") << " " << iDevice << endl;                          << " " << tr("Device") << " " << iDevice << endl;
1177                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();                  ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
1178                  qsamplerDeviceParamMap::ConstIterator deviceParam;                  DeviceParamMap::ConstIterator deviceParam;
1179                  for (deviceParam = device.params().begin();                  for (deviceParam = device.params().begin();
1180                                  deviceParam != device.params().end();                                  deviceParam != device.params().end();
1181                                          ++deviceParam) {                                          ++deviceParam) {
1182                          const qsamplerDeviceParam& param = deviceParam.value();                          const DeviceParam& param = deviceParam.value();
1183                          if (param.value.isEmpty()) ts << "# ";                          if (param.value.isEmpty()) ts << "# ";
1184                          ts << " " << deviceParam.key() << "='" << param.value << "'";                          ts << " " << deviceParam.key() << "='" << param.value << "'";
1185                  }                  }
1186                  ts << endl;                  ts << endl;
1187                  // MIDI port parameters...                  // MIDI port parameters...
1188                  int iPort = 0;                  int iPort = 0;
1189                  QListIterator<qsamplerDevicePort *> iter(device.ports());                  QListIterator<DevicePort *> iter(device.ports());
1190                  while (iter.hasNext()) {                  while (iter.hasNext()) {
1191                          qsamplerDevicePort *pPort = iter.next();                          DevicePort *pPort = iter.next();
1192                          qsamplerDeviceParamMap::ConstIterator portParam;                          DeviceParamMap::ConstIterator portParam;
1193                          for (portParam = pPort->params().begin();                          for (portParam = pPort->params().begin();
1194                                          portParam != pPort->params().end();                                          portParam != pPort->params().end();
1195                                                  ++portParam) {                                                  ++portParam) {
1196                                  const qsamplerDeviceParam& param = portParam.value();                                  const DeviceParam& param = portParam.value();
1197                                  if (param.fix || param.value.isEmpty()) ts << "# ";                                  if (param.fix || param.value.isEmpty()) ts << "# ";
1198                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice                                  ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
1199                                     << " " << iPort << " " << portParam.key()                                  << " " << iPort << " " << portParam.key()
1200                                     << "='" << param.value << "'" << endl;                                  << "='" << param.value << "'" << endl;
1201                          }                          }
1202                          iPort++;                          iPort++;
1203                  }                  }
1204                  // MIDI device index/id mapping.                  // MIDI device index/id mapping.
1205                  midiDeviceMap[device.deviceID()] = iDevice;                  midiDeviceMap.insert(device.deviceID(), iDevice++);
1206                  // Try to keep it snappy :)                  // Try to keep it snappy :)
1207                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1208          }          }
# Line 951  bool MainForm::saveSessionFile ( const Q Line 1213  bool MainForm::saveSessionFile ( const Q
1213          QMap<int, int> midiInstrumentMap;          QMap<int, int> midiInstrumentMap;
1214          int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);          int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);
1215          for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {          for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {
1216                  int iMidiMap = piMaps[iMap];                  const int iMidiMap = piMaps[iMap];
1217                  const char *pszMapName                  const char *pszMapName
1218                          = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);                          = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);
1219                  ts << "# " << tr("MIDI instrument map") << " " << iMap;                  ts << "# " << tr("MIDI instrument map") << " " << iMap;
# Line 1003  bool MainForm::saveSessionFile ( const Q Line 1265  bool MainForm::saveSessionFile ( const Q
1265                  }                  }
1266                  ts << endl;                  ts << endl;
1267                  // Check for errors...                  // Check for errors...
1268                  if (pInstrs == NULL && ::lscp_client_get_errno(m_pClient)) {                  if (pInstrs == nullptr && ::lscp_client_get_errno(m_pClient)) {
1269                          appendMessagesClient("lscp_list_midi_instruments");                          appendMessagesClient("lscp_list_midi_instruments");
1270                          iErrors++;                          iErrors++;
1271                  }                  }
1272                  // MIDI strument index/id mapping.                  // MIDI strument index/id mapping.
1273                  midiInstrumentMap[iMidiMap] = iMap;                  midiInstrumentMap.insert(iMidiMap, iMap);
1274          }          }
1275          // Check for errors...          // Check for errors...
1276          if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {          if (piMaps == nullptr && ::lscp_client_get_errno(m_pClient)) {
1277                  appendMessagesClient("lscp_list_midi_instrument_maps");                  appendMessagesClient("lscp_list_midi_instrument_maps");
1278                  iErrors++;                  iErrors++;
1279          }          }
1280  #endif  // CONFIG_MIDI_INSTRUMENT  #endif  // CONFIG_MIDI_INSTRUMENT
1281    
1282          // Sampler channel mapping.          // Sampler channel mapping...
1283      QWidgetList wlist = m_pWorkspace->windowList();          int iChannelID = 0;
1284      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          const QList<QMdiSubWindow *>& wlist
1285          ChannelStrip* pChannelStrip                  = m_pWorkspace->subWindowList();
1286                          = static_cast<ChannelStrip *> (wlist.at(iChannel));          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
1287          if (pChannelStrip) {                  ChannelStrip *pChannelStrip
1288              qsamplerChannel *pChannel = pChannelStrip->channel();                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
1289              if (pChannel) {                  if (pChannelStrip) {
1290                  ts << "# " << tr("Channel") << " " << iChannel << endl;                          Channel *pChannel = pChannelStrip->channel();
1291                  ts << "ADD CHANNEL" << endl;                          if (pChannel) {
1292                                    // Avoid "artifial" plug-in devices...
1293                                    const int iAudioDevice = pChannel->audioDevice();
1294                                    if (!audioDeviceMap.contains(iAudioDevice))
1295                                            continue;
1296                                    const int iMidiDevice = pChannel->midiDevice();
1297                                    if (!midiDeviceMap.contains(iMidiDevice))
1298                                            continue;
1299                                    // Go for regular, canonical devices...
1300                                    ts << "# " << tr("Channel") << " " << iChannelID << endl;
1301                                    ts << "ADD CHANNEL" << endl;
1302                                  if (audioDeviceMap.isEmpty()) {                                  if (audioDeviceMap.isEmpty()) {
1303                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannelID
1304                                                  << " " << pChannel->audioDriver() << endl;                                                  << " " << pChannel->audioDriver() << endl;
1305                                  } else {                                  } else {
1306                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannelID
1307                                                  << " " << audioDeviceMap[pChannel->audioDevice()] << endl;                                                  << " " << audioDeviceMap.value(iAudioDevice) << endl;
1308                                  }                                  }
1309                                  if (midiDeviceMap.isEmpty()) {                                  if (midiDeviceMap.isEmpty()) {
1310                                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel                                          ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID
1311                                                  << " " << pChannel->midiDriver() << endl;                                                  << " " << pChannel->midiDriver() << endl;
1312                                  } else {                                  } else {
1313                                          ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel                                          ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannelID
1314                                                  << " " << midiDeviceMap[pChannel->midiDevice()] << endl;                                                  << " " << midiDeviceMap.value(iMidiDevice) << endl;
1315                                  }                                  }
1316                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel                                  ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID
1317                                          << " " << pChannel->midiPort() << endl;                                          << " " << pChannel->midiPort() << endl;
1318                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";                                  ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannelID << " ";
1319                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)                                  if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
1320                      ts << "ALL";                                          ts << "ALL";
1321                  else                                  else
1322                      ts << pChannel->midiChannel();                                          ts << pChannel->midiChannel();
1323                  ts << endl;                                  ts << endl;
1324                  ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;                                  ts << "LOAD ENGINE " << pChannel->engineName()
1325                                            << " " << iChannelID << endl;
1326                                  if (pChannel->instrumentStatus() < 100) ts << "# ";                                  if (pChannel->instrumentStatus() < 100) ts << "# ";
1327                                  ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "                                  ts << "LOAD INSTRUMENT NON_MODAL '"
1328                                          << pChannel->instrumentNr() << " " << iChannel << endl;                                          << pChannel->instrumentFile() << "' "
1329                                  qsamplerChannelRoutingMap::ConstIterator audioRoute;                                          << pChannel->instrumentNr() << " " << iChannelID << endl;
1330                                    ChannelRoutingMap::ConstIterator audioRoute;
1331                                  for (audioRoute = pChannel->audioRouting().begin();                                  for (audioRoute = pChannel->audioRouting().begin();
1332                                                  audioRoute != pChannel->audioRouting().end();                                                  audioRoute != pChannel->audioRouting().end();
1333                                                          ++audioRoute) {                                                          ++audioRoute) {
1334                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel                                          ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannelID
1335                                                  << " " << audioRoute.key()                                                  << " " << audioRoute.key()
1336                                                  << " " << audioRoute.value() << endl;                                                  << " " << audioRoute.value() << endl;
1337                                  }                                  }
1338                                  ts << "SET CHANNEL VOLUME " << iChannel                                  ts << "SET CHANNEL VOLUME " << iChannelID
1339                                          << " " << pChannel->volume() << endl;                                          << " " << pChannel->volume() << endl;
1340                                  if (pChannel->channelMute())                                  if (pChannel->channelMute())
1341                                          ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl;                                          ts << "SET CHANNEL MUTE " << iChannelID << " 1" << endl;
1342                                  if (pChannel->channelSolo())                                  if (pChannel->channelSolo())
1343                                          ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl;                                          ts << "SET CHANNEL SOLO " << iChannelID << " 1" << endl;
1344  #ifdef CONFIG_MIDI_INSTRUMENT                          #ifdef CONFIG_MIDI_INSTRUMENT
1345                                  if (pChannel->midiMap() >= 0) {                                  const int iMidiMap = pChannel->midiMap();
1346                                          ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel                                  if (midiInstrumentMap.contains(iMidiMap)) {
1347                                                  << " " << midiInstrumentMap[pChannel->midiMap()] << endl;                                          ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannelID
1348                                                    << " " << midiInstrumentMap.value(iMidiMap) << endl;
1349                                  }                                  }
1350  #endif                          #endif
1351  #ifdef CONFIG_FXSEND                          #ifdef CONFIG_FXSEND
                                 int iChannelID = pChannel->channelID();  
1352                                  int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);                                  int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);
1353                                  for (int iFxSend = 0;                                  for (int iFxSend = 0;
1354                                                  piFxSends && piFxSends[iFxSend] >= 0;                                                  piFxSends && piFxSends[iFxSend] >= 0;
# Line 1082  bool MainForm::saveSessionFile ( const Q Line 1356  bool MainForm::saveSessionFile ( const Q
1356                                          lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(                                          lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(
1357                                                  m_pClient, iChannelID, piFxSends[iFxSend]);                                                  m_pClient, iChannelID, piFxSends[iFxSend]);
1358                                          if (pFxSendInfo) {                                          if (pFxSendInfo) {
1359                                                  ts << "CREATE FX_SEND " << iChannel                                                  ts << "CREATE FX_SEND " << iChannelID
1360                                                          << " " << pFxSendInfo->midi_controller;                                                          << " " << pFxSendInfo->midi_controller;
1361                                                  if (pFxSendInfo->name)                                                  if (pFxSendInfo->name)
1362                                                          ts << " '" << pFxSendInfo->name << "'";                                                          ts << " '" << pFxSendInfo->name << "'";
# Line 1092  bool MainForm::saveSessionFile ( const Q Line 1366  bool MainForm::saveSessionFile ( const Q
1366                                                                  piRouting && piRouting[iAudioSrc] >= 0;                                                                  piRouting && piRouting[iAudioSrc] >= 0;
1367                                                                          iAudioSrc++) {                                                                          iAudioSrc++) {
1368                                                          ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "                                                          ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "
1369                                                                  << iChannel                                                                  << iChannelID
1370                                                                  << " " << iFxSend                                                                  << " " << iFxSend
1371                                                                  << " " << iAudioSrc                                                                  << " " << iAudioSrc
1372                                                                  << " " << piRouting[iAudioSrc] << endl;                                                                  << " " << piRouting[iAudioSrc] << endl;
1373                                                  }                                                  }
1374  #ifdef CONFIG_FXSEND_LEVEL                                          #ifdef CONFIG_FXSEND_LEVEL
1375                                                  ts << "SET FX_SEND LEVEL " << iChannel                                                  ts << "SET FX_SEND LEVEL " << iChannelID
1376                                                          << " " << iFxSend                                                          << " " << iFxSend
1377                                                          << " " << pFxSendInfo->level << endl;                                                          << " " << pFxSendInfo->level << endl;
1378  #endif                                          #endif
1379                                          }       // Check for errors...                                          }       // Check for errors...
1380                                          else if (::lscp_client_get_errno(m_pClient)) {                                          else if (::lscp_client_get_errno(m_pClient)) {
1381                                                  appendMessagesClient("lscp_get_fxsend_info");                                                  appendMessagesClient("lscp_get_fxsend_info");
1382                                                  iErrors++;                                                  iErrors++;
1383                                          }                                          }
1384                                  }                                  }
1385  #endif                          #endif
1386                  ts << endl;                                  ts << endl;
1387              }                                  // Go for next channel...
1388          }                                  ++iChannelID;
1389          // Try to keep it snappy :)                          }
1390          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);                  }
1391      }                  // Try to keep it snappy :)
1392                    QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1393            }
1394    
1395  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
1396          ts << "# " << tr("Global volume level") << endl;          ts << "# " << tr("Global volume level") << endl;
# Line 1122  bool MainForm::saveSessionFile ( const Q Line 1398  bool MainForm::saveSessionFile ( const Q
1398          ts << endl;          ts << endl;
1399  #endif  #endif
1400    
1401      // Ok. we've wrote it.          // Ok. we've wrote it.
1402      file.close();          file.close();
1403    
1404          // We're fornerly done.          // We're fornerly done.
1405          QApplication::restoreOverrideCursor();          QApplication::restoreOverrideCursor();
1406    
1407      // Have we any errors?          // Have we any errors?
1408      if (iErrors > 0)          if (iErrors > 0) {
1409          appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));                  appendMessagesError(
1410                            tr("Some settings could not be saved\n"
1411      // Save as default session directory.                          "to \"%1\" session file.\n\nSorry.")
1412      if (m_pOptions)                          .arg(sFilename));
1413          m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();          }
1414      // We're not dirty anymore.  
1415      m_iDirtyCount = 0;          // Save as default session directory.
1416      // Stabilize form...          if (m_pOptions)
1417      m_sFilename = sFilename;                  m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1418      updateRecentFiles(sFilename);          // We're not dirty anymore.
1419      appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));          m_iDirtyCount = 0;
1420      stabilizeForm();          // Stabilize form...
1421      return true;          m_sFilename = sFilename;
1422            updateRecentFiles(sFilename);
1423            appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1424            stabilizeForm();
1425            return true;
1426  }  }
1427    
1428    
1429  // Session change receiver slot.  // Session change receiver slot.
1430  void MainForm::sessionDirty (void)  void MainForm::sessionDirty (void)
1431  {  {
1432      // Just mark the dirty form.          // Just mark the dirty form.
1433      m_iDirtyCount++;          m_iDirtyCount++;
1434      // and update the form status...          // and update the form status...
1435      stabilizeForm();          stabilizeForm();
1436  }  }
1437    
1438    
1439  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1440  // qsamplerMainForm -- File Action slots.  // QSampler::MainForm -- File Action slots.
1441    
1442  // Create a new sampler session.  // Create a new sampler session.
1443  void MainForm::fileNew (void)  void MainForm::fileNew (void)
1444  {  {
1445      // Of course we'll start clean new.          // Of course we'll start clean new.
1446      newSession();          newSession();
1447  }  }
1448    
1449    
1450  // Open an existing sampler session.  // Open an existing sampler session.
1451  void MainForm::fileOpen (void)  void MainForm::fileOpen (void)
1452  {  {
1453      // Open it right away.          // Open it right away.
1454      openSession();          openSession();
1455  }  }
1456    
1457    
# Line 1181  void MainForm::fileOpenRecent (void) Line 1461  void MainForm::fileOpenRecent (void)
1461          // Retrive filename index from action data...          // Retrive filename index from action data...
1462          QAction *pAction = qobject_cast<QAction *> (sender());          QAction *pAction = qobject_cast<QAction *> (sender());
1463          if (pAction && m_pOptions) {          if (pAction && m_pOptions) {
1464                  int iIndex = pAction->data().toInt();                  const int iIndex = pAction->data().toInt();
1465                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {                  if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1466                          QString sFilename = m_pOptions->recentFiles[iIndex];                          QString sFilename = m_pOptions->recentFiles[iIndex];
1467                          // Check if we can safely close the current session...                          // Check if we can safely close the current session...
# Line 1195  void MainForm::fileOpenRecent (void) Line 1475  void MainForm::fileOpenRecent (void)
1475  // Save current sampler session.  // Save current sampler session.
1476  void MainForm::fileSave (void)  void MainForm::fileSave (void)
1477  {  {
1478      // Save it right away.          // Save it right away.
1479      saveSession(false);          saveSession(false);
1480  }  }
1481    
1482    
1483  // Save current sampler session with another name.  // Save current sampler session with another name.
1484  void MainForm::fileSaveAs (void)  void MainForm::fileSaveAs (void)
1485  {  {
1486      // Save it right away, maybe with another name.          // Save it right away, maybe with another name.
1487      saveSession(true);          saveSession(true);
1488  }  }
1489    
1490    
1491  // Reset the sampler instance.  // Reset the sampler instance.
1492  void MainForm::fileReset (void)  void MainForm::fileReset (void)
1493  {  {
1494      if (m_pClient == NULL)          if (m_pClient == nullptr)
1495          return;                  return;
1496    
1497      // Ask user whether he/she want's an internal sampler reset...          // Ask user whether he/she want's an internal sampler reset...
1498      if (QMessageBox::warning(this,          if (m_pOptions && m_pOptions->bConfirmReset) {
1499                  QSAMPLER_TITLE ": " + tr("Warning"),                  const QString& sTitle = tr("Warning");
1500          tr("Resetting the sampler instance will close\n"                  const QString& sText = tr(
1501             "all device and channel configurations.\n\n"                          "Resetting the sampler instance will close\n"
1502             "Please note that this operation may cause\n"                          "all device and channel configurations.\n\n"
1503             "temporary MIDI and Audio disruption.\n\n"                          "Please note that this operation may cause\n"
1504             "Do you want to reset the sampler engine now?"),                          "temporary MIDI and Audio disruption.\n\n"
1505          tr("Reset"), tr("Cancel")) > 0)                          "Do you want to reset the sampler engine now?");
1506          return;          #if 0
1507                    if (QMessageBox::warning(this, sTitle, sText,
1508                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1509                            return;
1510            #else
1511                    QMessageBox mbox(this);
1512                    mbox.setIcon(QMessageBox::Warning);
1513                    mbox.setWindowTitle(sTitle);
1514                    mbox.setText(sText);
1515                    mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1516                    QCheckBox cbox(tr("Don't ask this again"));
1517                    cbox.setChecked(false);
1518                    cbox.blockSignals(true);
1519                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1520                    if (mbox.exec() == QMessageBox::Cancel)
1521                            return;
1522                    if (cbox.isChecked())
1523                            m_pOptions->bConfirmReset = false;
1524            #endif
1525            }
1526    
1527          // Trye closing the current session, first...          // Trye closing the current session, first...
1528          if (!closeSession(true))          if (!closeSession(true))
1529                  return;                  return;
1530    
1531      // Just do the reset, after closing down current session...          // Just do the reset, after closing down current session...
1532          // Do the actual sampler reset...          // Do the actual sampler reset...
1533          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {          if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1534                  appendMessagesClient("lscp_reset_sampler");                  appendMessagesClient("lscp_reset_sampler");
# Line 1237  void MainForm::fileReset (void) Line 1536  void MainForm::fileReset (void)
1536                  return;                  return;
1537          }          }
1538    
1539      // Log this.          // Log this.
1540      appendMessages(tr("Sampler reset."));          appendMessages(tr("Sampler reset."));
1541    
1542          // Make it a new session...          // Make it a new session...
1543          newSession();          newSession();
# Line 1248  void MainForm::fileReset (void) Line 1547  void MainForm::fileReset (void)
1547  // Restart the client/server instance.  // Restart the client/server instance.
1548  void MainForm::fileRestart (void)  void MainForm::fileRestart (void)
1549  {  {
1550      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
1551          return;                  return;
1552    
1553      bool bRestart = true;          bool bRestart = true;
1554    
1555      // Ask user whether he/she want's a complete restart...          // Ask user whether he/she want's a complete restart...
1556      // (if we're currently up and running)          // (if we're currently up and running)
1557      if (bRestart && m_pClient) {          if (m_pOptions && m_pOptions->bConfirmRestart) {
1558          bRestart = (QMessageBox::warning(this,                  const QString& sTitle = tr("Warning");
1559                          QSAMPLER_TITLE ": " + tr("Warning"),                  const QString& sText = tr(
1560              tr("New settings will be effective after\n"                          "New settings will be effective after\n"
1561                 "restarting the client/server connection.\n\n"                          "restarting the client/server connection.\n\n"
1562                 "Please note that this operation may cause\n"                          "Please note that this operation may cause\n"
1563                 "temporary MIDI and Audio disruption.\n\n"                          "temporary MIDI and Audio disruption.\n\n"
1564                 "Do you want to restart the connection now?"),                          "Do you want to restart the connection now?");
1565              tr("Restart"), tr("Cancel")) == 0);          #if 0
1566      }                  if (QMessageBox::warning(this, sTitle, sText,
1567                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1568      // Are we still for it?                          bRestart = false;
1569      if (bRestart && closeSession(true)) {          #else
1570          // Stop server, it will force the client too.                  QMessageBox mbox(this);
1571          stopServer();                  mbox.setIcon(QMessageBox::Warning);
1572          // Reschedule a restart...                  mbox.setWindowTitle(sTitle);
1573          startSchedule(m_pOptions->iStartDelay);                  mbox.setText(sText);
1574      }                  mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1575                    QCheckBox cbox(tr("Don't ask this again"));
1576                    cbox.setChecked(false);
1577                    cbox.blockSignals(true);
1578                    mbox.addButton(&cbox, QMessageBox::ActionRole);
1579                    if (mbox.exec() == QMessageBox::Cancel)
1580                            bRestart = false;
1581                    else
1582                    if (cbox.isChecked())
1583                            m_pOptions->bConfirmRestart = false;
1584            #endif
1585            }
1586    
1587            // Are we still for it?
1588            if (bRestart && closeSession(true)) {
1589                    // Stop server, it will force the client too.
1590                    stopServer();
1591                    // Reschedule a restart...
1592                    startSchedule(m_pOptions->iStartDelay);
1593            }
1594  }  }
1595    
1596    
1597  // Exit application program.  // Exit application program.
1598  void MainForm::fileExit (void)  void MainForm::fileExit (void)
1599  {  {
1600      // Go for close the whole thing.          // Go for close the whole thing.
1601      close();          close();
1602  }  }
1603    
1604    
1605  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1606  // qsamplerMainForm -- Edit Action slots.  // QSampler::MainForm -- Edit Action slots.
1607    
1608  // Add a new sampler channel.  // Add a new sampler channel.
1609  void MainForm::editAddChannel (void)  void MainForm::editAddChannel (void)
1610  {  {
1611      if (m_pClient == NULL)          ++m_iDirtySetup;
1612          return;          addChannelStrip();
1613            --m_iDirtySetup;
1614    }
1615    
1616    void MainForm::addChannelStrip (void)
1617    {
1618            if (m_pClient == nullptr)
1619                    return;
1620    
1621      // Just create the channel instance...          // Just create the channel instance...
1622      qsamplerChannel *pChannel = new qsamplerChannel();          Channel *pChannel = new Channel();
1623      if (pChannel == NULL)          if (pChannel == nullptr)
1624          return;                  return;
1625    
1626      // Before we show it up, may be we'll          // Before we show it up, may be we'll
1627      // better ask for some initial values?          // better ask for some initial values?
1628      if (!pChannel->channelSetup(this)) {          if (!pChannel->channelSetup(this)) {
1629          delete pChannel;                  delete pChannel;
1630          return;                  return;
1631      }          }
1632    
1633      // And give it to the strip (will own the channel instance, if successful).          // And give it to the strip...
1634      if (!createChannelStrip(pChannel)) {          // (will own the channel instance, if successful).
1635          delete pChannel;          if (!createChannelStrip(pChannel)) {
1636          return;                  delete pChannel;
1637      }                  return;
1638            }
1639      // Make that an overall update.  
1640      m_iDirtyCount++;          // Do we auto-arrange?
1641      stabilizeForm();          channelsArrangeAuto();
1642    
1643            // Make that an overall update.
1644            m_iDirtyCount++;
1645            stabilizeForm();
1646  }  }
1647    
1648    
1649  // Remove current sampler channel.  // Remove current sampler channel.
1650  void MainForm::editRemoveChannel (void)  void MainForm::editRemoveChannel (void)
1651  {  {
1652      if (m_pClient == NULL)          ++m_iDirtySetup;
1653          return;          removeChannelStrip();
1654            --m_iDirtySetup;
1655    }
1656    
1657    void MainForm::removeChannelStrip (void)
1658    {
1659            if (m_pClient == nullptr)
1660                    return;
1661    
1662            ChannelStrip *pChannelStrip = activeChannelStrip();
1663            if (pChannelStrip == nullptr)
1664                    return;
1665    
1666            Channel *pChannel = pChannelStrip->channel();
1667            if (pChannel == nullptr)
1668                    return;
1669    
1670      ChannelStrip* pChannelStrip = activeChannelStrip();          // Prompt user if he/she's sure about this...
1671      if (pChannelStrip == NULL)          if (m_pOptions && m_pOptions->bConfirmRemove) {
1672          return;                  const QString& sTitle = tr("Warning");
1673                    const QString& sText = tr(
1674      qsamplerChannel *pChannel = pChannelStrip->channel();                          "About to remove channel:\n\n"
1675      if (pChannel == NULL)                          "%1\n\n"
1676          return;                          "Are you sure?")
1677                            .arg(pChannelStrip->windowTitle());
1678      // Prompt user if he/she's sure about this...          #if 0
1679      if (m_pOptions && m_pOptions->bConfirmRemove) {                  if (QMessageBox::warning(this, sTitle, sText,
1680          if (QMessageBox::warning(this,                          QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Cancel)
1681                          QSAMPLER_TITLE ": " + tr("Warning"),                          return;
1682              tr("About to remove channel:\n\n"          #else
1683                 "%1\n\n"                  QMessageBox mbox(this);
1684                 "Are you sure?")                  mbox.setIcon(QMessageBox::Warning);
1685                 .arg(pChannelStrip->windowTitle()),                  mbox.setWindowTitle(sTitle);
1686              tr("OK"), tr("Cancel")) > 0)                  mbox.setText(sText);
1687              return;                  mbox.setStandardButtons(QMessageBox::Ok | QMessageBox::Cancel);
1688      }                  QCheckBox cbox(tr("Don't ask this again"));
1689                    cbox.setChecked(false);
1690      // Remove the existing sampler channel.                  cbox.blockSignals(true);
1691      if (!pChannel->removeChannel())                  mbox.addButton(&cbox, QMessageBox::ActionRole);
1692          return;                  if (mbox.exec() == QMessageBox::Cancel)
1693                            return;
1694      // Just delete the channel strip.                  if (cbox.isChecked())
1695      delete pChannelStrip;                          m_pOptions->bConfirmRemove = false;
1696            #endif
1697      // Do we auto-arrange?          }
1698      if (m_pOptions && m_pOptions->bAutoArrange)  
1699          channelsArrange();          // Remove the existing sampler channel.
1700            if (!pChannel->removeChannel())
1701      // We'll be dirty, for sure...                  return;
1702      m_iDirtyCount++;  
1703      stabilizeForm();          // Just delete the channel strip.
1704            destroyChannelStrip(pChannelStrip);
1705    
1706            // We'll be dirty, for sure...
1707            m_iDirtyCount++;
1708            stabilizeForm();
1709  }  }
1710    
1711    
1712  // Setup current sampler channel.  // Setup current sampler channel.
1713  void MainForm::editSetupChannel (void)  void MainForm::editSetupChannel (void)
1714  {  {
1715      if (m_pClient == NULL)          if (m_pClient == nullptr)
1716          return;                  return;
1717    
1718      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1719      if (pChannelStrip == NULL)          if (pChannelStrip == nullptr)
1720          return;                  return;
1721    
1722      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1723      pChannelStrip->channelSetup();          pChannelStrip->channelSetup();
1724  }  }
1725    
1726    
1727  // Edit current sampler channel.  // Edit current sampler channel.
1728  void MainForm::editEditChannel (void)  void MainForm::editEditChannel (void)
1729  {  {
1730      if (m_pClient == NULL)          if (m_pClient == nullptr)
1731          return;                  return;
1732    
1733      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1734      if (pChannelStrip == NULL)          if (pChannelStrip == nullptr)
1735          return;                  return;
1736    
1737      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1738      pChannelStrip->channelEdit();          pChannelStrip->channelEdit();
1739  }  }
1740    
1741    
1742  // Reset current sampler channel.  // Reset current sampler channel.
1743  void MainForm::editResetChannel (void)  void MainForm::editResetChannel (void)
1744  {  {
1745      if (m_pClient == NULL)          if (m_pClient == nullptr)
1746          return;                  return;
1747    
1748      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
1749      if (pChannelStrip == NULL)          if (pChannelStrip == nullptr)
1750          return;                  return;
1751    
1752      // Just invoque the channel strip procedure.          // Just invoque the channel strip procedure.
1753      pChannelStrip->channelReset();          pChannelStrip->channelReset();
1754  }  }
1755    
1756    
1757  // Reset all sampler channels.  // Reset all sampler channels.
1758  void MainForm::editResetAllChannels (void)  void MainForm::editResetAllChannels (void)
1759  {  {
1760          if (m_pClient == NULL)          if (m_pClient == nullptr)
1761                  return;                  return;
1762    
1763          // Invoque the channel strip procedure,          // Invoque the channel strip procedure,
1764          // for all channels out there...          // for all channels out there...
1765          m_pWorkspace->setUpdatesEnabled(false);          m_pWorkspace->setUpdatesEnabled(false);
1766          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
1767          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  = m_pWorkspace->subWindowList();
1768                  ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
1769                    ChannelStrip *pChannelStrip
1770                            = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
1771                  if (pChannelStrip)                  if (pChannelStrip)
1772                          pChannelStrip->channelReset();                          pChannelStrip->channelReset();
1773          }          }
# Line 1425  void MainForm::editResetAllChannels (voi Line 1776  void MainForm::editResetAllChannels (voi
1776    
1777    
1778  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1779  // qsamplerMainForm -- View Action slots.  // QSampler::MainForm -- View Action slots.
1780    
1781  // Show/hide the main program window menubar.  // Show/hide the main program window menubar.
1782  void MainForm::viewMenubar ( bool bOn )  void MainForm::viewMenubar ( bool bOn )
1783  {  {
1784      if (bOn)          if (bOn)
1785          ui.MenuBar->show();                  m_ui.MenuBar->show();
1786      else          else
1787          ui.MenuBar->hide();                  m_ui.MenuBar->hide();
1788  }  }
1789    
1790    
1791  // Show/hide the main program window toolbar.  // Show/hide the main program window toolbar.
1792  void MainForm::viewToolbar ( bool bOn )  void MainForm::viewToolbar ( bool bOn )
1793  {  {
1794      if (bOn) {          if (bOn) {
1795          ui.fileToolbar->show();                  m_ui.fileToolbar->show();
1796          ui.editToolbar->show();                  m_ui.editToolbar->show();
1797          ui.channelsToolbar->show();                  m_ui.channelsToolbar->show();
1798      } else {          } else {
1799          ui.fileToolbar->hide();                  m_ui.fileToolbar->hide();
1800          ui.editToolbar->hide();                  m_ui.editToolbar->hide();
1801          ui.channelsToolbar->hide();                  m_ui.channelsToolbar->hide();
1802      }          }
1803  }  }
1804    
1805    
1806  // Show/hide the main program window statusbar.  // Show/hide the main program window statusbar.
1807  void MainForm::viewStatusbar ( bool bOn )  void MainForm::viewStatusbar ( bool bOn )
1808  {  {
1809      if (bOn)          if (bOn)
1810          statusBar()->show();                  statusBar()->show();
1811      else          else
1812          statusBar()->hide();                  statusBar()->hide();
1813  }  }
1814    
1815    
1816  // Show/hide the messages window logger.  // Show/hide the messages window logger.
1817  void MainForm::viewMessages ( bool bOn )  void MainForm::viewMessages ( bool bOn )
1818  {  {
1819      if (bOn)          if (bOn)
1820          m_pMessages->show();                  m_pMessages->show();
1821      else          else
1822          m_pMessages->hide();                  m_pMessages->hide();
1823  }  }
1824    
1825    
1826  // Show/hide the MIDI instrument list-view form.  // Show/hide the MIDI instrument list-view form.
1827  void MainForm::viewInstruments (void)  void MainForm::viewInstruments (void)
1828  {  {
1829          if (m_pOptions == NULL)          if (m_pOptions == nullptr)
1830                  return;                  return;
1831    
1832          if (m_pInstrumentListForm) {          if (m_pInstrumentListForm) {
# Line 1494  void MainForm::viewInstruments (void) Line 1845  void MainForm::viewInstruments (void)
1845  // Show/hide the device configurator form.  // Show/hide the device configurator form.
1846  void MainForm::viewDevices (void)  void MainForm::viewDevices (void)
1847  {  {
1848          if (m_pOptions == NULL)          if (m_pOptions == nullptr)
1849                  return;                  return;
1850    
1851          if (m_pDeviceForm) {          if (m_pDeviceForm) {
# Line 1513  void MainForm::viewDevices (void) Line 1864  void MainForm::viewDevices (void)
1864  // Show options dialog.  // Show options dialog.
1865  void MainForm::viewOptions (void)  void MainForm::viewOptions (void)
1866  {  {
1867      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
1868          return;                  return;
1869    
1870      OptionsForm* pOptionsForm = new OptionsForm(this);          OptionsForm* pOptionsForm = new OptionsForm(this);
1871      if (pOptionsForm) {          if (pOptionsForm) {
1872          // Check out some initial nullities(tm)...                  // Check out some initial nullities(tm)...
1873          ChannelStrip* pChannelStrip = activeChannelStrip();                  ChannelStrip *pChannelStrip = activeChannelStrip();
1874          if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)                  if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1875              m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();                          m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1876          if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)                  if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1877              m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();                          m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1878          // To track down deferred or immediate changes.                  // To track down deferred or immediate changes.
1879          QString sOldServerHost      = m_pOptions->sServerHost;                  const QString sOldServerHost       = m_pOptions->sServerHost;
1880          int     iOldServerPort      = m_pOptions->iServerPort;                  const int     iOldServerPort       = m_pOptions->iServerPort;
1881          int     iOldServerTimeout   = m_pOptions->iServerTimeout;                  const int     iOldServerTimeout    = m_pOptions->iServerTimeout;
1882          bool    bOldServerStart     = m_pOptions->bServerStart;                  const bool    bOldServerStart      = m_pOptions->bServerStart;
1883          QString sOldServerCmdLine   = m_pOptions->sServerCmdLine;                  const QString sOldServerCmdLine    = m_pOptions->sServerCmdLine;
1884          QString sOldDisplayFont     = m_pOptions->sDisplayFont;                  const bool    bOldMessagesLog      = m_pOptions->bMessagesLog;
1885          bool    bOldDisplayEffect   = m_pOptions->bDisplayEffect;                  const QString sOldMessagesLogPath  = m_pOptions->sMessagesLogPath;
1886          int     iOldMaxVolume       = m_pOptions->iMaxVolume;                  const QString sOldDisplayFont      = m_pOptions->sDisplayFont;
1887          QString sOldMessagesFont    = m_pOptions->sMessagesFont;                  const bool    bOldDisplayEffect    = m_pOptions->bDisplayEffect;
1888          bool    bOldKeepOnTop       = m_pOptions->bKeepOnTop;                  const int     iOldMaxVolume        = m_pOptions->iMaxVolume;
1889          bool    bOldStdoutCapture   = m_pOptions->bStdoutCapture;                  const QString sOldMessagesFont     = m_pOptions->sMessagesFont;
1890          int     bOldMessagesLimit   = m_pOptions->bMessagesLimit;                  const bool    bOldKeepOnTop        = m_pOptions->bKeepOnTop;
1891          int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;                  const bool    bOldStdoutCapture    = m_pOptions->bStdoutCapture;
1892          bool    bOldCompletePath    = m_pOptions->bCompletePath;                  const int     bOldMessagesLimit    = m_pOptions->bMessagesLimit;
1893          bool    bOldInstrumentNames = m_pOptions->bInstrumentNames;                  const int     iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1894          int     iOldMaxRecentFiles  = m_pOptions->iMaxRecentFiles;                  const bool    bOldCompletePath     = m_pOptions->bCompletePath;
1895          // Load the current setup settings.                  const bool    bOldInstrumentNames  = m_pOptions->bInstrumentNames;
1896          pOptionsForm->setup(m_pOptions);                  const int     iOldMaxRecentFiles   = m_pOptions->iMaxRecentFiles;
1897          // Show the setup dialog...                  const int     iOldBaseFontSize     = m_pOptions->iBaseFontSize;
1898          if (pOptionsForm->exec()) {                  const QString sOldCustomStyleTheme = m_pOptions->sCustomStyleTheme;
1899              // Warn if something will be only effective on next run.                  const QString sOldCustomColorTheme = m_pOptions->sCustomColorTheme;
1900              if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||                  // Load the current setup settings.
1901                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture) ||                  pOptionsForm->setup(m_pOptions);
1902                  ( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||                  // Show the setup dialog...
1903                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)) {                  if (pOptionsForm->exec()) {
1904                  QMessageBox::information(this,                          // Warn if something will be only effective on next run.
1905                                          QSAMPLER_TITLE ": " + tr("Information"),                          int iNeedRestart = 0;
1906                      tr("Some settings may be only effective\n"                          if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1907                         "next time you start this program."), tr("OK"));                                  (!bOldStdoutCapture &&  m_pOptions->bStdoutCapture)) {
1908                  updateMessagesCapture();                                  updateMessagesCapture();
1909              }                                  ++iNeedRestart;
1910              // Check wheather something immediate has changed.                          }
1911              if (( bOldCompletePath && !m_pOptions->bCompletePath) ||                          if (( bOldKeepOnTop     && !m_pOptions->bKeepOnTop)     ||
1912                  (!bOldCompletePath &&  m_pOptions->bCompletePath) ||                                  (!bOldKeepOnTop     &&  m_pOptions->bKeepOnTop)     ||
1913                  (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))                                  (iOldBaseFontSize   !=  m_pOptions->iBaseFontSize)) {
1914                  updateRecentFilesMenu();                                  ++iNeedRestart;
1915              if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||                          }
1916                  (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))                          // Check whether restart is needed or whether
1917                  updateInstrumentNames();                          // custom options maybe set up immediately...
1918              if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||                          if (m_pOptions->sCustomStyleTheme != sOldCustomStyleTheme) {
1919                  (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))                                  if (m_pOptions->sCustomStyleTheme.isEmpty()) {
1920                  updateDisplayEffect();                                          ++iNeedRestart;
1921              if (sOldDisplayFont != m_pOptions->sDisplayFont)                                  } else {
1922                  updateDisplayFont();                                          QApplication::setStyle(
1923              if (iOldMaxVolume != m_pOptions->iMaxVolume)                                                  QStyleFactory::create(m_pOptions->sCustomStyleTheme));
1924                  updateMaxVolume();                                  }
1925              if (sOldMessagesFont != m_pOptions->sMessagesFont)                          }
1926                  updateMessagesFont();                          if (m_pOptions->sCustomColorTheme != sOldCustomColorTheme) {
1927              if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||                                  if (m_pOptions->sCustomColorTheme.isEmpty()) {
1928                  (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||                                          ++iNeedRestart;
1929                  (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))                                  } else {
1930                  updateMessagesLimit();                                          QPalette pal;
1931              // And now the main thing, whether we'll do client/server recycling?                                          if (PaletteForm::namedPalette(
1932              if ((sOldServerHost != m_pOptions->sServerHost) ||                                                          &m_pOptions->settings(), m_pOptions->sCustomColorTheme, pal))
1933                  (iOldServerPort != m_pOptions->iServerPort) ||                                                  QApplication::setPalette(pal);
1934                  (iOldServerTimeout != m_pOptions->iServerTimeout) ||                                  }
1935                  ( bOldServerStart && !m_pOptions->bServerStart) ||                          }
1936                  (!bOldServerStart &&  m_pOptions->bServerStart) ||                          // Check wheather something immediate has changed.
1937                  (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))                          if (( bOldMessagesLog && !m_pOptions->bMessagesLog) ||
1938                  fileRestart();                                  (!bOldMessagesLog &&  m_pOptions->bMessagesLog) ||
1939          }                                  (sOldMessagesLogPath != m_pOptions->sMessagesLogPath))
1940          // Done.                                  m_pMessages->setLogging(
1941          delete pOptionsForm;                                          m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath);
1942      }                          if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1943                                    (!bOldCompletePath &&  m_pOptions->bCompletePath) ||
1944                                    (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1945                                    updateRecentFilesMenu();
1946                            if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1947                                    (!bOldInstrumentNames &&  m_pOptions->bInstrumentNames))
1948                                    updateInstrumentNames();
1949                            if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1950                                    (!bOldDisplayEffect &&  m_pOptions->bDisplayEffect))
1951                                    updateDisplayEffect();
1952                            if (sOldDisplayFont != m_pOptions->sDisplayFont)
1953                                    updateDisplayFont();
1954                            if (iOldMaxVolume != m_pOptions->iMaxVolume)
1955                                    updateMaxVolume();
1956                            if (sOldMessagesFont != m_pOptions->sMessagesFont)
1957                                    updateMessagesFont();
1958                            if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1959                                    (!bOldMessagesLimit &&  m_pOptions->bMessagesLimit) ||
1960                                    (iOldMessagesLimitLines !=  m_pOptions->iMessagesLimitLines))
1961                                    updateMessagesLimit();
1962                            // Show restart needed message...
1963                            if (iNeedRestart > 0) {
1964                                    QMessageBox::information(this,
1965                                            tr("Information"),
1966                                            tr("Some settings may be only effective\n"
1967                                            "next time you start this program."));
1968                            }
1969                            // And now the main thing, whether we'll do client/server recycling?
1970                            if ((sOldServerHost != m_pOptions->sServerHost) ||
1971                                    (iOldServerPort != m_pOptions->iServerPort) ||
1972                                    (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1973                                    ( bOldServerStart && !m_pOptions->bServerStart) ||
1974                                    (!bOldServerStart &&  m_pOptions->bServerStart) ||
1975                                    (sOldServerCmdLine != m_pOptions->sServerCmdLine
1976                                    && m_pOptions->bServerStart))
1977                                    fileRestart();
1978                    }
1979                    // Done.
1980                    delete pOptionsForm;
1981            }
1982    
1983      // This makes it.          // This makes it.
1984      stabilizeForm();          stabilizeForm();
1985  }  }
1986    
1987    
1988  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
1989  // qsamplerMainForm -- Channels action slots.  // QSampler::MainForm -- Channels action slots.
1990    
1991  // Arrange channel strips.  // Arrange channel strips.
1992  void MainForm::channelsArrange (void)  void MainForm::channelsArrange (void)
1993  {  {
1994      // Full width vertical tiling          // Full width vertical tiling
1995      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
1996      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
1997          return;          if (wlist.isEmpty())
1998                    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);  
1999    
2000      stabilizeForm();          m_pWorkspace->setUpdatesEnabled(false);
2001            int y = 0;
2002            foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2003                    pMdiSubWindow->adjustSize();
2004                    const QRect& frameRect
2005                            = pMdiSubWindow->frameGeometry();
2006                    int w = m_pWorkspace->width();
2007                    if (w < frameRect.width())
2008                            w = frameRect.width();
2009                    const int h = frameRect.height();
2010                    pMdiSubWindow->setGeometry(0, y, w, h);
2011                    y += h;
2012            }
2013            m_pWorkspace->setUpdatesEnabled(true);
2014    
2015            stabilizeForm();
2016  }  }
2017    
2018    
2019  // Auto-arrange channel strips.  // Auto-arrange channel strips.
2020  void MainForm::channelsAutoArrange ( bool bOn )  void MainForm::channelsAutoArrange ( bool bOn )
2021  {  {
2022      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2023          return;                  return;
2024    
2025      // Toggle the auto-arrange flag.          // Toggle the auto-arrange flag.
2026      m_pOptions->bAutoArrange = bOn;          m_pOptions->bAutoArrange = bOn;
2027    
2028      // If on, update whole workspace...          // If on, update whole workspace...
2029      if (m_pOptions->bAutoArrange)          channelsArrangeAuto();
2030          channelsArrange();  }
2031    
2032    
2033    void MainForm::channelsArrangeAuto (void)
2034    {
2035            if (m_pOptions && m_pOptions->bAutoArrange)
2036                    channelsArrange();
2037  }  }
2038    
2039    
2040  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2041  // qsamplerMainForm -- Help Action slots.  // QSampler::MainForm -- Help Action slots.
2042    
2043  // Show information about the Qt toolkit.  // Show information about the Qt toolkit.
2044  void MainForm::helpAboutQt (void)  void MainForm::helpAboutQt (void)
2045  {  {
2046      QMessageBox::aboutQt(this);          QMessageBox::aboutQt(this);
2047  }  }
2048    
2049    
2050  // Show information about application program.  // Show information about application program.
2051  void MainForm::helpAbout (void)  void MainForm::helpAbout (void)
2052  {  {
2053      // Stuff the about box text...          QStringList list;
     QString sText = "<p>\n";  
     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";  
     sText += "<br />\n";  
     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";  
     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";  
2054  #ifdef CONFIG_DEBUG  #ifdef CONFIG_DEBUG
2055      sText += "<small><font color=\"red\">";          list << tr("Debugging option enabled.");
     sText += tr("Debugging option enabled.");  
     sText += "</font></small><br />";  
2056  #endif  #endif
2057  #ifndef CONFIG_LIBGIG  #ifndef CONFIG_LIBGIG
2058      sText += "<small><font color=\"red\">";          list << tr("GIG (libgig) file support disabled.");
     sText += tr("GIG (libgig) file support disabled.");  
     sText += "</font></small><br />";  
2059  #endif  #endif
2060  #ifndef CONFIG_INSTRUMENT_NAME  #ifndef CONFIG_INSTRUMENT_NAME
2061      sText += "<small><font color=\"red\">";          list << tr("LSCP (liblscp) instrument_name support disabled.");
     sText += tr("LSCP (liblscp) instrument_name support disabled.");  
     sText += "</font></small><br />";  
2062  #endif  #endif
2063  #ifndef CONFIG_MUTE_SOLO  #ifndef CONFIG_MUTE_SOLO
2064      sText += "<small><font color=\"red\">";          list << tr("Sampler channel Mute/Solo support disabled.");
     sText += tr("Sampler channel Mute/Solo support disabled.");  
     sText += "</font></small><br />";  
2065  #endif  #endif
2066  #ifndef CONFIG_AUDIO_ROUTING  #ifndef CONFIG_AUDIO_ROUTING
2067      sText += "<small><font color=\"red\">";          list << tr("LSCP (liblscp) audio_routing support disabled.");
     sText += tr("LSCP (liblscp) audio_routing support disabled.");  
     sText += "</font></small><br />";  
2068  #endif  #endif
2069  #ifndef CONFIG_FXSEND  #ifndef CONFIG_FXSEND
2070      sText += "<small><font color=\"red\">";          list << tr("Sampler channel Effect Sends support disabled.");
     sText += tr("Sampler channel Effect Sends support disabled.");  
     sText += "</font></small><br />";  
2071  #endif  #endif
2072  #ifndef CONFIG_VOLUME  #ifndef CONFIG_VOLUME
2073      sText += "<small><font color=\"red\">";          list << tr("Global volume support disabled.");
     sText += tr("Global volume support disabled.");  
     sText += "</font></small><br />";  
2074  #endif  #endif
2075  #ifndef CONFIG_MIDI_INSTRUMENT  #ifndef CONFIG_MIDI_INSTRUMENT
2076      sText += "<small><font color=\"red\">";          list << tr("MIDI instrument mapping support disabled.");
     sText += tr("MIDI instrument mapping support disabled.");  
     sText += "</font></small><br />";  
2077  #endif  #endif
2078  #ifndef CONFIG_EDIT_INSTRUMENT  #ifndef CONFIG_EDIT_INSTRUMENT
2079      sText += "<small><font color=\"red\">";          list << tr("Instrument editing support disabled.");
2080      sText += tr("Instrument editing support disabled.");  #endif
2081      sText += "</font></small><br />";  #ifndef CONFIG_EVENT_CHANNEL_MIDI
2082  #endif          list << tr("Channel MIDI event support disabled.");
2083      sText += "<br />\n";  #endif
2084      sText += tr("Using") + ": ";  #ifndef CONFIG_EVENT_DEVICE_MIDI
2085      sText += ::lscp_client_package();          list << tr("Device MIDI event support disabled.");
2086      sText += " ";  #endif
2087      sText += ::lscp_client_version();  #ifndef CONFIG_MAX_VOICES
2088            list << tr("Runtime max. voices / disk streams support disabled.");
2089    #endif
2090    
2091            // Stuff the about box text...
2092            QString sText = "<p>\n";
2093            sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
2094            sText += "<br />\n";
2095            sText += tr("Version") + ": <b>" CONFIG_BUILD_VERSION "</b><br />\n";
2096    //      sText += "<small>" + tr("Build") + ": " CONFIG_BUILD_DATE "</small><br />\n";
2097            if (!list.isEmpty()) {
2098                    sText += "<small><font color=\"red\">";
2099                    sText += list.join("<br />\n");
2100                    sText += "</font></small>";
2101            }
2102            sText += "<br />\n";
2103            sText += tr("Using: Qt %1").arg(qVersion());
2104    #if defined(QT_STATIC)
2105            sText += "-static";
2106    #endif
2107            sText += ", ";
2108            sText += ::lscp_client_package();
2109            sText += " ";
2110            sText += ::lscp_client_version();
2111  #ifdef CONFIG_LIBGIG  #ifdef CONFIG_LIBGIG
2112      sText += ", ";          sText += ", ";
2113      sText += gig::libraryName().c_str();          sText += gig::libraryName().c_str();
2114      sText += " ";          sText += " ";
2115      sText += gig::libraryVersion().c_str();          sText += gig::libraryVersion().c_str();
2116  #endif  #endif
2117      sText += "<br />\n";          sText += "<br />\n";
2118      sText += "<br />\n";          sText += "<br />\n";
2119      sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";          sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
2120      sText += "<br />\n";          sText += "<br />\n";
2121      sText += "<small>";          sText += "<small>";
2122      sText += QSAMPLER_COPYRIGHT "<br />\n";          sText += QSAMPLER_COPYRIGHT "<br />\n";
2123      sText += QSAMPLER_COPYRIGHT2 "<br />\n";          sText += QSAMPLER_COPYRIGHT2 "<br />\n";
2124      sText += "<br />\n";          sText += "<br />\n";
2125      sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";          sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
2126      sText += tr("under the terms of the GNU General Public License version 2 or later.");          sText += tr("under the terms of the GNU General Public License version 2 or later.");
2127      sText += "</small>";          sText += "</small>";
2128      sText += "</p>\n";          sText += "</p>\n";
2129    
2130      QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);          QMessageBox::about(this, tr("About"), sText);
2131  }  }
2132    
2133    
2134  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2135  // qsamplerMainForm -- Main window stabilization.  // QSampler::MainForm -- Main window stabilization.
2136    
2137  void MainForm::stabilizeForm (void)  void MainForm::stabilizeForm (void)
2138  {  {
2139      // Update the main application caption...          // Update the main application caption...
2140      QString sSessionName = sessionName(m_sFilename);          QString sSessionName = sessionName(m_sFilename);
2141      if (m_iDirtyCount > 0)          if (m_iDirtyCount > 0)
2142          sSessionName += " *";                  sSessionName += " *";
2143      setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));          setWindowTitle(sSessionName);
2144    
2145      // Update the main menu state...          // Update the main menu state...
2146      ChannelStrip* pChannelStrip = activeChannelStrip();          ChannelStrip *pChannelStrip = activeChannelStrip();
2147      bool bHasClient  = (m_pOptions != NULL && m_pClient != NULL);          const QList<QMdiSubWindow *>& wlist = m_pWorkspace->subWindowList();
2148      bool bHasChannel = (bHasClient && pChannelStrip != NULL);          const bool bHasClient = (m_pOptions != nullptr && m_pClient != nullptr);
2149      ui.fileNewAction->setEnabled(bHasClient);          const bool bHasChannel = (bHasClient && pChannelStrip != nullptr);
2150      ui.fileOpenAction->setEnabled(bHasClient);          const bool bHasChannels = (bHasClient && wlist.count() > 0);
2151      ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);          m_ui.fileNewAction->setEnabled(bHasClient);
2152      ui.fileSaveAsAction->setEnabled(bHasClient);          m_ui.fileOpenAction->setEnabled(bHasClient);
2153      ui.fileResetAction->setEnabled(bHasClient);          m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
2154      ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);          m_ui.fileSaveAsAction->setEnabled(bHasClient);
2155      ui.editAddChannelAction->setEnabled(bHasClient);          m_ui.fileResetAction->setEnabled(bHasClient);
2156      ui.editRemoveChannelAction->setEnabled(bHasChannel);          m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == nullptr);
2157      ui.editSetupChannelAction->setEnabled(bHasChannel);          m_ui.editAddChannelAction->setEnabled(bHasClient);
2158            m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
2159            m_ui.editSetupChannelAction->setEnabled(bHasChannel);
2160  #ifdef CONFIG_EDIT_INSTRUMENT  #ifdef CONFIG_EDIT_INSTRUMENT
2161      ui.editEditChannelAction->setEnabled(bHasChannel);          m_ui.editEditChannelAction->setEnabled(bHasChannel);
2162  #else  #else
2163      ui.editEditChannelAction->setEnabled(false);          m_ui.editEditChannelAction->setEnabled(false);
2164  #endif  #endif
2165      ui.editResetChannelAction->setEnabled(bHasChannel);          m_ui.editResetChannelAction->setEnabled(bHasChannel);
2166      ui.editResetAllChannelsAction->setEnabled(bHasChannel);          m_ui.editResetAllChannelsAction->setEnabled(bHasChannels);
2167      ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());          m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
2168  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2169          ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm          m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
2170                  && m_pInstrumentListForm->isVisible());                  && m_pInstrumentListForm->isVisible());
2171          ui.viewInstrumentsAction->setEnabled(bHasClient);          m_ui.viewInstrumentsAction->setEnabled(bHasClient);
2172  #else  #else
2173          ui.viewInstrumentsAction->setEnabled(false);          m_ui.viewInstrumentsAction->setEnabled(false);
2174  #endif  #endif
2175          ui.viewDevicesAction->setChecked(m_pDeviceForm          m_ui.viewDevicesAction->setChecked(m_pDeviceForm
2176                  && m_pDeviceForm->isVisible());                  && m_pDeviceForm->isVisible());
2177      ui.viewDevicesAction->setEnabled(bHasClient);          m_ui.viewDevicesAction->setEnabled(bHasClient);
2178      ui.channelsArrangeAction->setEnabled(bHasChannel);          m_ui.viewMidiDeviceStatusMenu->setEnabled(
2179                    DeviceStatusForm::getInstances().size() > 0);
2180            m_ui.channelsArrangeAction->setEnabled(bHasChannels);
2181    
2182  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2183          // Toolbar widgets are also affected...          // Toolbar widgets are also affected...
2184      m_pVolumeSlider->setEnabled(bHasClient);          m_pVolumeSlider->setEnabled(bHasClient);
2185      m_pVolumeSpinBox->setEnabled(bHasClient);          m_pVolumeSpinBox->setEnabled(bHasClient);
2186  #endif  #endif
2187    
2188      // Client/Server status...          // Client/Server status...
2189      if (bHasClient) {          if (bHasClient) {
2190          m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));                  m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
2191          m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));                  m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
2192      } else {                          + ':' + QString::number(m_pOptions->iServerPort));
2193          m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();          } else {
2194          m_statusItem[QSAMPLER_STATUS_SERVER]->clear();                  m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
2195      }                  m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
2196      // Channel status...          }
2197      if (bHasChannel)          // Channel status...
2198          m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());          if (bHasChannel)
2199      else                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
2200          m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();          else
2201      // Session status...                  m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
2202      if (m_iDirtyCount > 0)          // Session status...
2203          m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));          if (m_iDirtyCount > 0)
2204      else                  m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
2205          m_statusItem[QSAMPLER_STATUS_SESSION]->clear();          else
2206                    m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
2207    
2208      // Recent files menu.          // Recent files menu.
2209          ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);          m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
2210  }  }
2211    
2212    
# Line 1828  void MainForm::volumeChanged ( int iVolu Line 2227  void MainForm::volumeChanged ( int iVolu
2227                  m_pVolumeSpinBox->setValue(iVolume);                  m_pVolumeSpinBox->setValue(iVolume);
2228    
2229          // Do it as commanded...          // Do it as commanded...
2230          float fVolume = 0.01f * float(iVolume);          const float fVolume = 0.01f * float(iVolume);
2231          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)          if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)
2232                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));                  appendMessages(QObject::tr("Volume: %1.").arg(fVolume));
2233          else          else
# Line 1844  void MainForm::volumeChanged ( int iVolu Line 2243  void MainForm::volumeChanged ( int iVolu
2243    
2244    
2245  // Channel change receiver slot.  // Channel change receiver slot.
2246  void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)  void MainForm::channelStripChanged ( ChannelStrip *pChannelStrip )
2247  {  {
2248          // Add this strip to the changed list...          // Add this strip to the changed list...
2249          if (!m_changedStrips.contains(pChannelStrip)) {          if (!m_changedStrips.contains(pChannelStrip)) {
# Line 1852  void MainForm::channelStripChanged(Chann Line 2251  void MainForm::channelStripChanged(Chann
2251                  pChannelStrip->resetErrorCount();                  pChannelStrip->resetErrorCount();
2252          }          }
2253    
2254      // Just mark the dirty form.          // Just mark the dirty form.
2255      m_iDirtyCount++;          m_iDirtyCount++;
2256      // and update the form status...          // and update the form status...
2257      stabilizeForm();          stabilizeForm();
2258  }  }
2259    
2260    
# Line 1863  void MainForm::channelStripChanged(Chann Line 2262  void MainForm::channelStripChanged(Chann
2262  void MainForm::updateSession (void)  void MainForm::updateSession (void)
2263  {  {
2264  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2265          int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));          const int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));
2266          m_iVolumeChanging++;          m_iVolumeChanging++;
2267          m_pVolumeSlider->setValue(iVolume);          m_pVolumeSlider->setValue(iVolume);
2268          m_pVolumeSpinBox->setValue(iVolume);          m_pVolumeSpinBox->setValue(iVolume);
# Line 1871  void MainForm::updateSession (void) Line 2270  void MainForm::updateSession (void)
2270  #endif  #endif
2271  #ifdef CONFIG_MIDI_INSTRUMENT  #ifdef CONFIG_MIDI_INSTRUMENT
2272          // FIXME: Make some room for default instrument maps...          // FIXME: Make some room for default instrument maps...
2273          int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);          const int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
2274          if (iMaps < 0)          if (iMaps < 0)
2275                  appendMessagesClient("lscp_get_midi_instrument_maps");                  appendMessagesClient("lscp_get_midi_instrument_maps");
2276          else if (iMaps < 1) {          else if (iMaps < 1) {
# Line 1882  void MainForm::updateSession (void) Line 2281  void MainForm::updateSession (void)
2281          }          }
2282  #endif  #endif
2283    
2284            updateAllChannelStrips(false);
2285    
2286            // Do we auto-arrange?
2287            channelsArrangeAuto();
2288    
2289            // Remember to refresh devices and instruments...
2290            if (m_pInstrumentListForm)
2291                    m_pInstrumentListForm->refreshInstruments();
2292            if (m_pDeviceForm)
2293                    m_pDeviceForm->refreshDevices();
2294    }
2295    
2296    
2297    void MainForm::updateAllChannelStrips ( bool bRemoveDeadStrips )
2298    {
2299            // Skip if setting up a new channel strip...
2300            if (m_iDirtySetup > 0)
2301                    return;
2302    
2303          // Retrieve the current channel list.          // Retrieve the current channel list.
2304          int *piChannelIDs = ::lscp_list_channels(m_pClient);          int *piChannelIDs = ::lscp_list_channels(m_pClient);
2305          if (piChannelIDs == NULL) {          if (piChannelIDs == nullptr) {
2306                  if (::lscp_client_get_errno(m_pClient)) {                  if (::lscp_client_get_errno(m_pClient)) {
2307                          appendMessagesClient("lscp_list_channels");                          appendMessagesClient("lscp_list_channels");
2308                          appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));                          appendMessagesError(
2309                                    tr("Could not get current list of channels.\n\nSorry."));
2310                  }                  }
2311          } else {          } else {
2312                  // Try to (re)create each channel.                  // Try to (re)create each channel.
2313                  m_pWorkspace->setUpdatesEnabled(false);                  m_pWorkspace->setUpdatesEnabled(false);
2314                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {                  for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2315                          // Check if theres already a channel strip for this one...                          // Check if theres already a channel strip for this one...
2316                          if (!channelStrip(piChannelIDs[iChannel]))                          if (!channelStrip(piChannelIDs[iChannel]))
2317                                  createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));                                  createChannelStrip(new Channel(piChannelIDs[iChannel]));
2318                    }
2319                    // Do we auto-arrange?
2320                    channelsArrangeAuto();
2321                    // remove dead channel strips
2322                    if (bRemoveDeadStrips) {
2323                            const QList<QMdiSubWindow *>& wlist
2324                                    = m_pWorkspace->subWindowList();
2325                            foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2326                                    ChannelStrip *pChannelStrip
2327                                            = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2328                                    if (pChannelStrip) {
2329                                            bool bExists = false;
2330                                            for (int iChannel = 0; piChannelIDs[iChannel] >= 0; ++iChannel) {
2331                                                    Channel *pChannel = pChannelStrip->channel();
2332                                                    if (pChannel == nullptr)
2333                                                            break;
2334                                                    if (piChannelIDs[iChannel] == pChannel->channelID()) {
2335                                                            // strip exists, don't touch it
2336                                                            bExists = true;
2337                                                            break;
2338                                                    }
2339                                            }
2340                                            if (!bExists)
2341                                                    destroyChannelStrip(pChannelStrip);
2342                                    }
2343                            }
2344                  }                  }
2345                  m_pWorkspace->setUpdatesEnabled(true);                  m_pWorkspace->setUpdatesEnabled(true);
2346          }          }
2347    
2348      // Do we auto-arrange?          stabilizeForm();
     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();  
2349  }  }
2350    
2351    
2352  // Update the recent files list and menu.  // Update the recent files list and menu.
2353  void MainForm::updateRecentFiles ( const QString& sFilename )  void MainForm::updateRecentFiles ( const QString& sFilename )
2354  {  {
2355      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2356          return;                  return;
2357    
2358      // Remove from list if already there (avoid duplicates)          // Remove from list if already there (avoid duplicates)
2359      int iIndex = m_pOptions->recentFiles.indexOf(sFilename);          const int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2360      if (iIndex >= 0)          if (iIndex >= 0)
2361          m_pOptions->recentFiles.removeAt(iIndex);                  m_pOptions->recentFiles.removeAt(iIndex);
2362      // Put it to front...          // Put it to front...
2363      m_pOptions->recentFiles.push_front(sFilename);          m_pOptions->recentFiles.push_front(sFilename);
2364  }  }
2365    
2366    
2367  // Update the recent files list and menu.  // Update the recent files list and menu.
2368  void MainForm::updateRecentFilesMenu (void)  void MainForm::updateRecentFilesMenu (void)
2369  {  {
2370          if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2371                  return;                  return;
2372    
2373          // Time to keep the list under limits.          // Time to keep the list under limits.
# Line 1941  void MainForm::updateRecentFilesMenu (vo Line 2378  void MainForm::updateRecentFilesMenu (vo
2378          }          }
2379    
2380          // Rebuild the recent files menu...          // Rebuild the recent files menu...
2381          ui.fileOpenRecentMenu->clear();          m_ui.fileOpenRecentMenu->clear();
2382          for (int i = 0; i < iRecentFiles; i++) {          for (int i = 0; i < iRecentFiles; i++) {
2383                  const QString& sFilename = m_pOptions->recentFiles[i];                  const QString& sFilename = m_pOptions->recentFiles[i];
2384                  if (QFileInfo(sFilename).exists()) {                  if (QFileInfo(sFilename).exists()) {
2385                          QAction *pAction = ui.fileOpenRecentMenu->addAction(                          QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2386                                  QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),                                  QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2387                                  this, SLOT(fileOpenRecent()));                                  this, SLOT(fileOpenRecent()));
2388                          pAction->setData(i);                          pAction->setData(i);
# Line 1957  void MainForm::updateRecentFilesMenu (vo Line 2394  void MainForm::updateRecentFilesMenu (vo
2394  // Force update of the channels instrument names mode.  // Force update of the channels instrument names mode.
2395  void MainForm::updateInstrumentNames (void)  void MainForm::updateInstrumentNames (void)
2396  {  {
2397      // Full channel list update...          // Full channel list update...
2398      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2399      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2400          return;          if (wlist.isEmpty())
2401                    return;
2402      m_pWorkspace->setUpdatesEnabled(false);  
2403      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2404          ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2405          if (pChannelStrip)                  ChannelStrip *pChannelStrip
2406              pChannelStrip->updateInstrumentName(true);                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2407      }                  if (pChannelStrip)
2408      m_pWorkspace->setUpdatesEnabled(true);                          pChannelStrip->updateInstrumentName(true);
2409            }
2410            m_pWorkspace->setUpdatesEnabled(true);
2411  }  }
2412    
2413    
2414  // Force update of the channels display font.  // Force update of the channels display font.
2415  void MainForm::updateDisplayFont (void)  void MainForm::updateDisplayFont (void)
2416  {  {
2417      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2418          return;                  return;
2419    
2420      // Check if display font is legal.          // Check if display font is legal.
2421      if (m_pOptions->sDisplayFont.isEmpty())          if (m_pOptions->sDisplayFont.isEmpty())
2422          return;                  return;
2423      // Realize it.  
2424      QFont font;          // Realize it.
2425      if (!font.fromString(m_pOptions->sDisplayFont))          QFont font;
2426          return;          if (!font.fromString(m_pOptions->sDisplayFont))
2427                    return;
2428      // Full channel list update...  
2429      QWidgetList wlist = m_pWorkspace->windowList();          // Full channel list update...
2430      if (wlist.isEmpty())          const QList<QMdiSubWindow *>& wlist
2431          return;                  = m_pWorkspace->subWindowList();
2432            if (wlist.isEmpty())
2433      m_pWorkspace->setUpdatesEnabled(false);                  return;
2434      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {  
2435          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          m_pWorkspace->setUpdatesEnabled(false);
2436          if (pChannelStrip)          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2437              pChannelStrip->setDisplayFont(font);                  ChannelStrip *pChannelStrip
2438      }                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2439      m_pWorkspace->setUpdatesEnabled(true);                  if (pChannelStrip)
2440                            pChannelStrip->setDisplayFont(font);
2441            }
2442            m_pWorkspace->setUpdatesEnabled(true);
2443  }  }
2444    
2445    
2446  // Update channel strips background effect.  // Update channel strips background effect.
2447  void MainForm::updateDisplayEffect (void)  void MainForm::updateDisplayEffect (void)
2448  {  {
2449      // Full channel list update...          // Full channel list update...
2450      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2451      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2452          return;          if (wlist.isEmpty())
2453                    return;
2454      m_pWorkspace->setUpdatesEnabled(false);  
2455      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2456          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2457                    ChannelStrip *pChannelStrip
2458                            = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2459                  if (pChannelStrip)                  if (pChannelStrip)
2460                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);                          pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2461      }          }
2462      m_pWorkspace->setUpdatesEnabled(true);          m_pWorkspace->setUpdatesEnabled(true);
2463  }  }
2464    
2465    
2466  // Force update of the channels maximum volume setting.  // Force update of the channels maximum volume setting.
2467  void MainForm::updateMaxVolume (void)  void MainForm::updateMaxVolume (void)
2468  {  {
2469      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2470          return;                  return;
2471    
2472  #ifdef CONFIG_VOLUME  #ifdef CONFIG_VOLUME
2473          m_iVolumeChanging++;          m_iVolumeChanging++;
# Line 2032  void MainForm::updateMaxVolume (void) Line 2476  void MainForm::updateMaxVolume (void)
2476          m_iVolumeChanging--;          m_iVolumeChanging--;
2477  #endif  #endif
2478    
2479      // Full channel list update...          // Full channel list update...
2480      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2481      if (wlist.isEmpty())                  = m_pWorkspace->subWindowList();
2482          return;          if (wlist.isEmpty())
2483                    return;
2484      m_pWorkspace->setUpdatesEnabled(false);  
2485      for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          m_pWorkspace->setUpdatesEnabled(false);
2486          ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2487          if (pChannelStrip)                  ChannelStrip *pChannelStrip
2488              pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2489      }                  if (pChannelStrip)
2490      m_pWorkspace->setUpdatesEnabled(true);                          pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2491            }
2492            m_pWorkspace->setUpdatesEnabled(true);
2493  }  }
2494    
2495    
2496  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2497  // qsamplerMainForm -- Messages window form handlers.  // QSampler::MainForm -- Messages window form handlers.
2498    
2499  // Messages output methods.  // Messages output methods.
2500  void MainForm::appendMessages( const QString& s )  void MainForm::appendMessages ( const QString& s )
2501  {  {
2502      if (m_pMessages)          if (m_pMessages)
2503          m_pMessages->appendMessages(s);                  m_pMessages->appendMessages(s);
2504    
2505      statusBar()->showMessage(s, 3000);          statusBar()->showMessage(s, 3000);
2506  }  }
2507    
2508  void MainForm::appendMessagesColor( const QString& s, const QString& c )  void MainForm::appendMessagesColor ( const QString& s, const QColor& rgb )
2509  {  {
2510      if (m_pMessages)          if (m_pMessages)
2511          m_pMessages->appendMessagesColor(s, c);                  m_pMessages->appendMessagesColor(s, rgb);
2512    
2513      statusBar()->showMessage(s, 3000);          statusBar()->showMessage(s, 3000);
2514  }  }
2515    
2516  void MainForm::appendMessagesText( const QString& s )  void MainForm::appendMessagesText ( const QString& s )
2517  {  {
2518      if (m_pMessages)          if (m_pMessages)
2519          m_pMessages->appendMessagesText(s);                  m_pMessages->appendMessagesText(s);
2520  }  }
2521    
2522  void MainForm::appendMessagesError( const QString& s )  void MainForm::appendMessagesError ( const QString& s )
2523  {  {
2524      if (m_pMessages)          if (m_pMessages)
2525          m_pMessages->show();                  m_pMessages->show();
2526    
2527      appendMessagesColor(s.simplified(), "#ff0000");          appendMessagesColor(s.simplified(), Qt::red);
2528    
2529          // Make it look responsive...:)          // Make it look responsive...:)
2530          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2531    
2532      QMessageBox::critical(this,          if (m_pOptions && m_pOptions->bConfirmError) {
2533                  QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));                  const QString& sTitle = tr("Error");
2534            #if 0
2535                    QMessageBox::critical(this, sTitle, sText, QMessageBox::Cancel);
2536            #else
2537                    QMessageBox mbox(this);
2538                    mbox.setIcon(QMessageBox::Critical);
2539                    mbox.setWindowTitle(sTitle);
2540                    mbox.setText(s);
2541                    mbox.setStandardButtons(QMessageBox::Cancel);
2542                    QCheckBox cbox(tr("Don't show this again"));
2543                    cbox.setChecked(false);
2544                    cbox.blockSignals(true);
2545                    mbox.addButton(&cbox, QMessageBox::ActionRole);
2546                    if (mbox.exec() && cbox.isChecked())
2547                            m_pOptions->bConfirmError = false;
2548            #endif
2549            }
2550  }  }
2551    
2552    
2553  // This is a special message format, just for client results.  // This is a special message format, just for client results.
2554  void MainForm::appendMessagesClient( const QString& s )  void MainForm::appendMessagesClient( const QString& s )
2555  {  {
2556      if (m_pClient == NULL)          if (m_pClient == nullptr)
2557          return;                  return;
2558    
2559      appendMessagesColor(s + QString(": %1 (errno=%2)")          appendMessagesColor(s + QString(": %1 (errno=%2)")
2560          .arg(::lscp_client_get_result(m_pClient))                  .arg(::lscp_client_get_result(m_pClient))
2561          .arg(::lscp_client_get_errno(m_pClient)), "#996666");                  .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2562    
2563          // Make it look responsive...:)          // Make it look responsive...:)
2564          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);          QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
# Line 2106  void MainForm::appendMessagesClient( con Line 2568  void MainForm::appendMessagesClient( con
2568  // Force update of the messages font.  // Force update of the messages font.
2569  void MainForm::updateMessagesFont (void)  void MainForm::updateMessagesFont (void)
2570  {  {
2571      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2572          return;                  return;
2573    
2574      if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {          if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2575          QFont font;                  QFont font;
2576          if (font.fromString(m_pOptions->sMessagesFont))                  if (font.fromString(m_pOptions->sMessagesFont))
2577              m_pMessages->setMessagesFont(font);                          m_pMessages->setMessagesFont(font);
2578      }          }
2579  }  }
2580    
2581    
2582  // Update messages window line limit.  // Update messages window line limit.
2583  void MainForm::updateMessagesLimit (void)  void MainForm::updateMessagesLimit (void)
2584  {  {
2585      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2586          return;                  return;
2587    
2588      if (m_pMessages) {          if (m_pMessages) {
2589          if (m_pOptions->bMessagesLimit)                  if (m_pOptions->bMessagesLimit)
2590              m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);                          m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2591          else                  else
2592              m_pMessages->setMessagesLimit(-1);                          m_pMessages->setMessagesLimit(-1);
2593      }          }
2594  }  }
2595    
2596    
2597  // Enablement of the messages capture feature.  // Enablement of the messages capture feature.
2598  void MainForm::updateMessagesCapture (void)  void MainForm::updateMessagesCapture (void)
2599  {  {
2600      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2601          return;                  return;
2602    
2603      if (m_pMessages)          if (m_pMessages)
2604          m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);                  m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2605  }  }
2606    
2607    
2608  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2609  // qsamplerMainForm -- MDI channel strip management.  // QSampler::MainForm -- MDI channel strip management.
2610    
2611  // The channel strip creation executive.  // The channel strip creation executive.
2612  ChannelStrip* MainForm::createChannelStrip(qsamplerChannel* pChannel)  ChannelStrip *MainForm::createChannelStrip ( Channel *pChannel )
2613  {  {
2614      if (m_pClient == NULL || pChannel == NULL)          if (m_pClient == nullptr || pChannel == nullptr)
2615          return NULL;                  return nullptr;
2616    
2617      // Prepare for auto-arrange?          // Add a new channel itema...
2618      ChannelStrip* pChannelStrip = NULL;          ChannelStrip *pChannelStrip = new ChannelStrip();
2619      int y = 0;          if (pChannelStrip == nullptr)
2620      if (m_pOptions && m_pOptions->bAutoArrange) {                  return nullptr;
2621          QWidgetList wlist = m_pWorkspace->windowList();  
2622          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          // Set some initial channel strip options...
2623                          pChannelStrip = static_cast<ChannelStrip *> (wlist.at(iChannel));          if (m_pOptions) {
2624                          if (pChannelStrip) {                  // Background display effect...
2625                          //  y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();                  pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2626                                  y += pChannelStrip->parentWidget()->frameGeometry().height();                  // We'll need a display font.
2627                          }                  QFont font;
2628          }                  if (!m_pOptions->sDisplayFont.isEmpty() &&
2629      }                          font.fromString(m_pOptions->sDisplayFont))
2630                            pChannelStrip->setDisplayFont(font);
2631                    // Maximum allowed volume setting.
2632                    pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2633            }
2634    
2635            // Add it to workspace...
2636            QMdiSubWindow *pMdiSubWindow
2637                    = m_pWorkspace->addSubWindow(pChannelStrip,
2638                            Qt::SubWindow | Qt::FramelessWindowHint);
2639            pMdiSubWindow->setAttribute(Qt::WA_DeleteOnClose);
2640    
2641      // Add a new channel itema...          // Actual channel strip setup...
2642      pChannelStrip = new ChannelStrip();          pChannelStrip->setup(pChannel);
     if (pChannelStrip == NULL)  
         return NULL;  
2643    
         m_pWorkspace->addWindow(pChannelStrip, Qt::FramelessWindowHint);  
   
     // Actual channel strip setup...  
     pChannelStrip->setup(pChannel);  
2644          QObject::connect(pChannelStrip,          QObject::connect(pChannelStrip,
2645                  SIGNAL(channelChanged(ChannelStrip*)),                  SIGNAL(channelChanged(ChannelStrip *)),
2646                  SLOT(channelStripChanged(ChannelStrip*)));                  SLOT(channelStripChanged(ChannelStrip *)));
2647      // Set some initial aesthetic options...  
2648      if (m_pOptions) {          // Now we show up us to the world.
2649          // Background display effect...          pChannelStrip->show();
         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);  
     }  
2650    
2651          // This is pretty new, so we'll watch for it closely.          // This is pretty new, so we'll watch for it closely.
2652          channelStripChanged(pChannelStrip);          channelStripChanged(pChannelStrip);
2653    
2654      // Return our successful reference...          // Return our successful reference...
2655      return pChannelStrip;          return pChannelStrip;
2656    }
2657    
2658    
2659    void MainForm::destroyChannelStrip ( ChannelStrip *pChannelStrip )
2660    {
2661            QMdiSubWindow *pMdiSubWindow
2662                    = static_cast<QMdiSubWindow *> (pChannelStrip->parentWidget());
2663            if (pMdiSubWindow == nullptr)
2664                    return;
2665    
2666            // Just delete the channel strip.
2667            delete pChannelStrip;
2668            delete pMdiSubWindow;
2669    
2670            // Do we auto-arrange?
2671            channelsArrangeAuto();
2672  }  }
2673    
2674    
2675  // Retrieve the active channel strip.  // Retrieve the active channel strip.
2676  ChannelStrip* MainForm::activeChannelStrip (void)  ChannelStrip *MainForm::activeChannelStrip (void)
2677  {  {
2678      return static_cast<ChannelStrip *> (m_pWorkspace->activeWindow());          QMdiSubWindow *pMdiSubWindow = m_pWorkspace->activeSubWindow();
2679            if (pMdiSubWindow)
2680                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2681            else
2682                    return nullptr;
2683  }  }
2684    
2685    
2686  // Retrieve a channel strip by index.  // Retrieve a channel strip by index.
2687  ChannelStrip* MainForm::channelStripAt ( int iChannel )  ChannelStrip *MainForm::channelStripAt ( int iStrip )
2688  {  {
2689      QWidgetList wlist = m_pWorkspace->windowList();          if (!m_pWorkspace) return nullptr;
2690      if (wlist.isEmpty())  
2691          return NULL;          const QList<QMdiSubWindow *>& wlist
2692                    = m_pWorkspace->subWindowList();
2693            if (wlist.isEmpty())
2694                    return nullptr;
2695    
2696      return static_cast<ChannelStrip *> (wlist.at(iChannel));          if (iStrip < 0 || iStrip >= wlist.count())
2697                    return nullptr;
2698    
2699            QMdiSubWindow *pMdiSubWindow = wlist.at(iStrip);
2700            if (pMdiSubWindow)
2701                    return static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2702            else
2703                    return nullptr;
2704  }  }
2705    
2706    
2707  // Retrieve a channel strip by sampler channel id.  // Retrieve a channel strip by sampler channel id.
2708  ChannelStrip* MainForm::channelStrip ( int iChannelID )  ChannelStrip *MainForm::channelStrip ( int iChannelID )
2709  {  {
2710          QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2711                    = m_pWorkspace->subWindowList();
2712          if (wlist.isEmpty())          if (wlist.isEmpty())
2713                  return NULL;                  return nullptr;
2714    
2715          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {          foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2716                  ChannelStrip* pChannelStrip                  ChannelStrip *pChannelStrip
2717                          = static_cast<ChannelStrip*> (wlist.at(iChannel));                          = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2718                  if (pChannelStrip) {                  if (pChannelStrip) {
2719                          qsamplerChannel *pChannel = pChannelStrip->channel();                          Channel *pChannel = pChannelStrip->channel();
2720                          if (pChannel && pChannel->channelID() == iChannelID)                          if (pChannel && pChannel->channelID() == iChannelID)
2721                                  return pChannelStrip;                                  return pChannelStrip;
2722                  }                  }
2723          }          }
2724    
2725          // Not found.          // Not found.
2726          return NULL;          return nullptr;
2727  }  }
2728    
2729    
2730  // Construct the windows menu.  // Construct the windows menu.
2731  void MainForm::channelsMenuAboutToShow (void)  void MainForm::channelsMenuAboutToShow (void)
2732  {  {
2733      ui.channelsMenu->clear();          m_ui.channelsMenu->clear();
2734          ui.channelsMenu->addAction(ui.channelsArrangeAction);          m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2735          ui.channelsMenu->addAction(ui.channelsAutoArrangeAction);          m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2736    
2737      QWidgetList wlist = m_pWorkspace->windowList();          const QList<QMdiSubWindow *>& wlist
2738      if (!wlist.isEmpty()) {                  = m_pWorkspace->subWindowList();
2739                  ui.channelsMenu->addSeparator();          if (!wlist.isEmpty()) {
2740          for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {                  m_ui.channelsMenu->addSeparator();
2741                          ChannelStrip* pChannelStrip                  int iStrip = 0;
2742                                  = static_cast<ChannelStrip*> (wlist.at(iChannel));                  foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2743                            ChannelStrip *pChannelStrip
2744                                    = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2745                          if (pChannelStrip) {                          if (pChannelStrip) {
2746                                  QAction *pAction = ui.channelsMenu->addAction(                                  QAction *pAction = m_ui.channelsMenu->addAction(
2747                                          pChannelStrip->windowTitle(), this, SLOT(channelsMenuActivated()));                                          pChannelStrip->windowTitle(),
2748                                            this, SLOT(channelsMenuActivated()));
2749                                  pAction->setCheckable(true);                                  pAction->setCheckable(true);
2750                                  pAction->setChecked(activeChannelStrip() == pChannelStrip);                                  pAction->setChecked(activeChannelStrip() == pChannelStrip);
2751                                  pAction->setData(iChannel);                                  pAction->setData(iStrip);
2752                          }                          }
2753          }                          ++iStrip;
2754      }                  }
2755            }
2756  }  }
2757    
2758    
# Line 2277  void MainForm::channelsMenuActivated (vo Line 2761  void MainForm::channelsMenuActivated (vo
2761  {  {
2762          // Retrive channel index from action data...          // Retrive channel index from action data...
2763          QAction *pAction = qobject_cast<QAction *> (sender());          QAction *pAction = qobject_cast<QAction *> (sender());
2764          if (pAction == NULL)          if (pAction == nullptr)
2765                  return;                  return;
2766    
2767          ChannelStrip* pChannelStrip = channelStripAt(pAction->data().toInt());          ChannelStrip *pChannelStrip = channelStripAt(pAction->data().toInt());
2768          if (pChannelStrip) {          if (pChannelStrip) {
2769                  pChannelStrip->showNormal();                  pChannelStrip->showNormal();
2770                  pChannelStrip->setFocus();                  pChannelStrip->setFocus();
# Line 2289  void MainForm::channelsMenuActivated (vo Line 2773  void MainForm::channelsMenuActivated (vo
2773    
2774    
2775  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2776  // qsamplerMainForm -- Timer stuff.  // QSampler::MainForm -- Timer stuff.
2777    
2778  // Set the pseudo-timer delay schedule.  // Set the pseudo-timer delay schedule.
2779  void MainForm::startSchedule ( int iStartDelay )  void MainForm::startSchedule ( int iStartDelay )
2780  {  {
2781      m_iStartDelay  = 1 + (iStartDelay * 1000);          m_iStartDelay  = 1 + (iStartDelay * 1000);
2782      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2783  }  }
2784    
2785  // Suspend the pseudo-timer delay schedule.  // Suspend the pseudo-timer delay schedule.
2786  void MainForm::stopSchedule (void)  void MainForm::stopSchedule (void)
2787  {  {
2788      m_iStartDelay  = 0;          m_iStartDelay  = 0;
2789      m_iTimerDelay  = 0;          m_iTimerDelay  = 0;
2790  }  }
2791    
2792  // Timer slot funtion.  // Timer slot funtion.
2793  void MainForm::timerSlot (void)  void MainForm::timerSlot (void)
2794  {  {
2795      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2796          return;                  return;
2797    
2798      // Is it the first shot on server start after a few delay?          // Is it the first shot on server start after a few delay?
2799      if (m_iTimerDelay < m_iStartDelay) {          if (m_iTimerDelay < m_iStartDelay) {
2800          m_iTimerDelay += QSAMPLER_TIMER_MSECS;                  m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2801          if (m_iTimerDelay >= m_iStartDelay) {                  if (m_iTimerDelay >= m_iStartDelay) {
2802              // If we cannot start it now, maybe a lil'mo'later ;)                          // If we cannot start it now, maybe a lil'mo'later ;)
2803              if (!startClient()) {                          if (!startClient()) {
2804                  m_iStartDelay += m_iTimerDelay;                                  m_iStartDelay += m_iTimerDelay;
2805                  m_iTimerDelay  = 0;                                  m_iTimerDelay  = 0;
2806              }                          }
2807          }                  }
2808      }          }
2809    
2810          if (m_pClient) {          if (m_pClient) {
2811                  // Update the channel information for each pending strip...                  // Update the channel information for each pending strip...
# Line 2330  void MainForm::timerSlot (void) Line 2814  void MainForm::timerSlot (void)
2814                          ChannelStrip *pChannelStrip = iter.next();                          ChannelStrip *pChannelStrip = iter.next();
2815                          // If successfull, remove from pending list...                          // If successfull, remove from pending list...
2816                          if (pChannelStrip->updateChannelInfo()) {                          if (pChannelStrip->updateChannelInfo()) {
2817                                  int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);                                  const int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2818                                  if (iChannelStrip >= 0)                                  if (iChannelStrip >= 0)
2819                                          m_changedStrips.removeAt(iChannelStrip);                                          m_changedStrips.removeAt(iChannelStrip);
2820                          }                          }
# Line 2341  void MainForm::timerSlot (void) Line 2825  void MainForm::timerSlot (void)
2825                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {                          if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime)  {
2826                                  m_iTimerSlot = 0;                                  m_iTimerSlot = 0;
2827                                  // Update the channel stream usage for each strip...                                  // Update the channel stream usage for each strip...
2828                                  QWidgetList wlist = m_pWorkspace->windowList();                                  const QList<QMdiSubWindow *>& wlist
2829                                  for (int iChannel = 0;                                          = m_pWorkspace->subWindowList();
2830                                                  iChannel < (int) wlist.count(); iChannel++) {                                  foreach (QMdiSubWindow *pMdiSubWindow, wlist) {
2831                                          ChannelStrip* pChannelStrip                                          ChannelStrip *pChannelStrip
2832                                                  = (ChannelStrip*) wlist.at(iChannel);                                                  = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
2833                                          if (pChannelStrip && pChannelStrip->isVisible())                                          if (pChannelStrip && pChannelStrip->isVisible())
2834                                                  pChannelStrip->updateChannelUsage();                                                  pChannelStrip->updateChannelUsage();
2835                                  }                                  }
2836                          }                          }
2837                  }                  }
2838    
2839            #if CONFIG_LSCP_CLIENT_CONNECTION_LOST
2840                    // If we lost connection to server: Try to automatically reconnect if we
2841                    // did not start the server.
2842                    //
2843                    // TODO: If we started the server, then we might inform the user that
2844                    // the server probably crashed and asking user ONCE whether we should
2845                    // restart the server.
2846                    if (lscp_client_connection_lost(m_pClient) && !m_pServer)
2847                            startAutoReconnectClient();
2848            #endif // CONFIG_LSCP_CLIENT_CONNECTION_LOST
2849          }          }
2850    
2851      // Register the next timer slot.          // Register the next timer slot.
2852      QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));          QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2853  }  }
2854    
2855    
2856  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
2857  // qsamplerMainForm -- Server stuff.  // QSampler::MainForm -- Server stuff.
2858    
2859  // Start linuxsampler server...  // Start linuxsampler server...
2860  void MainForm::startServer (void)  void MainForm::startServer (void)
2861  {  {
2862      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
2863          return;                  return;
2864    
2865      // Aren't already a client, are we?          // Aren't already a client, are we?
2866      if (!m_pOptions->bServerStart || m_pClient)          if (!m_pOptions->bServerStart || m_pClient)
2867          return;                  return;
   
     // Is the server process instance still here?  
     if (m_pServer) {  
         switch (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);  
                 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)),  
                 SLOT(processServerExit()));  
2868    
2869      // Build process arguments...          // Is the server process instance still here?
2870      QStringList serverCmdLine = m_pOptions->sServerCmdLine.split(' ');          if (m_pServer) {
2871                    if (QMessageBox::warning(this,
2872                            tr("Warning"),
2873                            tr("Could not start the LinuxSampler server.\n\n"
2874                            "Maybe it is already started."),
2875                            QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
2876                            m_pServer->terminate();
2877                            m_pServer->kill();
2878                    }
2879                    return;
2880            }
2881    
2882      appendMessages(tr("Server is starting..."));          // Reset our timer counters...
2883      appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");          stopSchedule();
2884    
2885            // Verify we have something to start with...
2886            if (m_pOptions->sServerCmdLine.isEmpty())
2887                    return;
2888    
2889            // OK. Let's build the startup process...
2890            m_pServer = new QProcess();
2891            m_bForceServerStop = true;
2892    
2893      const QString prog = (serverCmdLine.size() > 0) ? serverCmdLine[0] : QString();          // Setup stdout/stderr capture...
2894      const QStringList args = serverCmdLine.mid(1);          m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2895            QObject::connect(m_pServer,
2896                    SIGNAL(readyReadStandardOutput()),
2897                    SLOT(readServerStdout()));
2898            QObject::connect(m_pServer,
2899                    SIGNAL(readyReadStandardError()),
2900                    SLOT(readServerStdout()));
2901    
2902      // Go jack, go...          // The unforgiveable signal communication...
2903      m_pServer->start(prog, args);          QObject::connect(m_pServer,
2904      if (!m_pServer->waitForStarted()) {                  SIGNAL(finished(int, QProcess::ExitStatus)),
2905          appendMessagesError(tr("Could not start server.\n\nSorry."));                  SLOT(processServerExit()));
         processServerExit();  
         return;  
     }  
2906    
2907      // Show startup results...          // Build process arguments...
2908      appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));          QStringList args = m_pOptions->sServerCmdLine.split(' ');
2909            QString sCommand = args[0];
2910            args.removeAt(0);
2911    
2912            appendMessages(tr("Server is starting..."));
2913            appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2914    
2915            // Go linuxsampler, go...
2916            m_pServer->start(sCommand, args);
2917            if (!m_pServer->waitForStarted()) {
2918                    appendMessagesError(tr("Could not start server.\n\nSorry."));
2919                    processServerExit();
2920                    return;
2921            }
2922    
2923      // Reset (yet again) the timer counters,          // Show startup results...
2924      // but this time is deferred as the user opted.          appendMessages(
2925      startSchedule(m_pOptions->iStartDelay);                  tr("Server was started with PID=%1.")
2926      stabilizeForm();                  #if QT_VERSION < QT_VERSION_CHECK(5, 3, 0)
2927                            .arg(quint64(m_pServer->pid())));
2928                    #else
2929                            .arg(quint64(m_pServer->processId())));
2930                    #endif
2931    
2932            // Reset (yet again) the timer counters,
2933            // but this time is deferred as the user opted.
2934            startSchedule(m_pOptions->iStartDelay);
2935            stabilizeForm();
2936  }  }
2937    
2938    
2939  // Stop linuxsampler server...  // Stop linuxsampler server...
2940  void MainForm::stopServer (void)  void MainForm::stopServer ( bool bInteractive )
2941  {  {
2942      // Stop client code.          // Stop client code.
2943      stopClient();          stopClient();
2944    
2945            if (m_pServer && bInteractive) {
2946                    if (QMessageBox::question(this,
2947                            tr("The backend's fate ..."),
2948                            tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2949                            "running in the background. The sampler would continue to work\n"
2950                            "according to your current sampler session and you could alter the\n"
2951                            "sampler session at any time by relaunching QSampler.\n\n"
2952                            "Do you want LinuxSampler to stop?"),
2953                            QMessageBox::Yes | QMessageBox::No,
2954                            QMessageBox::Yes) == QMessageBox::No) {
2955                            m_bForceServerStop = false;
2956                    }
2957            }
2958    
2959      // And try to stop server.          bool bGraceWait = true;
     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::ExcludeUserInputEvents);  
2960    
2961       // Do final processing anyway.          // And try to stop server.
2962       processServerExit();          if (m_pServer && m_bForceServerStop) {
2963                    appendMessages(tr("Server is stopping..."));
2964                    if (m_pServer->state() == QProcess::Running) {
2965                    #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32)
2966                            // Try harder...
2967                            m_pServer->kill();
2968                    #else
2969                            // Try softly...
2970                            m_pServer->terminate();
2971                            bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000);
2972                            if (bFinished) bGraceWait = false;
2973                    #endif
2974                    }
2975            }       // Do final processing anyway.
2976            else processServerExit();
2977    
2978            // Give it some time to terminate gracefully and stabilize...
2979            if (bGraceWait) {
2980                    QElapsedTimer timer;
2981                    timer.start();
2982                    while (timer.elapsed() < QSAMPLER_TIMER_MSECS)
2983                            QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2984            }
2985  }  }
2986    
2987    
2988  // Stdout handler...  // Stdout handler...
2989  void MainForm::readServerStdout (void)  void MainForm::readServerStdout (void)
2990  {  {
2991      if (m_pMessages)          if (m_pMessages)
2992          m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());                  m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2993  }  }
2994    
2995    
2996  // Linuxsampler server cleanup.  // Linuxsampler server cleanup.
2997  void MainForm::processServerExit (void)  void MainForm::processServerExit (void)
2998  {  {
2999      // Force client code cleanup.          // Force client code cleanup.
3000      stopClient();          stopClient();
3001    
3002      // Flush anything that maybe pending...          // Flush anything that maybe pending...
3003      if (m_pMessages)          if (m_pMessages)
3004          m_pMessages->flushStdoutBuffer();                  m_pMessages->flushStdoutBuffer();
3005    
3006      if (m_pServer) {          if (m_pServer && m_bForceServerStop) {
3007          // Force final server shutdown...                  if (m_pServer->state() != QProcess::NotRunning) {
3008          appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));                          appendMessages(tr("Server is being forced..."));
3009          m_pServer->terminate();                          // Force final server shutdown...
3010          if (!m_pServer->waitForFinished(2000))                          m_pServer->kill();
3011              m_pServer->kill();                          // Give it some time to terminate gracefully and stabilize...
3012          // Destroy it.                          QElapsedTimer timer;
3013          delete m_pServer;                          timer.start();
3014          m_pServer = NULL;                          while (timer.elapsed() < QSAMPLER_TIMER_MSECS)
3015      }                                  QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
3016                    }
3017                    // Force final server shutdown...
3018                    appendMessages(
3019                            tr("Server was stopped with exit status %1.")
3020                            .arg(m_pServer->exitStatus()));
3021                    delete m_pServer;
3022                    m_pServer = nullptr;
3023            }
3024    
3025      // Again, make status visible stable.          // Again, make status visible stable.
3026      stabilizeForm();          stabilizeForm();
3027  }  }
3028    
3029    
3030  //-------------------------------------------------------------------------  //-------------------------------------------------------------------------
3031  // qsamplerMainForm -- Client stuff.  // QSampler::MainForm -- Client stuff.
3032    
3033  // The LSCP client callback procedure.  // The LSCP client callback procedure.
3034  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*/,
3035            lscp_event_t event, const char *pchData, int cchData, void *pvData )
3036  {  {
3037      MainForm* pMainForm = (MainForm *) pvData;          MainForm* pMainForm = (MainForm *) pvData;
3038      if (pMainForm == NULL)          if (pMainForm == nullptr)
3039          return LSCP_FAILED;                  return LSCP_FAILED;
3040    
3041      // ATTN: DO NOT EVER call any GUI code here,          // ATTN: DO NOT EVER call any GUI code here,
3042      // as this is run under some other thread context.          // as this is run under some other thread context.
3043      // A custom event must be posted here...          // A custom event must be posted here...
3044      QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));          QApplication::postEvent(pMainForm,
3045                    new LscpEvent(event, pchData, cchData));
3046    
3047      return LSCP_OK;          return LSCP_OK;
3048  }  }
3049    
3050    
3051  // Start our almighty client...  // Start our almighty client...
3052  bool MainForm::startClient (void)  bool MainForm::startClient (bool bReconnectOnly)
3053  {  {
3054      // Have it a setup?          // Have it a setup?
3055      if (m_pOptions == NULL)          if (m_pOptions == nullptr)
3056          return false;                  return false;
3057    
3058      // Aren't we already started, are we?          // Aren't we already started, are we?
3059      if (m_pClient)          if (m_pClient)
3060          return true;                  return true;
3061    
3062      // Log prepare here.          // Log prepare here.
3063      appendMessages(tr("Client connecting..."));          appendMessages(tr("Client connecting..."));
3064    
3065      // Create the client handle...          // Create the client handle...
3066          m_pClient = ::lscp_client_create(          m_pClient = ::lscp_client_create(
3067                  m_pOptions->sServerHost.toUtf8().constData(),                  m_pOptions->sServerHost.toUtf8().constData(),
3068                  m_pOptions->iServerPort, qsampler_client_callback, this);                  m_pOptions->iServerPort, qsampler_client_callback, this);
3069      if (m_pClient == NULL) {          if (m_pClient == nullptr) {
3070          // Is this the first try?                  // Is this the first try?
3071          // maybe we need to start a local server...                  // maybe we need to start a local server...
3072          if ((m_pServer && m_pServer->state() == QProcess::Running) || !m_pOptions->bServerStart)                  if ((m_pServer && m_pServer->state() == QProcess::Running)
3073              appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));                          || !m_pOptions->bServerStart || bReconnectOnly)
3074          else                  {
3075              startServer();                          // if this method is called from autoReconnectClient()
3076          // This is always a failure.                          // then don't bother user with an error message...
3077          stabilizeForm();                          if (!bReconnectOnly) {
3078          return false;                                  appendMessagesError(
3079      }                                          tr("Could not connect to server as client.\n\nSorry.")
3080      // Just set receive timeout value, blindly.                                  );
3081      ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);                          }
3082      appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));                  } else {
3083                            startServer();
3084                    }
3085                    // This is always a failure.
3086                    stabilizeForm();
3087                    return false;
3088            }
3089    
3090            // Just set receive timeout value, blindly.
3091            ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
3092            appendMessages(
3093                    tr("Client receive timeout is set to %1 msec.")
3094                    .arg(::lscp_client_get_timeout(m_pClient)));
3095    
3096          // Subscribe to channel info change notifications...          // Subscribe to channel info change notifications...
3097            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK)
3098                    appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)");
3099          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)          if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
3100                  appendMessagesClient("lscp_client_subscribe");                  appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
3101    
3102            DeviceStatusForm::onDevicesChanged(); // initialize
3103            updateViewMidiDeviceStatusMenu();
3104            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
3105                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
3106            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
3107                    appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
3108            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK)
3109                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)");
3110            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK)
3111                    appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)");
3112    
3113    #if CONFIG_EVENT_CHANNEL_MIDI
3114            // Subscribe to channel MIDI data notifications...
3115            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
3116                    appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
3117    #endif
3118    
3119    #if CONFIG_EVENT_DEVICE_MIDI
3120            // Subscribe to channel MIDI data notifications...
3121            if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
3122                    appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
3123    #endif
3124    
3125      // We may stop scheduling around.          // We may stop scheduling around.
3126      stopSchedule();          stopSchedule();
3127    
3128      // We'll accept drops from now on...          // We'll accept drops from now on...
3129      setAcceptDrops(true);          setAcceptDrops(true);
3130    
3131      // Log success here.          // Log success here.
3132      appendMessages(tr("Client connected."));          appendMessages(tr("Client connected."));
3133    
3134          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3135          // if visible, that we're ready...          // if visible, that we're ready...
3136          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3137              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3138          if (m_pDeviceForm)          if (m_pDeviceForm)
3139              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3140    
3141            // Is any session pending to be loaded?
3142            if (!m_pOptions->sSessionFile.isEmpty()) {
3143                    // Just load the prabably startup session...
3144                    if (loadSessionFile(m_pOptions->sSessionFile)) {
3145                            m_pOptions->sSessionFile = QString();
3146                            return true;
3147                    }
3148            }
3149    
3150      // Is any session pending to be loaded?          // send the current / loaded fine tuning settings to the sampler
3151      if (!m_pOptions->sSessionFile.isEmpty()) {          m_pOptions->sendFineTuningSettings();
         // Just load the prabably startup session...  
         if (loadSessionFile(m_pOptions->sSessionFile)) {  
             m_pOptions->sSessionFile = QString::null;  
             return true;  
         }  
     }  
3152    
3153      // Make a new session          // Make a new session
3154      return newSession();          return newSession();
3155  }  }
3156    
3157    
3158  // Stop client...  // Stop client...
3159  void MainForm::stopClient (void)  void MainForm::stopClient (void)
3160  {  {
3161      if (m_pClient == NULL)          if (m_pClient == nullptr)
3162          return;                  return;
   
     // Log prepare here.  
     appendMessages(tr("Client disconnecting..."));  
3163    
3164      // Clear timer counters...          // Log prepare here.
3165      stopSchedule();          appendMessages(tr("Client disconnecting..."));
3166    
3167      // We'll reject drops from now on...          // Clear timer counters...
3168      setAcceptDrops(false);          stopSchedule();
3169    
3170      // Force any channel strips around, but          // We'll reject drops from now on...
3171      // but avoid removing the corresponding          setAcceptDrops(false);
     // channels from the back-end server.  
     m_iDirtyCount = 0;  
     closeSession(false);  
3172    
3173      // Close us as a client...          // Force any channel strips around, but
3174            // but avoid removing the corresponding
3175            // channels from the back-end server.
3176            m_iDirtyCount = 0;
3177            closeSession(false);
3178    
3179            // Close us as a client...
3180    #if CONFIG_EVENT_DEVICE_MIDI
3181            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
3182    #endif
3183    #if CONFIG_EVENT_CHANNEL_MIDI
3184            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
3185    #endif
3186            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO);
3187            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT);
3188            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
3189            ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
3190          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
3191      ::lscp_client_destroy(m_pClient);          ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT);
3192      m_pClient = NULL;          ::lscp_client_destroy(m_pClient);
3193            m_pClient = nullptr;
3194    
3195          // Hard-notify instrumnet and device configuration forms,          // Hard-notify instrumnet and device configuration forms,
3196          // if visible, that we're running out...          // if visible, that we're running out...
3197          if (m_pInstrumentListForm)          if (m_pInstrumentListForm)
3198              m_pInstrumentListForm->refreshInstruments();                  m_pInstrumentListForm->refreshInstruments();
3199          if (m_pDeviceForm)          if (m_pDeviceForm)
3200              m_pDeviceForm->refreshDevices();                  m_pDeviceForm->refreshDevices();
3201    
3202      // Log final here.          // Log final here.
3203      appendMessages(tr("Client disconnected."));          appendMessages(tr("Client disconnected."));
3204    
3205      // Make visible status.          // Make visible status.
3206      stabilizeForm();          stabilizeForm();
3207    }
3208    
3209    
3210    void MainForm::startAutoReconnectClient (void)
3211    {
3212            stopClient();
3213            appendMessages(tr("Trying to reconnect..."));
3214            QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(autoReconnectClient()));
3215    }
3216    
3217    
3218    void MainForm::autoReconnectClient (void)
3219    {
3220            const bool bSuccess = startClient(true);
3221            if (!bSuccess)
3222                    QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(autoReconnectClient()));
3223    }
3224    
3225    
3226    // Channel strip activation/selection.
3227    void MainForm::activateStrip ( QMdiSubWindow *pMdiSubWindow )
3228    {
3229            ChannelStrip *pChannelStrip = nullptr;
3230            if (pMdiSubWindow)
3231                    pChannelStrip = static_cast<ChannelStrip *> (pMdiSubWindow->widget());
3232            if (pChannelStrip)
3233                    pChannelStrip->setSelected(true);
3234    
3235            stabilizeForm();
3236    }
3237    
3238    
3239    // Channel toolbar orientation change.
3240    void MainForm::channelsToolbarOrientation ( Qt::Orientation orientation )
3241    {
3242    #ifdef CONFIG_VOLUME
3243            m_pVolumeSlider->setOrientation(orientation);
3244            if (orientation == Qt::Horizontal) {
3245                    m_pVolumeSlider->setMinimumHeight(24);
3246                    m_pVolumeSlider->setMaximumHeight(32);
3247                    m_pVolumeSlider->setMinimumWidth(120);
3248                    m_pVolumeSlider->setMaximumWidth(640);
3249                    m_pVolumeSpinBox->setMaximumWidth(64);
3250                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::UpDownArrows);
3251            } else {
3252                    m_pVolumeSlider->setMinimumHeight(120);
3253                    m_pVolumeSlider->setMaximumHeight(480);
3254                    m_pVolumeSlider->setMinimumWidth(24);
3255                    m_pVolumeSlider->setMaximumWidth(32);
3256                    m_pVolumeSpinBox->setMaximumWidth(32);
3257                    m_pVolumeSpinBox->setButtonSymbols(QSpinBox::NoButtons);
3258            }
3259    #endif
3260  }  }
3261    
3262    
3263  } // namespace QSampler  } // namespace QSampler
3264    
3265    

Legend:
Removed from v.1507  
changed lines
  Added in v.3837

  ViewVC Help
Powered by ViewVC