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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2108 - (hide annotations) (download)
Thu Jul 15 08:03:32 2010 UTC (13 years, 8 months ago) by capela
File size: 82057 byte(s)
* Sampler channel and instrument file requester support for
  other than GIG instrument files (*gig *.dls) has been added,
  now also allowing for SFZ instrument files (*.sfz) loading.

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

  ViewVC Help
Powered by ViewVC