/[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 969 - (hide annotations) (download) (as text)
Wed Dec 6 19:38:02 2006 UTC (17 years, 3 months ago) by capela
File MIME type: text/x-c++hdr
File size: 70004 byte(s)
* Fixed MIDI instrument volume setting.
* Enforcing uniqueness of bank and program key pair
  while editing the MIDI instrument map.

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

  ViewVC Help
Powered by ViewVC