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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2050 - (hide annotations) (download)
Mon Jan 18 08:52:45 2010 UTC (14 years, 2 months ago) by capela
File size: 82004 byte(s)
* LADISH Level 1 support has been added: SIGUSR1 signal trap
  just makes it a shortcut to File/Save.

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

  ViewVC Help
Powered by ViewVC