/[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 1000 - (hide annotations) (download) (as text)
Fri Dec 22 01:31:28 2006 UTC (17 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 73559 byte(s)
* Fixed sampler channel MIDI instrument map assignment on session save.

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

  ViewVC Help
Powered by ViewVC