/[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 470 - (hide annotations) (download) (as text)
Wed Mar 16 22:07:14 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 65755 byte(s)
* Fixed device parameter settings 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     }
602     }
603     // Try to make it snappy :)
604     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
605     }
606    
607     // Ok. we've read it.
608     file.close();
609    
610 capela 395 // Now we'll try to create (update) the whole GUI session.
611     updateSession();
612 capela 109
613 capela 470 // Have we any errors?
614     if (iErrors > 0)
615     appendMessagesError(tr("Session loaded with errors\nfrom \"%1\".\n\nSorry.").arg(sFilename));
616    
617 capela 109 // Save as default session directory.
618     if (m_pOptions)
619     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
620 capela 470 // We're not dirty anymore, if loaded without errors,
621     m_iDirtyCount = iErrors;
622 capela 109 // Stabilize form...
623     m_sFilename = sFilename;
624     updateRecentFiles(sFilename);
625     appendMessages(tr("Open session: \"%1\".").arg(sessionName(m_sFilename)));
626 capela 301
627     // Make that an overall update.
628 capela 109 stabilizeForm();
629     return true;
630     }
631    
632    
633     // Save current session to specific file path.
634     bool qsamplerMainForm::saveSessionFile ( const QString& sFilename )
635     {
636     // Open and write into real file.
637     QFile file(sFilename);
638     if (!file.open(IO_WriteOnly | IO_Truncate)) {
639     appendMessagesError(tr("Could not open \"%1\" session file.\n\nSorry.").arg(sFilename));
640     return false;
641     }
642    
643     // Write the file.
644 capela 455 int iErrors = 0;
645 capela 109 QTextStream ts(&file);
646     ts << "# " << QSAMPLER_TITLE " - " << tr(QSAMPLER_SUBTITLE) << endl;
647     ts << "# " << tr("Version")
648     << ": " QSAMPLER_VERSION << endl;
649     ts << "# " << tr("Build")
650     << ": " __DATE__ " " __TIME__ << endl;
651     ts << "#" << endl;
652     ts << "# " << tr("File")
653     << ": " << QFileInfo(sFilename).fileName() << endl;
654     ts << "# " << tr("Date")
655 capela 455 << ": " << QDate::currentDate().toString("MMM dd yyyy")
656 capela 109 << " " << QTime::currentTime().toString("hh:mm:ss") << endl;
657     ts << "#" << endl;
658     ts << endl;
659 capela 455 // It is assumed that this new kind of device+session file
660     // will be loaded from a complete
661     int *piDeviceIDs;
662     int iDevice;
663     ts << "RESET" << endl;
664     // Audio device mapping.
665     QMap<int, int> audioDeviceMap;
666     piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio);
667     for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
668 capela 463 ts << endl;
669 capela 455 qsamplerDevice device(m_pClient, qsamplerDevice::Audio, piDeviceIDs[iDevice]);
670 capela 463 // Audio device specification...
671 capela 470 ts << "# " << device.deviceTypeName() << " " << device.driverName()
672 capela 455 << " " << tr("Device") << " " << iDevice << endl;
673     ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName();
674 capela 463 qsamplerDeviceParamMap::ConstIterator deviceParam;
675     for (deviceParam = device.params().begin();
676     deviceParam != device.params().end();
677     ++deviceParam) {
678 capela 470 const qsamplerDeviceParam& param = deviceParam.data();
679     if (!param.fix && !param.value.isEmpty())
680     ts << " " << deviceParam.key() << "='" << param.value << "'";
681 capela 463 }
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 capela 470 const qsamplerDeviceParam& param = portParam.data();
693     if (!param.fix && !param.value.isEmpty()) {
694     ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice
695     << " " << iPort << " " << portParam.key()
696     << "='" << param.value << "'" << endl;
697     }
698 capela 463 }
699     }
700 capela 469 // Audio device index/id mapping.
701 capela 455 audioDeviceMap[device.deviceID()] = iDevice;
702     // Try to keep it snappy :)
703     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
704     }
705     // MIDI device mapping.
706     QMap<int, int> midiDeviceMap;
707     piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi);
708     for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) {
709 capela 463 ts << endl;
710 capela 455 qsamplerDevice device(m_pClient, qsamplerDevice::Midi, piDeviceIDs[iDevice]);
711 capela 463 // MIDI device specification...
712 capela 455 ts << "# " << device.deviceTypeName() << " " << device.driverName()
713     << " " << tr("Device") << " " << iDevice << endl;
714     ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName();
715 capela 463 qsamplerDeviceParamMap::ConstIterator deviceParam;
716     for (deviceParam = device.params().begin();
717     deviceParam != device.params().end();
718     ++deviceParam) {
719 capela 470 const qsamplerDeviceParam& param = deviceParam.data();
720     if (!param.fix && !param.value.isEmpty())
721     ts << " " << deviceParam.key() << "='" << param.value << "'";
722 capela 463 }
723 capela 455 ts << endl;
724 capela 463 // MIDI port parameters...
725     int iPort = 0;
726     for (qsamplerDevicePort *pPort = device.ports().first();
727     pPort;
728     pPort = device.ports().next(), ++iPort) {
729     qsamplerDeviceParamMap::ConstIterator portParam;
730     for (portParam = pPort->params().begin();
731     portParam != pPort->params().end();
732     ++portParam) {
733 capela 470 const qsamplerDeviceParam& param = portParam.data();
734     if (!param.fix && !param.value.isEmpty()) {
735     ts << "SET MIDI_INPUT_CHANNEL_PARAMETER " << iDevice
736     << " " << iPort << " " << portParam.key()
737     << "='" << param.value << "'" << endl;
738     }
739 capela 463 }
740     }
741 capela 469 // MIDI device index/id mapping.
742     midiDeviceMap[device.deviceID()] = iDevice;
743     // Try to keep it snappy :)
744     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
745 capela 455 }
746     ts << endl;
747     // Sampler channel mapping.
748 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
749     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
750 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
751     if (pChannelStrip) {
752     qsamplerChannel *pChannel = pChannelStrip->channel();
753     if (pChannel) {
754 capela 455 ts << "# " << tr("Channel") << " " << iChannel << endl;
755 capela 264 ts << "ADD CHANNEL" << endl;
756 capela 455 if (audioDeviceMap.isEmpty()) {
757     ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
758     << " " << pChannel->audioDriver() << endl;
759     } else {
760     ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel
761     << " " << audioDeviceMap[pChannel->audioDevice()] << endl;
762     }
763     if (midiDeviceMap.isEmpty()) {
764     ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel
765     << " " << pChannel->midiDriver() << endl;
766     } else {
767     ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel
768     << " " << midiDeviceMap[pChannel->midiDevice()] << endl;
769     }
770     ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
771     << " " << pChannel->midiPort() << endl;
772 capela 409 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
773 capela 304 if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
774     ts << "ALL";
775     else
776 capela 264 ts << pChannel->midiChannel();
777     ts << endl;
778 capela 409 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;
779     ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannel << endl;
780     ts << "SET CHANNEL VOLUME " << iChannel << " " << pChannel->volume() << endl;
781 capela 264 ts << endl;
782     }
783     }
784 capela 109 // Try to keep it snappy :)
785     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
786     }
787    
788     // Ok. we've wrote it.
789     file.close();
790    
791     // Have we any errors?
792     if (iErrors > 0)
793     appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
794    
795     // Save as default session directory.
796     if (m_pOptions)
797     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
798     // We're not dirty anymore.
799     m_iDirtyCount = 0;
800     // Stabilize form...
801     m_sFilename = sFilename;
802     updateRecentFiles(sFilename);
803     appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
804     stabilizeForm();
805     return true;
806     }
807    
808    
809 capela 433 // Session change receiver slot.
810     void qsamplerMainForm::sessionDirty (void)
811     {
812     // Just mark the dirty form.
813     m_iDirtyCount++;
814     // and update the form status...
815     stabilizeForm();
816     }
817    
818    
819 capela 109 //-------------------------------------------------------------------------
820     // qsamplerMainForm -- File Action slots.
821    
822     // Create a new sampler session.
823     void qsamplerMainForm::fileNew (void)
824     {
825     // Of course we'll start clean new.
826     newSession();
827     }
828    
829    
830     // Open an existing sampler session.
831     void qsamplerMainForm::fileOpen (void)
832     {
833     // Open it right away.
834     openSession();
835     }
836    
837    
838     // Open a recent file session.
839     void qsamplerMainForm::fileOpenRecent ( int iIndex )
840     {
841     // Check if we can safely close the current session...
842     if (m_pOptions && closeSession(true)) {
843     QString sFilename = m_pOptions->recentFiles[iIndex];
844     loadSessionFile(sFilename);
845     }
846     }
847    
848    
849     // Save current sampler session.
850     void qsamplerMainForm::fileSave (void)
851     {
852     // Save it right away.
853     saveSession(false);
854     }
855    
856    
857     // Save current sampler session with another name.
858     void qsamplerMainForm::fileSaveAs (void)
859     {
860     // Save it right away, maybe with another name.
861     saveSession(true);
862     }
863    
864    
865 capela 255 // Reset the sampler instance.
866     void qsamplerMainForm::fileReset (void)
867     {
868     if (m_pClient == NULL)
869     return;
870    
871     // Ask user whether he/she want's an internal sampler reset...
872     if (QMessageBox::warning(this, tr("Warning"),
873     tr("Resetting the sampler instance will close\n"
874     "all device and channel configurations.\n\n"
875     "Please note that this operation may cause\n"
876     "temporary MIDI and Audio disruption\n\n"
877     "Do you want to reset the sampler engine now?"),
878     tr("Reset"), tr("Cancel")) > 0)
879     return;
880    
881     // Just do the reset, after closing down current session...
882 capela 261 if (closeSession(true) && ::lscp_reset_sampler(m_pClient) != LSCP_OK) {
883 capela 255 appendMessagesClient("lscp_reset_sampler");
884 capela 261 appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
885     return;
886     }
887    
888     // Log this.
889     appendMessages(tr("Sampler reset."));
890 capela 395
891     // Make it a new session...
892     newSession();
893 capela 255 }
894    
895    
896 capela 109 // Restart the client/server instance.
897     void qsamplerMainForm::fileRestart (void)
898     {
899     if (m_pOptions == NULL)
900     return;
901    
902     bool bRestart = true;
903    
904     // Ask user whether he/she want's a complete restart...
905     // (if we're currently up and running)
906     if (bRestart && m_pClient) {
907     bRestart = (QMessageBox::warning(this, tr("Warning"),
908     tr("New settings will be effective after\n"
909     "restarting the client/server connection.\n\n"
910     "Please note that this operation may cause\n"
911     "temporary MIDI and Audio disruption\n\n"
912     "Do you want to restart the connection now?"),
913     tr("Restart"), tr("Cancel")) == 0);
914     }
915    
916     // Are we still for it?
917     if (bRestart && closeSession(true)) {
918     // Stop server, it will force the client too.
919     stopServer();
920     // Reschedule a restart...
921     startSchedule(m_pOptions->iStartDelay);
922     }
923     }
924    
925    
926     // Exit application program.
927     void qsamplerMainForm::fileExit (void)
928     {
929     // Go for close the whole thing.
930     close();
931     }
932    
933    
934     //-------------------------------------------------------------------------
935     // qsamplerMainForm -- Edit Action slots.
936    
937     // Add a new sampler channel.
938     void qsamplerMainForm::editAddChannel (void)
939     {
940     if (m_pClient == NULL)
941     return;
942    
943 capela 303 // Just create the channel instance...
944     qsamplerChannel *pChannel = new qsamplerChannel(this);
945     if (pChannel == NULL)
946     return;
947    
948     // Before we show it up, may be we'll
949     // better ask for some initial values?
950     if (!pChannel->channelSetup(this)) {
951     delete pChannel;
952     return;
953     }
954    
955     // And give it to the strip (will own the channel instance, if successful).
956     if (!createChannelStrip(pChannel)) {
957     delete pChannel;
958     return;
959     }
960    
961     // Make that an overall update.
962     m_iDirtyCount++;
963     stabilizeForm();
964 capela 109 }
965    
966    
967     // Remove current sampler channel.
968     void qsamplerMainForm::editRemoveChannel (void)
969     {
970     if (m_pClient == NULL)
971     return;
972    
973 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
974     if (pChannelStrip == NULL)
975     return;
976    
977     qsamplerChannel *pChannel = pChannelStrip->channel();
978 capela 109 if (pChannel == NULL)
979     return;
980    
981     // Prompt user if he/she's sure about this...
982     if (m_pOptions && m_pOptions->bConfirmRemove) {
983     if (QMessageBox::warning(this, tr("Warning"),
984     tr("About to remove channel:\n\n"
985     "%1\n\n"
986     "Are you sure?")
987 capela 264 .arg(pChannelStrip->caption()),
988 capela 109 tr("OK"), tr("Cancel")) > 0)
989     return;
990     }
991    
992     // Remove the existing sampler channel.
993 capela 295 if (!pChannel->removeChannel())
994 capela 109 return;
995    
996     // Just delete the channel strip.
997 capela 265 delete pChannelStrip;
998    
999 capela 109 // Do we auto-arrange?
1000     if (m_pOptions && m_pOptions->bAutoArrange)
1001     channelsArrange();
1002    
1003     // We'll be dirty, for sure...
1004     m_iDirtyCount++;
1005     stabilizeForm();
1006     }
1007    
1008    
1009     // Setup current sampler channel.
1010     void qsamplerMainForm::editSetupChannel (void)
1011     {
1012     if (m_pClient == NULL)
1013     return;
1014    
1015 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1016     if (pChannelStrip == NULL)
1017 capela 109 return;
1018    
1019     // Just invoque the channel strip procedure.
1020 capela 295 pChannelStrip->channelSetup();
1021 capela 109 }
1022    
1023    
1024     // Reset current sampler channel.
1025     void qsamplerMainForm::editResetChannel (void)
1026     {
1027     if (m_pClient == NULL)
1028     return;
1029    
1030 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1031     if (pChannelStrip == NULL)
1032     return;
1033    
1034 capela 400 // Just invoque the channel strip procedure.
1035     pChannelStrip->channelReset();
1036 capela 109 }
1037    
1038    
1039 capela 404 // Reset all sampler channels.
1040     void qsamplerMainForm::editResetAllChannels (void)
1041     {
1042     if (m_pClient == NULL)
1043     return;
1044    
1045     // Invoque the channel strip procedure,
1046     // for all channels out there...
1047     m_pWorkspace->setUpdatesEnabled(false);
1048     QWidgetList wlist = m_pWorkspace->windowList();
1049     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1050     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1051     if (pChannelStrip)
1052     pChannelStrip->channelReset();
1053     }
1054     m_pWorkspace->setUpdatesEnabled(true);
1055     }
1056    
1057    
1058 capela 109 //-------------------------------------------------------------------------
1059     // qsamplerMainForm -- View Action slots.
1060    
1061     // Show/hide the main program window menubar.
1062     void qsamplerMainForm::viewMenubar ( bool bOn )
1063     {
1064     if (bOn)
1065     MenuBar->show();
1066     else
1067     MenuBar->hide();
1068     }
1069    
1070    
1071     // Show/hide the main program window toolbar.
1072     void qsamplerMainForm::viewToolbar ( bool bOn )
1073     {
1074     if (bOn) {
1075     fileToolbar->show();
1076     editToolbar->show();
1077     channelsToolbar->show();
1078     } else {
1079     fileToolbar->hide();
1080     editToolbar->hide();
1081     channelsToolbar->hide();
1082     }
1083     }
1084    
1085    
1086     // Show/hide the main program window statusbar.
1087     void qsamplerMainForm::viewStatusbar ( bool bOn )
1088     {
1089     if (bOn)
1090     statusBar()->show();
1091     else
1092     statusBar()->hide();
1093     }
1094    
1095    
1096     // Show/hide the messages window logger.
1097     void qsamplerMainForm::viewMessages ( bool bOn )
1098     {
1099     if (bOn)
1100     m_pMessages->show();
1101     else
1102     m_pMessages->hide();
1103     }
1104    
1105    
1106 capela 428 // Show/hide the device configurator form.
1107     void qsamplerMainForm::viewDevices (void)
1108     {
1109     if (m_pOptions == NULL)
1110     return;
1111    
1112     if (m_pDeviceForm) {
1113     m_pOptions->saveWidgetGeometry(m_pDeviceForm);
1114     m_pDeviceForm->setClient(m_pClient);
1115     if (m_pDeviceForm->isVisible()) {
1116     m_pDeviceForm->hide();
1117     } else {
1118     m_pDeviceForm->show();
1119     m_pDeviceForm->raise();
1120     m_pDeviceForm->setActiveWindow();
1121     }
1122     }
1123     }
1124    
1125    
1126 capela 109 // Show options dialog.
1127     void qsamplerMainForm::viewOptions (void)
1128     {
1129     if (m_pOptions == NULL)
1130     return;
1131    
1132     qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
1133     if (pOptionsForm) {
1134     // Check out some initial nullities(tm)...
1135 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1136     if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1137     m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1138 capela 109 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1139     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1140     // To track down deferred or immediate changes.
1141     QString sOldServerHost = m_pOptions->sServerHost;
1142     int iOldServerPort = m_pOptions->iServerPort;
1143     int iOldServerTimeout = m_pOptions->iServerTimeout;
1144     bool bOldServerStart = m_pOptions->bServerStart;
1145     QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
1146     QString sOldDisplayFont = m_pOptions->sDisplayFont;
1147 capela 267 bool bOldDisplayEffect = m_pOptions->bDisplayEffect;
1148 capela 119 int iOldMaxVolume = m_pOptions->iMaxVolume;
1149 capela 109 QString sOldMessagesFont = m_pOptions->sMessagesFont;
1150 capela 454 bool bOldKeepOnTop = m_pOptions->bKeepOnTop;
1151 capela 109 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
1152     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
1153     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1154     bool bOldCompletePath = m_pOptions->bCompletePath;
1155 capela 371 bool bOldInstrumentNames = m_pOptions->bInstrumentNames;
1156 capela 109 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
1157     // Load the current setup settings.
1158     pOptionsForm->setup(m_pOptions);
1159     // Show the setup dialog...
1160     if (pOptionsForm->exec()) {
1161     // Warn if something will be only effective on next run.
1162     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1163 capela 454 (!bOldStdoutCapture && m_pOptions->bStdoutCapture) ||
1164     ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) ||
1165     (!bOldKeepOnTop && m_pOptions->bKeepOnTop)) {
1166 capela 109 QMessageBox::information(this, tr("Information"),
1167     tr("Some settings may be only effective\n"
1168     "next time you start this program."), tr("OK"));
1169     updateMessagesCapture();
1170     }
1171     // Check wheather something immediate has changed.
1172     if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1173     (!bOldCompletePath && m_pOptions->bCompletePath) ||
1174     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1175     updateRecentFilesMenu();
1176 capela 371 if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1177     (!bOldInstrumentNames && m_pOptions->bInstrumentNames))
1178     updateInstrumentNames();
1179 capela 267 if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1180     (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
1181     updateDisplayEffect();
1182 capela 109 if (sOldDisplayFont != m_pOptions->sDisplayFont)
1183     updateDisplayFont();
1184 capela 119 if (iOldMaxVolume != m_pOptions->iMaxVolume)
1185     updateMaxVolume();
1186 capela 109 if (sOldMessagesFont != m_pOptions->sMessagesFont)
1187     updateMessagesFont();
1188     if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1189     (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
1190     (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
1191     updateMessagesLimit();
1192     // And now the main thing, whether we'll do client/server recycling?
1193     if ((sOldServerHost != m_pOptions->sServerHost) ||
1194     (iOldServerPort != m_pOptions->iServerPort) ||
1195     (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1196     ( bOldServerStart && !m_pOptions->bServerStart) ||
1197     (!bOldServerStart && m_pOptions->bServerStart) ||
1198     (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
1199     fileRestart();
1200     }
1201     // Done.
1202     delete pOptionsForm;
1203     }
1204    
1205     // This makes it.
1206     stabilizeForm();
1207     }
1208    
1209    
1210     //-------------------------------------------------------------------------
1211     // qsamplerMainForm -- Channels action slots.
1212    
1213     // Arrange channel strips.
1214     void qsamplerMainForm::channelsArrange (void)
1215     {
1216     // Full width vertical tiling
1217     QWidgetList wlist = m_pWorkspace->windowList();
1218     if (wlist.isEmpty())
1219     return;
1220    
1221     m_pWorkspace->setUpdatesEnabled(false);
1222     int y = 0;
1223     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1224 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1225     /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1226 capela 109 // Prevent flicker...
1227 capela 264 pChannelStrip->hide();
1228     pChannelStrip->showNormal();
1229 capela 109 } */
1230 capela 264 pChannelStrip->adjustSize();
1231 capela 109 int iWidth = m_pWorkspace->width();
1232 capela 264 if (iWidth < pChannelStrip->width())
1233     iWidth = pChannelStrip->width();
1234     // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1235     int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1236     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1237 capela 109 y += iHeight;
1238     }
1239     m_pWorkspace->setUpdatesEnabled(true);
1240    
1241     stabilizeForm();
1242     }
1243    
1244    
1245     // Auto-arrange channel strips.
1246     void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1247     {
1248     if (m_pOptions == NULL)
1249     return;
1250    
1251     // Toggle the auto-arrange flag.
1252     m_pOptions->bAutoArrange = bOn;
1253    
1254     // If on, update whole workspace...
1255     if (m_pOptions->bAutoArrange)
1256     channelsArrange();
1257     }
1258    
1259    
1260     //-------------------------------------------------------------------------
1261     // qsamplerMainForm -- Help Action slots.
1262    
1263     // Show information about the Qt toolkit.
1264     void qsamplerMainForm::helpAboutQt (void)
1265     {
1266     QMessageBox::aboutQt(this);
1267     }
1268    
1269    
1270     // Show information about application program.
1271     void qsamplerMainForm::helpAbout (void)
1272     {
1273     // Stuff the about box text...
1274     QString sText = "<p>\n";
1275     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1276     sText += "<br />\n";
1277     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1278     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1279     #ifdef CONFIG_DEBUG
1280     sText += "<small><font color=\"red\">";
1281     sText += tr("Debugging option enabled.");
1282     sText += "</font></small><br />";
1283     #endif
1284 capela 176 #ifndef CONFIG_LIBGIG
1285     sText += "<small><font color=\"red\">";
1286     sText += tr("GIG (libgig) file support disabled.");
1287     sText += "</font></small><br />";
1288     #endif
1289 capela 382 #ifndef CONFIG_INSTRUMENT_NAME
1290     sText += "<small><font color=\"red\">";
1291     sText += tr("LSCP (liblscp) instrument_name support disabled.");
1292     sText += "</font></small><br />";
1293     #endif
1294 capela 109 sText += "<br />\n";
1295     sText += tr("Using") + ": ";
1296     sText += ::lscp_client_package();
1297     sText += " ";
1298     sText += ::lscp_client_version();
1299     sText += "<br />\n";
1300     sText += "<br />\n";
1301     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1302     sText += "<br />\n";
1303     sText += "<small>";
1304     sText += QSAMPLER_COPYRIGHT "<br />\n";
1305     sText += "<br />\n";
1306     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1307     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1308     sText += "</small>";
1309     sText += "</p>\n";
1310    
1311     QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1312     }
1313    
1314    
1315     //-------------------------------------------------------------------------
1316     // qsamplerMainForm -- Main window stabilization.
1317    
1318     void qsamplerMainForm::stabilizeForm (void)
1319     {
1320     // Update the main application caption...
1321 capela 418 QString sSessionName = sessionName(m_sFilename);
1322 capela 109 if (m_iDirtyCount > 0)
1323 capela 418 sSessionName += '*';
1324     setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1325 capela 109
1326     // Update the main menu state...
1327 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1328 capela 109 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1329 capela 264 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1330 capela 109 fileNewAction->setEnabled(bHasClient);
1331     fileOpenAction->setEnabled(bHasClient);
1332     fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1333     fileSaveAsAction->setEnabled(bHasClient);
1334 capela 255 fileResetAction->setEnabled(bHasClient);
1335 capela 109 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1336     editAddChannelAction->setEnabled(bHasClient);
1337     editRemoveChannelAction->setEnabled(bHasChannel);
1338     editSetupChannelAction->setEnabled(bHasChannel);
1339     editResetChannelAction->setEnabled(bHasChannel);
1340 capela 404 editResetAllChannelsAction->setEnabled(bHasChannel);
1341 capela 428 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1342     viewDevicesAction->setOn(m_pDeviceForm && m_pDeviceForm->isVisible());
1343     viewDevicesAction->setEnabled(bHasClient);
1344 capela 109 channelsArrangeAction->setEnabled(bHasChannel);
1345    
1346     // Client/Server status...
1347     if (bHasClient) {
1348 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1349     m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1350 capela 109 } else {
1351 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
1352     m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
1353 capela 109 }
1354     // Channel status...
1355     if (bHasChannel)
1356 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());
1357 capela 109 else
1358 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
1359 capela 109 // Session status...
1360     if (m_iDirtyCount > 0)
1361 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1362 capela 109 else
1363 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
1364 capela 109
1365     // Recent files menu.
1366     m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1367    
1368     // Always make the latest message visible.
1369     if (m_pMessages)
1370     m_pMessages->scrollToBottom();
1371     }
1372    
1373    
1374     // Channel change receiver slot.
1375 capela 400 void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip *pChannelStrip )
1376 capela 109 {
1377 capela 400 // Add this strip to the changed list...
1378     if (m_changedStrips.containsRef(pChannelStrip) == 0)
1379     m_changedStrips.append(pChannelStrip);
1380    
1381 capela 109 // Just mark the dirty form.
1382     m_iDirtyCount++;
1383     // and update the form status...
1384     stabilizeForm();
1385     }
1386    
1387    
1388 capela 395 // Grab and restore current sampler channels session.
1389     void qsamplerMainForm::updateSession (void)
1390     {
1391     // Retrieve the current channel list.
1392     int *piChannelIDs = ::lscp_list_channels(m_pClient);
1393     if (piChannelIDs == NULL) {
1394     if (::lscp_client_get_errno(m_pClient)) {
1395     appendMessagesClient("lscp_list_channels");
1396     appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));
1397     }
1398     return;
1399     }
1400    
1401     // Try to (re)create each channel.
1402     m_pWorkspace->setUpdatesEnabled(false);
1403     for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
1404     // Check if theres already a channel strip for this one...
1405     if (!channelStrip(piChannelIDs[iChannel]))
1406     createChannelStrip(new qsamplerChannel(this, piChannelIDs[iChannel]));
1407     // Make it visibly responsive...
1408     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1409     }
1410     m_pWorkspace->setUpdatesEnabled(true);
1411 capela 469
1412     // Remember to refresh devices
1413     if (m_pDeviceForm)
1414     m_pDeviceForm->refreshDevices();
1415 capela 395 }
1416    
1417    
1418 capela 109 // Update the recent files list and menu.
1419     void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1420     {
1421     if (m_pOptions == NULL)
1422     return;
1423    
1424     // Remove from list if already there (avoid duplicates)
1425     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1426     if (iter != m_pOptions->recentFiles.end())
1427     m_pOptions->recentFiles.remove(iter);
1428     // Put it to front...
1429     m_pOptions->recentFiles.push_front(sFilename);
1430    
1431     // May update the menu.
1432     updateRecentFilesMenu();
1433     }
1434    
1435    
1436     // Update the recent files list and menu.
1437     void qsamplerMainForm::updateRecentFilesMenu (void)
1438     {
1439     if (m_pOptions == NULL)
1440     return;
1441    
1442     // Time to keep the list under limits.
1443     int iRecentFiles = m_pOptions->recentFiles.count();
1444     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1445     m_pOptions->recentFiles.pop_back();
1446     iRecentFiles--;
1447     }
1448    
1449     // rebuild the recent files menu...
1450     m_pRecentFilesMenu->clear();
1451     for (int i = 0; i < iRecentFiles; i++) {
1452     const QString& sFilename = m_pOptions->recentFiles[i];
1453     if (QFileInfo(sFilename).exists()) {
1454     m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1455     .arg(i + 1).arg(sessionName(sFilename)),
1456     this, SLOT(fileOpenRecent(int)), 0, i);
1457     }
1458     }
1459     }
1460    
1461    
1462 capela 371 // Force update of the channels instrument names mode.
1463     void qsamplerMainForm::updateInstrumentNames (void)
1464     {
1465     // Full channel list update...
1466     QWidgetList wlist = m_pWorkspace->windowList();
1467     if (wlist.isEmpty())
1468     return;
1469    
1470     m_pWorkspace->setUpdatesEnabled(false);
1471     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1472     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1473     if (pChannelStrip)
1474     pChannelStrip->updateInstrumentName(true);
1475     }
1476     m_pWorkspace->setUpdatesEnabled(true);
1477     }
1478    
1479    
1480 capela 109 // Force update of the channels display font.
1481     void qsamplerMainForm::updateDisplayFont (void)
1482     {
1483     if (m_pOptions == NULL)
1484     return;
1485    
1486     // Check if display font is legal.
1487     if (m_pOptions->sDisplayFont.isEmpty())
1488     return;
1489     // Realize it.
1490     QFont font;
1491     if (!font.fromString(m_pOptions->sDisplayFont))
1492     return;
1493    
1494     // Full channel list update...
1495     QWidgetList wlist = m_pWorkspace->windowList();
1496     if (wlist.isEmpty())
1497     return;
1498    
1499     m_pWorkspace->setUpdatesEnabled(false);
1500     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1501 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1502     if (pChannelStrip)
1503     pChannelStrip->setDisplayFont(font);
1504 capela 109 }
1505     m_pWorkspace->setUpdatesEnabled(true);
1506     }
1507    
1508    
1509 capela 267 // Update channel strips background effect.
1510     void qsamplerMainForm::updateDisplayEffect (void)
1511     {
1512     QPixmap pm;
1513     if (m_pOptions->bDisplayEffect)
1514     pm = QPixmap::fromMimeSource("displaybg1.png");
1515    
1516     // Full channel list update...
1517     QWidgetList wlist = m_pWorkspace->windowList();
1518     if (wlist.isEmpty())
1519     return;
1520    
1521     m_pWorkspace->setUpdatesEnabled(false);
1522     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1523     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1524     if (pChannelStrip)
1525     pChannelStrip->setDisplayBackground(pm);
1526     }
1527     m_pWorkspace->setUpdatesEnabled(true);
1528     }
1529    
1530    
1531 capela 119 // Force update of the channels maximum volume setting.
1532     void qsamplerMainForm::updateMaxVolume (void)
1533     {
1534     if (m_pOptions == NULL)
1535     return;
1536    
1537     // Full channel list update...
1538     QWidgetList wlist = m_pWorkspace->windowList();
1539     if (wlist.isEmpty())
1540     return;
1541    
1542     m_pWorkspace->setUpdatesEnabled(false);
1543     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1544 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1545     if (pChannelStrip)
1546     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1547 capela 119 }
1548     m_pWorkspace->setUpdatesEnabled(true);
1549     }
1550    
1551    
1552 capela 109 //-------------------------------------------------------------------------
1553     // qsamplerMainForm -- Messages window form handlers.
1554    
1555     // Messages output methods.
1556     void qsamplerMainForm::appendMessages( const QString& s )
1557     {
1558     if (m_pMessages)
1559     m_pMessages->appendMessages(s);
1560    
1561     statusBar()->message(s, 3000);
1562     }
1563    
1564     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1565     {
1566     if (m_pMessages)
1567     m_pMessages->appendMessagesColor(s, c);
1568    
1569     statusBar()->message(s, 3000);
1570     }
1571    
1572     void qsamplerMainForm::appendMessagesText( const QString& s )
1573     {
1574     if (m_pMessages)
1575     m_pMessages->appendMessagesText(s);
1576     }
1577    
1578     void qsamplerMainForm::appendMessagesError( const QString& s )
1579     {
1580     if (m_pMessages)
1581     m_pMessages->show();
1582    
1583     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1584    
1585     QMessageBox::critical(this, tr("Error"), s, tr("Cancel"));
1586     }
1587    
1588    
1589     // This is a special message format, just for client results.
1590     void qsamplerMainForm::appendMessagesClient( const QString& s )
1591     {
1592     if (m_pClient == NULL)
1593     return;
1594    
1595     appendMessagesColor(s + QString(": %1 (errno=%2)")
1596     .arg(::lscp_client_get_result(m_pClient))
1597     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1598     }
1599    
1600    
1601     // Force update of the messages font.
1602     void qsamplerMainForm::updateMessagesFont (void)
1603     {
1604     if (m_pOptions == NULL)
1605     return;
1606    
1607     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1608     QFont font;
1609     if (font.fromString(m_pOptions->sMessagesFont))
1610     m_pMessages->setMessagesFont(font);
1611     }
1612     }
1613    
1614    
1615     // Update messages window line limit.
1616     void qsamplerMainForm::updateMessagesLimit (void)
1617     {
1618     if (m_pOptions == NULL)
1619     return;
1620    
1621     if (m_pMessages) {
1622     if (m_pOptions->bMessagesLimit)
1623     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1624     else
1625     m_pMessages->setMessagesLimit(0);
1626     }
1627     }
1628    
1629    
1630     // Enablement of the messages capture feature.
1631     void qsamplerMainForm::updateMessagesCapture (void)
1632     {
1633     if (m_pOptions == NULL)
1634     return;
1635    
1636     if (m_pMessages)
1637     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1638     }
1639    
1640    
1641     //-------------------------------------------------------------------------
1642     // qsamplerMainForm -- MDI channel strip management.
1643    
1644     // The channel strip creation executive.
1645 capela 303 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( qsamplerChannel *pChannel )
1646 capela 109 {
1647 capela 303 if (m_pClient == NULL || pChannel == NULL)
1648 capela 295 return NULL;
1649 capela 109
1650     // Prepare for auto-arrange?
1651 capela 264 qsamplerChannelStrip *pChannelStrip = NULL;
1652 capela 109 int y = 0;
1653     if (m_pOptions && m_pOptions->bAutoArrange) {
1654     QWidgetList wlist = m_pWorkspace->windowList();
1655     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1656 capela 264 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1657 capela 395 if (pChannelStrip) {
1658     // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1659     y += pChannelStrip->parentWidget()->frameGeometry().height();
1660     }
1661 capela 109 }
1662     }
1663    
1664     // Add a new channel itema...
1665     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1666 capela 264 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1667 capela 303 if (pChannelStrip == NULL)
1668     return NULL;
1669    
1670     // Actual channel strip setup...
1671     pChannelStrip->setup(pChannel);
1672 capela 295 QObject::connect(pChannelStrip, SIGNAL(channelChanged(qsamplerChannelStrip *)), this, SLOT(channelStripChanged(qsamplerChannelStrip *)));
1673 capela 267 // Set some initial aesthetic options...
1674     if (m_pOptions) {
1675     // Background display effect...
1676     pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1677     // We'll need a display font.
1678     QFont font;
1679     if (font.fromString(m_pOptions->sDisplayFont))
1680     pChannelStrip->setDisplayFont(font);
1681     // Maximum allowed volume setting.
1682     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1683     }
1684 capela 295
1685 capela 109 // Now we show up us to the world.
1686 capela 264 pChannelStrip->show();
1687 capela 109 // Only then, we'll auto-arrange...
1688     if (m_pOptions && m_pOptions->bAutoArrange) {
1689     int iWidth = m_pWorkspace->width();
1690     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1691 capela 264 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1692     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1693 capela 109 }
1694 capela 400
1695     // This is pretty new, so we'll watch for it closely.
1696     channelStripChanged(pChannelStrip);
1697    
1698 capela 295 // Return our successful reference...
1699     return pChannelStrip;
1700 capela 109 }
1701    
1702    
1703     // Retrieve the active channel strip.
1704 capela 264 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
1705 capela 109 {
1706     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
1707     }
1708    
1709    
1710     // Retrieve a channel strip by index.
1711 capela 264 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
1712 capela 109 {
1713     QWidgetList wlist = m_pWorkspace->windowList();
1714     if (wlist.isEmpty())
1715 capela 395 return NULL;
1716 capela 109
1717     return (qsamplerChannelStrip *) wlist.at(iChannel);
1718     }
1719    
1720    
1721 capela 395 // Retrieve a channel strip by sampler channel id.
1722     qsamplerChannelStrip *qsamplerMainForm::channelStrip ( int iChannelID )
1723     {
1724     QWidgetList wlist = m_pWorkspace->windowList();
1725     if (wlist.isEmpty())
1726     return NULL;
1727    
1728     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1729     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1730     if (pChannelStrip) {
1731     qsamplerChannel *pChannel = pChannelStrip->channel();
1732     if (pChannel && pChannel->channelID() == iChannelID)
1733     return pChannelStrip;
1734     }
1735     }
1736    
1737     // Not found.
1738     return NULL;
1739     }
1740    
1741    
1742 capela 109 // Construct the windows menu.
1743     void qsamplerMainForm::channelsMenuAboutToShow (void)
1744     {
1745     channelsMenu->clear();
1746     channelsArrangeAction->addTo(channelsMenu);
1747     channelsAutoArrangeAction->addTo(channelsMenu);
1748    
1749     QWidgetList wlist = m_pWorkspace->windowList();
1750     if (!wlist.isEmpty()) {
1751     channelsMenu->insertSeparator();
1752     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1753 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1754     if (pChannelStrip) {
1755     int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
1756     channelsMenu->setItemParameter(iItemID, iChannel);
1757     channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
1758     }
1759 capela 109 }
1760     }
1761     }
1762    
1763    
1764     // Windows menu activation slot
1765     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
1766     {
1767 capela 264 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
1768     if (pChannelStrip)
1769     pChannelStrip->showNormal();
1770     pChannelStrip->setFocus();
1771 capela 109 }
1772    
1773    
1774     //-------------------------------------------------------------------------
1775     // qsamplerMainForm -- Timer stuff.
1776    
1777     // Set the pseudo-timer delay schedule.
1778     void qsamplerMainForm::startSchedule ( int iStartDelay )
1779     {
1780     m_iStartDelay = 1 + (iStartDelay * 1000);
1781     m_iTimerDelay = 0;
1782     }
1783    
1784     // Suspend the pseudo-timer delay schedule.
1785     void qsamplerMainForm::stopSchedule (void)
1786     {
1787     m_iStartDelay = 0;
1788     m_iTimerDelay = 0;
1789     }
1790    
1791     // Timer slot funtion.
1792     void qsamplerMainForm::timerSlot (void)
1793     {
1794     if (m_pOptions == NULL)
1795     return;
1796    
1797     // Is it the first shot on server start after a few delay?
1798     if (m_iTimerDelay < m_iStartDelay) {
1799     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
1800     if (m_iTimerDelay >= m_iStartDelay) {
1801     // If we cannot start it now, maybe a lil'mo'later ;)
1802     if (!startClient()) {
1803     m_iStartDelay += m_iTimerDelay;
1804     m_iTimerDelay = 0;
1805     }
1806     }
1807     }
1808    
1809     // Refresh each channel usage, on each period...
1810 capela 400 if (m_pClient && (m_changedStrips.count() > 0 || m_pOptions->bAutoRefresh)) {
1811 capela 109 m_iTimerSlot += QSAMPLER_TIMER_MSECS;
1812 capela 296 if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime && m_pWorkspace->isUpdatesEnabled()) {
1813 capela 109 m_iTimerSlot = 0;
1814 capela 400 // Update the channel information for each pending strip...
1815     for (qsamplerChannelStrip *pChannelStrip = m_changedStrips.first();
1816     pChannelStrip;
1817     pChannelStrip = m_changedStrips.next()) {
1818     // If successfull, remove from pending list...
1819     if (pChannelStrip->updateChannelInfo())
1820     m_changedStrips.remove(pChannelStrip);
1821     }
1822     // Update the channel stream usage for each strip...
1823 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
1824     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1825 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1826 capela 400 if (pChannelStrip && pChannelStrip->isVisible())
1827     pChannelStrip->updateChannelUsage();
1828 capela 109 }
1829     }
1830     }
1831    
1832     // Register the next timer slot.
1833     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
1834     }
1835    
1836    
1837     //-------------------------------------------------------------------------
1838     // qsamplerMainForm -- Server stuff.
1839    
1840     // Start linuxsampler server...
1841     void qsamplerMainForm::startServer (void)
1842     {
1843     if (m_pOptions == NULL)
1844     return;
1845    
1846     // Aren't already a client, are we?
1847     if (!m_pOptions->bServerStart || m_pClient)
1848     return;
1849    
1850     // Is the server process instance still here?
1851     if (m_pServer) {
1852     switch (QMessageBox::warning(this, tr("Warning"),
1853     tr("Could not start the LinuxSampler server.\n\n"
1854     "Maybe it ss already started."),
1855     tr("Stop"), tr("Kill"), tr("Cancel"))) {
1856     case 0:
1857     m_pServer->tryTerminate();
1858     break;
1859     case 1:
1860     m_pServer->kill();
1861     break;
1862     }
1863     return;
1864     }
1865    
1866     // Reset our timer counters...
1867     stopSchedule();
1868    
1869     // OK. Let's build the startup process...
1870     m_pServer = new QProcess(this);
1871    
1872     // Setup stdout/stderr capture...
1873     //if (m_pOptions->bStdoutCapture) {
1874     m_pServer->setCommunication(QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
1875     QObject::connect(m_pServer, SIGNAL(readyReadStdout()), this, SLOT(readServerStdout()));
1876     QObject::connect(m_pServer, SIGNAL(readyReadStderr()), this, SLOT(readServerStdout()));
1877     //}
1878     // The unforgiveable signal communication...
1879     QObject::connect(m_pServer, SIGNAL(processExited()), this, SLOT(processServerExit()));
1880    
1881     // Build process arguments...
1882     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
1883    
1884     appendMessages(tr("Server is starting..."));
1885     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
1886    
1887     // Go jack, go...
1888     if (!m_pServer->start()) {
1889     appendMessagesError(tr("Could not start server.\n\nSorry."));
1890     processServerExit();
1891     return;
1892     }
1893    
1894     // Show startup results...
1895     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
1896    
1897     // Reset (yet again) the timer counters,
1898     // but this time is deferred as the user opted.
1899     startSchedule(m_pOptions->iStartDelay);
1900     stabilizeForm();
1901     }
1902    
1903    
1904     // Stop linuxsampler server...
1905     void qsamplerMainForm::stopServer (void)
1906     {
1907     // Stop client code.
1908     stopClient();
1909    
1910     // And try to stop server.
1911     if (m_pServer) {
1912     appendMessages(tr("Server is stopping..."));
1913 capela 122 if (m_pServer->isRunning())
1914 capela 109 m_pServer->tryTerminate();
1915     }
1916    
1917 capela 122 // Give it some time to terminate gracefully and stabilize...
1918     QTime t;
1919     t.start();
1920     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
1921     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1922    
1923 capela 109 // Do final processing anyway.
1924     processServerExit();
1925     }
1926    
1927    
1928     // Stdout handler...
1929     void qsamplerMainForm::readServerStdout (void)
1930     {
1931     if (m_pMessages)
1932     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
1933     }
1934    
1935    
1936     // Linuxsampler server cleanup.
1937     void qsamplerMainForm::processServerExit (void)
1938     {
1939     // Force client code cleanup.
1940     stopClient();
1941    
1942     // Flush anything that maybe pending...
1943     if (m_pMessages)
1944     m_pMessages->flushStdoutBuffer();
1945    
1946     if (m_pServer) {
1947     // Force final server shutdown...
1948     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
1949     if (!m_pServer->normalExit())
1950     m_pServer->kill();
1951     // Destroy it.
1952     delete m_pServer;
1953     m_pServer = NULL;
1954     }
1955    
1956     // Again, make status visible stable.
1957     stabilizeForm();
1958     }
1959    
1960    
1961     //-------------------------------------------------------------------------
1962     // qsamplerMainForm -- Client stuff.
1963    
1964     // The LSCP client callback procedure.
1965 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
1966 capela 109 {
1967 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
1968     if (pMainForm == NULL)
1969     return LSCP_FAILED;
1970    
1971     // ATTN: DO NOT EVER call any GUI code here,
1972 capela 145 // as this is run under some other thread context.
1973     // A custom event must be posted here...
1974 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
1975 capela 109
1976     return LSCP_OK;
1977     }
1978    
1979    
1980     // Start our almighty client...
1981     bool qsamplerMainForm::startClient (void)
1982     {
1983     // Have it a setup?
1984     if (m_pOptions == NULL)
1985     return false;
1986    
1987     // Aren't we already started, are we?
1988     if (m_pClient)
1989     return true;
1990    
1991     // Log prepare here.
1992     appendMessages(tr("Client connecting..."));
1993    
1994     // Create the client handle...
1995     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
1996     if (m_pClient == NULL) {
1997     // Is this the first try?
1998     // maybe we need to start a local server...
1999     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
2000     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
2001     else
2002     startServer();
2003     // This is always a failure.
2004     stabilizeForm();
2005     return false;
2006     }
2007     // Just set receive timeout value, blindly.
2008     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
2009     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
2010    
2011     // We may stop scheduling around.
2012     stopSchedule();
2013    
2014     // We'll accept drops from now on...
2015     setAcceptDrops(true);
2016    
2017     // Log success here.
2018     appendMessages(tr("Client connected."));
2019    
2020 capela 428 // Hard-notify device configuration form,
2021     // if visible, that we're ready...
2022     if (m_pDeviceForm && m_pDeviceForm->isVisible())
2023     m_pDeviceForm->setClient(m_pClient);
2024    
2025 capela 109 // Is any session pending to be loaded?
2026     if (!m_pOptions->sSessionFile.isEmpty()) {
2027     // Just load the prabably startup session...
2028     if (loadSessionFile(m_pOptions->sSessionFile)) {
2029     m_pOptions->sSessionFile = QString::null;
2030     return true;
2031     }
2032     }
2033    
2034     // Make a new session
2035     return newSession();
2036     }
2037    
2038    
2039     // Stop client...
2040     void qsamplerMainForm::stopClient (void)
2041     {
2042     if (m_pClient == NULL)
2043     return;
2044    
2045 capela 428 // Hard-notify device configuration form,
2046     // if visible, that we're running out...
2047     if (m_pDeviceForm && m_pDeviceForm->isVisible())
2048     m_pDeviceForm->setClient(NULL);
2049    
2050 capela 109 // Log prepare here.
2051     appendMessages(tr("Client disconnecting..."));
2052    
2053     // Clear timer counters...
2054     stopSchedule();
2055    
2056     // We'll reject drops from now on...
2057     setAcceptDrops(false);
2058    
2059     // Force any channel strips around, but
2060     // but avoid removing the corresponding
2061     // channels from the back-end server.
2062     m_iDirtyCount = 0;
2063     closeSession(false);
2064    
2065     // Close us as a client...
2066     lscp_client_destroy(m_pClient);
2067     m_pClient = NULL;
2068    
2069     // Log final here.
2070     appendMessages(tr("Client disconnected."));
2071    
2072     // Make visible status.
2073     stabilizeForm();
2074     }
2075    
2076    
2077     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC