/[svn]/qsampler/trunk/src/qsamplerMainForm.ui.h
ViewVC logotype

Contents of /qsampler/trunk/src/qsamplerMainForm.ui.h

Parent Directory Parent Directory | Revision Log Revision Log


Revision 463 - (show annotations) (download) (as text)
Tue Mar 15 15:32:29 2005 UTC (19 years, 1 month ago) by capela
File MIME type: text/x-c++hdr
File size: 65100 byte(s)
* Device port/channel configuration is now complete (EXPERIMENTAL).

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

  ViewVC Help
Powered by ViewVC