/[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 995 - (hide annotations) (download) (as text)
Thu Dec 21 13:58:52 2006 UTC (17 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 73272 byte(s)
* Manual sampler reset also resets all MIDI instrument maps.

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

  ViewVC Help
Powered by ViewVC