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

  ViewVC Help
Powered by ViewVC