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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2144 - (hide annotations) (download)
Wed Oct 6 18:49:54 2010 UTC (13 years, 5 months ago) by persson
File size: 83196 byte(s)
* Fixes for cross compiling and building for Windows with configure
  and make.
* Made lookup of translation files more robust on Windows

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 persson 2144 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
100 capela 2112
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 persson 2144 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_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 capela 2113 m_pUsr1Notifier = NULL;
232 capela 2112
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 persson 2144 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
407 capela 2112 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 persson 2144 #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H)
695 capela 2113
696 capela 2112 char c;
697    
698     if (::read(g_fdUsr1[1], &c, sizeof(c)) > 0)
699 capela 2050 saveSession(false);
700 capela 2113
701     #endif
702 schoenebeck 1461 }
703    
704 capela 2038
705     void MainForm::updateViewMidiDeviceStatusMenu (void)
706     {
707 schoenebeck 1698 m_ui.viewMidiDeviceStatusMenu->clear();
708 capela 2038 const std::map<int, DeviceStatusForm *> statusForms
709     = DeviceStatusForm::getInstances();
710     std::map<int, DeviceStatusForm *>::const_iterator iter
711     = statusForms.begin();
712     for ( ; iter != statusForms.end(); ++iter) {
713     DeviceStatusForm *pStatusForm = iter->second;
714 schoenebeck 1698 m_ui.viewMidiDeviceStatusMenu->addAction(
715 capela 2038 pStatusForm->visibleAction());
716 schoenebeck 1698 }
717     }
718    
719 capela 2038
720 schoenebeck 1461 // Context menu event handler.
721     void MainForm::contextMenuEvent( QContextMenuEvent *pEvent )
722     {
723 capela 1509 stabilizeForm();
724 schoenebeck 1461
725 capela 1509 m_ui.editMenu->exec(pEvent->globalPos());
726 schoenebeck 1461 }
727    
728    
729     //-------------------------------------------------------------------------
730     // qsamplerMainForm -- Brainless public property accessors.
731    
732     // The global options settings property.
733 capela 1558 Options *MainForm::options (void) const
734 schoenebeck 1461 {
735 capela 1509 return m_pOptions;
736 schoenebeck 1461 }
737    
738    
739     // The LSCP client descriptor property.
740 capela 1509 lscp_client_t *MainForm::client (void) const
741 schoenebeck 1461 {
742 capela 1509 return m_pClient;
743 schoenebeck 1461 }
744    
745    
746     // The pseudo-singleton instance accessor.
747     MainForm *MainForm::getInstance (void)
748     {
749     return g_pMainForm;
750     }
751    
752    
753     //-------------------------------------------------------------------------
754     // qsamplerMainForm -- Session file stuff.
755    
756     // Format the displayable session filename.
757     QString MainForm::sessionName ( const QString& sFilename )
758     {
759 capela 1509 bool bCompletePath = (m_pOptions && m_pOptions->bCompletePath);
760     QString sSessionName = sFilename;
761     if (sSessionName.isEmpty())
762     sSessionName = tr("Untitled") + QString::number(m_iUntitled);
763     else if (!bCompletePath)
764     sSessionName = QFileInfo(sSessionName).fileName();
765     return sSessionName;
766 schoenebeck 1461 }
767    
768    
769     // Create a new session file from scratch.
770     bool MainForm::newSession (void)
771     {
772 capela 1509 // Check if we can do it.
773     if (!closeSession(true))
774     return false;
775 schoenebeck 1461
776     // Give us what the server has, right now...
777     updateSession();
778    
779 capela 1509 // Ok increment untitled count.
780     m_iUntitled++;
781 schoenebeck 1461
782 capela 1509 // Stabilize form.
783     m_sFilename = QString::null;
784     m_iDirtyCount = 0;
785     appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename)));
786     stabilizeForm();
787 schoenebeck 1461
788 capela 1509 return true;
789 schoenebeck 1461 }
790    
791    
792     // Open an existing sampler session.
793     bool MainForm::openSession (void)
794     {
795 capela 1509 if (m_pOptions == NULL)
796     return false;
797 schoenebeck 1461
798 capela 1509 // Ask for the filename to open...
799 capela 1499 QString sFilename = QFileDialog::getOpenFileName(this,
800     QSAMPLER_TITLE ": " + tr("Open Session"), // Caption.
801     m_pOptions->sSessionDir, // Start here.
802     tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files)
803     );
804 schoenebeck 1461
805 capela 1509 // Have we cancelled?
806     if (sFilename.isEmpty())
807     return false;
808 schoenebeck 1461
809 capela 1509 // Check if we're going to discard safely the current one...
810     if (!closeSession(true))
811     return false;
812 schoenebeck 1461
813 capela 1509 // Load it right away.
814     return loadSessionFile(sFilename);
815 schoenebeck 1461 }
816    
817    
818     // Save current sampler session with another name.
819     bool MainForm::saveSession ( bool bPrompt )
820     {
821 capela 1509 if (m_pOptions == NULL)
822     return false;
823 schoenebeck 1461
824 capela 1509 QString sFilename = m_sFilename;
825 schoenebeck 1461
826 capela 1509 // Ask for the file to save, if there's none...
827     if (bPrompt || sFilename.isEmpty()) {
828     // If none is given, assume default directory.
829     if (sFilename.isEmpty())
830     sFilename = m_pOptions->sSessionDir;
831     // Prompt the guy...
832 capela 1499 sFilename = QFileDialog::getSaveFileName(this,
833     QSAMPLER_TITLE ": " + tr("Save Session"), // Caption.
834     sFilename, // Start here.
835     tr("LSCP Session files") + " (*.lscp)" // Filter (LSCP files)
836     );
837 capela 1509 // Have we cancelled it?
838     if (sFilename.isEmpty())
839     return false;
840     // Enforce .lscp extension...
841     if (QFileInfo(sFilename).suffix().isEmpty())
842     sFilename += ".lscp";
843     // Check if already exists...
844     if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) {
845     if (QMessageBox::warning(this,
846 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Warning"),
847 capela 1509 tr("The file already exists:\n\n"
848     "\"%1\"\n\n"
849     "Do you want to replace it?")
850     .arg(sFilename),
851 capela 1840 QMessageBox::Yes | QMessageBox::No)
852     == QMessageBox::No)
853 capela 1509 return false;
854     }
855     }
856 schoenebeck 1461
857 capela 1509 // Save it right away.
858     return saveSessionFile(sFilename);
859 schoenebeck 1461 }
860    
861    
862     // Close current session.
863     bool MainForm::closeSession ( bool bForce )
864     {
865 capela 1509 bool bClose = true;
866 schoenebeck 1461
867 capela 1509 // Are we dirty enough to prompt it?
868     if (m_iDirtyCount > 0) {
869     switch (QMessageBox::warning(this,
870 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Warning"),
871 capela 1509 tr("The current session has been changed:\n\n"
872     "\"%1\"\n\n"
873     "Do you want to save the changes?")
874     .arg(sessionName(m_sFilename)),
875 capela 1840 QMessageBox::Save |
876     QMessageBox::Discard |
877     QMessageBox::Cancel)) {
878     case QMessageBox::Save:
879 capela 1509 bClose = saveSession(false);
880     // Fall thru....
881 capela 1840 case QMessageBox::Discard:
882 capela 1509 break;
883     default: // Cancel.
884     bClose = false;
885     break;
886     }
887     }
888 schoenebeck 1461
889 capela 1509 // If we may close it, dot it.
890     if (bClose) {
891     // Remove all channel strips from sight...
892     m_pWorkspace->setUpdatesEnabled(false);
893     QWidgetList wlist = m_pWorkspace->windowList();
894     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
895     ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
896     if (pChannelStrip) {
897 capela 1558 Channel *pChannel = pChannelStrip->channel();
898 capela 1509 if (bForce && pChannel)
899     pChannel->removeChannel();
900     delete pChannelStrip;
901     }
902     }
903     m_pWorkspace->setUpdatesEnabled(true);
904     // We're now clean, for sure.
905     m_iDirtyCount = 0;
906     }
907 schoenebeck 1461
908 capela 1509 return bClose;
909 schoenebeck 1461 }
910    
911    
912     // Load a session from specific file path.
913     bool MainForm::loadSessionFile ( const QString& sFilename )
914     {
915 capela 1509 if (m_pClient == NULL)
916     return false;
917 schoenebeck 1461
918 capela 1509 // Open and read from real file.
919     QFile file(sFilename);
920     if (!file.open(QIODevice::ReadOnly)) {
921     appendMessagesError(
922     tr("Could not open \"%1\" session file.\n\nSorry.")
923     .arg(sFilename));
924     return false;
925     }
926 schoenebeck 1461
927     // Tell the world we'll take some time...
928     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
929    
930 capela 1509 // Read the file.
931 schoenebeck 1461 int iLine = 0;
932 capela 1509 int iErrors = 0;
933     QTextStream ts(&file);
934     while (!ts.atEnd()) {
935     // Read the line.
936     QString sCommand = ts.readLine().trimmed();
937 schoenebeck 1461 iLine++;
938 capela 1509 // If not empty, nor a comment, call the server...
939     if (!sCommand.isEmpty() && sCommand[0] != '#') {
940 schoenebeck 1461 // Remember that, no matter what,
941     // all LSCP commands are CR/LF terminated.
942     sCommand += "\r\n";
943 capela 1499 if (::lscp_client_query(m_pClient, sCommand.toUtf8().constData())
944     != LSCP_OK) {
945 schoenebeck 1461 appendMessagesColor(QString("%1(%2): %3")
946     .arg(QFileInfo(sFilename).fileName()).arg(iLine)
947 capela 1499 .arg(sCommand.simplified()), "#996633");
948 schoenebeck 1461 appendMessagesClient("lscp_client_query");
949     iErrors++;
950     }
951 capela 1509 }
952     // Try to make it snappy :)
953     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
954     }
955 schoenebeck 1461
956 capela 1509 // Ok. we've read it.
957     file.close();
958 schoenebeck 1461
959     // Now we'll try to create (update) the whole GUI session.
960     updateSession();
961    
962     // We're fornerly done.
963     QApplication::restoreOverrideCursor();
964    
965     // Have we any errors?
966 capela 1509 if (iErrors > 0) {
967     appendMessagesError(
968     tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.")
969     .arg(sFilename));
970     }
971 schoenebeck 1461
972 capela 1509 // Save as default session directory.
973     if (m_pOptions)
974     m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
975 schoenebeck 1461 // We're not dirty anymore, if loaded without errors,
976     m_iDirtyCount = iErrors;
977 capela 1509 // Stabilize form...
978     m_sFilename = sFilename;
979     updateRecentFiles(sFilename);
980     appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
981 schoenebeck 1461
982 capela 1509 // Make that an overall update.
983     stabilizeForm();
984     return true;
985 schoenebeck 1461 }
986    
987    
988     // Save current session to specific file path.
989     bool MainForm::saveSessionFile ( const QString& sFilename )
990     {
991     if (m_pClient == NULL)
992     return false;
993    
994     // Check whether server is apparently OK...
995     if (::lscp_get_channels(m_pClient) < 0) {
996     appendMessagesClient("lscp_get_channels");
997     return false;
998     }
999    
1000 capela 1509 // Open and write into real file.
1001     QFile file(sFilename);
1002     if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
1003     appendMessagesError(
1004     tr("Could not open \"%1\" session file.\n\nSorry.")
1005     .arg(sFilename));
1006     return false;
1007     }
1008 schoenebeck 1461
1009     // Tell the world we'll take some time...
1010     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1011    
1012 capela 1509 // Write the file.
1013     int iErrors = 0;
1014     QTextStream ts(&file);
1015     ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
1016     ts << "# " << tr("Version")
1017     << ": " QSAMPLER_VERSION << endl;
1018     ts << "# " << tr("Build")
1019     << ": " __DATE__ " " __TIME__ << endl;
1020     ts << "#" << endl;
1021     ts << "# " << tr("File")
1022     << ": " << QFileInfo(sFilename).fileName() << endl;
1023     ts << "# " << tr("Date")
1024     << ": " << QDate::currentDate().toString("MMM dd yyyy")
1025     << " " << QTime::currentTime().toString("hh:mm:ss") << endl;
1026     ts << "#" << endl;
1027     ts << endl;
1028 schoenebeck 1461
1029     // It is assumed that this new kind of device+session file
1030     // will be loaded from a complete initialized server...
1031     int *piDeviceIDs;
1032     int iDevice;
1033     ts << "RESET" << endl;
1034    
1035     // Audio device mapping.
1036     QMap<int, int> audioDeviceMap;
1037 capela 1558 piDeviceIDs = Device::getDevices(m_pClient, Device::Audio);
1038 schoenebeck 1461 for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
1039     ts << endl;
1040 capela 1558 Device device(Device::Audio, piDeviceIDs[iDevice]);
1041 schoenebeck 1461 // Audio device specification...
1042     ts << "# " << device.deviceTypeName() << " " << device.driverName()
1043     << " " << tr("Device") << " " << iDevice << endl;
1044     ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
1045 capela 1558 DeviceParamMap::ConstIterator deviceParam;
1046 schoenebeck 1461 for (deviceParam = device.params().begin();
1047     deviceParam != device.params().end();
1048     ++deviceParam) {
1049 capela 1558 const DeviceParam& param = deviceParam.value();
1050 schoenebeck 1461 if (param.value.isEmpty()) ts << "# ";
1051     ts << " " << deviceParam.key() << "='" << param.value << "'";
1052     }
1053     ts << endl;
1054     // Audio channel parameters...
1055     int iPort = 0;
1056 capela 1558 QListIterator<DevicePort *> iter(device.ports());
1057 capela 1499 while (iter.hasNext()) {
1058 capela 1558 DevicePort *pPort = iter.next();
1059     DeviceParamMap::ConstIterator portParam;
1060 schoenebeck 1461 for (portParam = pPort->params().begin();
1061     portParam != pPort->params().end();
1062     ++portParam) {
1063 capela 1558 const DeviceParam& param = portParam.value();
1064 schoenebeck 1461 if (param.fix || param.value.isEmpty()) ts << "# ";
1065     ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
1066     << " " << iPort << " " << portParam.key()
1067     << "='" << param.value << "'" << endl;
1068     }
1069 capela 1499 iPort++;
1070 schoenebeck 1461 }
1071     // Audio device index/id mapping.
1072     audioDeviceMap[device.deviceID()] = iDevice;
1073     // Try to keep it snappy :)
1074 capela 1499 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1075 schoenebeck 1461 }
1076    
1077     // MIDI device mapping.
1078     QMap<int, int> midiDeviceMap;
1079 capela 1558 piDeviceIDs = Device::getDevices(m_pClient, Device::Midi);
1080 schoenebeck 1461 for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
1081     ts << endl;
1082 capela 1558 Device device(Device::Midi, piDeviceIDs[iDevice]);
1083 schoenebeck 1461 // MIDI device specification...
1084     ts << "# " << device.deviceTypeName() << " " << device.driverName()
1085     << " " << tr("Device") << " " << iDevice << endl;
1086     ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
1087 capela 1558 DeviceParamMap::ConstIterator deviceParam;
1088 schoenebeck 1461 for (deviceParam = device.params().begin();
1089     deviceParam != device.params().end();
1090     ++deviceParam) {
1091 capela 1558 const DeviceParam& param = deviceParam.value();
1092 schoenebeck 1461 if (param.value.isEmpty()) ts << "# ";
1093     ts << " " << deviceParam.key() << "='" << param.value << "'";
1094     }
1095     ts << endl;
1096     // MIDI port parameters...
1097     int iPort = 0;
1098 capela 1558 QListIterator<DevicePort *> iter(device.ports());
1099 capela 1499 while (iter.hasNext()) {
1100 capela 1558 DevicePort *pPort = iter.next();
1101     DeviceParamMap::ConstIterator portParam;
1102 schoenebeck 1461 for (portParam = pPort->params().begin();
1103     portParam != pPort->params().end();
1104     ++portParam) {
1105 capela 1558 const DeviceParam& param = portParam.value();
1106 schoenebeck 1461 if (param.fix || param.value.isEmpty()) ts << "# ";
1107     ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice
1108 capela 1509 << " " << iPort << " " << portParam.key()
1109     << "='" << param.value << "'" << endl;
1110 schoenebeck 1461 }
1111 capela 1499 iPort++;
1112 schoenebeck 1461 }
1113     // MIDI device index/id mapping.
1114     midiDeviceMap[device.deviceID()] = iDevice;
1115     // Try to keep it snappy :)
1116 capela 1499 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1117 schoenebeck 1461 }
1118     ts << endl;
1119    
1120     #ifdef CONFIG_MIDI_INSTRUMENT
1121     // MIDI instrument mapping...
1122     QMap<int, int> midiInstrumentMap;
1123     int *piMaps = ::lscp_list_midi_instrument_maps(m_pClient);
1124     for (int iMap = 0; piMaps && piMaps[iMap] >= 0; iMap++) {
1125     int iMidiMap = piMaps[iMap];
1126     const char *pszMapName
1127     = ::lscp_get_midi_instrument_map_name(m_pClient, iMidiMap);
1128     ts << "# " << tr("MIDI instrument map") << " " << iMap;
1129     if (pszMapName)
1130     ts << " - " << pszMapName;
1131     ts << endl;
1132     ts << "ADD MIDI_INSTRUMENT_MAP";
1133     if (pszMapName)
1134     ts << " '" << pszMapName << "'";
1135     ts << endl;
1136     // MIDI instrument mapping...
1137     lscp_midi_instrument_t *pInstrs
1138     = ::lscp_list_midi_instruments(m_pClient, iMidiMap);
1139     for (int iInstr = 0; pInstrs && pInstrs[iInstr].map >= 0; iInstr++) {
1140     lscp_midi_instrument_info_t *pInstrInfo
1141     = ::lscp_get_midi_instrument_info(m_pClient, &pInstrs[iInstr]);
1142     if (pInstrInfo) {
1143     ts << "MAP MIDI_INSTRUMENT "
1144     << iMap << " "
1145     << pInstrs[iInstr].bank << " "
1146     << pInstrs[iInstr].prog << " "
1147     << pInstrInfo->engine_name << " '"
1148     << pInstrInfo->instrument_file << "' "
1149     << pInstrInfo->instrument_nr << " "
1150     << pInstrInfo->volume << " ";
1151     switch (pInstrInfo->load_mode) {
1152     case LSCP_LOAD_PERSISTENT:
1153     ts << "PERSISTENT";
1154     break;
1155     case LSCP_LOAD_ON_DEMAND_HOLD:
1156     ts << "ON_DEMAND_HOLD";
1157     break;
1158     case LSCP_LOAD_ON_DEMAND:
1159     case LSCP_LOAD_DEFAULT:
1160     default:
1161     ts << "ON_DEMAND";
1162     break;
1163     }
1164     if (pInstrInfo->name)
1165     ts << " '" << pInstrInfo->name << "'";
1166     ts << endl;
1167     } // Check for errors...
1168     else if (::lscp_client_get_errno(m_pClient)) {
1169     appendMessagesClient("lscp_get_midi_instrument_info");
1170     iErrors++;
1171     }
1172     // Try to keep it snappy :)
1173 capela 1499 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1174 schoenebeck 1461 }
1175     ts << endl;
1176     // Check for errors...
1177     if (pInstrs == NULL && ::lscp_client_get_errno(m_pClient)) {
1178     appendMessagesClient("lscp_list_midi_instruments");
1179     iErrors++;
1180     }
1181     // MIDI strument index/id mapping.
1182     midiInstrumentMap[iMidiMap] = iMap;
1183     }
1184     // Check for errors...
1185     if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) {
1186     appendMessagesClient("lscp_list_midi_instrument_maps");
1187     iErrors++;
1188     }
1189     #endif // CONFIG_MIDI_INSTRUMENT
1190    
1191     // Sampler channel mapping.
1192 capela 1509 QWidgetList wlist = m_pWorkspace->windowList();
1193     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1194     ChannelStrip* pChannelStrip
1195 schoenebeck 1461 = static_cast<ChannelStrip *> (wlist.at(iChannel));
1196 capela 1509 if (pChannelStrip) {
1197 capela 1558 Channel *pChannel = pChannelStrip->channel();
1198 capela 1509 if (pChannel) {
1199     ts << "# " << tr("Channel") << " " << iChannel << endl;
1200     ts << "ADD CHANNEL" << endl;
1201 schoenebeck 1461 if (audioDeviceMap.isEmpty()) {
1202     ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
1203     << " " << pChannel->audioDriver() << endl;
1204     } else {
1205     ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel
1206     << " " << audioDeviceMap[pChannel->audioDevice()] << endl;
1207     }
1208     if (midiDeviceMap.isEmpty()) {
1209     ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel
1210     << " " << pChannel->midiDriver() << endl;
1211     } else {
1212     ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel
1213     << " " << midiDeviceMap[pChannel->midiDevice()] << endl;
1214     }
1215     ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
1216     << " " << pChannel->midiPort() << endl;
1217 capela 1509 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
1218     if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
1219     ts << "ALL";
1220     else
1221     ts << pChannel->midiChannel();
1222     ts << endl;
1223     ts << "LOAD ENGINE " << pChannel->engineName()
1224     << " " << iChannel << endl;
1225 schoenebeck 1461 if (pChannel->instrumentStatus() < 100) ts << "# ";
1226 capela 1509 ts << "LOAD INSTRUMENT NON_MODAL '"
1227     << pChannel->instrumentFile() << "' "
1228 schoenebeck 1461 << pChannel->instrumentNr() << " " << iChannel << endl;
1229 capela 1558 ChannelRoutingMap::ConstIterator audioRoute;
1230 schoenebeck 1461 for (audioRoute = pChannel->audioRouting().begin();
1231     audioRoute != pChannel->audioRouting().end();
1232     ++audioRoute) {
1233     ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel
1234     << " " << audioRoute.key()
1235 capela 1499 << " " << audioRoute.value() << endl;
1236 schoenebeck 1461 }
1237     ts << "SET CHANNEL VOLUME " << iChannel
1238     << " " << pChannel->volume() << endl;
1239     if (pChannel->channelMute())
1240     ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl;
1241     if (pChannel->channelSolo())
1242     ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl;
1243     #ifdef CONFIG_MIDI_INSTRUMENT
1244     if (pChannel->midiMap() >= 0) {
1245     ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel
1246     << " " << midiInstrumentMap[pChannel->midiMap()] << endl;
1247     }
1248     #endif
1249     #ifdef CONFIG_FXSEND
1250     int iChannelID = pChannel->channelID();
1251     int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);
1252     for (int iFxSend = 0;
1253     piFxSends && piFxSends[iFxSend] >= 0;
1254     iFxSend++) {
1255     lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(
1256     m_pClient, iChannelID, piFxSends[iFxSend]);
1257     if (pFxSendInfo) {
1258     ts << "CREATE FX_SEND " << iChannel
1259     << " " << pFxSendInfo->midi_controller;
1260     if (pFxSendInfo->name)
1261     ts << " '" << pFxSendInfo->name << "'";
1262     ts << endl;
1263     int *piRouting = pFxSendInfo->audio_routing;
1264     for (int iAudioSrc = 0;
1265     piRouting && piRouting[iAudioSrc] >= 0;
1266     iAudioSrc++) {
1267     ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "
1268     << iChannel
1269     << " " << iFxSend
1270     << " " << iAudioSrc
1271     << " " << piRouting[iAudioSrc] << endl;
1272     }
1273     #ifdef CONFIG_FXSEND_LEVEL
1274     ts << "SET FX_SEND LEVEL " << iChannel
1275     << " " << iFxSend
1276     << " " << pFxSendInfo->level << endl;
1277     #endif
1278     } // Check for errors...
1279     else if (::lscp_client_get_errno(m_pClient)) {
1280     appendMessagesClient("lscp_get_fxsend_info");
1281     iErrors++;
1282     }
1283     }
1284     #endif
1285 capela 1509 ts << endl;
1286     }
1287     }
1288     // Try to keep it snappy :)
1289     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
1290     }
1291 schoenebeck 1461
1292     #ifdef CONFIG_VOLUME
1293     ts << "# " << tr("Global volume level") << endl;
1294     ts << "SET VOLUME " << ::lscp_get_volume(m_pClient) << endl;
1295     ts << endl;
1296     #endif
1297    
1298 capela 1509 // Ok. we've wrote it.
1299     file.close();
1300 schoenebeck 1461
1301     // We're fornerly done.
1302     QApplication::restoreOverrideCursor();
1303    
1304 capela 1509 // Have we any errors?
1305     if (iErrors > 0) {
1306     appendMessagesError(
1307     tr("Some settings could not be saved\n"
1308     "to \"%1\" session file.\n\nSorry.")
1309     .arg(sFilename));
1310     }
1311 schoenebeck 1461
1312 capela 1509 // Save as default session directory.
1313     if (m_pOptions)
1314     m_pOptions->sSessionDir = QFileInfo(sFilename).dir().absolutePath();
1315     // We're not dirty anymore.
1316     m_iDirtyCount = 0;
1317     // Stabilize form...
1318     m_sFilename = sFilename;
1319     updateRecentFiles(sFilename);
1320     appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1321     stabilizeForm();
1322     return true;
1323 schoenebeck 1461 }
1324    
1325    
1326     // Session change receiver slot.
1327     void MainForm::sessionDirty (void)
1328     {
1329 capela 1509 // Just mark the dirty form.
1330     m_iDirtyCount++;
1331     // and update the form status...
1332     stabilizeForm();
1333 schoenebeck 1461 }
1334    
1335    
1336     //-------------------------------------------------------------------------
1337     // qsamplerMainForm -- File Action slots.
1338    
1339     // Create a new sampler session.
1340     void MainForm::fileNew (void)
1341     {
1342 capela 1509 // Of course we'll start clean new.
1343     newSession();
1344 schoenebeck 1461 }
1345    
1346    
1347     // Open an existing sampler session.
1348     void MainForm::fileOpen (void)
1349     {
1350 capela 1509 // Open it right away.
1351     openSession();
1352 schoenebeck 1461 }
1353    
1354    
1355     // Open a recent file session.
1356 capela 1499 void MainForm::fileOpenRecent (void)
1357 schoenebeck 1461 {
1358 capela 1499 // Retrive filename index from action data...
1359     QAction *pAction = qobject_cast<QAction *> (sender());
1360     if (pAction && m_pOptions) {
1361     int iIndex = pAction->data().toInt();
1362     if (iIndex >= 0 && iIndex < m_pOptions->recentFiles.count()) {
1363     QString sFilename = m_pOptions->recentFiles[iIndex];
1364     // Check if we can safely close the current session...
1365     if (!sFilename.isEmpty() && closeSession(true))
1366     loadSessionFile(sFilename);
1367     }
1368     }
1369 schoenebeck 1461 }
1370    
1371    
1372     // Save current sampler session.
1373     void MainForm::fileSave (void)
1374     {
1375 capela 1509 // Save it right away.
1376     saveSession(false);
1377 schoenebeck 1461 }
1378    
1379    
1380     // Save current sampler session with another name.
1381     void MainForm::fileSaveAs (void)
1382     {
1383 capela 1509 // Save it right away, maybe with another name.
1384     saveSession(true);
1385 schoenebeck 1461 }
1386    
1387    
1388     // Reset the sampler instance.
1389     void MainForm::fileReset (void)
1390     {
1391 capela 1509 if (m_pClient == NULL)
1392     return;
1393 schoenebeck 1461
1394 capela 1509 // Ask user whether he/she want's an internal sampler reset...
1395     if (QMessageBox::warning(this,
1396 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Warning"),
1397 capela 1509 tr("Resetting the sampler instance will close\n"
1398     "all device and channel configurations.\n\n"
1399     "Please note that this operation may cause\n"
1400     "temporary MIDI and Audio disruption.\n\n"
1401     "Do you want to reset the sampler engine now?"),
1402 capela 1840 QMessageBox::Ok | QMessageBox::Cancel)
1403     == QMessageBox::Cancel)
1404 capela 1509 return;
1405 schoenebeck 1461
1406     // Trye closing the current session, first...
1407     if (!closeSession(true))
1408     return;
1409    
1410 capela 1509 // Just do the reset, after closing down current session...
1411 schoenebeck 1461 // Do the actual sampler reset...
1412     if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1413     appendMessagesClient("lscp_reset_sampler");
1414     appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
1415     return;
1416     }
1417    
1418 capela 1509 // Log this.
1419     appendMessages(tr("Sampler reset."));
1420 schoenebeck 1461
1421     // Make it a new session...
1422     newSession();
1423     }
1424    
1425    
1426     // Restart the client/server instance.
1427     void MainForm::fileRestart (void)
1428     {
1429 capela 1509 if (m_pOptions == NULL)
1430     return;
1431 schoenebeck 1461
1432 capela 1509 bool bRestart = true;
1433 schoenebeck 1461
1434 capela 1509 // Ask user whether he/she want's a complete restart...
1435     // (if we're currently up and running)
1436     if (bRestart && m_pClient) {
1437     bRestart = (QMessageBox::warning(this,
1438 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Warning"),
1439 capela 1509 tr("New settings will be effective after\n"
1440     "restarting the client/server connection.\n\n"
1441     "Please note that this operation may cause\n"
1442     "temporary MIDI and Audio disruption.\n\n"
1443     "Do you want to restart the connection now?"),
1444 capela 1840 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok);
1445 capela 1509 }
1446 schoenebeck 1461
1447 capela 1509 // Are we still for it?
1448     if (bRestart && closeSession(true)) {
1449     // Stop server, it will force the client too.
1450     stopServer();
1451     // Reschedule a restart...
1452     startSchedule(m_pOptions->iStartDelay);
1453     }
1454 schoenebeck 1461 }
1455    
1456    
1457     // Exit application program.
1458     void MainForm::fileExit (void)
1459     {
1460 capela 1509 // Go for close the whole thing.
1461     close();
1462 schoenebeck 1461 }
1463    
1464    
1465     //-------------------------------------------------------------------------
1466     // qsamplerMainForm -- Edit Action slots.
1467    
1468     // Add a new sampler channel.
1469     void MainForm::editAddChannel (void)
1470     {
1471 capela 1509 if (m_pClient == NULL)
1472     return;
1473 schoenebeck 1461
1474 capela 1509 // Just create the channel instance...
1475 capela 1558 Channel *pChannel = new Channel();
1476 capela 1509 if (pChannel == NULL)
1477     return;
1478 schoenebeck 1461
1479 capela 1509 // Before we show it up, may be we'll
1480     // better ask for some initial values?
1481     if (!pChannel->channelSetup(this)) {
1482     delete pChannel;
1483     return;
1484     }
1485 schoenebeck 1461
1486 capela 1509 // And give it to the strip...
1487     // (will own the channel instance, if successful).
1488     if (!createChannelStrip(pChannel)) {
1489     delete pChannel;
1490     return;
1491     }
1492 schoenebeck 1461
1493 capela 1515 // Do we auto-arrange?
1494     if (m_pOptions && m_pOptions->bAutoArrange)
1495     channelsArrange();
1496    
1497 capela 1509 // Make that an overall update.
1498     m_iDirtyCount++;
1499     stabilizeForm();
1500 schoenebeck 1461 }
1501    
1502    
1503     // Remove current sampler channel.
1504     void MainForm::editRemoveChannel (void)
1505     {
1506 capela 1509 if (m_pClient == NULL)
1507     return;
1508 schoenebeck 1461
1509 capela 1509 ChannelStrip* pChannelStrip = activeChannelStrip();
1510     if (pChannelStrip == NULL)
1511     return;
1512 schoenebeck 1461
1513 capela 1558 Channel *pChannel = pChannelStrip->channel();
1514 capela 1509 if (pChannel == NULL)
1515     return;
1516 schoenebeck 1461
1517 capela 1509 // Prompt user if he/she's sure about this...
1518     if (m_pOptions && m_pOptions->bConfirmRemove) {
1519     if (QMessageBox::warning(this,
1520 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Warning"),
1521 capela 1509 tr("About to remove channel:\n\n"
1522     "%1\n\n"
1523     "Are you sure?")
1524     .arg(pChannelStrip->windowTitle()),
1525 capela 1840 QMessageBox::Ok | QMessageBox::Cancel)
1526     == QMessageBox::Cancel)
1527 capela 1509 return;
1528     }
1529 schoenebeck 1461
1530 capela 1509 // Remove the existing sampler channel.
1531     if (!pChannel->removeChannel())
1532     return;
1533 schoenebeck 1461
1534 capela 1509 // Just delete the channel strip.
1535     delete pChannelStrip;
1536 schoenebeck 1461
1537 capela 1509 // Do we auto-arrange?
1538     if (m_pOptions && m_pOptions->bAutoArrange)
1539     channelsArrange();
1540 schoenebeck 1461
1541 capela 1509 // We'll be dirty, for sure...
1542     m_iDirtyCount++;
1543     stabilizeForm();
1544 schoenebeck 1461 }
1545    
1546    
1547     // Setup current sampler channel.
1548     void MainForm::editSetupChannel (void)
1549     {
1550 capela 1509 if (m_pClient == NULL)
1551     return;
1552 schoenebeck 1461
1553 capela 1509 ChannelStrip* pChannelStrip = activeChannelStrip();
1554     if (pChannelStrip == NULL)
1555     return;
1556 schoenebeck 1461
1557 capela 1509 // Just invoque the channel strip procedure.
1558     pChannelStrip->channelSetup();
1559 schoenebeck 1461 }
1560    
1561    
1562     // Edit current sampler channel.
1563     void MainForm::editEditChannel (void)
1564     {
1565 capela 1509 if (m_pClient == NULL)
1566     return;
1567 schoenebeck 1461
1568 capela 1509 ChannelStrip* pChannelStrip = activeChannelStrip();
1569     if (pChannelStrip == NULL)
1570     return;
1571 schoenebeck 1461
1572 capela 1509 // Just invoque the channel strip procedure.
1573     pChannelStrip->channelEdit();
1574 schoenebeck 1461 }
1575    
1576    
1577     // Reset current sampler channel.
1578     void MainForm::editResetChannel (void)
1579     {
1580 capela 1509 if (m_pClient == NULL)
1581     return;
1582 schoenebeck 1461
1583 capela 1509 ChannelStrip* pChannelStrip = activeChannelStrip();
1584     if (pChannelStrip == NULL)
1585     return;
1586 schoenebeck 1461
1587 capela 1509 // Just invoque the channel strip procedure.
1588     pChannelStrip->channelReset();
1589 schoenebeck 1461 }
1590    
1591    
1592     // Reset all sampler channels.
1593     void MainForm::editResetAllChannels (void)
1594     {
1595     if (m_pClient == NULL)
1596     return;
1597    
1598     // Invoque the channel strip procedure,
1599     // for all channels out there...
1600     m_pWorkspace->setUpdatesEnabled(false);
1601     QWidgetList wlist = m_pWorkspace->windowList();
1602     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1603     ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
1604     if (pChannelStrip)
1605     pChannelStrip->channelReset();
1606     }
1607     m_pWorkspace->setUpdatesEnabled(true);
1608     }
1609    
1610    
1611     //-------------------------------------------------------------------------
1612     // qsamplerMainForm -- View Action slots.
1613    
1614     // Show/hide the main program window menubar.
1615     void MainForm::viewMenubar ( bool bOn )
1616     {
1617 capela 1509 if (bOn)
1618     m_ui.MenuBar->show();
1619     else
1620     m_ui.MenuBar->hide();
1621 schoenebeck 1461 }
1622    
1623    
1624     // Show/hide the main program window toolbar.
1625     void MainForm::viewToolbar ( bool bOn )
1626     {
1627 capela 1509 if (bOn) {
1628     m_ui.fileToolbar->show();
1629     m_ui.editToolbar->show();
1630     m_ui.channelsToolbar->show();
1631     } else {
1632     m_ui.fileToolbar->hide();
1633     m_ui.editToolbar->hide();
1634     m_ui.channelsToolbar->hide();
1635     }
1636 schoenebeck 1461 }
1637    
1638    
1639     // Show/hide the main program window statusbar.
1640     void MainForm::viewStatusbar ( bool bOn )
1641     {
1642 capela 1509 if (bOn)
1643     statusBar()->show();
1644     else
1645     statusBar()->hide();
1646 schoenebeck 1461 }
1647    
1648    
1649     // Show/hide the messages window logger.
1650     void MainForm::viewMessages ( bool bOn )
1651     {
1652 capela 1509 if (bOn)
1653     m_pMessages->show();
1654     else
1655     m_pMessages->hide();
1656 schoenebeck 1461 }
1657    
1658    
1659     // Show/hide the MIDI instrument list-view form.
1660     void MainForm::viewInstruments (void)
1661     {
1662     if (m_pOptions == NULL)
1663     return;
1664    
1665     if (m_pInstrumentListForm) {
1666     m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
1667     if (m_pInstrumentListForm->isVisible()) {
1668     m_pInstrumentListForm->hide();
1669     } else {
1670     m_pInstrumentListForm->show();
1671     m_pInstrumentListForm->raise();
1672 capela 1499 m_pInstrumentListForm->activateWindow();
1673 schoenebeck 1461 }
1674     }
1675     }
1676    
1677    
1678     // Show/hide the device configurator form.
1679     void MainForm::viewDevices (void)
1680     {
1681     if (m_pOptions == NULL)
1682     return;
1683    
1684     if (m_pDeviceForm) {
1685     m_pOptions->saveWidgetGeometry(m_pDeviceForm);
1686     if (m_pDeviceForm->isVisible()) {
1687     m_pDeviceForm->hide();
1688     } else {
1689     m_pDeviceForm->show();
1690     m_pDeviceForm->raise();
1691 capela 1499 m_pDeviceForm->activateWindow();
1692 schoenebeck 1461 }
1693     }
1694     }
1695    
1696    
1697     // Show options dialog.
1698     void MainForm::viewOptions (void)
1699     {
1700 capela 1509 if (m_pOptions == NULL)
1701     return;
1702 schoenebeck 1461
1703 capela 1509 OptionsForm* pOptionsForm = new OptionsForm(this);
1704     if (pOptionsForm) {
1705     // Check out some initial nullities(tm)...
1706     ChannelStrip* pChannelStrip = activeChannelStrip();
1707     if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1708     m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1709     if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1710     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1711     // To track down deferred or immediate changes.
1712     QString sOldServerHost = m_pOptions->sServerHost;
1713     int iOldServerPort = m_pOptions->iServerPort;
1714     int iOldServerTimeout = m_pOptions->iServerTimeout;
1715     bool bOldServerStart = m_pOptions->bServerStart;
1716     QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
1717 schoenebeck 1803 bool bOldMessagesLog = m_pOptions->bMessagesLog;
1718 capela 1738 QString sOldMessagesLogPath = m_pOptions->sMessagesLogPath;
1719 capela 1509 QString sOldDisplayFont = m_pOptions->sDisplayFont;
1720     bool bOldDisplayEffect = m_pOptions->bDisplayEffect;
1721     int iOldMaxVolume = m_pOptions->iMaxVolume;
1722     QString sOldMessagesFont = m_pOptions->sMessagesFont;
1723     bool bOldKeepOnTop = m_pOptions->bKeepOnTop;
1724     bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
1725     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
1726     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1727     bool bOldCompletePath = m_pOptions->bCompletePath;
1728     bool bOldInstrumentNames = m_pOptions->bInstrumentNames;
1729     int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
1730 capela 1749 int iOldBaseFontSize = m_pOptions->iBaseFontSize;
1731 capela 1509 // Load the current setup settings.
1732     pOptionsForm->setup(m_pOptions);
1733     // Show the setup dialog...
1734     if (pOptionsForm->exec()) {
1735     // Warn if something will be only effective on next run.
1736     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1737     (!bOldStdoutCapture && m_pOptions->bStdoutCapture) ||
1738     ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) ||
1739 capela 1749 (!bOldKeepOnTop && m_pOptions->bKeepOnTop) ||
1740     (iOldBaseFontSize != m_pOptions->iBaseFontSize)) {
1741 capela 1509 QMessageBox::information(this,
1742 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Information"),
1743 capela 1509 tr("Some settings may be only effective\n"
1744 capela 1840 "next time you start this program."));
1745 capela 1509 updateMessagesCapture();
1746     }
1747     // Check wheather something immediate has changed.
1748 capela 1738 if (( bOldMessagesLog && !m_pOptions->bMessagesLog) ||
1749     (!bOldMessagesLog && m_pOptions->bMessagesLog) ||
1750     (sOldMessagesLogPath != m_pOptions->sMessagesLogPath))
1751     m_pMessages->setLogging(
1752     m_pOptions->bMessagesLog, m_pOptions->sMessagesLogPath);
1753 capela 1509 if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1754     (!bOldCompletePath && m_pOptions->bCompletePath) ||
1755     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1756     updateRecentFilesMenu();
1757     if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1758     (!bOldInstrumentNames && m_pOptions->bInstrumentNames))
1759     updateInstrumentNames();
1760     if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1761     (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
1762     updateDisplayEffect();
1763     if (sOldDisplayFont != m_pOptions->sDisplayFont)
1764     updateDisplayFont();
1765     if (iOldMaxVolume != m_pOptions->iMaxVolume)
1766     updateMaxVolume();
1767     if (sOldMessagesFont != m_pOptions->sMessagesFont)
1768     updateMessagesFont();
1769     if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1770     (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
1771     (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
1772     updateMessagesLimit();
1773     // And now the main thing, whether we'll do client/server recycling?
1774     if ((sOldServerHost != m_pOptions->sServerHost) ||
1775     (iOldServerPort != m_pOptions->iServerPort) ||
1776     (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1777     ( bOldServerStart && !m_pOptions->bServerStart) ||
1778     (!bOldServerStart && m_pOptions->bServerStart) ||
1779     (sOldServerCmdLine != m_pOptions->sServerCmdLine
1780     && m_pOptions->bServerStart))
1781     fileRestart();
1782     }
1783     // Done.
1784     delete pOptionsForm;
1785     }
1786 schoenebeck 1461
1787 capela 1509 // This makes it.
1788     stabilizeForm();
1789 schoenebeck 1461 }
1790    
1791    
1792     //-------------------------------------------------------------------------
1793     // qsamplerMainForm -- Channels action slots.
1794    
1795     // Arrange channel strips.
1796     void MainForm::channelsArrange (void)
1797     {
1798 capela 1509 // Full width vertical tiling
1799     QWidgetList wlist = m_pWorkspace->windowList();
1800     if (wlist.isEmpty())
1801     return;
1802 schoenebeck 1461
1803 capela 1509 m_pWorkspace->setUpdatesEnabled(false);
1804     int y = 0;
1805     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1806     ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
1807     /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1808     // Prevent flicker...
1809     pChannelStrip->hide();
1810     pChannelStrip->showNormal();
1811     } */
1812     pChannelStrip->adjustSize();
1813     int iWidth = m_pWorkspace->width();
1814     if (iWidth < pChannelStrip->width())
1815     iWidth = pChannelStrip->width();
1816     // int iHeight = pChannelStrip->height()
1817     // + pChannelStrip->parentWidget()->baseSize().height();
1818     int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1819     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1820     y += iHeight;
1821     }
1822     m_pWorkspace->setUpdatesEnabled(true);
1823 schoenebeck 1461
1824 capela 1509 stabilizeForm();
1825 schoenebeck 1461 }
1826    
1827    
1828     // Auto-arrange channel strips.
1829     void MainForm::channelsAutoArrange ( bool bOn )
1830     {
1831 capela 1509 if (m_pOptions == NULL)
1832     return;
1833 schoenebeck 1461
1834 capela 1509 // Toggle the auto-arrange flag.
1835     m_pOptions->bAutoArrange = bOn;
1836 schoenebeck 1461
1837 capela 1509 // If on, update whole workspace...
1838     if (m_pOptions->bAutoArrange)
1839     channelsArrange();
1840 schoenebeck 1461 }
1841    
1842    
1843     //-------------------------------------------------------------------------
1844     // qsamplerMainForm -- Help Action slots.
1845    
1846     // Show information about the Qt toolkit.
1847     void MainForm::helpAboutQt (void)
1848     {
1849 capela 1509 QMessageBox::aboutQt(this);
1850 schoenebeck 1461 }
1851    
1852    
1853     // Show information about application program.
1854     void MainForm::helpAbout (void)
1855     {
1856 capela 1509 // Stuff the about box text...
1857     QString sText = "<p>\n";
1858     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1859     sText += "<br />\n";
1860     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1861     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1862 schoenebeck 1461 #ifdef CONFIG_DEBUG
1863 capela 1509 sText += "<small><font color=\"red\">";
1864     sText += tr("Debugging option enabled.");
1865     sText += "</font></small><br />";
1866 schoenebeck 1461 #endif
1867     #ifndef CONFIG_LIBGIG
1868 capela 1509 sText += "<small><font color=\"red\">";
1869     sText += tr("GIG (libgig) file support disabled.");
1870     sText += "</font></small><br />";
1871 schoenebeck 1461 #endif
1872     #ifndef CONFIG_INSTRUMENT_NAME
1873 capela 1509 sText += "<small><font color=\"red\">";
1874     sText += tr("LSCP (liblscp) instrument_name support disabled.");
1875     sText += "</font></small><br />";
1876 schoenebeck 1461 #endif
1877     #ifndef CONFIG_MUTE_SOLO
1878 capela 1509 sText += "<small><font color=\"red\">";
1879     sText += tr("Sampler channel Mute/Solo support disabled.");
1880     sText += "</font></small><br />";
1881 schoenebeck 1461 #endif
1882     #ifndef CONFIG_AUDIO_ROUTING
1883 capela 1509 sText += "<small><font color=\"red\">";
1884     sText += tr("LSCP (liblscp) audio_routing support disabled.");
1885     sText += "</font></small><br />";
1886 schoenebeck 1461 #endif
1887     #ifndef CONFIG_FXSEND
1888 capela 1509 sText += "<small><font color=\"red\">";
1889     sText += tr("Sampler channel Effect Sends support disabled.");
1890     sText += "</font></small><br />";
1891 schoenebeck 1461 #endif
1892     #ifndef CONFIG_VOLUME
1893 capela 1509 sText += "<small><font color=\"red\">";
1894     sText += tr("Global volume support disabled.");
1895     sText += "</font></small><br />";
1896 schoenebeck 1461 #endif
1897     #ifndef CONFIG_MIDI_INSTRUMENT
1898 capela 1509 sText += "<small><font color=\"red\">";
1899     sText += tr("MIDI instrument mapping support disabled.");
1900     sText += "</font></small><br />";
1901 schoenebeck 1461 #endif
1902     #ifndef CONFIG_EDIT_INSTRUMENT
1903 capela 1509 sText += "<small><font color=\"red\">";
1904     sText += tr("Instrument editing support disabled.");
1905     sText += "</font></small><br />";
1906 schoenebeck 1461 #endif
1907 capela 1815 #ifndef CONFIG_EVENT_CHANNEL_MIDI
1908     sText += "<small><font color=\"red\">";
1909     sText += tr("Channel MIDI event support disabled.");
1910     sText += "</font></small><br />";
1911     #endif
1912     #ifndef CONFIG_EVENT_DEVICE_MIDI
1913     sText += "<small><font color=\"red\">";
1914     sText += tr("Device MIDI event support disabled.");
1915     sText += "</font></small><br />";
1916     #endif
1917     #ifndef CONFIG_MAX_VOICES
1918     sText += "<small><font color=\"red\">";
1919     sText += tr("Runtime max. voices / disk streams support disabled.");
1920     sText += "</font></small><br />";
1921     #endif
1922 capela 1509 sText += "<br />\n";
1923     sText += tr("Using") + ": ";
1924     sText += ::lscp_client_package();
1925     sText += " ";
1926     sText += ::lscp_client_version();
1927 schoenebeck 1461 #ifdef CONFIG_LIBGIG
1928 capela 1509 sText += ", ";
1929     sText += gig::libraryName().c_str();
1930     sText += " ";
1931     sText += gig::libraryVersion().c_str();
1932 schoenebeck 1461 #endif
1933 capela 1509 sText += "<br />\n";
1934     sText += "<br />\n";
1935     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1936     sText += "<br />\n";
1937     sText += "<small>";
1938     sText += QSAMPLER_COPYRIGHT "<br />\n";
1939     sText += QSAMPLER_COPYRIGHT2 "<br />\n";
1940     sText += "<br />\n";
1941     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1942     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1943     sText += "</small>";
1944     sText += "</p>\n";
1945 schoenebeck 1461
1946 capela 1509 QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1947 schoenebeck 1461 }
1948    
1949    
1950     //-------------------------------------------------------------------------
1951     // qsamplerMainForm -- Main window stabilization.
1952    
1953     void MainForm::stabilizeForm (void)
1954     {
1955 capela 1509 // Update the main application caption...
1956     QString sSessionName = sessionName(m_sFilename);
1957     if (m_iDirtyCount > 0)
1958     sSessionName += " *";
1959     setWindowTitle(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1960 schoenebeck 1461
1961 capela 1509 // Update the main menu state...
1962 capela 2038 ChannelStrip *pChannelStrip = activeChannelStrip();
1963     bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1964 capela 1509 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1965 capela 2038 bool bHasChannels = (bHasClient && m_pWorkspace->windowList().count() > 0);
1966 capela 1509 m_ui.fileNewAction->setEnabled(bHasClient);
1967     m_ui.fileOpenAction->setEnabled(bHasClient);
1968     m_ui.fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1969     m_ui.fileSaveAsAction->setEnabled(bHasClient);
1970     m_ui.fileResetAction->setEnabled(bHasClient);
1971     m_ui.fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1972     m_ui.editAddChannelAction->setEnabled(bHasClient);
1973     m_ui.editRemoveChannelAction->setEnabled(bHasChannel);
1974     m_ui.editSetupChannelAction->setEnabled(bHasChannel);
1975 schoenebeck 1461 #ifdef CONFIG_EDIT_INSTRUMENT
1976 capela 1509 m_ui.editEditChannelAction->setEnabled(bHasChannel);
1977 schoenebeck 1461 #else
1978 capela 1509 m_ui.editEditChannelAction->setEnabled(false);
1979 schoenebeck 1461 #endif
1980 capela 1509 m_ui.editResetChannelAction->setEnabled(bHasChannel);
1981 capela 2038 m_ui.editResetAllChannelsAction->setEnabled(bHasChannels);
1982 capela 1509 m_ui.viewMessagesAction->setChecked(m_pMessages && m_pMessages->isVisible());
1983 schoenebeck 1461 #ifdef CONFIG_MIDI_INSTRUMENT
1984 capela 1509 m_ui.viewInstrumentsAction->setChecked(m_pInstrumentListForm
1985 schoenebeck 1461 && m_pInstrumentListForm->isVisible());
1986 capela 1509 m_ui.viewInstrumentsAction->setEnabled(bHasClient);
1987 schoenebeck 1461 #else
1988 capela 1509 m_ui.viewInstrumentsAction->setEnabled(false);
1989 schoenebeck 1461 #endif
1990 capela 1509 m_ui.viewDevicesAction->setChecked(m_pDeviceForm
1991 schoenebeck 1461 && m_pDeviceForm->isVisible());
1992 capela 1509 m_ui.viewDevicesAction->setEnabled(bHasClient);
1993 capela 2038 m_ui.viewMidiDeviceStatusMenu->setEnabled(
1994     DeviceStatusForm::getInstances().size() > 0);
1995     m_ui.channelsArrangeAction->setEnabled(bHasChannels);
1996 schoenebeck 1461
1997     #ifdef CONFIG_VOLUME
1998     // Toolbar widgets are also affected...
1999 capela 1509 m_pVolumeSlider->setEnabled(bHasClient);
2000     m_pVolumeSpinBox->setEnabled(bHasClient);
2001 schoenebeck 1461 #endif
2002    
2003 capela 1509 // Client/Server status...
2004     if (bHasClient) {
2005     m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
2006     m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost
2007     + ':' + QString::number(m_pOptions->iServerPort));
2008     } else {
2009     m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
2010     m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
2011     }
2012     // Channel status...
2013     if (bHasChannel)
2014     m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->windowTitle());
2015     else
2016     m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
2017     // Session status...
2018     if (m_iDirtyCount > 0)
2019     m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
2020     else
2021     m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
2022 schoenebeck 1461
2023 capela 1509 // Recent files menu.
2024     m_ui.fileOpenRecentMenu->setEnabled(m_pOptions->recentFiles.count() > 0);
2025 schoenebeck 1461 }
2026    
2027    
2028     // Global volume change receiver slot.
2029     void MainForm::volumeChanged ( int iVolume )
2030     {
2031     #ifdef CONFIG_VOLUME
2032    
2033     if (m_iVolumeChanging > 0)
2034     return;
2035    
2036     m_iVolumeChanging++;
2037    
2038     // Update the toolbar widgets...
2039     if (m_pVolumeSlider->value() != iVolume)
2040     m_pVolumeSlider->setValue(iVolume);
2041     if (m_pVolumeSpinBox->value() != iVolume)
2042     m_pVolumeSpinBox->setValue(iVolume);
2043    
2044     // Do it as commanded...
2045     float fVolume = 0.01f * float(iVolume);
2046     if (::lscp_set_volume(m_pClient, fVolume) == LSCP_OK)
2047     appendMessages(QObject::tr("Volume: %1.").arg(fVolume));
2048     else
2049     appendMessagesClient("lscp_set_volume");
2050    
2051     m_iVolumeChanging--;
2052    
2053     m_iDirtyCount++;
2054     stabilizeForm();
2055    
2056     #endif
2057     }
2058    
2059    
2060     // Channel change receiver slot.
2061     void MainForm::channelStripChanged(ChannelStrip* pChannelStrip)
2062     {
2063     // Add this strip to the changed list...
2064 capela 1499 if (!m_changedStrips.contains(pChannelStrip)) {
2065 schoenebeck 1461 m_changedStrips.append(pChannelStrip);
2066     pChannelStrip->resetErrorCount();
2067     }
2068    
2069 capela 1509 // Just mark the dirty form.
2070     m_iDirtyCount++;
2071     // and update the form status...
2072     stabilizeForm();
2073 schoenebeck 1461 }
2074    
2075    
2076     // Grab and restore current sampler channels session.
2077     void MainForm::updateSession (void)
2078     {
2079     #ifdef CONFIG_VOLUME
2080     int iVolume = ::lroundf(100.0f * ::lscp_get_volume(m_pClient));
2081     m_iVolumeChanging++;
2082     m_pVolumeSlider->setValue(iVolume);
2083     m_pVolumeSpinBox->setValue(iVolume);
2084     m_iVolumeChanging--;
2085     #endif
2086     #ifdef CONFIG_MIDI_INSTRUMENT
2087     // FIXME: Make some room for default instrument maps...
2088     int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
2089     if (iMaps < 0)
2090     appendMessagesClient("lscp_get_midi_instrument_maps");
2091     else if (iMaps < 1) {
2092 capela 1499 ::lscp_add_midi_instrument_map(m_pClient,
2093     tr("Chromatic").toUtf8().constData());
2094     ::lscp_add_midi_instrument_map(m_pClient,
2095     tr("Drum Kits").toUtf8().constData());
2096 schoenebeck 1461 }
2097     #endif
2098    
2099 schoenebeck 1702 updateAllChannelStrips(false);
2100    
2101     // Do we auto-arrange?
2102     if (m_pOptions && m_pOptions->bAutoArrange)
2103     channelsArrange();
2104    
2105     // Remember to refresh devices and instruments...
2106     if (m_pInstrumentListForm)
2107     m_pInstrumentListForm->refreshInstruments();
2108     if (m_pDeviceForm)
2109     m_pDeviceForm->refreshDevices();
2110     }
2111    
2112     void MainForm::updateAllChannelStrips(bool bRemoveDeadStrips) {
2113 schoenebeck 1461 // Retrieve the current channel list.
2114     int *piChannelIDs = ::lscp_list_channels(m_pClient);
2115     if (piChannelIDs == NULL) {
2116     if (::lscp_client_get_errno(m_pClient)) {
2117     appendMessagesClient("lscp_list_channels");
2118 capela 1509 appendMessagesError(
2119     tr("Could not get current list of channels.\n\nSorry."));
2120 schoenebeck 1461 }
2121     } else {
2122     // Try to (re)create each channel.
2123     m_pWorkspace->setUpdatesEnabled(false);
2124     for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
2125     // Check if theres already a channel strip for this one...
2126     if (!channelStrip(piChannelIDs[iChannel]))
2127 capela 1558 createChannelStrip(new Channel(piChannelIDs[iChannel]));
2128 schoenebeck 1461 }
2129 schoenebeck 1702
2130     // Do we auto-arrange?
2131     if (m_pOptions && m_pOptions->bAutoArrange)
2132     channelsArrange();
2133    
2134     stabilizeForm();
2135    
2136     // remove dead channel strips
2137     if (bRemoveDeadStrips) {
2138     for (int i = 0; channelStripAt(i); ++i) {
2139     ChannelStrip* pChannelStrip = channelStripAt(i);
2140     bool bExists = false;
2141     for (int j = 0; piChannelIDs[j] >= 0; ++j) {
2142     if (!pChannelStrip->channel()) break;
2143     if (piChannelIDs[j] == pChannelStrip->channel()->channelID()) {
2144     // strip exists, don't touch it
2145     bExists = true;
2146     break;
2147     }
2148     }
2149     if (!bExists) destroyChannelStrip(pChannelStrip);
2150     }
2151     }
2152 schoenebeck 1461 m_pWorkspace->setUpdatesEnabled(true);
2153     }
2154     }
2155    
2156     // Update the recent files list and menu.
2157     void MainForm::updateRecentFiles ( const QString& sFilename )
2158     {
2159 capela 1509 if (m_pOptions == NULL)
2160     return;
2161 schoenebeck 1461
2162 capela 1509 // Remove from list if already there (avoid duplicates)
2163     int iIndex = m_pOptions->recentFiles.indexOf(sFilename);
2164     if (iIndex >= 0)
2165     m_pOptions->recentFiles.removeAt(iIndex);
2166     // Put it to front...
2167     m_pOptions->recentFiles.push_front(sFilename);
2168 schoenebeck 1461 }
2169    
2170    
2171     // Update the recent files list and menu.
2172     void MainForm::updateRecentFilesMenu (void)
2173     {
2174 capela 1499 if (m_pOptions == NULL)
2175     return;
2176 schoenebeck 1461
2177 capela 1499 // Time to keep the list under limits.
2178     int iRecentFiles = m_pOptions->recentFiles.count();
2179     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
2180     m_pOptions->recentFiles.pop_back();
2181     iRecentFiles--;
2182     }
2183 schoenebeck 1461
2184 capela 1499 // Rebuild the recent files menu...
2185 capela 1509 m_ui.fileOpenRecentMenu->clear();
2186 capela 1499 for (int i = 0; i < iRecentFiles; i++) {
2187     const QString& sFilename = m_pOptions->recentFiles[i];
2188     if (QFileInfo(sFilename).exists()) {
2189 capela 1509 QAction *pAction = m_ui.fileOpenRecentMenu->addAction(
2190 capela 1499 QString("&%1 %2").arg(i + 1).arg(sessionName(sFilename)),
2191     this, SLOT(fileOpenRecent()));
2192     pAction->setData(i);
2193     }
2194     }
2195 schoenebeck 1461 }
2196    
2197    
2198     // Force update of the channels instrument names mode.
2199     void MainForm::updateInstrumentNames (void)
2200     {
2201 capela 1509 // Full channel list update...
2202     QWidgetList wlist = m_pWorkspace->windowList();
2203     if (wlist.isEmpty())
2204     return;
2205 schoenebeck 1461
2206 capela 1509 m_pWorkspace->setUpdatesEnabled(false);
2207     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2208     ChannelStrip *pChannelStrip = (ChannelStrip *) wlist.at(iChannel);
2209     if (pChannelStrip)
2210     pChannelStrip->updateInstrumentName(true);
2211     }
2212     m_pWorkspace->setUpdatesEnabled(true);
2213 schoenebeck 1461 }
2214    
2215    
2216     // Force update of the channels display font.
2217     void MainForm::updateDisplayFont (void)
2218     {
2219 capela 1509 if (m_pOptions == NULL)
2220     return;
2221 schoenebeck 1461
2222 capela 1509 // Check if display font is legal.
2223     if (m_pOptions->sDisplayFont.isEmpty())
2224     return;
2225     // Realize it.
2226     QFont font;
2227     if (!font.fromString(m_pOptions->sDisplayFont))
2228     return;
2229 schoenebeck 1461
2230 capela 1509 // Full channel list update...
2231     QWidgetList wlist = m_pWorkspace->windowList();
2232     if (wlist.isEmpty())
2233     return;
2234 schoenebeck 1461
2235 capela 1509 m_pWorkspace->setUpdatesEnabled(false);
2236     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2237     ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2238     if (pChannelStrip)
2239     pChannelStrip->setDisplayFont(font);
2240     }
2241     m_pWorkspace->setUpdatesEnabled(true);
2242 schoenebeck 1461 }
2243    
2244    
2245     // Update channel strips background effect.
2246     void MainForm::updateDisplayEffect (void)
2247     {
2248 capela 1509 // Full channel list update...
2249     QWidgetList wlist = m_pWorkspace->windowList();
2250     if (wlist.isEmpty())
2251     return;
2252 schoenebeck 1461
2253 capela 1509 m_pWorkspace->setUpdatesEnabled(false);
2254     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2255     ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2256 capela 1499 if (pChannelStrip)
2257     pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2258 capela 1509 }
2259     m_pWorkspace->setUpdatesEnabled(true);
2260 schoenebeck 1461 }
2261    
2262    
2263     // Force update of the channels maximum volume setting.
2264     void MainForm::updateMaxVolume (void)
2265     {
2266 capela 1509 if (m_pOptions == NULL)
2267     return;
2268 schoenebeck 1461
2269     #ifdef CONFIG_VOLUME
2270     m_iVolumeChanging++;
2271 capela 1499 m_pVolumeSlider->setMaximum(m_pOptions->iMaxVolume);
2272     m_pVolumeSpinBox->setMaximum(m_pOptions->iMaxVolume);
2273 schoenebeck 1461 m_iVolumeChanging--;
2274     #endif
2275    
2276 capela 1509 // Full channel list update...
2277     QWidgetList wlist = m_pWorkspace->windowList();
2278     if (wlist.isEmpty())
2279     return;
2280 schoenebeck 1461
2281 capela 1509 m_pWorkspace->setUpdatesEnabled(false);
2282     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2283     ChannelStrip* pChannelStrip = (ChannelStrip*) wlist.at(iChannel);
2284     if (pChannelStrip)
2285     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2286     }
2287     m_pWorkspace->setUpdatesEnabled(true);
2288 schoenebeck 1461 }
2289    
2290    
2291     //-------------------------------------------------------------------------
2292     // qsamplerMainForm -- Messages window form handlers.
2293    
2294     // Messages output methods.
2295     void MainForm::appendMessages( const QString& s )
2296     {
2297 capela 1509 if (m_pMessages)
2298     m_pMessages->appendMessages(s);
2299 schoenebeck 1461
2300 capela 1509 statusBar()->showMessage(s, 3000);
2301 schoenebeck 1461 }
2302    
2303     void MainForm::appendMessagesColor( const QString& s, const QString& c )
2304     {
2305 capela 1509 if (m_pMessages)
2306     m_pMessages->appendMessagesColor(s, c);
2307 schoenebeck 1461
2308 capela 1509 statusBar()->showMessage(s, 3000);
2309 schoenebeck 1461 }
2310    
2311     void MainForm::appendMessagesText( const QString& s )
2312     {
2313 capela 1509 if (m_pMessages)
2314     m_pMessages->appendMessagesText(s);
2315 schoenebeck 1461 }
2316    
2317     void MainForm::appendMessagesError( const QString& s )
2318     {
2319 capela 1509 if (m_pMessages)
2320     m_pMessages->show();
2321 schoenebeck 1461
2322 capela 1509 appendMessagesColor(s.simplified(), "#ff0000");
2323 schoenebeck 1461
2324     // Make it look responsive...:)
2325 capela 1499 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2326 schoenebeck 1461
2327 capela 1509 QMessageBox::critical(this,
2328 capela 1840 QSAMPLER_TITLE ": " + tr("Error"), s, QMessageBox::Cancel);
2329 schoenebeck 1461 }
2330    
2331    
2332     // This is a special message format, just for client results.
2333     void MainForm::appendMessagesClient( const QString& s )
2334     {
2335 capela 1509 if (m_pClient == NULL)
2336     return;
2337 schoenebeck 1461
2338 capela 1509 appendMessagesColor(s + QString(": %1 (errno=%2)")
2339     .arg(::lscp_client_get_result(m_pClient))
2340     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
2341 schoenebeck 1461
2342     // Make it look responsive...:)
2343 capela 1499 QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2344 schoenebeck 1461 }
2345    
2346    
2347     // Force update of the messages font.
2348     void MainForm::updateMessagesFont (void)
2349     {
2350 capela 1509 if (m_pOptions == NULL)
2351     return;
2352 schoenebeck 1461
2353 capela 1509 if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
2354     QFont font;
2355     if (font.fromString(m_pOptions->sMessagesFont))
2356     m_pMessages->setMessagesFont(font);
2357     }
2358 schoenebeck 1461 }
2359    
2360    
2361     // Update messages window line limit.
2362     void MainForm::updateMessagesLimit (void)
2363     {
2364 capela 1509 if (m_pOptions == NULL)
2365     return;
2366 schoenebeck 1461
2367 capela 1509 if (m_pMessages) {
2368     if (m_pOptions->bMessagesLimit)
2369     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
2370     else
2371     m_pMessages->setMessagesLimit(-1);
2372     }
2373 schoenebeck 1461 }
2374    
2375    
2376     // Enablement of the messages capture feature.
2377     void MainForm::updateMessagesCapture (void)
2378     {
2379 capela 1509 if (m_pOptions == NULL)
2380     return;
2381 schoenebeck 1461
2382 capela 1509 if (m_pMessages)
2383     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
2384 schoenebeck 1461 }
2385    
2386    
2387     //-------------------------------------------------------------------------
2388     // qsamplerMainForm -- MDI channel strip management.
2389    
2390     // The channel strip creation executive.
2391 capela 1558 ChannelStrip* MainForm::createChannelStrip ( Channel *pChannel )
2392 schoenebeck 1461 {
2393 capela 1509 if (m_pClient == NULL || pChannel == NULL)
2394     return NULL;
2395 schoenebeck 1461
2396 capela 1509 // Add a new channel itema...
2397 capela 1515 ChannelStrip *pChannelStrip = new ChannelStrip();
2398 capela 1509 if (pChannelStrip == NULL)
2399     return NULL;
2400 schoenebeck 1461
2401 capela 1515 // Set some initial channel strip options...
2402 capela 1509 if (m_pOptions) {
2403     // Background display effect...
2404     pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
2405     // We'll need a display font.
2406     QFont font;
2407     if (font.fromString(m_pOptions->sDisplayFont))
2408     pChannelStrip->setDisplayFont(font);
2409     // Maximum allowed volume setting.
2410     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
2411     }
2412 schoenebeck 1461
2413 capela 1515 // Add it to workspace...
2414     m_pWorkspace->addWindow(pChannelStrip, Qt::FramelessWindowHint);
2415    
2416     // Actual channel strip setup...
2417     pChannelStrip->setup(pChannel);
2418    
2419     QObject::connect(pChannelStrip,
2420     SIGNAL(channelChanged(ChannelStrip*)),
2421     SLOT(channelStripChanged(ChannelStrip*)));
2422    
2423 capela 1509 // Now we show up us to the world.
2424     pChannelStrip->show();
2425 schoenebeck 1461
2426     // This is pretty new, so we'll watch for it closely.
2427     channelStripChanged(pChannelStrip);
2428    
2429 capela 1509 // Return our successful reference...
2430     return pChannelStrip;
2431 schoenebeck 1461 }
2432    
2433 schoenebeck 1702 void MainForm::destroyChannelStrip(ChannelStrip* pChannelStrip) {
2434     // Just delete the channel strip.
2435     delete pChannelStrip;
2436 schoenebeck 1461
2437 schoenebeck 1702 // Do we auto-arrange?
2438     if (m_pOptions && m_pOptions->bAutoArrange)
2439     channelsArrange();
2440    
2441     stabilizeForm();
2442     }
2443    
2444 schoenebeck 1461 // Retrieve the active channel strip.
2445     ChannelStrip* MainForm::activeChannelStrip (void)
2446     {
2447 capela 1509 return static_cast<ChannelStrip *> (m_pWorkspace->activeWindow());
2448 schoenebeck 1461 }
2449    
2450    
2451     // Retrieve a channel strip by index.
2452     ChannelStrip* MainForm::channelStripAt ( int iChannel )
2453     {
2454 schoenebeck 1702 if (!m_pWorkspace) return NULL;
2455    
2456 capela 1509 QWidgetList wlist = m_pWorkspace->windowList();
2457     if (wlist.isEmpty())
2458     return NULL;
2459 schoenebeck 1461
2460 schoenebeck 1702 if (iChannel < 0 || iChannel >= wlist.size())
2461     return NULL;
2462    
2463     return dynamic_cast<ChannelStrip *> (wlist.at(iChannel));
2464 schoenebeck 1461 }
2465    
2466    
2467     // Retrieve a channel strip by sampler channel id.
2468     ChannelStrip* MainForm::channelStrip ( int iChannelID )
2469     {
2470     QWidgetList wlist = m_pWorkspace->windowList();
2471     if (wlist.isEmpty())
2472     return NULL;
2473    
2474     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2475 capela 1499 ChannelStrip* pChannelStrip
2476     = static_cast<ChannelStrip*> (wlist.at(iChannel));
2477 schoenebeck 1461 if (pChannelStrip) {
2478 capela 1558 Channel *pChannel = pChannelStrip->channel();
2479 schoenebeck 1461 if (pChannel && pChannel->channelID() == iChannelID)
2480     return pChannelStrip;
2481     }
2482     }
2483    
2484     // Not found.
2485     return NULL;
2486     }
2487    
2488    
2489     // Construct the windows menu.
2490     void MainForm::channelsMenuAboutToShow (void)
2491     {
2492 capela 1509 m_ui.channelsMenu->clear();
2493     m_ui.channelsMenu->addAction(m_ui.channelsArrangeAction);
2494     m_ui.channelsMenu->addAction(m_ui.channelsAutoArrangeAction);
2495 schoenebeck 1461
2496 capela 1509 QWidgetList wlist = m_pWorkspace->windowList();
2497     if (!wlist.isEmpty()) {
2498     m_ui.channelsMenu->addSeparator();
2499     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2500 capela 1499 ChannelStrip* pChannelStrip
2501     = static_cast<ChannelStrip*> (wlist.at(iChannel));
2502     if (pChannelStrip) {
2503 capela 1509 QAction *pAction = m_ui.channelsMenu->addAction(
2504     pChannelStrip->windowTitle(),
2505     this, SLOT(channelsMenuActivated()));
2506 capela 1507 pAction->setCheckable(true);
2507     pAction->setChecked(activeChannelStrip() == pChannelStrip);
2508 capela 1499 pAction->setData(iChannel);
2509     }
2510 capela 1509 }
2511     }
2512 schoenebeck 1461 }
2513    
2514    
2515     // Windows menu activation slot
2516 capela 1499 void MainForm::channelsMenuActivated (void)
2517 schoenebeck 1461 {
2518 capela 1499 // Retrive channel index from action data...
2519     QAction *pAction = qobject_cast<QAction *> (sender());
2520     if (pAction == NULL)
2521     return;
2522    
2523     ChannelStrip* pChannelStrip = channelStripAt(pAction->data().toInt());
2524     if (pChannelStrip) {
2525     pChannelStrip->showNormal();
2526     pChannelStrip->setFocus();
2527     }
2528 schoenebeck 1461 }
2529    
2530    
2531     //-------------------------------------------------------------------------
2532     // qsamplerMainForm -- Timer stuff.
2533    
2534     // Set the pseudo-timer delay schedule.
2535     void MainForm::startSchedule ( int iStartDelay )
2536     {
2537 capela 1509 m_iStartDelay = 1 + (iStartDelay * 1000);
2538     m_iTimerDelay = 0;
2539 schoenebeck 1461 }
2540    
2541     // Suspend the pseudo-timer delay schedule.
2542     void MainForm::stopSchedule (void)
2543     {
2544 capela 1509 m_iStartDelay = 0;
2545     m_iTimerDelay = 0;
2546 schoenebeck 1461 }
2547    
2548     // Timer slot funtion.
2549     void MainForm::timerSlot (void)
2550     {
2551 capela 1509 if (m_pOptions == NULL)
2552     return;
2553 schoenebeck 1461
2554 capela 1509 // Is it the first shot on server start after a few delay?
2555     if (m_iTimerDelay < m_iStartDelay) {
2556     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2557     if (m_iTimerDelay >= m_iStartDelay) {
2558     // If we cannot start it now, maybe a lil'mo'later ;)
2559     if (!startClient()) {
2560     m_iStartDelay += m_iTimerDelay;
2561     m_iTimerDelay = 0;
2562     }
2563     }
2564     }
2565 schoenebeck 1461
2566     if (m_pClient) {
2567     // Update the channel information for each pending strip...
2568 capela 1499 QListIterator<ChannelStrip *> iter(m_changedStrips);
2569     while (iter.hasNext()) {
2570     ChannelStrip *pChannelStrip = iter.next();
2571     // If successfull, remove from pending list...
2572     if (pChannelStrip->updateChannelInfo()) {
2573     int iChannelStrip = m_changedStrips.indexOf(pChannelStrip);
2574     if (iChannelStrip >= 0)
2575     m_changedStrips.removeAt(iChannelStrip);
2576 schoenebeck 1461 }
2577     }
2578     // Refresh each channel usage, on each period...
2579     if (m_pOptions->bAutoRefresh) {
2580     m_iTimerSlot += QSAMPLER_TIMER_MSECS;
2581     if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
2582     m_iTimerSlot = 0;
2583     // Update the channel stream usage for each strip...
2584     QWidgetList wlist = m_pWorkspace->windowList();
2585     for (int iChannel = 0;
2586     iChannel < (int) wlist.count(); iChannel++) {
2587     ChannelStrip* pChannelStrip
2588     = (ChannelStrip*) wlist.at(iChannel);
2589     if (pChannelStrip && pChannelStrip->isVisible())
2590     pChannelStrip->updateChannelUsage();
2591     }
2592     }
2593     }
2594     }
2595    
2596 capela 1509 // Register the next timer slot.
2597     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2598 schoenebeck 1461 }
2599    
2600    
2601     //-------------------------------------------------------------------------
2602     // qsamplerMainForm -- Server stuff.
2603    
2604     // Start linuxsampler server...
2605     void MainForm::startServer (void)
2606     {
2607 capela 1509 if (m_pOptions == NULL)
2608     return;
2609 schoenebeck 1461
2610 capela 1509 // Aren't already a client, are we?
2611     if (!m_pOptions->bServerStart || m_pClient)
2612     return;
2613 schoenebeck 1461
2614 capela 1509 // Is the server process instance still here?
2615     if (m_pServer) {
2616 capela 1840 if (QMessageBox::warning(this,
2617 schoenebeck 1461 QSAMPLER_TITLE ": " + tr("Warning"),
2618 capela 1509 tr("Could not start the LinuxSampler server.\n\n"
2619 schoenebeck 1626 "Maybe it is already started."),
2620 capela 1840 QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) {
2621 capela 1509 m_pServer->terminate();
2622     m_pServer->kill();
2623     }
2624     return;
2625     }
2626 schoenebeck 1461
2627 capela 1509 // Reset our timer counters...
2628     stopSchedule();
2629 schoenebeck 1461
2630 capela 1509 // Verify we have something to start with...
2631     if (m_pOptions->sServerCmdLine.isEmpty())
2632     return;
2633 schoenebeck 1461
2634 capela 1509 // OK. Let's build the startup process...
2635 schoenebeck 1626 m_pServer = new QProcess();
2636     bForceServerStop = true;
2637 capela 1509
2638     // Setup stdout/stderr capture...
2639     // if (m_pOptions->bStdoutCapture) {
2640 capela 1559 #if QT_VERSION >= 0x040200
2641     m_pServer->setProcessChannelMode(QProcess::ForwardedChannels);
2642     #endif
2643 schoenebeck 1461 QObject::connect(m_pServer,
2644 schoenebeck 1470 SIGNAL(readyReadStandardOutput()),
2645 schoenebeck 1461 SLOT(readServerStdout()));
2646     QObject::connect(m_pServer,
2647 schoenebeck 1470 SIGNAL(readyReadStandardError()),
2648 schoenebeck 1461 SLOT(readServerStdout()));
2649 capela 1509 // }
2650    
2651 schoenebeck 1461 // The unforgiveable signal communication...
2652     QObject::connect(m_pServer,
2653 capela 1559 SIGNAL(finished(int, QProcess::ExitStatus)),
2654 schoenebeck 1461 SLOT(processServerExit()));
2655    
2656 capela 1509 // Build process arguments...
2657     QStringList args = m_pOptions->sServerCmdLine.split(' ');
2658     QString sCommand = args[0];
2659     args.removeAt(0);
2660 schoenebeck 1461
2661 capela 1509 appendMessages(tr("Server is starting..."));
2662     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2663 schoenebeck 1461
2664 capela 1509 // Go linuxsampler, go...
2665     m_pServer->start(sCommand, args);
2666     if (!m_pServer->waitForStarted()) {
2667     appendMessagesError(tr("Could not start server.\n\nSorry."));
2668     processServerExit();
2669     return;
2670     }
2671 schoenebeck 1461
2672 capela 1509 // Show startup results...
2673     appendMessages(
2674     tr("Server was started with PID=%1.").arg((long) m_pServer->pid()));
2675 schoenebeck 1461
2676 capela 1509 // Reset (yet again) the timer counters,
2677     // but this time is deferred as the user opted.
2678     startSchedule(m_pOptions->iStartDelay);
2679     stabilizeForm();
2680 schoenebeck 1461 }
2681    
2682    
2683     // Stop linuxsampler server...
2684 schoenebeck 1626 void MainForm::stopServer (bool bInteractive)
2685 schoenebeck 1461 {
2686 capela 1509 // Stop client code.
2687     stopClient();
2688 schoenebeck 1461
2689 schoenebeck 1626 if (m_pServer && bInteractive) {
2690     if (QMessageBox::question(this,
2691     QSAMPLER_TITLE ": " + tr("The backend's fate ..."),
2692     tr("You have the option to keep the sampler backend (LinuxSampler)\n"
2693     "running in the background. The sampler would continue to work\n"
2694     "according to your current sampler session and you could alter the\n"
2695     "sampler session at any time by relaunching QSampler.\n\n"
2696 capela 1890 "Do you want LinuxSampler to stop?"),
2697 capela 1840 QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)
2698 schoenebeck 1626 {
2699     bForceServerStop = false;
2700     }
2701     }
2702    
2703 capela 1509 // And try to stop server.
2704 schoenebeck 1626 if (m_pServer && bForceServerStop) {
2705 capela 1509 appendMessages(tr("Server is stopping..."));
2706 capela 1559 if (m_pServer->state() == QProcess::Running) {
2707     #if defined(WIN32)
2708     // Try harder...
2709     m_pServer->kill();
2710     #else
2711     // Try softly...
2712 capela 1509 m_pServer->terminate();
2713 capela 1559 #endif
2714     }
2715     } // Do final processing anyway.
2716     else processServerExit();
2717 schoenebeck 1461
2718 capela 1509 // Give it some time to terminate gracefully and stabilize...
2719     QTime t;
2720     t.start();
2721     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2722     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2723 schoenebeck 1461 }
2724    
2725    
2726     // Stdout handler...
2727     void MainForm::readServerStdout (void)
2728     {
2729 capela 1509 if (m_pMessages)
2730     m_pMessages->appendStdoutBuffer(m_pServer->readAllStandardOutput());
2731 schoenebeck 1461 }
2732    
2733    
2734     // Linuxsampler server cleanup.
2735     void MainForm::processServerExit (void)
2736     {
2737 capela 1509 // Force client code cleanup.
2738     stopClient();
2739 schoenebeck 1461
2740 capela 1509 // Flush anything that maybe pending...
2741     if (m_pMessages)
2742     m_pMessages->flushStdoutBuffer();
2743 schoenebeck 1461
2744 schoenebeck 1626 if (m_pServer && bForceServerStop) {
2745 capela 1559 if (m_pServer->state() != QProcess::NotRunning) {
2746     appendMessages(tr("Server is being forced..."));
2747     // Force final server shutdown...
2748     m_pServer->kill();
2749     // Give it some time to terminate gracefully and stabilize...
2750     QTime t;
2751     t.start();
2752     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2753     QApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
2754     }
2755 capela 1509 // Force final server shutdown...
2756     appendMessages(
2757     tr("Server was stopped with exit status %1.")
2758     .arg(m_pServer->exitStatus()));
2759     delete m_pServer;
2760     m_pServer = NULL;
2761     }
2762 schoenebeck 1461
2763 capela 1509 // Again, make status visible stable.
2764     stabilizeForm();
2765 schoenebeck 1461 }
2766    
2767    
2768     //-------------------------------------------------------------------------
2769     // qsamplerMainForm -- Client stuff.
2770    
2771     // The LSCP client callback procedure.
2772 capela 1509 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/,
2773     lscp_event_t event, const char *pchData, int cchData, void *pvData )
2774 schoenebeck 1461 {
2775 capela 1509 MainForm* pMainForm = (MainForm *) pvData;
2776     if (pMainForm == NULL)
2777     return LSCP_FAILED;
2778 schoenebeck 1461
2779 capela 1509 // ATTN: DO NOT EVER call any GUI code here,
2780     // as this is run under some other thread context.
2781     // A custom event must be posted here...
2782     QApplication::postEvent(pMainForm,
2783 capela 2050 new LscpEvent(event, pchData, cchData));
2784 schoenebeck 1461
2785 capela 1509 return LSCP_OK;
2786 schoenebeck 1461 }
2787    
2788    
2789     // Start our almighty client...
2790     bool MainForm::startClient (void)
2791     {
2792 capela 1509 // Have it a setup?
2793     if (m_pOptions == NULL)
2794     return false;
2795 schoenebeck 1461
2796 capela 1509 // Aren't we already started, are we?
2797     if (m_pClient)
2798     return true;
2799 schoenebeck 1461
2800 capela 1509 // Log prepare here.
2801     appendMessages(tr("Client connecting..."));
2802 schoenebeck 1461
2803 capela 1509 // Create the client handle...
2804 capela 1499 m_pClient = ::lscp_client_create(
2805     m_pOptions->sServerHost.toUtf8().constData(),
2806     m_pOptions->iServerPort, qsampler_client_callback, this);
2807 capela 1509 if (m_pClient == NULL) {
2808     // Is this the first try?
2809     // maybe we need to start a local server...
2810     if ((m_pServer && m_pServer->state() == QProcess::Running)
2811     || !m_pOptions->bServerStart) {
2812     appendMessagesError(
2813     tr("Could not connect to server as client.\n\nSorry."));
2814     } else {
2815     startServer();
2816     }
2817     // This is always a failure.
2818     stabilizeForm();
2819     return false;
2820     }
2821     // Just set receive timeout value, blindly.
2822     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
2823     appendMessages(
2824     tr("Client receive timeout is set to %1 msec.")
2825     .arg(::lscp_client_get_timeout(m_pClient)));
2826 schoenebeck 1461
2827     // Subscribe to channel info change notifications...
2828 schoenebeck 1702 if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT) != LSCP_OK)
2829     appendMessagesClient("lscp_client_subscribe(CHANNEL_COUNT)");
2830 schoenebeck 1461 if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
2831 schoenebeck 1691 appendMessagesClient("lscp_client_subscribe(CHANNEL_INFO)");
2832 schoenebeck 1461
2833 schoenebeck 1698 DeviceStatusForm::onDevicesChanged(); // initialize
2834     updateViewMidiDeviceStatusMenu();
2835     if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT) != LSCP_OK)
2836     appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_COUNT)");
2837 schoenebeck 1699 if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO) != LSCP_OK)
2838     appendMessagesClient("lscp_client_subscribe(MIDI_INPUT_DEVICE_INFO)");
2839 schoenebeck 1702 if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT) != LSCP_OK)
2840     appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_COUNT)");
2841     if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO) != LSCP_OK)
2842     appendMessagesClient("lscp_client_subscribe(AUDIO_OUTPUT_DEVICE_INFO)");
2843 schoenebeck 1698
2844 capela 1704 #if CONFIG_EVENT_CHANNEL_MIDI
2845 schoenebeck 1691 // Subscribe to channel MIDI data notifications...
2846     if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI) != LSCP_OK)
2847     appendMessagesClient("lscp_client_subscribe(CHANNEL_MIDI)");
2848     #endif
2849    
2850 capela 1704 #if CONFIG_EVENT_DEVICE_MIDI
2851 schoenebeck 1698 // Subscribe to channel MIDI data notifications...
2852     if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI) != LSCP_OK)
2853     appendMessagesClient("lscp_client_subscribe(DEVICE_MIDI)");
2854     #endif
2855    
2856 capela 1509 // We may stop scheduling around.
2857     stopSchedule();
2858 schoenebeck 1461
2859 capela 1509 // We'll accept drops from now on...
2860     setAcceptDrops(true);
2861 schoenebeck 1461
2862 capela 1509 // Log success here.
2863     appendMessages(tr("Client connected."));
2864 schoenebeck 1461
2865     // Hard-notify instrumnet and device configuration forms,
2866     // if visible, that we're ready...
2867     if (m_pInstrumentListForm)
2868 capela 1509 m_pInstrumentListForm->refreshInstruments();
2869 schoenebeck 1461 if (m_pDeviceForm)
2870 capela 1509 m_pDeviceForm->refreshDevices();
2871 schoenebeck 1461
2872 capela 1509 // Is any session pending to be loaded?
2873     if (!m_pOptions->sSessionFile.isEmpty()) {
2874     // Just load the prabably startup session...
2875     if (loadSessionFile(m_pOptions->sSessionFile)) {
2876     m_pOptions->sSessionFile = QString::null;
2877     return true;
2878     }
2879     }
2880 schoenebeck 1461
2881 schoenebeck 1803 // send the current / loaded fine tuning settings to the sampler
2882     m_pOptions->sendFineTuningSettings();
2883    
2884 capela 1509 // Make a new session
2885     return newSession();
2886 schoenebeck 1461 }
2887    
2888    
2889     // Stop client...
2890     void MainForm::stopClient (void)
2891     {
2892 capela 1509 if (m_pClient == NULL)
2893     return;
2894 schoenebeck 1461
2895 capela 1509 // Log prepare here.
2896     appendMessages(tr("Client disconnecting..."));
2897 schoenebeck 1461
2898 capela 1509 // Clear timer counters...
2899     stopSchedule();
2900 schoenebeck 1461
2901 capela 1509 // We'll reject drops from now on...
2902     setAcceptDrops(false);
2903 schoenebeck 1461
2904 capela 1509 // Force any channel strips around, but
2905     // but avoid removing the corresponding
2906     // channels from the back-end server.
2907     m_iDirtyCount = 0;
2908     closeSession(false);
2909 schoenebeck 1461
2910 capela 1509 // Close us as a client...
2911 capela 1704 #if CONFIG_EVENT_DEVICE_MIDI
2912 schoenebeck 1698 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_DEVICE_MIDI);
2913     #endif
2914 capela 1704 #if CONFIG_EVENT_CHANNEL_MIDI
2915 schoenebeck 1691 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_MIDI);
2916     #endif
2917 schoenebeck 1702 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_INFO);
2918     ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_AUDIO_OUTPUT_DEVICE_COUNT);
2919 schoenebeck 1699 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_INFO);
2920 schoenebeck 1698 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_MIDI_INPUT_DEVICE_COUNT);
2921 schoenebeck 1461 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
2922 schoenebeck 1702 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_COUNT);
2923 capela 1509 ::lscp_client_destroy(m_pClient);
2924     m_pClient = NULL;
2925 schoenebeck 1461
2926     // Hard-notify instrumnet and device configuration forms,
2927     // if visible, that we're running out...
2928     if (m_pInstrumentListForm)
2929 capela 1509 m_pInstrumentListForm->refreshInstruments();
2930 schoenebeck 1461 if (m_pDeviceForm)
2931 capela 1509 m_pDeviceForm->refreshDevices();
2932 schoenebeck 1461
2933 capela 1509 // Log final here.
2934     appendMessages(tr("Client disconnected."));
2935 schoenebeck 1461
2936 capela 1509 // Make visible status.
2937     stabilizeForm();
2938 schoenebeck 1461 }
2939    
2940 capela 1514
2941     // Channel strip activation/selection.
2942     void MainForm::activateStrip ( QWidget *pWidget )
2943     {
2944     ChannelStrip *pChannelStrip
2945     = static_cast<ChannelStrip *> (pWidget);
2946     if (pChannelStrip)
2947     pChannelStrip->setSelected(true);
2948    
2949     stabilizeForm();
2950     }
2951    
2952    
2953 schoenebeck 1461 } // namespace QSampler
2954 capela 1464
2955    
2956     // end of qsamplerMainForm.cpp

  ViewVC Help
Powered by ViewVC