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

  ViewVC Help
Powered by ViewVC