/[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 961 - (hide annotations) (download) (as text)
Sun Dec 3 18:26:13 2006 UTC (17 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 69980 byte(s)
- Adding preliminary MIDI instrument mapping support; now
  with an instrument list widget and editing capabilities.

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

  ViewVC Help
Powered by ViewVC