/[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 487 - (show annotations) (download) (as text)
Thu Mar 31 14:17:19 2005 UTC (19 years ago) by capela
File MIME type: text/x-c++hdr
File size: 65802 byte(s)
* Device setup is now also accessible from the sampler channel dialog.

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

  ViewVC Help
Powered by ViewVC