/[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 1033 - (hide annotations) (download) (as text)
Mon Jan 15 11:27:22 2007 UTC (17 years, 3 months ago) by capela
File MIME type: text/x-c++hdr
File size: 74104 byte(s)
* Sampler channel FX send level is now also saved.

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 455 // Sampler channel mapping.
900 capela 109 QWidgetList wlist = m_pWorkspace->windowList();
901     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
902 capela 1024 qsamplerChannelStrip *pChannelStrip
903     = static_cast<qsamplerChannelStrip *> (wlist.at(iChannel));
904 capela 264 if (pChannelStrip) {
905     qsamplerChannel *pChannel = pChannelStrip->channel();
906     if (pChannel) {
907 capela 455 ts << "# " << tr("Channel") << " " << iChannel << endl;
908 capela 264 ts << "ADD CHANNEL" << endl;
909 capela 586 if (audioDeviceMap.isEmpty()) {
910     ts << "SET CHANNEL AUDIO_OUTPUT_TYPE " << iChannel
911     << " " << pChannel->audioDriver() << endl;
912     } else {
913     ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannel
914     << " " << audioDeviceMap[pChannel->audioDevice()] << endl;
915 capela 455 }
916 capela 586 if (midiDeviceMap.isEmpty()) {
917     ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannel
918     << " " << pChannel->midiDriver() << endl;
919     } else {
920     ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannel
921     << " " << midiDeviceMap[pChannel->midiDevice()] << endl;
922     }
923     ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannel
924     << " " << pChannel->midiPort() << endl;
925 capela 409 ts << "SET CHANNEL MIDI_INPUT_CHANNEL " << iChannel << " ";
926 capela 304 if (pChannel->midiChannel() == LSCP_MIDI_CHANNEL_ALL)
927     ts << "ALL";
928     else
929 capela 264 ts << pChannel->midiChannel();
930     ts << endl;
931 capela 409 ts << "LOAD ENGINE " << pChannel->engineName() << " " << iChannel << endl;
932 capela 980 if (pChannel->instrumentStatus() < 100) ts << "# ";
933     ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' "
934     << pChannel->instrumentNr() << " " << iChannel << endl;
935 capela 758 qsamplerChannelRoutingMap::ConstIterator audioRoute;
936     for (audioRoute = pChannel->audioRouting().begin();
937     audioRoute != pChannel->audioRouting().end();
938     ++audioRoute) {
939     ts << "SET CHANNEL AUDIO_OUTPUT_CHANNEL " << iChannel
940     << " " << audioRoute.key()
941     << " " << audioRoute.data() << endl;
942     }
943 capela 980 ts << "SET CHANNEL VOLUME " << iChannel
944     << " " << pChannel->volume() << endl;
945 capela 758 if (pChannel->channelMute())
946     ts << "SET CHANNEL MUTE " << iChannel << " 1" << endl;
947     if (pChannel->channelSolo())
948     ts << "SET CHANNEL SOLO " << iChannel << " 1" << endl;
949 capela 980 #ifdef CONFIG_MIDI_INSTRUMENT
950     if (pChannel->midiMap() >= 0) {
951     ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannel
952 capela 986 << " " << midiInstrumentMap[pChannel->midiMap()] << endl;
953 capela 980 }
954     #endif
955 capela 1024 #ifdef CONFIG_FXSEND
956     int iChannelID = pChannel->channelID();
957     int *piFxSends = ::lscp_list_fxsends(m_pClient, iChannelID);
958 capela 1025 for (int iFxSend = 0;
959     piFxSends && piFxSends[iFxSend] >= 0;
960     iFxSend++) {
961     lscp_fxsend_info_t *pFxSendInfo = ::lscp_get_fxsend_info(
962     m_pClient, iChannelID, piFxSends[iFxSend]);
963 capela 1024 if (pFxSendInfo) {
964     ts << "CREATE FX_SEND " << iChannel
965     << " " << pFxSendInfo->midi_controller;
966     if (pFxSendInfo->name)
967     ts << " '" << pFxSendInfo->name << "'";
968     ts << endl;
969     int *piRouting = pFxSendInfo->audio_routing;
970 capela 1025 for (int iAudioSrc = 0;
971     piRouting && piRouting[iAudioSrc] >= 0;
972     iAudioSrc++) {
973     ts << "SET FX_SEND AUDIO_OUTPUT_CHANNEL "
974     << iChannel
975 capela 1024 << " " << iFxSend
976 capela 1025 << " " << iAudioSrc
977     << " " << piRouting[iAudioSrc] << endl;
978 capela 1024 }
979 capela 1033 #ifdef CONFIG_FXSEND_LEVEL
980     ts << "SET FX_SEND LEVEL " << iChannel
981     << " " << iFxSend
982     << " " << pFxSendInfo->level << endl;
983     #endif
984 capela 1024 } // Check for errors...
985     else if (::lscp_client_get_errno(m_pClient)) {
986     appendMessagesClient("lscp_get_fxsend_info");
987     iErrors++;
988     }
989     }
990     #endif
991 capela 264 ts << endl;
992     }
993     }
994 capela 109 // Try to keep it snappy :)
995     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
996     }
997    
998     // Ok. we've wrote it.
999     file.close();
1000    
1001 capela 987 // We're fornerly done.
1002     QApplication::restoreOverrideCursor();
1003    
1004 capela 109 // Have we any errors?
1005     if (iErrors > 0)
1006     appendMessagesError(tr("Some settings could not be saved\nto \"%1\" session file.\n\nSorry.").arg(sFilename));
1007    
1008     // Save as default session directory.
1009     if (m_pOptions)
1010     m_pOptions->sSessionDir = QFileInfo(sFilename).dirPath(true);
1011     // We're not dirty anymore.
1012     m_iDirtyCount = 0;
1013     // Stabilize form...
1014     m_sFilename = sFilename;
1015     updateRecentFiles(sFilename);
1016     appendMessages(tr("Save session: \"%1\".").arg(sessionName(m_sFilename)));
1017     stabilizeForm();
1018     return true;
1019     }
1020    
1021    
1022 capela 433 // Session change receiver slot.
1023     void qsamplerMainForm::sessionDirty (void)
1024     {
1025     // Just mark the dirty form.
1026     m_iDirtyCount++;
1027     // and update the form status...
1028     stabilizeForm();
1029     }
1030    
1031    
1032 capela 109 //-------------------------------------------------------------------------
1033     // qsamplerMainForm -- File Action slots.
1034    
1035     // Create a new sampler session.
1036     void qsamplerMainForm::fileNew (void)
1037     {
1038     // Of course we'll start clean new.
1039     newSession();
1040     }
1041    
1042    
1043     // Open an existing sampler session.
1044     void qsamplerMainForm::fileOpen (void)
1045     {
1046     // Open it right away.
1047     openSession();
1048     }
1049    
1050    
1051     // Open a recent file session.
1052     void qsamplerMainForm::fileOpenRecent ( int iIndex )
1053     {
1054     // Check if we can safely close the current session...
1055     if (m_pOptions && closeSession(true)) {
1056     QString sFilename = m_pOptions->recentFiles[iIndex];
1057     loadSessionFile(sFilename);
1058     }
1059     }
1060    
1061    
1062     // Save current sampler session.
1063     void qsamplerMainForm::fileSave (void)
1064     {
1065     // Save it right away.
1066     saveSession(false);
1067     }
1068    
1069    
1070     // Save current sampler session with another name.
1071     void qsamplerMainForm::fileSaveAs (void)
1072     {
1073     // Save it right away, maybe with another name.
1074     saveSession(true);
1075     }
1076    
1077    
1078 capela 255 // Reset the sampler instance.
1079     void qsamplerMainForm::fileReset (void)
1080     {
1081     if (m_pClient == NULL)
1082     return;
1083    
1084     // Ask user whether he/she want's an internal sampler reset...
1085 capela 757 if (QMessageBox::warning(this,
1086     QSAMPLER_TITLE ": " + tr("Warning"),
1087 capela 255 tr("Resetting the sampler instance will close\n"
1088     "all device and channel configurations.\n\n"
1089     "Please note that this operation may cause\n"
1090 capela 586 "temporary MIDI and Audio disruption.\n\n"
1091 capela 255 "Do you want to reset the sampler engine now?"),
1092     tr("Reset"), tr("Cancel")) > 0)
1093     return;
1094    
1095 capela 996 // Trye closing the current session, first...
1096     if (!closeSession(true))
1097     return;
1098    
1099 capela 255 // Just do the reset, after closing down current session...
1100 capela 1013 // Do the actual sampler reset...
1101     if (::lscp_reset_sampler(m_pClient) != LSCP_OK) {
1102     appendMessagesClient("lscp_reset_sampler");
1103     appendMessagesError(tr("Could not reset sampler instance.\n\nSorry."));
1104 capela 996 return;
1105 capela 1013 }
1106 capela 261
1107     // Log this.
1108     appendMessages(tr("Sampler reset."));
1109 capela 395
1110     // Make it a new session...
1111     newSession();
1112 capela 255 }
1113    
1114    
1115 capela 109 // Restart the client/server instance.
1116     void qsamplerMainForm::fileRestart (void)
1117     {
1118     if (m_pOptions == NULL)
1119     return;
1120 capela 586
1121 capela 109 bool bRestart = true;
1122 capela 586
1123 capela 109 // Ask user whether he/she want's a complete restart...
1124     // (if we're currently up and running)
1125     if (bRestart && m_pClient) {
1126 capela 757 bRestart = (QMessageBox::warning(this,
1127     QSAMPLER_TITLE ": " + tr("Warning"),
1128 capela 109 tr("New settings will be effective after\n"
1129     "restarting the client/server connection.\n\n"
1130     "Please note that this operation may cause\n"
1131 capela 586 "temporary MIDI and Audio disruption.\n\n"
1132 capela 109 "Do you want to restart the connection now?"),
1133     tr("Restart"), tr("Cancel")) == 0);
1134     }
1135    
1136     // Are we still for it?
1137     if (bRestart && closeSession(true)) {
1138     // Stop server, it will force the client too.
1139     stopServer();
1140     // Reschedule a restart...
1141     startSchedule(m_pOptions->iStartDelay);
1142     }
1143     }
1144    
1145    
1146     // Exit application program.
1147     void qsamplerMainForm::fileExit (void)
1148     {
1149     // Go for close the whole thing.
1150     close();
1151     }
1152    
1153    
1154     //-------------------------------------------------------------------------
1155     // qsamplerMainForm -- Edit Action slots.
1156    
1157     // Add a new sampler channel.
1158     void qsamplerMainForm::editAddChannel (void)
1159     {
1160     if (m_pClient == NULL)
1161     return;
1162    
1163 capela 303 // Just create the channel instance...
1164 capela 961 qsamplerChannel *pChannel = new qsamplerChannel();
1165 capela 303 if (pChannel == NULL)
1166     return;
1167    
1168     // Before we show it up, may be we'll
1169     // better ask for some initial values?
1170     if (!pChannel->channelSetup(this)) {
1171     delete pChannel;
1172     return;
1173     }
1174 capela 586
1175 capela 303 // And give it to the strip (will own the channel instance, if successful).
1176     if (!createChannelStrip(pChannel)) {
1177     delete pChannel;
1178     return;
1179     }
1180    
1181     // Make that an overall update.
1182     m_iDirtyCount++;
1183     stabilizeForm();
1184 capela 109 }
1185    
1186    
1187     // Remove current sampler channel.
1188     void qsamplerMainForm::editRemoveChannel (void)
1189     {
1190     if (m_pClient == NULL)
1191     return;
1192    
1193 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1194     if (pChannelStrip == NULL)
1195     return;
1196 capela 586
1197 capela 264 qsamplerChannel *pChannel = pChannelStrip->channel();
1198 capela 109 if (pChannel == NULL)
1199     return;
1200    
1201     // Prompt user if he/she's sure about this...
1202     if (m_pOptions && m_pOptions->bConfirmRemove) {
1203 capela 757 if (QMessageBox::warning(this,
1204     QSAMPLER_TITLE ": " + tr("Warning"),
1205 capela 109 tr("About to remove channel:\n\n"
1206     "%1\n\n"
1207     "Are you sure?")
1208 capela 264 .arg(pChannelStrip->caption()),
1209 capela 109 tr("OK"), tr("Cancel")) > 0)
1210     return;
1211     }
1212    
1213     // Remove the existing sampler channel.
1214 capela 295 if (!pChannel->removeChannel())
1215 capela 109 return;
1216    
1217     // Just delete the channel strip.
1218 capela 265 delete pChannelStrip;
1219 capela 586
1220 capela 109 // Do we auto-arrange?
1221     if (m_pOptions && m_pOptions->bAutoArrange)
1222     channelsArrange();
1223    
1224     // We'll be dirty, for sure...
1225     m_iDirtyCount++;
1226     stabilizeForm();
1227     }
1228    
1229    
1230     // Setup current sampler channel.
1231     void qsamplerMainForm::editSetupChannel (void)
1232     {
1233     if (m_pClient == NULL)
1234     return;
1235    
1236 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1237     if (pChannelStrip == NULL)
1238 capela 109 return;
1239    
1240     // Just invoque the channel strip procedure.
1241 capela 295 pChannelStrip->channelSetup();
1242 capela 109 }
1243    
1244    
1245     // Reset current sampler channel.
1246     void qsamplerMainForm::editResetChannel (void)
1247     {
1248     if (m_pClient == NULL)
1249     return;
1250    
1251 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1252     if (pChannelStrip == NULL)
1253     return;
1254    
1255 capela 400 // Just invoque the channel strip procedure.
1256     pChannelStrip->channelReset();
1257 capela 109 }
1258    
1259    
1260 capela 404 // Reset all sampler channels.
1261     void qsamplerMainForm::editResetAllChannels (void)
1262     {
1263 capela 586 if (m_pClient == NULL)
1264     return;
1265 capela 404
1266 capela 586 // Invoque the channel strip procedure,
1267 capela 404 // for all channels out there...
1268 capela 586 m_pWorkspace->setUpdatesEnabled(false);
1269     QWidgetList wlist = m_pWorkspace->windowList();
1270     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1271     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1272     if (pChannelStrip)
1273     pChannelStrip->channelReset();
1274     }
1275     m_pWorkspace->setUpdatesEnabled(true);
1276 capela 404 }
1277    
1278    
1279 capela 109 //-------------------------------------------------------------------------
1280     // qsamplerMainForm -- View Action slots.
1281    
1282     // Show/hide the main program window menubar.
1283     void qsamplerMainForm::viewMenubar ( bool bOn )
1284     {
1285     if (bOn)
1286     MenuBar->show();
1287     else
1288     MenuBar->hide();
1289     }
1290    
1291    
1292     // Show/hide the main program window toolbar.
1293     void qsamplerMainForm::viewToolbar ( bool bOn )
1294     {
1295     if (bOn) {
1296     fileToolbar->show();
1297     editToolbar->show();
1298     channelsToolbar->show();
1299     } else {
1300     fileToolbar->hide();
1301     editToolbar->hide();
1302     channelsToolbar->hide();
1303     }
1304     }
1305    
1306    
1307     // Show/hide the main program window statusbar.
1308     void qsamplerMainForm::viewStatusbar ( bool bOn )
1309     {
1310     if (bOn)
1311     statusBar()->show();
1312     else
1313     statusBar()->hide();
1314     }
1315    
1316    
1317     // Show/hide the messages window logger.
1318     void qsamplerMainForm::viewMessages ( bool bOn )
1319     {
1320     if (bOn)
1321     m_pMessages->show();
1322     else
1323     m_pMessages->hide();
1324     }
1325    
1326    
1327 capela 961 // Show/hide the MIDI instrument list-view form.
1328     void qsamplerMainForm::viewInstruments (void)
1329     {
1330     if (m_pOptions == NULL)
1331     return;
1332    
1333     if (m_pInstrumentListForm) {
1334     m_pOptions->saveWidgetGeometry(m_pInstrumentListForm);
1335     if (m_pInstrumentListForm->isVisible()) {
1336     m_pInstrumentListForm->hide();
1337     } else {
1338     m_pInstrumentListForm->show();
1339     m_pInstrumentListForm->raise();
1340     m_pInstrumentListForm->setActiveWindow();
1341     }
1342     }
1343     }
1344    
1345    
1346 capela 428 // Show/hide the device configurator form.
1347     void qsamplerMainForm::viewDevices (void)
1348     {
1349 capela 586 if (m_pOptions == NULL)
1350     return;
1351 capela 428
1352 capela 586 if (m_pDeviceForm) {
1353     m_pOptions->saveWidgetGeometry(m_pDeviceForm);
1354     if (m_pDeviceForm->isVisible()) {
1355     m_pDeviceForm->hide();
1356     } else {
1357     m_pDeviceForm->show();
1358     m_pDeviceForm->raise();
1359     m_pDeviceForm->setActiveWindow();
1360     }
1361     }
1362 capela 428 }
1363    
1364    
1365 capela 109 // Show options dialog.
1366     void qsamplerMainForm::viewOptions (void)
1367     {
1368     if (m_pOptions == NULL)
1369     return;
1370    
1371     qsamplerOptionsForm *pOptionsForm = new qsamplerOptionsForm(this);
1372     if (pOptionsForm) {
1373     // Check out some initial nullities(tm)...
1374 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1375     if (m_pOptions->sDisplayFont.isEmpty() && pChannelStrip)
1376     m_pOptions->sDisplayFont = pChannelStrip->displayFont().toString();
1377 capela 109 if (m_pOptions->sMessagesFont.isEmpty() && m_pMessages)
1378     m_pOptions->sMessagesFont = m_pMessages->messagesFont().toString();
1379     // To track down deferred or immediate changes.
1380     QString sOldServerHost = m_pOptions->sServerHost;
1381     int iOldServerPort = m_pOptions->iServerPort;
1382     int iOldServerTimeout = m_pOptions->iServerTimeout;
1383     bool bOldServerStart = m_pOptions->bServerStart;
1384     QString sOldServerCmdLine = m_pOptions->sServerCmdLine;
1385     QString sOldDisplayFont = m_pOptions->sDisplayFont;
1386 capela 267 bool bOldDisplayEffect = m_pOptions->bDisplayEffect;
1387 capela 119 int iOldMaxVolume = m_pOptions->iMaxVolume;
1388 capela 109 QString sOldMessagesFont = m_pOptions->sMessagesFont;
1389 capela 454 bool bOldKeepOnTop = m_pOptions->bKeepOnTop;
1390 capela 109 bool bOldStdoutCapture = m_pOptions->bStdoutCapture;
1391     int bOldMessagesLimit = m_pOptions->bMessagesLimit;
1392     int iOldMessagesLimitLines = m_pOptions->iMessagesLimitLines;
1393     bool bOldCompletePath = m_pOptions->bCompletePath;
1394 capela 371 bool bOldInstrumentNames = m_pOptions->bInstrumentNames;
1395 capela 109 int iOldMaxRecentFiles = m_pOptions->iMaxRecentFiles;
1396     // Load the current setup settings.
1397     pOptionsForm->setup(m_pOptions);
1398     // Show the setup dialog...
1399     if (pOptionsForm->exec()) {
1400     // Warn if something will be only effective on next run.
1401     if (( bOldStdoutCapture && !m_pOptions->bStdoutCapture) ||
1402 capela 454 (!bOldStdoutCapture && m_pOptions->bStdoutCapture) ||
1403     ( bOldKeepOnTop && !m_pOptions->bKeepOnTop) ||
1404     (!bOldKeepOnTop && m_pOptions->bKeepOnTop)) {
1405 capela 757 QMessageBox::information(this,
1406     QSAMPLER_TITLE ": " + tr("Information"),
1407 capela 109 tr("Some settings may be only effective\n"
1408     "next time you start this program."), tr("OK"));
1409     updateMessagesCapture();
1410     }
1411     // Check wheather something immediate has changed.
1412     if (( bOldCompletePath && !m_pOptions->bCompletePath) ||
1413     (!bOldCompletePath && m_pOptions->bCompletePath) ||
1414     (iOldMaxRecentFiles != m_pOptions->iMaxRecentFiles))
1415     updateRecentFilesMenu();
1416 capela 371 if (( bOldInstrumentNames && !m_pOptions->bInstrumentNames) ||
1417     (!bOldInstrumentNames && m_pOptions->bInstrumentNames))
1418     updateInstrumentNames();
1419 capela 267 if (( bOldDisplayEffect && !m_pOptions->bDisplayEffect) ||
1420     (!bOldDisplayEffect && m_pOptions->bDisplayEffect))
1421     updateDisplayEffect();
1422 capela 109 if (sOldDisplayFont != m_pOptions->sDisplayFont)
1423     updateDisplayFont();
1424 capela 119 if (iOldMaxVolume != m_pOptions->iMaxVolume)
1425     updateMaxVolume();
1426 capela 109 if (sOldMessagesFont != m_pOptions->sMessagesFont)
1427     updateMessagesFont();
1428     if (( bOldMessagesLimit && !m_pOptions->bMessagesLimit) ||
1429     (!bOldMessagesLimit && m_pOptions->bMessagesLimit) ||
1430     (iOldMessagesLimitLines != m_pOptions->iMessagesLimitLines))
1431     updateMessagesLimit();
1432     // And now the main thing, whether we'll do client/server recycling?
1433     if ((sOldServerHost != m_pOptions->sServerHost) ||
1434     (iOldServerPort != m_pOptions->iServerPort) ||
1435     (iOldServerTimeout != m_pOptions->iServerTimeout) ||
1436     ( bOldServerStart && !m_pOptions->bServerStart) ||
1437     (!bOldServerStart && m_pOptions->bServerStart) ||
1438     (sOldServerCmdLine != m_pOptions->sServerCmdLine && m_pOptions->bServerStart))
1439     fileRestart();
1440     }
1441     // Done.
1442     delete pOptionsForm;
1443     }
1444    
1445     // This makes it.
1446     stabilizeForm();
1447     }
1448    
1449    
1450     //-------------------------------------------------------------------------
1451     // qsamplerMainForm -- Channels action slots.
1452    
1453     // Arrange channel strips.
1454     void qsamplerMainForm::channelsArrange (void)
1455     {
1456     // Full width vertical tiling
1457     QWidgetList wlist = m_pWorkspace->windowList();
1458     if (wlist.isEmpty())
1459     return;
1460    
1461     m_pWorkspace->setUpdatesEnabled(false);
1462     int y = 0;
1463     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1464 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1465     /* if (pChannelStrip->testWState(WState_Maximized | WState_Minimized)) {
1466 capela 109 // Prevent flicker...
1467 capela 264 pChannelStrip->hide();
1468     pChannelStrip->showNormal();
1469 capela 109 } */
1470 capela 264 pChannelStrip->adjustSize();
1471 capela 109 int iWidth = m_pWorkspace->width();
1472 capela 264 if (iWidth < pChannelStrip->width())
1473     iWidth = pChannelStrip->width();
1474     // int iHeight = pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1475     int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1476     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1477 capela 109 y += iHeight;
1478     }
1479     m_pWorkspace->setUpdatesEnabled(true);
1480 capela 586
1481 capela 109 stabilizeForm();
1482     }
1483    
1484    
1485     // Auto-arrange channel strips.
1486     void qsamplerMainForm::channelsAutoArrange ( bool bOn )
1487     {
1488     if (m_pOptions == NULL)
1489     return;
1490    
1491     // Toggle the auto-arrange flag.
1492     m_pOptions->bAutoArrange = bOn;
1493    
1494     // If on, update whole workspace...
1495     if (m_pOptions->bAutoArrange)
1496     channelsArrange();
1497     }
1498    
1499    
1500     //-------------------------------------------------------------------------
1501     // qsamplerMainForm -- Help Action slots.
1502    
1503     // Show information about the Qt toolkit.
1504     void qsamplerMainForm::helpAboutQt (void)
1505     {
1506     QMessageBox::aboutQt(this);
1507     }
1508    
1509    
1510     // Show information about application program.
1511     void qsamplerMainForm::helpAbout (void)
1512     {
1513     // Stuff the about box text...
1514     QString sText = "<p>\n";
1515     sText += "<b>" QSAMPLER_TITLE " - " + tr(QSAMPLER_SUBTITLE) + "</b><br />\n";
1516     sText += "<br />\n";
1517     sText += tr("Version") + ": <b>" QSAMPLER_VERSION "</b><br />\n";
1518     sText += "<small>" + tr("Build") + ": " __DATE__ " " __TIME__ "</small><br />\n";
1519     #ifdef CONFIG_DEBUG
1520     sText += "<small><font color=\"red\">";
1521     sText += tr("Debugging option enabled.");
1522     sText += "</font></small><br />";
1523     #endif
1524 capela 176 #ifndef CONFIG_LIBGIG
1525     sText += "<small><font color=\"red\">";
1526     sText += tr("GIG (libgig) file support disabled.");
1527     sText += "</font></small><br />";
1528     #endif
1529 capela 382 #ifndef CONFIG_INSTRUMENT_NAME
1530     sText += "<small><font color=\"red\">";
1531     sText += tr("LSCP (liblscp) instrument_name support disabled.");
1532     sText += "</font></small><br />";
1533     #endif
1534 capela 751 #ifndef CONFIG_MUTE_SOLO
1535     sText += "<small><font color=\"red\">";
1536     sText += tr("Sampler channel Mute/Solo support disabled.");
1537     sText += "</font></small><br />";
1538     #endif
1539 capela 1024 #ifndef CONFIG_AUDIO_ROUTING
1540     sText += "<small><font color=\"red\">";
1541     sText += tr("LSCP (liblscp) audio_routing support disabled.");
1542     sText += "</font></small><br />";
1543     #endif
1544     #ifndef CONFIG_FXSEND
1545     sText += "<small><font color=\"red\">";
1546     sText += tr("Sampler channel Effect Sends support disabled.");
1547     sText += "</font></small><br />";
1548     #endif
1549 capela 961 #ifndef CONFIG_MIDI_INSTRUMENT
1550     sText += "<small><font color=\"red\">";
1551     sText += tr("MIDI instrument mapping support disabled.");
1552     sText += "</font></small><br />";
1553     #endif
1554 capela 109 sText += "<br />\n";
1555     sText += tr("Using") + ": ";
1556     sText += ::lscp_client_package();
1557     sText += " ";
1558     sText += ::lscp_client_version();
1559 capela 605 #ifdef CONFIG_LIBGIG
1560 schoenebeck 519 sText += ", ";
1561 schoenebeck 736 sText += gig::libraryName().c_str();
1562 schoenebeck 519 sText += " ";
1563 schoenebeck 736 sText += gig::libraryVersion().c_str();
1564 schoenebeck 519 #endif
1565 capela 109 sText += "<br />\n";
1566     sText += "<br />\n";
1567     sText += tr("Website") + ": <a href=\"" QSAMPLER_WEBSITE "\">" QSAMPLER_WEBSITE "</a><br />\n";
1568     sText += "<br />\n";
1569     sText += "<small>";
1570     sText += QSAMPLER_COPYRIGHT "<br />\n";
1571     sText += "<br />\n";
1572     sText += tr("This program is free software; you can redistribute it and/or modify it") + "<br />\n";
1573     sText += tr("under the terms of the GNU General Public License version 2 or later.");
1574     sText += "</small>";
1575     sText += "</p>\n";
1576    
1577     QMessageBox::about(this, tr("About") + " " QSAMPLER_TITLE, sText);
1578     }
1579    
1580    
1581     //-------------------------------------------------------------------------
1582     // qsamplerMainForm -- Main window stabilization.
1583    
1584     void qsamplerMainForm::stabilizeForm (void)
1585     {
1586     // Update the main application caption...
1587 capela 418 QString sSessionName = sessionName(m_sFilename);
1588 capela 109 if (m_iDirtyCount > 0)
1589 capela 772 sSessionName += " *";
1590 capela 418 setCaption(tr(QSAMPLER_TITLE " - [%1]").arg(sSessionName));
1591 capela 109
1592     // Update the main menu state...
1593 capela 264 qsamplerChannelStrip *pChannelStrip = activeChannelStrip();
1594 capela 109 bool bHasClient = (m_pOptions != NULL && m_pClient != NULL);
1595 capela 264 bool bHasChannel = (bHasClient && pChannelStrip != NULL);
1596 capela 109 fileNewAction->setEnabled(bHasClient);
1597     fileOpenAction->setEnabled(bHasClient);
1598     fileSaveAction->setEnabled(bHasClient && m_iDirtyCount > 0);
1599     fileSaveAsAction->setEnabled(bHasClient);
1600 capela 255 fileResetAction->setEnabled(bHasClient);
1601 capela 109 fileRestartAction->setEnabled(bHasClient || m_pServer == NULL);
1602     editAddChannelAction->setEnabled(bHasClient);
1603     editRemoveChannelAction->setEnabled(bHasChannel);
1604     editSetupChannelAction->setEnabled(bHasChannel);
1605     editResetChannelAction->setEnabled(bHasChannel);
1606 capela 404 editResetAllChannelsAction->setEnabled(bHasChannel);
1607 capela 428 viewMessagesAction->setOn(m_pMessages && m_pMessages->isVisible());
1608 capela 961 #ifdef CONFIG_MIDI_INSTRUMENT
1609     viewInstrumentsAction->setOn(m_pInstrumentListForm
1610     && m_pInstrumentListForm->isVisible());
1611     viewInstrumentsAction->setEnabled(bHasClient);
1612     #endif
1613     viewDevicesAction->setOn(m_pDeviceForm
1614     && m_pDeviceForm->isVisible());
1615 capela 428 viewDevicesAction->setEnabled(bHasClient);
1616 capela 109 channelsArrangeAction->setEnabled(bHasChannel);
1617    
1618     // Client/Server status...
1619     if (bHasClient) {
1620 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->setText(tr("Connected"));
1621     m_statusItem[QSAMPLER_STATUS_SERVER]->setText(m_pOptions->sServerHost + ":" + QString::number(m_pOptions->iServerPort));
1622 capela 109 } else {
1623 capela 428 m_statusItem[QSAMPLER_STATUS_CLIENT]->clear();
1624     m_statusItem[QSAMPLER_STATUS_SERVER]->clear();
1625 capela 109 }
1626     // Channel status...
1627     if (bHasChannel)
1628 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->setText(pChannelStrip->caption());
1629 capela 109 else
1630 capela 428 m_statusItem[QSAMPLER_STATUS_CHANNEL]->clear();
1631 capela 109 // Session status...
1632     if (m_iDirtyCount > 0)
1633 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->setText(tr("MOD"));
1634 capela 109 else
1635 capela 428 m_statusItem[QSAMPLER_STATUS_SESSION]->clear();
1636 capela 109
1637     // Recent files menu.
1638     m_pRecentFilesMenu->setEnabled(bHasClient && m_pOptions->recentFiles.count() > 0);
1639    
1640     // Always make the latest message visible.
1641     if (m_pMessages)
1642     m_pMessages->scrollToBottom();
1643     }
1644    
1645    
1646     // Channel change receiver slot.
1647 capela 400 void qsamplerMainForm::channelStripChanged( qsamplerChannelStrip *pChannelStrip )
1648 capela 109 {
1649 capela 400 // Add this strip to the changed list...
1650 capela 586 if (m_changedStrips.containsRef(pChannelStrip) == 0) {
1651 capela 400 m_changedStrips.append(pChannelStrip);
1652 capela 586 pChannelStrip->resetErrorCount();
1653     }
1654 capela 400
1655 capela 109 // Just mark the dirty form.
1656     m_iDirtyCount++;
1657     // and update the form status...
1658     stabilizeForm();
1659     }
1660    
1661    
1662 capela 395 // Grab and restore current sampler channels session.
1663     void qsamplerMainForm::updateSession (void)
1664     {
1665 capela 980 #ifdef CONFIG_MIDI_INSTRUMENT
1666 capela 1013 // FIXME: Make some room for default instrument maps...
1667 capela 980 int iMaps = ::lscp_get_midi_instrument_maps(m_pClient);
1668     if (iMaps < 0)
1669     appendMessagesClient("lscp_get_midi_instrument_maps");
1670     else if (iMaps < 1) {
1671     ::lscp_add_midi_instrument_map(m_pClient, tr("Chromatic").latin1());
1672     ::lscp_add_midi_instrument_map(m_pClient, tr("Drum Kits").latin1());
1673     }
1674     #endif
1675    
1676 capela 395 // Retrieve the current channel list.
1677     int *piChannelIDs = ::lscp_list_channels(m_pClient);
1678     if (piChannelIDs == NULL) {
1679     if (::lscp_client_get_errno(m_pClient)) {
1680     appendMessagesClient("lscp_list_channels");
1681     appendMessagesError(tr("Could not get current list of channels.\n\nSorry."));
1682     }
1683 capela 987 } else {
1684     // Try to (re)create each channel.
1685     m_pWorkspace->setUpdatesEnabled(false);
1686     for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) {
1687     // Check if theres already a channel strip for this one...
1688     if (!channelStrip(piChannelIDs[iChannel]))
1689     createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel]));
1690     }
1691     m_pWorkspace->setUpdatesEnabled(true);
1692 capela 395 }
1693    
1694 capela 987 // Do we auto-arrange?
1695     if (m_pOptions && m_pOptions->bAutoArrange)
1696     channelsArrange();
1697 capela 980
1698 capela 961 // Remember to refresh devices and instruments...
1699     if (m_pInstrumentListForm)
1700     m_pInstrumentListForm->refreshInstruments();
1701 capela 469 if (m_pDeviceForm)
1702     m_pDeviceForm->refreshDevices();
1703 capela 395 }
1704    
1705    
1706 capela 109 // Update the recent files list and menu.
1707     void qsamplerMainForm::updateRecentFiles ( const QString& sFilename )
1708     {
1709     if (m_pOptions == NULL)
1710     return;
1711    
1712     // Remove from list if already there (avoid duplicates)
1713     QStringList::Iterator iter = m_pOptions->recentFiles.find(sFilename);
1714     if (iter != m_pOptions->recentFiles.end())
1715     m_pOptions->recentFiles.remove(iter);
1716     // Put it to front...
1717     m_pOptions->recentFiles.push_front(sFilename);
1718    
1719     // May update the menu.
1720     updateRecentFilesMenu();
1721     }
1722    
1723    
1724     // Update the recent files list and menu.
1725     void qsamplerMainForm::updateRecentFilesMenu (void)
1726     {
1727     if (m_pOptions == NULL)
1728     return;
1729    
1730     // Time to keep the list under limits.
1731     int iRecentFiles = m_pOptions->recentFiles.count();
1732     while (iRecentFiles > m_pOptions->iMaxRecentFiles) {
1733     m_pOptions->recentFiles.pop_back();
1734     iRecentFiles--;
1735     }
1736    
1737     // rebuild the recent files menu...
1738     m_pRecentFilesMenu->clear();
1739     for (int i = 0; i < iRecentFiles; i++) {
1740     const QString& sFilename = m_pOptions->recentFiles[i];
1741     if (QFileInfo(sFilename).exists()) {
1742     m_pRecentFilesMenu->insertItem(QString("&%1 %2")
1743     .arg(i + 1).arg(sessionName(sFilename)),
1744     this, SLOT(fileOpenRecent(int)), 0, i);
1745     }
1746     }
1747     }
1748    
1749    
1750 capela 371 // Force update of the channels instrument names mode.
1751     void qsamplerMainForm::updateInstrumentNames (void)
1752     {
1753     // Full channel list update...
1754     QWidgetList wlist = m_pWorkspace->windowList();
1755     if (wlist.isEmpty())
1756     return;
1757    
1758     m_pWorkspace->setUpdatesEnabled(false);
1759     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1760     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1761     if (pChannelStrip)
1762     pChannelStrip->updateInstrumentName(true);
1763     }
1764     m_pWorkspace->setUpdatesEnabled(true);
1765     }
1766    
1767    
1768 capela 109 // Force update of the channels display font.
1769     void qsamplerMainForm::updateDisplayFont (void)
1770     {
1771     if (m_pOptions == NULL)
1772     return;
1773    
1774     // Check if display font is legal.
1775     if (m_pOptions->sDisplayFont.isEmpty())
1776     return;
1777     // Realize it.
1778     QFont font;
1779     if (!font.fromString(m_pOptions->sDisplayFont))
1780     return;
1781    
1782     // Full channel list update...
1783     QWidgetList wlist = m_pWorkspace->windowList();
1784     if (wlist.isEmpty())
1785     return;
1786    
1787     m_pWorkspace->setUpdatesEnabled(false);
1788     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1789 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1790     if (pChannelStrip)
1791     pChannelStrip->setDisplayFont(font);
1792 capela 109 }
1793     m_pWorkspace->setUpdatesEnabled(true);
1794     }
1795    
1796    
1797 capela 267 // Update channel strips background effect.
1798     void qsamplerMainForm::updateDisplayEffect (void)
1799     {
1800     QPixmap pm;
1801     if (m_pOptions->bDisplayEffect)
1802     pm = QPixmap::fromMimeSource("displaybg1.png");
1803    
1804     // Full channel list update...
1805     QWidgetList wlist = m_pWorkspace->windowList();
1806     if (wlist.isEmpty())
1807     return;
1808    
1809     m_pWorkspace->setUpdatesEnabled(false);
1810     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1811     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1812     if (pChannelStrip)
1813     pChannelStrip->setDisplayBackground(pm);
1814     }
1815     m_pWorkspace->setUpdatesEnabled(true);
1816     }
1817    
1818    
1819 capela 119 // Force update of the channels maximum volume setting.
1820     void qsamplerMainForm::updateMaxVolume (void)
1821     {
1822     if (m_pOptions == NULL)
1823     return;
1824    
1825     // Full channel list update...
1826     QWidgetList wlist = m_pWorkspace->windowList();
1827     if (wlist.isEmpty())
1828     return;
1829    
1830     m_pWorkspace->setUpdatesEnabled(false);
1831     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1832 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1833     if (pChannelStrip)
1834     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1835 capela 119 }
1836     m_pWorkspace->setUpdatesEnabled(true);
1837     }
1838    
1839    
1840 capela 109 //-------------------------------------------------------------------------
1841     // qsamplerMainForm -- Messages window form handlers.
1842    
1843     // Messages output methods.
1844     void qsamplerMainForm::appendMessages( const QString& s )
1845     {
1846     if (m_pMessages)
1847     m_pMessages->appendMessages(s);
1848    
1849     statusBar()->message(s, 3000);
1850     }
1851    
1852     void qsamplerMainForm::appendMessagesColor( const QString& s, const QString& c )
1853     {
1854     if (m_pMessages)
1855     m_pMessages->appendMessagesColor(s, c);
1856    
1857     statusBar()->message(s, 3000);
1858     }
1859    
1860     void qsamplerMainForm::appendMessagesText( const QString& s )
1861     {
1862     if (m_pMessages)
1863     m_pMessages->appendMessagesText(s);
1864     }
1865    
1866     void qsamplerMainForm::appendMessagesError( const QString& s )
1867     {
1868     if (m_pMessages)
1869     m_pMessages->show();
1870    
1871     appendMessagesColor(s.simplifyWhiteSpace(), "#ff0000");
1872    
1873 capela 987 // Make it look responsive...:)
1874     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1875    
1876 capela 757 QMessageBox::critical(this,
1877     QSAMPLER_TITLE ": " + tr("Error"), s, tr("Cancel"));
1878 capela 109 }
1879    
1880    
1881     // This is a special message format, just for client results.
1882     void qsamplerMainForm::appendMessagesClient( const QString& s )
1883     {
1884     if (m_pClient == NULL)
1885     return;
1886    
1887     appendMessagesColor(s + QString(": %1 (errno=%2)")
1888     .arg(::lscp_client_get_result(m_pClient))
1889     .arg(::lscp_client_get_errno(m_pClient)), "#996666");
1890 capela 987
1891     // Make it look responsive...:)
1892     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
1893 capela 109 }
1894    
1895    
1896     // Force update of the messages font.
1897     void qsamplerMainForm::updateMessagesFont (void)
1898     {
1899     if (m_pOptions == NULL)
1900     return;
1901    
1902     if (m_pMessages && !m_pOptions->sMessagesFont.isEmpty()) {
1903     QFont font;
1904     if (font.fromString(m_pOptions->sMessagesFont))
1905     m_pMessages->setMessagesFont(font);
1906     }
1907     }
1908    
1909    
1910     // Update messages window line limit.
1911     void qsamplerMainForm::updateMessagesLimit (void)
1912     {
1913     if (m_pOptions == NULL)
1914     return;
1915    
1916     if (m_pMessages) {
1917     if (m_pOptions->bMessagesLimit)
1918     m_pMessages->setMessagesLimit(m_pOptions->iMessagesLimitLines);
1919     else
1920 capela 661 m_pMessages->setMessagesLimit(-1);
1921 capela 109 }
1922     }
1923    
1924    
1925     // Enablement of the messages capture feature.
1926     void qsamplerMainForm::updateMessagesCapture (void)
1927     {
1928     if (m_pOptions == NULL)
1929     return;
1930    
1931     if (m_pMessages)
1932     m_pMessages->setCaptureEnabled(m_pOptions->bStdoutCapture);
1933     }
1934    
1935    
1936     //-------------------------------------------------------------------------
1937     // qsamplerMainForm -- MDI channel strip management.
1938    
1939     // The channel strip creation executive.
1940 capela 303 qsamplerChannelStrip *qsamplerMainForm::createChannelStrip ( qsamplerChannel *pChannel )
1941 capela 109 {
1942 capela 303 if (m_pClient == NULL || pChannel == NULL)
1943 capela 295 return NULL;
1944 capela 109
1945     // Prepare for auto-arrange?
1946 capela 264 qsamplerChannelStrip *pChannelStrip = NULL;
1947 capela 109 int y = 0;
1948     if (m_pOptions && m_pOptions->bAutoArrange) {
1949     QWidgetList wlist = m_pWorkspace->windowList();
1950     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
1951 capela 264 pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
1952 capela 395 if (pChannelStrip) {
1953     // y += pChannelStrip->height() + pChannelStrip->parentWidget()->baseSize().height();
1954     y += pChannelStrip->parentWidget()->frameGeometry().height();
1955     }
1956 capela 109 }
1957     }
1958    
1959     // Add a new channel itema...
1960     WFlags wflags = Qt::WStyle_Customize | Qt::WStyle_Tool | Qt::WStyle_Title | Qt::WStyle_NoBorder;
1961 capela 264 pChannelStrip = new qsamplerChannelStrip(m_pWorkspace, 0, wflags);
1962 capela 303 if (pChannelStrip == NULL)
1963     return NULL;
1964 capela 586
1965 capela 303 // Actual channel strip setup...
1966     pChannelStrip->setup(pChannel);
1967 capela 1018 QObject::connect(pChannelStrip,
1968     SIGNAL(channelChanged(qsamplerChannelStrip *)),
1969     SLOT(channelStripChanged(qsamplerChannelStrip *)));
1970 capela 267 // Set some initial aesthetic options...
1971     if (m_pOptions) {
1972     // Background display effect...
1973     pChannelStrip->setDisplayEffect(m_pOptions->bDisplayEffect);
1974     // We'll need a display font.
1975     QFont font;
1976     if (font.fromString(m_pOptions->sDisplayFont))
1977     pChannelStrip->setDisplayFont(font);
1978     // Maximum allowed volume setting.
1979     pChannelStrip->setMaxVolume(m_pOptions->iMaxVolume);
1980     }
1981 capela 295
1982 capela 109 // Now we show up us to the world.
1983 capela 264 pChannelStrip->show();
1984 capela 109 // Only then, we'll auto-arrange...
1985     if (m_pOptions && m_pOptions->bAutoArrange) {
1986     int iWidth = m_pWorkspace->width();
1987     // int iHeight = pChannel->height() + pChannel->parentWidget()->baseSize().height();
1988 capela 264 int iHeight = pChannelStrip->parentWidget()->frameGeometry().height();
1989     pChannelStrip->parentWidget()->setGeometry(0, y, iWidth, iHeight);
1990 capela 109 }
1991 capela 400
1992     // This is pretty new, so we'll watch for it closely.
1993     channelStripChanged(pChannelStrip);
1994    
1995 capela 295 // Return our successful reference...
1996     return pChannelStrip;
1997 capela 109 }
1998    
1999    
2000     // Retrieve the active channel strip.
2001 capela 264 qsamplerChannelStrip *qsamplerMainForm::activeChannelStrip (void)
2002 capela 109 {
2003     return (qsamplerChannelStrip *) m_pWorkspace->activeWindow();
2004     }
2005    
2006    
2007     // Retrieve a channel strip by index.
2008 capela 264 qsamplerChannelStrip *qsamplerMainForm::channelStripAt ( int iChannel )
2009 capela 109 {
2010     QWidgetList wlist = m_pWorkspace->windowList();
2011     if (wlist.isEmpty())
2012 capela 395 return NULL;
2013 capela 109
2014     return (qsamplerChannelStrip *) wlist.at(iChannel);
2015     }
2016    
2017    
2018 capela 395 // Retrieve a channel strip by sampler channel id.
2019     qsamplerChannelStrip *qsamplerMainForm::channelStrip ( int iChannelID )
2020     {
2021     QWidgetList wlist = m_pWorkspace->windowList();
2022     if (wlist.isEmpty())
2023     return NULL;
2024 capela 586
2025 capela 395 for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2026     qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
2027     if (pChannelStrip) {
2028     qsamplerChannel *pChannel = pChannelStrip->channel();
2029     if (pChannel && pChannel->channelID() == iChannelID)
2030     return pChannelStrip;
2031     }
2032     }
2033    
2034     // Not found.
2035     return NULL;
2036     }
2037    
2038    
2039 capela 109 // Construct the windows menu.
2040     void qsamplerMainForm::channelsMenuAboutToShow (void)
2041     {
2042     channelsMenu->clear();
2043     channelsArrangeAction->addTo(channelsMenu);
2044     channelsAutoArrangeAction->addTo(channelsMenu);
2045    
2046     QWidgetList wlist = m_pWorkspace->windowList();
2047     if (!wlist.isEmpty()) {
2048     channelsMenu->insertSeparator();
2049     for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) {
2050 capela 264 qsamplerChannelStrip *pChannelStrip = (qsamplerChannelStrip *) wlist.at(iChannel);
2051     if (pChannelStrip) {
2052     int iItemID = channelsMenu->insertItem(pChannelStrip->caption(), this, SLOT(channelsMenuActivated(int)));
2053     channelsMenu->setItemParameter(iItemID, iChannel);
2054     channelsMenu->setItemChecked(iItemID, activeChannelStrip() == pChannelStrip);
2055     }
2056 capela 109 }
2057     }
2058     }
2059    
2060    
2061     // Windows menu activation slot
2062     void qsamplerMainForm::channelsMenuActivated ( int iChannel )
2063     {
2064 capela 264 qsamplerChannelStrip *pChannelStrip = channelStripAt(iChannel);
2065     if (pChannelStrip)
2066     pChannelStrip->showNormal();
2067     pChannelStrip->setFocus();
2068 capela 109 }
2069    
2070    
2071     //-------------------------------------------------------------------------
2072     // qsamplerMainForm -- Timer stuff.
2073    
2074     // Set the pseudo-timer delay schedule.
2075     void qsamplerMainForm::startSchedule ( int iStartDelay )
2076     {
2077     m_iStartDelay = 1 + (iStartDelay * 1000);
2078     m_iTimerDelay = 0;
2079     }
2080    
2081     // Suspend the pseudo-timer delay schedule.
2082     void qsamplerMainForm::stopSchedule (void)
2083     {
2084     m_iStartDelay = 0;
2085     m_iTimerDelay = 0;
2086     }
2087    
2088     // Timer slot funtion.
2089     void qsamplerMainForm::timerSlot (void)
2090     {
2091     if (m_pOptions == NULL)
2092     return;
2093    
2094     // Is it the first shot on server start after a few delay?
2095     if (m_iTimerDelay < m_iStartDelay) {
2096     m_iTimerDelay += QSAMPLER_TIMER_MSECS;
2097     if (m_iTimerDelay >= m_iStartDelay) {
2098     // If we cannot start it now, maybe a lil'mo'later ;)
2099     if (!startClient()) {
2100     m_iStartDelay += m_iTimerDelay;
2101     m_iTimerDelay = 0;
2102     }
2103     }
2104     }
2105 capela 586
2106 capela 664 if (m_pClient) {
2107     // Update the channel information for each pending strip...
2108     if (m_changedStrips.count() > 0) {
2109 capela 586 for (qsamplerChannelStrip *pChannelStrip = m_changedStrips.first();
2110 capela 664 pChannelStrip; pChannelStrip = m_changedStrips.next()) {
2111 capela 400 // If successfull, remove from pending list...
2112     if (pChannelStrip->updateChannelInfo())
2113 capela 586 m_changedStrips.remove(pChannelStrip);
2114 capela 400 }
2115 capela 664 }
2116     // Refresh each channel usage, on each period...
2117     if (m_pOptions->bAutoRefresh) {
2118     m_iTimerSlot += QSAMPLER_TIMER_MSECS;
2119     if (m_iTimerSlot >= m_pOptions->iAutoRefreshTime) {
2120     m_iTimerSlot = 0;
2121     // Update the channel stream usage for each strip...
2122     QWidgetList wlist = m_pWorkspace->windowList();
2123     for (int iChannel = 0;
2124     iChannel < (int) wlist.count(); iChannel++) {
2125     qsamplerChannelStrip *pChannelStrip
2126     = (qsamplerChannelStrip *) wlist.at(iChannel);
2127     if (pChannelStrip && pChannelStrip->isVisible())
2128     pChannelStrip->updateChannelUsage();
2129     }
2130 capela 586 }
2131     }
2132     }
2133 capela 109
2134     // Register the next timer slot.
2135     QTimer::singleShot(QSAMPLER_TIMER_MSECS, this, SLOT(timerSlot()));
2136     }
2137    
2138    
2139     //-------------------------------------------------------------------------
2140     // qsamplerMainForm -- Server stuff.
2141    
2142     // Start linuxsampler server...
2143     void qsamplerMainForm::startServer (void)
2144     {
2145     if (m_pOptions == NULL)
2146     return;
2147    
2148     // Aren't already a client, are we?
2149     if (!m_pOptions->bServerStart || m_pClient)
2150     return;
2151    
2152     // Is the server process instance still here?
2153     if (m_pServer) {
2154 capela 757 switch (QMessageBox::warning(this,
2155     QSAMPLER_TITLE ": " + tr("Warning"),
2156 capela 109 tr("Could not start the LinuxSampler server.\n\n"
2157     "Maybe it ss already started."),
2158     tr("Stop"), tr("Kill"), tr("Cancel"))) {
2159     case 0:
2160     m_pServer->tryTerminate();
2161     break;
2162     case 1:
2163     m_pServer->kill();
2164     break;
2165     }
2166     return;
2167     }
2168    
2169     // Reset our timer counters...
2170     stopSchedule();
2171    
2172     // OK. Let's build the startup process...
2173     m_pServer = new QProcess(this);
2174    
2175     // Setup stdout/stderr capture...
2176 capela 1018 // if (m_pOptions->bStdoutCapture) {
2177     m_pServer->setCommunication(
2178     QProcess::Stdout | QProcess::Stderr | QProcess::DupStderr);
2179     QObject::connect(m_pServer,
2180     SIGNAL(readyReadStdout()),
2181     SLOT(readServerStdout()));
2182     QObject::connect(m_pServer,
2183     SIGNAL(readyReadStderr()),
2184     SLOT(readServerStdout()));
2185     // }
2186     // The unforgiveable signal communication...
2187     QObject::connect(m_pServer,
2188     SIGNAL(processExited()),
2189     SLOT(processServerExit()));
2190 capela 109
2191     // Build process arguments...
2192     m_pServer->setArguments(QStringList::split(' ', m_pOptions->sServerCmdLine));
2193    
2194     appendMessages(tr("Server is starting..."));
2195     appendMessagesColor(m_pOptions->sServerCmdLine, "#990099");
2196    
2197     // Go jack, go...
2198     if (!m_pServer->start()) {
2199     appendMessagesError(tr("Could not start server.\n\nSorry."));
2200     processServerExit();
2201     return;
2202     }
2203    
2204     // Show startup results...
2205     appendMessages(tr("Server was started with PID=%1.").arg((long) m_pServer->processIdentifier()));
2206    
2207     // Reset (yet again) the timer counters,
2208     // but this time is deferred as the user opted.
2209     startSchedule(m_pOptions->iStartDelay);
2210     stabilizeForm();
2211     }
2212    
2213    
2214     // Stop linuxsampler server...
2215     void qsamplerMainForm::stopServer (void)
2216     {
2217     // Stop client code.
2218     stopClient();
2219    
2220     // And try to stop server.
2221     if (m_pServer) {
2222     appendMessages(tr("Server is stopping..."));
2223 capela 122 if (m_pServer->isRunning())
2224 capela 109 m_pServer->tryTerminate();
2225     }
2226    
2227 capela 122 // Give it some time to terminate gracefully and stabilize...
2228     QTime t;
2229     t.start();
2230     while (t.elapsed() < QSAMPLER_TIMER_MSECS)
2231     QApplication::eventLoop()->processEvents(QEventLoop::ExcludeUserInput);
2232    
2233 capela 109 // Do final processing anyway.
2234     processServerExit();
2235     }
2236    
2237    
2238     // Stdout handler...
2239     void qsamplerMainForm::readServerStdout (void)
2240     {
2241     if (m_pMessages)
2242     m_pMessages->appendStdoutBuffer(m_pServer->readStdout());
2243     }
2244    
2245    
2246     // Linuxsampler server cleanup.
2247     void qsamplerMainForm::processServerExit (void)
2248     {
2249     // Force client code cleanup.
2250     stopClient();
2251    
2252     // Flush anything that maybe pending...
2253     if (m_pMessages)
2254     m_pMessages->flushStdoutBuffer();
2255    
2256     if (m_pServer) {
2257     // Force final server shutdown...
2258     appendMessages(tr("Server was stopped with exit status %1.").arg(m_pServer->exitStatus()));
2259     if (!m_pServer->normalExit())
2260     m_pServer->kill();
2261     // Destroy it.
2262     delete m_pServer;
2263     m_pServer = NULL;
2264     }
2265    
2266     // Again, make status visible stable.
2267     stabilizeForm();
2268     }
2269    
2270    
2271     //-------------------------------------------------------------------------
2272     // qsamplerMainForm -- Client stuff.
2273    
2274     // The LSCP client callback procedure.
2275 capela 149 lscp_status_t qsampler_client_callback ( lscp_client_t */*pClient*/, lscp_event_t event, const char *pchData, int cchData, void *pvData )
2276 capela 109 {
2277 capela 149 qsamplerMainForm *pMainForm = (qsamplerMainForm *) pvData;
2278     if (pMainForm == NULL)
2279     return LSCP_FAILED;
2280    
2281     // ATTN: DO NOT EVER call any GUI code here,
2282 capela 145 // as this is run under some other thread context.
2283     // A custom event must be posted here...
2284 capela 149 QApplication::postEvent(pMainForm, new qsamplerCustomEvent(event, pchData, cchData));
2285 capela 109
2286     return LSCP_OK;
2287     }
2288    
2289    
2290     // Start our almighty client...
2291     bool qsamplerMainForm::startClient (void)
2292     {
2293     // Have it a setup?
2294     if (m_pOptions == NULL)
2295     return false;
2296    
2297     // Aren't we already started, are we?
2298     if (m_pClient)
2299     return true;
2300    
2301     // Log prepare here.
2302     appendMessages(tr("Client connecting..."));
2303    
2304     // Create the client handle...
2305     m_pClient = ::lscp_client_create(m_pOptions->sServerHost.latin1(), m_pOptions->iServerPort, qsampler_client_callback, this);
2306     if (m_pClient == NULL) {
2307     // Is this the first try?
2308     // maybe we need to start a local server...
2309     if ((m_pServer && m_pServer->isRunning()) || !m_pOptions->bServerStart)
2310     appendMessagesError(tr("Could not connect to server as client.\n\nSorry."));
2311     else
2312     startServer();
2313     // This is always a failure.
2314     stabilizeForm();
2315     return false;
2316     }
2317     // Just set receive timeout value, blindly.
2318     ::lscp_client_set_timeout(m_pClient, m_pOptions->iServerTimeout);
2319     appendMessages(tr("Client receive timeout is set to %1 msec.").arg(::lscp_client_get_timeout(m_pClient)));
2320    
2321 capela 662 // Subscribe to channel info change notifications...
2322     if (::lscp_client_subscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO) != LSCP_OK)
2323     appendMessagesClient("lscp_client_subscribe");
2324    
2325 capela 109 // We may stop scheduling around.
2326     stopSchedule();
2327    
2328     // We'll accept drops from now on...
2329     setAcceptDrops(true);
2330    
2331     // Log success here.
2332     appendMessages(tr("Client connected."));
2333    
2334 capela 961 // Hard-notify instrumnet and device configuration forms,
2335 capela 428 // if visible, that we're ready...
2336 capela 961 if (m_pInstrumentListForm)
2337     m_pInstrumentListForm->refreshInstruments();
2338     if (m_pDeviceForm)
2339     m_pDeviceForm->refreshDevices();
2340 capela 662
2341 capela 109 // Is any session pending to be loaded?
2342     if (!m_pOptions->sSessionFile.isEmpty()) {
2343     // Just load the prabably startup session...
2344     if (loadSessionFile(m_pOptions->sSessionFile)) {
2345     m_pOptions->sSessionFile = QString::null;
2346     return true;
2347     }
2348     }
2349    
2350     // Make a new session
2351     return newSession();
2352     }
2353    
2354    
2355     // Stop client...
2356     void qsamplerMainForm::stopClient (void)
2357     {
2358     if (m_pClient == NULL)
2359     return;
2360    
2361     // Log prepare here.
2362     appendMessages(tr("Client disconnecting..."));
2363    
2364     // Clear timer counters...
2365     stopSchedule();
2366    
2367     // We'll reject drops from now on...
2368     setAcceptDrops(false);
2369    
2370     // Force any channel strips around, but
2371     // but avoid removing the corresponding
2372     // channels from the back-end server.
2373     m_iDirtyCount = 0;
2374     closeSession(false);
2375 capela 586
2376 capela 109 // Close us as a client...
2377 capela 662 ::lscp_client_unsubscribe(m_pClient, LSCP_EVENT_CHANNEL_INFO);
2378     ::lscp_client_destroy(m_pClient);
2379 capela 109 m_pClient = NULL;
2380    
2381 capela 961 // Hard-notify instrumnet and device configuration forms,
2382     // if visible, that we're running out...
2383     if (m_pInstrumentListForm)
2384     m_pInstrumentListForm->refreshInstruments();
2385     if (m_pDeviceForm)
2386     m_pDeviceForm->refreshDevices();
2387    
2388 capela 109 // Log final here.
2389     appendMessages(tr("Client disconnected."));
2390    
2391     // Make visible status.
2392     stabilizeForm();
2393     }
2394    
2395    
2396     // end of qsamplerMainForm.ui.h

  ViewVC Help
Powered by ViewVC