/[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 1024 - (hide annotations) (download) (as text)
Fri Jan 12 10:56:31 2007 UTC (17 years, 2 months ago) by capela
File MIME type: text/x-c++hdr
File size: 73957 byte(s)
* Initial support for sampler channel FX sends, while saving
  the session state, only at code-level.

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

  ViewVC Help
Powered by ViewVC