/[svn]/qsampler/trunk/src/qsamplerMainForm.ui.h
ViewVC logotype

Annotation of /qsampler/trunk/src/qsamplerMainForm.ui.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1372 - (hide annotations) (download) (as text)
Wed Oct 3 11:34:30 2007 UTC (16 years, 7 months ago) by capela
File MIME type: text/x-c++hdr
File size: 77776 byte(s)
* The new channel instrument editor tool is now also accessible
  from the main menu and toolbar.

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

  ViewVC Help
Powered by ViewVC