/[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 1034 - (hide annotations) (download) (as text)
Mon Jan 15 16:21:01 2007 UTC (17 years, 3 months ago) by capela
File MIME type: text/x-c++hdr
File size: 76852 byte(s)
* Master sampler volume slider/spinbox combo is now featured.

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

  ViewVC Help
Powered by ViewVC