/[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 753 - (hide annotations) (download) (as text)
Wed Aug 24 17:44:59 2005 UTC (18 years, 7 months ago) by capela
File MIME type: text/x-c++hdr
File size: 66343 byte(s)
Attempt to bring those aging autoconf templates to date;
  sample SPEC file for RPM build is now being included and
  generated at configure time.

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

  ViewVC Help
Powered by ViewVC