/[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 519 - (show annotations) (download) (as text)
Sun May 8 17:04:10 2005 UTC (18 years, 10 months ago) by schoenebeck
File MIME type: text/x-c++hdr
File size: 65977 byte(s)
* Show appropriate message in channel strip while loading an instrument.
* Show libgig version in About box (in case libgig is used).

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

  ViewVC Help
Powered by ViewVC