/[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 1036 - (hide annotations) (download) (as text)
Mon Jan 15 19:11:59 2007 UTC (15 years, 4 months ago) by capela
File MIME type: text/x-c++hdr
File size: 77085 byte(s)
* Master volume slider has tick marks and value is now
  rounded properly on session startup.
* Channel button colors have changed: yellow for mute
  and cyan for solo is now the rule, but note that this color
  highlighting is only rendered on some widget styles.

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

  ViewVC Help
Powered by ViewVC