--- qsampler/trunk/src/qsamplerMainForm.cpp 2017/04/27 11:09:16 3128 +++ qsampler/trunk/src/qsamplerMainForm.cpp 2019/07/25 18:22:31 3534 @@ -1,7 +1,7 @@ // qsamplerMainForm.cpp // /**************************************************************************** - Copyright (C) 2004-2017, rncbc aka Rui Nuno Capela. All rights reserved. + Copyright (C) 2004-2019, rncbc aka Rui Nuno Capela. All rights reserved. Copyright (C) 2007,2008,2015 Christian Schoenebeck This program is free software; you can redistribute it and/or @@ -58,20 +58,16 @@ #include #include -#if QT_VERSION >= 0x050000 +#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) #include #endif -#if QT_VERSION < 0x040500 +#if QT_VERSION < QT_VERSION_CHECK(4, 5, 0) namespace Qt { const WindowFlags WindowCloseButtonHint = WindowFlags(0x08000000); } #endif -#ifdef HAVE_SIGNAL_H -#include -#endif - #ifdef CONFIG_LIBGIG #include #endif @@ -91,8 +87,9 @@ // All winsock apps needs this. -#if defined(WIN32) +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) static WSADATA _wsaData; +#undef HAVE_SIGNAL_H #endif @@ -103,20 +100,31 @@ #include +#include #include #include - #include // File descriptor for SIGUSR1 notifier. -static int g_fdUsr1[2]; +static int g_fdSigusr1[2] = { -1, -1 }; // Unix SIGUSR1 signal handler. static void qsampler_sigusr1_handler ( int /* signo */ ) { char c = 1; - (::write(g_fdUsr1[0], &c, sizeof(c)) > 0); + (::write(g_fdSigusr1[0], &c, sizeof(c)) > 0); +} + +// File descriptor for SIGTERM notifier. +static int g_fdSigterm[2] = { -1, -1 }; + +// Unix SIGTERM signal handler. +static void qsampler_sigterm_handler ( int /* signo */ ) +{ + char c = 1; + + (::write(g_fdSigterm[0], &c, sizeof(c)) > 0); } #endif // HAVE_SIGNAL_H @@ -233,25 +241,48 @@ // LADISH Level 1 suport. // Initialize file descriptors for SIGUSR1 socket notifier. - ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdUsr1); - m_pUsr1Notifier - = new QSocketNotifier(g_fdUsr1[1], QSocketNotifier::Read, this); + ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigusr1); + m_pSigusr1Notifier + = new QSocketNotifier(g_fdSigusr1[1], QSocketNotifier::Read, this); - QObject::connect(m_pUsr1Notifier, + QObject::connect(m_pSigusr1Notifier, SIGNAL(activated(int)), SLOT(handle_sigusr1())); // Install SIGUSR1 signal handler. - struct sigaction usr1; - usr1.sa_handler = qsampler_sigusr1_handler; - sigemptyset(&usr1.sa_mask); - usr1.sa_flags = 0; - usr1.sa_flags |= SA_RESTART; - ::sigaction(SIGUSR1, &usr1, NULL); + struct sigaction sigusr1; + sigusr1.sa_handler = qsampler_sigusr1_handler; + sigemptyset(&sigusr1.sa_mask); + sigusr1.sa_flags = 0; + sigusr1.sa_flags |= SA_RESTART; + ::sigaction(SIGUSR1, &sigusr1, NULL); + + // Initialize file descriptors for SIGTERM socket notifier. + ::socketpair(AF_UNIX, SOCK_STREAM, 0, g_fdSigterm); + m_pSigtermNotifier + = new QSocketNotifier(g_fdSigterm[1], QSocketNotifier::Read, this); + + QObject::connect(m_pSigtermNotifier, + SIGNAL(activated(int)), + SLOT(handle_sigterm())); + + // Install SIGTERM signal handler. + struct sigaction sigterm; + sigterm.sa_handler = qsampler_sigterm_handler; + sigemptyset(&sigterm.sa_mask); + sigterm.sa_flags = 0; + sigterm.sa_flags |= SA_RESTART; + ::sigaction(SIGTERM, &sigterm, NULL); + ::sigaction(SIGQUIT, &sigterm, NULL); + + // Ignore SIGHUP/SIGINT signals. + ::signal(SIGHUP, SIG_IGN); + ::signal(SIGINT, SIG_IGN); #else // HAVE_SIGNAL_H - m_pUsr1Notifier = NULL; + m_pSigusr1Notifier = NULL; + m_pSigtermNotifier = NULL; #endif // !HAVE_SIGNAL_H @@ -324,7 +355,7 @@ m_statusItem[QSAMPLER_STATUS_SESSION] = pLabel; statusBar()->addWidget(pLabel); -#if defined(WIN32) +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) WSAStartup(MAKEWORD(1, 1), &_wsaData); #endif @@ -425,13 +456,15 @@ // Do final processing anyway. processServerExit(); -#if defined(WIN32) +#if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) WSACleanup(); #endif #if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) - if (m_pUsr1Notifier) - delete m_pUsr1Notifier; + if (m_pSigusr1Notifier) + delete m_pSigusr1Notifier; + if (m_pSigtermNotifier) + delete m_pSigtermNotifier; #endif // Finally drop any widgets around... @@ -721,13 +754,26 @@ char c; - if (::read(g_fdUsr1[1], &c, sizeof(c)) > 0) + if (::read(g_fdSigusr1[1], &c, sizeof(c)) > 0) saveSession(false); #endif } +void MainForm::handle_sigterm (void) +{ +#if defined(HAVE_SIGNAL_H) && defined(HAVE_SYS_SOCKET_H) + + char c; + + if (::read(g_fdSigterm[1], &c, sizeof(c)) > 0) + close(); + +#endif +} + + void MainForm::updateViewMidiDeviceStatusMenu (void) { m_ui.viewMidiDeviceStatusMenu->clear(); @@ -806,7 +852,7 @@ m_iUntitled++; // Stabilize form. - m_sFilename = QString::null; + m_sFilename = QString(); m_iDirtyCount = 0; appendMessages(tr("New session: \"%1\".").arg(sessionName(m_sFilename))); stabilizeForm(); @@ -866,6 +912,7 @@ // Enforce .lscp extension... if (QFileInfo(sFilename).suffix().isEmpty()) sFilename += ".lscp"; + #if 0 // Check if already exists... if (sFilename != m_sFilename && QFileInfo(sFilename).exists()) { if (QMessageBox::warning(this, @@ -878,6 +925,7 @@ == QMessageBox::No) return false; } + #endif } // Save it right away. @@ -1060,16 +1108,19 @@ // It is assumed that this new kind of device+session file // will be loaded from a complete initialized server... int *piDeviceIDs; - int iDevice; + int i, iDevice; ts << "RESET" << endl; // Audio device mapping. - QMap audioDeviceMap; + QMap audioDeviceMap; iDevice = 0; piDeviceIDs = Device::getDevices(m_pClient, Device::Audio); - for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { - ts << endl; - Device device(Device::Audio, piDeviceIDs[iDevice]); + for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { + Device device(Device::Audio, piDeviceIDs[i]); + // Avoid plug-in driver devices... + if (device.driverName().toUpper() == "PLUGIN") + continue; // Audio device specification... + ts << endl; ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE AUDIO_OUTPUT_DEVICE " << device.driverName(); @@ -1100,18 +1151,21 @@ iPort++; } // Audio device index/id mapping. - audioDeviceMap[device.deviceID()] = iDevice; + audioDeviceMap.insert(device.deviceID(), iDevice++); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } // MIDI device mapping. - QMap midiDeviceMap; + QMap midiDeviceMap; iDevice = 0; piDeviceIDs = Device::getDevices(m_pClient, Device::Midi); - for (iDevice = 0; piDeviceIDs && piDeviceIDs[iDevice] >= 0; iDevice++) { - ts << endl; - Device device(Device::Midi, piDeviceIDs[iDevice]); + for (i = 0; piDeviceIDs && piDeviceIDs[i] >= 0; ++i) { + Device device(Device::Midi, piDeviceIDs[i]); + // Avoid plug-in driver devices... + if (device.driverName().toUpper() == "PLUGIN") + continue; // MIDI device specification... + ts << endl; ts << "# " << device.deviceTypeName() << " " << device.driverName() << " " << tr("Device") << " " << iDevice << endl; ts << "CREATE MIDI_INPUT_DEVICE " << device.driverName(); @@ -1142,7 +1196,7 @@ iPort++; } // MIDI device index/id mapping. - midiDeviceMap[device.deviceID()] = iDevice; + midiDeviceMap.insert(device.deviceID(), iDevice++); // Try to keep it snappy :) QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); } @@ -1210,7 +1264,7 @@ iErrors++; } // MIDI strument index/id mapping. - midiInstrumentMap[iMidiMap] = iMap; + midiInstrumentMap.insert(iMidiMap, iMap); } // Check for errors... if (piMaps == NULL && ::lscp_client_get_errno(m_pClient)) { @@ -1219,7 +1273,8 @@ } #endif // CONFIG_MIDI_INSTRUMENT - // Sampler channel mapping. + // Sampler channel mapping... + int iChannelID = 0; const QList& wlist = m_pWorkspace->subWindowList(); const int iStripCount = wlist.count(); @@ -1231,7 +1286,14 @@ if (pChannelStrip) { Channel *pChannel = pChannelStrip->channel(); if (pChannel) { - const int iChannelID = pChannel->channelID(); + // Avoid "artifial" plug-in devices... + const int iAudioDevice = pChannel->audioDevice(); + if (!audioDeviceMap.contains(iAudioDevice)) + continue; + const int iMidiDevice = pChannel->midiDevice(); + if (!midiDeviceMap.contains(iMidiDevice)) + continue; + // Go for regular, canonical devices... ts << "# " << tr("Channel") << " " << iChannelID << endl; ts << "ADD CHANNEL" << endl; if (audioDeviceMap.isEmpty()) { @@ -1239,14 +1301,14 @@ << " " << pChannel->audioDriver() << endl; } else { ts << "SET CHANNEL AUDIO_OUTPUT_DEVICE " << iChannelID - << " " << audioDeviceMap[pChannel->audioDevice()] << endl; + << " " << audioDeviceMap.value(iAudioDevice) << endl; } if (midiDeviceMap.isEmpty()) { ts << "SET CHANNEL MIDI_INPUT_TYPE " << iChannelID << " " << pChannel->midiDriver() << endl; } else { ts << "SET CHANNEL MIDI_INPUT_DEVICE " << iChannelID - << " " << midiDeviceMap[pChannel->midiDevice()] << endl; + << " " << midiDeviceMap.value(iMidiDevice) << endl; } ts << "SET CHANNEL MIDI_INPUT_PORT " << iChannelID << " " << pChannel->midiPort() << endl; @@ -1277,9 +1339,10 @@ if (pChannel->channelSolo()) ts << "SET CHANNEL SOLO " << iChannelID << " 1" << endl; #ifdef CONFIG_MIDI_INSTRUMENT - if (pChannel->midiMap() >= 0) { + const int iMidiMap = pChannel->midiMap(); + if (midiInstrumentMap.contains(iMidiMap)) { ts << "SET CHANNEL MIDI_INSTRUMENT_MAP " << iChannelID - << " " << midiInstrumentMap[pChannel->midiMap()] << endl; + << " " << midiInstrumentMap.value(iMidiMap) << endl; } #endif #ifdef CONFIG_FXSEND @@ -1318,6 +1381,8 @@ } #endif ts << endl; + // Go for next channel... + ++iChannelID; } } // Try to keep it snappy :) @@ -2864,26 +2929,32 @@ } } + bool bGraceWait = true; + // And try to stop server. if (m_pServer && m_bForceServerStop) { appendMessages(tr("Server is stopping...")); if (m_pServer->state() == QProcess::Running) { - #if defined(WIN32) + #if defined(__WIN32__) || defined(_WIN32) || defined(WIN32) // Try harder... m_pServer->kill(); #else // Try softly... m_pServer->terminate(); + bool bFinished = m_pServer->waitForFinished(QSAMPLER_TIMER_MSECS * 1000); + if (bFinished) bGraceWait = false; #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); + if (bGraceWait) { + QTime t; + t.start(); + while (t.elapsed() < QSAMPLER_TIMER_MSECS) + QApplication::processEvents(QEventLoop::ExcludeUserInputEvents); + } } @@ -3038,7 +3109,7 @@ if (!m_pOptions->sSessionFile.isEmpty()) { // Just load the prabably startup session... if (loadSessionFile(m_pOptions->sSessionFile)) { - m_pOptions->sSessionFile = QString::null; + m_pOptions->sSessionFile = QString(); return true; } }