/[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 1018 - (hide annotations) (download) (as text)
Wed Jan 10 19:39:00 2007 UTC (17 years, 2 months ago) by capela
File MIME type: text/x-c++hdr
File size: 72526 byte(s)
* Regression on sampler channel strip display,
 MIDI port / channel is now back.

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

  ViewVC Help
Powered by ViewVC