/[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 469 - (hide annotations) (download) (as text)
Wed Mar 16 17:56:46 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 65391 byte(s)
* Fixed MIDI device mapping on session save.

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

  ViewVC Help
Powered by ViewVC