--- qsampler/trunk/src/qsamplerMainForm.cpp 2007/11/23 18:15:33 1515 +++ qsampler/trunk/src/qsamplerMainForm.cpp 2008/01/05 13:29:11 1626 @@ -77,6 +77,15 @@ } #endif + +// All winsock apps needs this. +#if defined(WIN32) +static WSADATA _wsaData; +#endif + + +namespace QSampler { + // Timer constant stuff. #define QSAMPLER_TIMER_MSECS 200 @@ -87,23 +96,17 @@ #define QSAMPLER_STATUS_SESSION 3 // Current session modification state. -// All winsock apps needs this. -#if defined(WIN32) -static WSADATA _wsaData; -#endif - - //------------------------------------------------------------------------- -// qsamplerCustomEvent -- specialty for callback comunication. +// CustomEvent -- specialty for callback comunication. #define QSAMPLER_CUSTOM_EVENT QEvent::Type(QEvent::User + 0) -class qsamplerCustomEvent : public QEvent +class CustomEvent : public QEvent { public: // Constructor. - qsamplerCustomEvent(lscp_event_t event, const char *pchData, int cchData) + CustomEvent(lscp_event_t event, const char *pchData, int cchData) : QEvent(QSAMPLER_CUSTOM_EVENT) { m_event = event; @@ -126,8 +129,6 @@ //------------------------------------------------------------------------- // qsamplerMainForm -- Main window form implementation. -namespace QSampler { - // Kind of singleton reference. MainForm* MainForm::g_pMainForm = NULL; @@ -366,7 +367,7 @@ // Make and set a proper setup options step. -void MainForm::setup ( qsamplerOptions *pOptions ) +void MainForm::setup ( Options *pOptions ) { // We got options? m_pOptions = pOptions; @@ -382,7 +383,7 @@ if (m_pOptions->bKeepOnTop) wflags |= Qt::Tool; // Some child forms are to be created right now. - m_pMessages = new qsamplerMessages(this); + m_pMessages = new Messages(this); m_pDeviceForm = new DeviceForm(this, wflags); #ifdef CONFIG_MIDI_INSTRUMENT m_pInstrumentListForm = new InstrumentListForm(this, wflags); @@ -470,7 +471,7 @@ if (m_pDeviceForm) m_pDeviceForm->close(); // Stop client and/or server, gracefully. - stopServer(); + stopServer(true /*interactive*/); } } @@ -511,9 +512,9 @@ QListIterator iter(pMimeData->urls()); while (iter.hasNext()) { const QString& sPath = iter.next().toLocalFile(); - if (qsamplerChannel::isInstrumentFile(sPath)) { + if (Channel::isInstrumentFile(sPath)) { // Try to create a new channel from instrument file... - qsamplerChannel *pChannel = new qsamplerChannel(); + Channel *pChannel = new Channel(); if (pChannel == NULL) return; // Start setting the instrument filename... @@ -549,7 +550,7 @@ { // For the time being, just pump it to messages. if (pCustomEvent->type() == QSAMPLER_CUSTOM_EVENT) { - qsamplerCustomEvent *pEvent = (qsamplerCustomEvent *) pCustomEvent; + CustomEvent *pEvent = static_cast (pCustomEvent); if (pEvent->event() == LSCP_EVENT_CHANNEL_INFO) { int iChannelID = pEvent->data().toInt(); ChannelStrip *pChannelStrip = channelStrip(iChannelID); @@ -576,7 +577,7 @@ // qsamplerMainForm -- Brainless public property accessors. // The global options settings property. -qsamplerOptions *MainForm::options (void) const +Options *MainForm::options (void) const { return m_pOptions; } @@ -737,7 +738,7 @@ for (int iChannel = 0; iChannel < (int) wlist.count(); iChannel++) { ChannelStrip *pChannelStrip = (ChannelStrip*) wlist.at(iChannel); if (pChannelStrip) { - qsamplerChannel *pChannel = pChannelStrip->channel(); + Channel *pChannel = pChannelStrip->channel(); if (bForce && pChannel) pChannel->removeChannel(); delete pChannelStrip; @@ -877,33 +878,33 @@ // Audio device mapping. QMap audioDeviceMap; - piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Audio); + piDeviceIDs = Device::getDevices(m_pClient, Device::Audio); for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { ts << endl; - qsamplerDevice device(qsamplerDevice::Audio, piDeviceIDs[iDevice]); + Device device(Device::Audio, piDeviceIDs[iDevice]); // Audio device specification... ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName(); - qsamplerDeviceParamMap::ConstIterator deviceParam; + DeviceParamMap::ConstIterator deviceParam; for (deviceParam = device.params().begin(); deviceParam != device.params().end(); ++deviceParam) { - const qsamplerDeviceParam& param = deviceParam.value(); + const DeviceParam& param = deviceParam.value(); if (param.value.isEmpty()) ts << "# "; ts << " " << deviceParam.key() << "='" << param.value << "'"; } ts << endl; // Audio channel parameters... int iPort = 0; - QListIterator iter(device.ports()); + QListIterator iter(device.ports()); while (iter.hasNext()) { - qsamplerDevicePort *pPort = iter.next(); - qsamplerDeviceParamMap::ConstIterator portParam; + DevicePort *pPort = iter.next(); + DeviceParamMap::ConstIterator portParam; for (portParam = pPort->params().begin(); portParam != pPort->params().end(); ++portParam) { - const qsamplerDeviceParam& param = portParam.value(); + const DeviceParam& param = portParam.value(); if (param.fix || param.value.isEmpty()) ts << "# "; ts << "SET AUDIO_OUTPUT_CHANNEL_PARAMETER " << iDevice << " " << iPort << " " << portParam.key() @@ -919,33 +920,33 @@ // MIDI device mapping. QMap midiDeviceMap; - piDeviceIDs = qsamplerDevice::getDevices(m_pClient, qsamplerDevice::Midi); + piDeviceIDs = Device::getDevices(m_pClient, Device::Midi); for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { ts << endl; - qsamplerDevice device(qsamplerDevice::Midi, piDeviceIDs[iDevice]); + Device device(Device::Midi, piDeviceIDs[iDevice]); // MIDI device specification... ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName(); - qsamplerDeviceParamMap::ConstIterator deviceParam; + DeviceParamMap::ConstIterator deviceParam; for (deviceParam = device.params().begin(); deviceParam != device.params().end(); ++deviceParam) { - const qsamplerDeviceParam& param = deviceParam.value(); + const DeviceParam& param = deviceParam.value(); if (param.value.isEmpty()) ts << "# "; ts << " " << deviceParam.key() << "='" << param.value << "'"; } ts << endl; // MIDI port parameters... int iPort = 0; - QListIterator iter(device.ports()); + QListIterator iter(device.ports()); while (iter.hasNext()) { - qsamplerDevicePort *pPort = iter.next(); - qsamplerDeviceParamMap::ConstIterator portParam; + DevicePort *pPort = iter.next(); + DeviceParamMap::ConstIterator portParam; for (portParam = pPort->params().begin(); portParam != pPort->params().end(); ++portParam) { - const qsamplerDeviceParam& param = portParam.value(); + const DeviceParam& param = portParam.value(); if (param.fix || param.value.isEmpty()) ts << "# "; ts << "SET MIDI_INPUT_PORT_PARAMETER " << iDevice << " " << iPort << " " << portParam.key() @@ -1037,7 +1038,7 @@ ChannelStrip* pChannelStrip = static_cast (wlist.at(iChannel)); if (pChannelStrip) { - qsamplerChannel *pChannel = pChannelStrip->channel(); + Channel *pChannel = pChannelStrip->channel(); if (pChannel) { ts << "# " << tr("Channel") << " " << iChannel << endl; ts << "ADD CHANNEL" << endl; @@ -1069,7 +1070,7 @@ ts << "LOAD INSTRUMENT NON_MODAL '" << pChannel->instrumentFile() << "' " << pChannel->instrumentNr() << " " << iChannel << endl; - qsamplerChannelRoutingMap::ConstIterator audioRoute; + ChannelRoutingMap::ConstIterator audioRoute; for (audioRoute = pChannel->audioRouting().begin(); audioRoute != pChannel->audioRouting().end(); ++audioRoute) { @@ -1314,7 +1315,7 @@ return; // Just create the channel instance... - qsamplerChannel *pChannel = new qsamplerChannel(); + Channel *pChannel = new Channel(); if (pChannel == NULL) return; @@ -1352,7 +1353,7 @@ if (pChannelStrip == NULL) return; - qsamplerChannel *pChannel = pChannelStrip->channel(); + Channel *pChannel = pChannelStrip->channel(); if (pChannel == NULL) return; @@ -1924,7 +1925,7 @@ for (int iChannel = 0; piChannelIDs[iChannel] >= 0; iChannel++) { // Check if theres already a channel strip for this one... if (!channelStrip(piChannelIDs[iChannel])) - createChannelStrip(new qsamplerChannel(piChannelIDs[iChannel])); + createChannelStrip(new Channel(piChannelIDs[iChannel])); } m_pWorkspace->setUpdatesEnabled(true); } @@ -2176,7 +2177,7 @@ // qsamplerMainForm -- MDI channel strip management. // The channel strip creation executive. -ChannelStrip* MainForm::createChannelStrip ( qsamplerChannel *pChannel ) +ChannelStrip* MainForm::createChannelStrip ( Channel *pChannel ) { if (m_pClient == NULL || pChannel == NULL) return NULL; @@ -2248,7 +2249,7 @@ ChannelStrip* pChannelStrip = static_cast (wlist.at(iChannel)); if (pChannelStrip) { - qsamplerChannel *pChannel = pChannelStrip->channel(); + Channel *pChannel = pChannelStrip->channel(); if (pChannel && pChannel->channelID() == iChannelID) return pChannelStrip; } @@ -2389,7 +2390,7 @@ switch (QMessageBox::warning(this, QSAMPLER_TITLE ": " + tr("Warning"), tr("Could not start the LinuxSampler server.\n\n" - "Maybe it ss already started."), + "Maybe it is already started."), tr("Stop"), tr("Kill"), tr("Cancel"))) { case 0: m_pServer->terminate(); @@ -2409,12 +2410,14 @@ return; // OK. Let's build the startup process... - m_pServer = new QProcess(this); + m_pServer = new QProcess(); + bForceServerStop = true; // Setup stdout/stderr capture... // if (m_pOptions->bStdoutCapture) { - //m_pServer->setProcessChannelMode( - // QProcess::StandardOutput); +#if QT_VERSION >= 0x040200 + m_pServer->setProcessChannelMode(QProcess::ForwardedChannels); +#endif QObject::connect(m_pServer, SIGNAL(readyReadStandardOutput()), SLOT(readServerStdout())); @@ -2425,7 +2428,7 @@ // The unforgiveable signal communication... QObject::connect(m_pServer, - SIGNAL(finished(int,QProcess::ExitStatus)), + SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processServerExit())); // Build process arguments... @@ -2456,26 +2459,46 @@ // Stop linuxsampler server... -void MainForm::stopServer (void) +void MainForm::stopServer (bool bInteractive) { // Stop client code. stopClient(); + if (m_pServer && bInteractive) { + if (QMessageBox::question(this, + QSAMPLER_TITLE ": " + tr("The backend's fate ..."), + tr("You have the option to keep the sampler backend (LinuxSampler)\n" + "running in the background. The sampler would continue to work\n" + "according to your current sampler session and you could alter the\n" + "sampler session at any time by relaunching QSampler.\n\n" + "Do you want LinuxSampler to stop or to keep running in\n" + "the background?"), + tr("Stop"), tr("Keep Running")) == 1) + { + bForceServerStop = false; + } + } + // And try to stop server. - if (m_pServer) { + if (m_pServer && bForceServerStop) { appendMessages(tr("Server is stopping...")); - if (m_pServer->state() == QProcess::Running) + if (m_pServer->state() == QProcess::Running) { +#if defined(WIN32) + // Try harder... + m_pServer->kill(); +#else + // Try softly... m_pServer->terminate(); - } +#endif + } + } // Do final processing anyway. + else processServerExit(); // Give it some time to terminate gracefully and stabilize... QTime t; t.start(); while (t.elapsed() < QSAMPLER_TIMER_MSECS) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); - - // Do final processing anyway. - processServerExit(); } @@ -2497,15 +2520,21 @@ if (m_pMessages) m_pMessages->flushStdoutBuffer(); - if (m_pServer) { + if (m_pServer && bForceServerStop) { + if (m_pServer->state() != QProcess::NotRunning) { + appendMessages(tr("Server is being forced...")); + // Force final server shutdown... + m_pServer->kill(); + // Give it some time to terminate gracefully and stabilize... + QTime t; + t.start(); + while (t.elapsed() < QSAMPLER_TIMER_MSECS) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } // Force final server shutdown... appendMessages( tr("Server was stopped with exit status %1.") .arg(m_pServer->exitStatus())); - m_pServer->terminate(); - if (!m_pServer->waitForFinished(2000)) - m_pServer->kill(); - // Destroy it. delete m_pServer; m_pServer = NULL; } @@ -2530,7 +2559,7 @@ // as this is run under some other thread context. // A custom event must be posted here... QApplication::postEvent(pMainForm, - new qsamplerCustomEvent(event, pchData, cchData)); + new CustomEvent(event, pchData, cchData)); return LSCP_OK; }