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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1890 - (hide annotations) (download)
Tue Apr 28 09:06:43 2009 UTC (14 years, 11 months ago) by capela
File size: 81047 byte(s)
- Got rid of some Qt3 support remnants: QApplication::argc() and
  QApplication::argv() replaced by QApplication::arguments().

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

  ViewVC Help
Powered by ViewVC