/[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 455 - (show annotations) (download) (as text)
Mon Mar 14 12:59:27 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 64096 byte(s)
* Device configuration is now included and saved on session files.

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

  ViewVC Help
Powered by ViewVC