/[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 477 - (show annotations) (download) (as text)
Fri Mar 18 22:38:44 2005 UTC (19 years, 1 month ago) by capela
File MIME type: text/x-c++hdr
File size: 65724 byte(s)
* Fixed device parameter settings on session save.

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

  ViewVC Help
Powered by ViewVC