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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2112 - (hide annotations) (download)
Wed Jul 21 18:33:25 2010 UTC (13 years, 9 months ago) by capela
File size: 83024 byte(s)
- Moving from old deprecated Qt3'ish custom event post handling
  into regular asynchronous signal/slot strategy. (EXPERIMENTAL)

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

  ViewVC Help
Powered by ViewVC