/[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 519 - (hide annotations) (download) (as text)
Sun May 8 17:04:10 2005 UTC (18 years, 11 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 65977 byte(s)
* Show appropriate message in channel strip while loading an instrument.
* Show libgig version in About box (in case libgig is used).

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

  ViewVC Help
Powered by ViewVC