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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1473 - (hide annotations) (download)
Mon Nov 5 19:07:26 2007 UTC (12 years, 3 months ago) by capela
File size: 79187 byte(s)
* Qt4 migration: still far from complete, the .ui files got shaved
  with special regard to some redundant or duplicated signal/slot
  connections and to the options dialog font aesthetics as also
  other minors.

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

  ViewVC Help
Powered by ViewVC