Merge pull request #229 from pljones/feature/170-allow-triggered-recording-cuts
Feature/170 allow triggered recording cuts
This commit is contained in:
commit
e529baeb94
6 changed files with 120 additions and 35 deletions
|
@ -314,6 +314,10 @@ void CJamRecorder::Init( const CServer* server,
|
||||||
throw std::runtime_error( (recordBaseDir.absolutePath() + " is a directory but cannot be written to").toStdString() );
|
throw std::runtime_error( (recordBaseDir.absolutePath() + " is a directory but cannot be written to").toStdString() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QObject::connect( (const QObject *)server, SIGNAL ( RestartRecorder() ),
|
||||||
|
this, SLOT( OnTriggerSession() ),
|
||||||
|
Qt::ConnectionType::QueuedConnection );
|
||||||
|
|
||||||
QObject::connect( (const QObject *)server, SIGNAL ( Stopped() ),
|
QObject::connect( (const QObject *)server, SIGNAL ( Stopped() ),
|
||||||
this, SLOT( OnEnd() ),
|
this, SLOT( OnEnd() ),
|
||||||
Qt::ConnectionType::QueuedConnection );
|
Qt::ConnectionType::QueuedConnection );
|
||||||
|
@ -322,13 +326,12 @@ void CJamRecorder::Init( const CServer* server,
|
||||||
this, SLOT( OnDisconnected ( int ) ),
|
this, SLOT( OnDisconnected ( int ) ),
|
||||||
Qt::ConnectionType::QueuedConnection );
|
Qt::ConnectionType::QueuedConnection );
|
||||||
|
|
||||||
qRegisterMetaType<CVector<int16_t>>();
|
qRegisterMetaType<CVector<int16_t>> ( "CVector<int16_t>" );
|
||||||
QObject::connect( (const QObject *)server, SIGNAL ( AudioFrame( const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ),
|
QObject::connect( (const QObject *)server, SIGNAL ( AudioFrame( const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ),
|
||||||
this, SLOT( OnFrame (const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ),
|
this, SLOT( OnFrame (const int, const QString, const CHostAddress, const int, const CVector<int16_t> ) ),
|
||||||
Qt::ConnectionType::QueuedConnection );
|
Qt::ConnectionType::QueuedConnection );
|
||||||
|
|
||||||
QObject::connect( QCoreApplication::instance(),
|
QObject::connect( QCoreApplication::instance(), SIGNAL ( aboutToQuit() ),
|
||||||
SIGNAL ( aboutToQuit() ),
|
|
||||||
this, SLOT( OnAboutToQuit() ) );
|
this, SLOT( OnAboutToQuit() ) );
|
||||||
|
|
||||||
iServerFrameSizeSamples = _iServerFrameSizeSamples;
|
iServerFrameSizeSamples = _iServerFrameSizeSamples;
|
||||||
|
@ -338,11 +341,10 @@ void CJamRecorder::Init( const CServer* server,
|
||||||
thisThread->start();
|
thisThread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief CJamRecorder::OnStart Start up tasks when the first client connects
|
* @brief CJamRecorder::Start Start up tasks for a new session
|
||||||
*/
|
*/
|
||||||
void CJamRecorder::OnStart() {
|
void CJamRecorder::Start() {
|
||||||
// Ensure any previous cleaning up has been done.
|
// Ensure any previous cleaning up has been done.
|
||||||
OnEnd();
|
OnEnd();
|
||||||
|
|
||||||
|
@ -350,11 +352,17 @@ void CJamRecorder::OnStart() {
|
||||||
isRecording = true;
|
isRecording = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief CJamRecorder::OnEnd Finalise the recording and emit the Reaper RPP file
|
* @brief CJamRecorder::OnEnd Finalise the recording and emit the Reaper RPP file
|
||||||
|
*
|
||||||
|
* Emits RecordingSessionEnded with the Reaper project file name,
|
||||||
|
* or null if was not recording or a problem occurs
|
||||||
*/
|
*/
|
||||||
void CJamRecorder::OnEnd()
|
void CJamRecorder::OnEnd()
|
||||||
{
|
{
|
||||||
|
QString reaperProjectFileName = QString::Null();
|
||||||
|
|
||||||
if ( isRecording )
|
if ( isRecording )
|
||||||
{
|
{
|
||||||
isRecording = false;
|
isRecording = false;
|
||||||
|
@ -366,21 +374,46 @@ void CJamRecorder::OnEnd()
|
||||||
if (fi.exists())
|
if (fi.exists())
|
||||||
{
|
{
|
||||||
qWarning() << "CJamRecorder::OnEnd():" << fi.absolutePath() << "exists and will not be overwritten.";
|
qWarning() << "CJamRecorder::OnEnd():" << fi.absolutePath() << "exists and will not be overwritten.";
|
||||||
|
reaperProjectFileName = QString::Null();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
QFile outf (reaperProjectFileName);
|
QFile outf (reaperProjectFileName);
|
||||||
outf.open(QFile::WriteOnly);
|
if ( outf.open(QFile::WriteOnly) )
|
||||||
QTextStream out(&outf);
|
{
|
||||||
out << CReaperProject( currentSession->Tracks(), iServerFrameSizeSamples ).toString() << endl;
|
QTextStream out(&outf);
|
||||||
qDebug() << "Session RPP:" << reaperProjectFileName;
|
out << CReaperProject( currentSession->Tracks(), iServerFrameSizeSamples ).toString() << endl;
|
||||||
|
qDebug() << "Session RPP:" << reaperProjectFileName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
qWarning() << "CJamRecorder::OnEnd():" << fi.absolutePath() << "could not be created, no RPP written.";
|
||||||
|
reaperProjectFileName = QString::Null();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
delete currentSession;
|
delete currentSession;
|
||||||
currentSession = nullptr;
|
currentSession = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit RecordingSessionEnded ( reaperProjectFileName );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CJamRecorder::OnTriggerSession End one session and start a new one
|
||||||
|
*/
|
||||||
|
void CJamRecorder::OnTriggerSession()
|
||||||
|
{
|
||||||
|
// This should magically get everything right...
|
||||||
|
if ( isRecording )
|
||||||
|
{
|
||||||
|
Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CJamRecorder::OnAboutToQuit End any recording and exit thread
|
||||||
|
*/
|
||||||
void CJamRecorder::OnAboutToQuit()
|
void CJamRecorder::OnAboutToQuit()
|
||||||
{
|
{
|
||||||
OnEnd();
|
OnEnd();
|
||||||
|
@ -452,7 +485,7 @@ void CJamRecorder::OnFrame(const int iChID, const QString name, const CHostAddre
|
||||||
// Make sure we are ready
|
// Make sure we are ready
|
||||||
if ( !isRecording )
|
if ( !isRecording )
|
||||||
{
|
{
|
||||||
OnStart();
|
Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSession->Frame( iChID, name, address, numAudioChannels, data, iServerFrameSizeSamples );
|
currentSession->Frame( iChID, name, address, numAudioChannels, data, iServerFrameSizeSamples );
|
||||||
|
|
|
@ -143,21 +143,44 @@ public:
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Create recording directory, if necessary, and connect signal handlers
|
||||||
|
* @param server Server object emiting signals
|
||||||
|
*/
|
||||||
void Init( const CServer* server, const int _iServerFrameSizeSamples );
|
void Init( const CServer* server, const int _iServerFrameSizeSamples );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SessionDirToReaper Method that allows an RPP file to be recreated
|
||||||
|
* @param strSessionDirName Where the session wave files are
|
||||||
|
* @param serverFrameSizeSamples What the server frame size was for the session
|
||||||
|
*/
|
||||||
static void SessionDirToReaper( QString& strSessionDirName, int serverFrameSizeSamples );
|
static void SessionDirToReaper( QString& strSessionDirName, int serverFrameSizeSamples );
|
||||||
|
|
||||||
public slots:
|
private:
|
||||||
/**
|
void Start();
|
||||||
* @brief Raised when first client joins the server, triggering a new recording.
|
|
||||||
*/
|
|
||||||
void OnStart();
|
|
||||||
|
|
||||||
|
QDir recordBaseDir;
|
||||||
|
|
||||||
|
bool isRecording;
|
||||||
|
CJamSession* currentSession;
|
||||||
|
int iServerFrameSizeSamples;
|
||||||
|
|
||||||
|
QThread* thisThread;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void RecordingSessionEnded ( QString sessionDir );
|
||||||
|
|
||||||
|
private slots:
|
||||||
/**
|
/**
|
||||||
* @brief Raised when last client leaves the server, ending the recording.
|
* @brief Raised when last client leaves the server, ending the recording.
|
||||||
*/
|
*/
|
||||||
void OnEnd();
|
void OnEnd();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Raised to end one session and start a new one.
|
||||||
|
*/
|
||||||
|
void OnTriggerSession();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Raised when application is stopping
|
* @brief Raised when application is stopping
|
||||||
*/
|
*/
|
||||||
|
@ -173,15 +196,6 @@ public slots:
|
||||||
* @brief Raised when a frame of data is available to process
|
* @brief Raised when a frame of data is available to process
|
||||||
*/
|
*/
|
||||||
void OnFrame ( const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector<int16_t> data );
|
void OnFrame ( const int iChID, const QString name, const CHostAddress address, const int numAudioChannels, const CVector<int16_t> data );
|
||||||
|
|
||||||
private:
|
|
||||||
QDir recordBaseDir;
|
|
||||||
|
|
||||||
bool isRecording;
|
|
||||||
CJamSession* currentSession;
|
|
||||||
int iServerFrameSizeSamples;
|
|
||||||
|
|
||||||
QThread* thisThread;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -471,8 +471,8 @@ CServer::CServer ( const int iNewMaxNumChan,
|
||||||
this, SLOT ( OnAboutToQuit() ) );
|
this, SLOT ( OnAboutToQuit() ) );
|
||||||
|
|
||||||
QObject::connect ( pSignalHandler,
|
QObject::connect ( pSignalHandler,
|
||||||
SIGNAL ( ShutdownSignal ( int ) ),
|
SIGNAL ( HandledSignal ( int ) ),
|
||||||
this, SLOT ( OnShutdown ( int ) ) );
|
this, SLOT ( OnHandledSignal ( int ) ) );
|
||||||
|
|
||||||
connectChannelSignalsToServerSlots<MAX_NUM_CHANNELS>();
|
connectChannelSignalsToServerSlots<MAX_NUM_CHANNELS>();
|
||||||
|
|
||||||
|
@ -665,10 +665,35 @@ void CServer::OnAboutToQuit()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServer::OnShutdown ( int )
|
void CServer::OnHandledSignal ( int sigNum )
|
||||||
{
|
{
|
||||||
// This should trigger OnAboutToQuit
|
#ifdef _WIN32
|
||||||
|
|
||||||
|
// Windows does not actually get OnHandledSignal triggered
|
||||||
QCoreApplication::instance()->exit();
|
QCoreApplication::instance()->exit();
|
||||||
|
Q_UNUSED ( sigNum )
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
switch ( sigNum )
|
||||||
|
{
|
||||||
|
|
||||||
|
case SIGUSR1:
|
||||||
|
RequestNewRecording();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
// This should trigger OnAboutToQuit
|
||||||
|
QCoreApplication::instance()->exit();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void CServer::Start()
|
void CServer::Start()
|
||||||
|
@ -1565,3 +1590,11 @@ void CServer::CreateLevelsForAllConChannels ( const int i
|
||||||
vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevel ) );
|
vecLevelsOut[j] = static_cast<uint16_t> ( ceil ( dCurSigLevel ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CServer::RequestNewRecording()
|
||||||
|
{
|
||||||
|
if ( bEnableRecording )
|
||||||
|
{
|
||||||
|
emit RestartRecorder();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -285,6 +285,8 @@ protected:
|
||||||
const CVector<CVector<int16_t> > vecvecsData,
|
const CVector<CVector<int16_t> > vecvecsData,
|
||||||
CVector<uint16_t>& vecLevelsOut );
|
CVector<uint16_t>& vecLevelsOut );
|
||||||
|
|
||||||
|
void RequestNewRecording();
|
||||||
|
|
||||||
// do not use the vector class since CChannel does not have appropriate
|
// do not use the vector class since CChannel does not have appropriate
|
||||||
// copy constructor/operator
|
// copy constructor/operator
|
||||||
CChannel vecChannels[MAX_NUM_CHANNELS];
|
CChannel vecChannels[MAX_NUM_CHANNELS];
|
||||||
|
@ -364,6 +366,7 @@ signals:
|
||||||
const CHostAddress RecHostAddr,
|
const CHostAddress RecHostAddr,
|
||||||
const int iNumAudChan,
|
const int iNumAudChan,
|
||||||
const CVector<int16_t> vecsData );
|
const CVector<int16_t> vecsData );
|
||||||
|
void RestartRecorder();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void OnTimer();
|
void OnTimer();
|
||||||
|
@ -441,5 +444,5 @@ public slots:
|
||||||
|
|
||||||
void OnAboutToQuit();
|
void OnAboutToQuit();
|
||||||
|
|
||||||
void OnShutdown ( int );
|
void OnHandledSignal ( int sigNum );
|
||||||
};
|
};
|
||||||
|
|
|
@ -75,7 +75,7 @@ CSignalHandler* CSignalHandler::getSingletonP() { return singleton; }
|
||||||
|
|
||||||
bool CSignalHandler::emitSignal ( int sigNum )
|
bool CSignalHandler::emitSignal ( int sigNum )
|
||||||
{
|
{
|
||||||
return QMetaObject::invokeMethod( singleton, "ShutdownSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) );
|
return QMetaObject::invokeMethod( singleton, "HandledSignal", Qt::QueuedConnection, Q_ARG( int, sigNum ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -124,11 +124,11 @@ QReadWriteLock* CSignalWin::getLock() const
|
||||||
return &lock;
|
return &lock;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI CSignalWin::signalHandler ( _In_ DWORD sigNum )
|
BOOL WINAPI CSignalWin::signalHandler ( _In_ DWORD )
|
||||||
{
|
{
|
||||||
auto self = getSelf<CSignalWin>();
|
auto self = getSelf<CSignalWin>();
|
||||||
QReadLocker lock ( self->getLock() );
|
QReadLocker lock ( self->getLock() );
|
||||||
return self->pSignalHandler->emitSignal ( static_cast<int>( sigNum ) );
|
return self->pSignalHandler->emitSignal ( -1 );
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
@ -145,12 +145,14 @@ CSignalUnix::CSignalUnix ( CSignalHandler* nPSignalHandler ) :
|
||||||
|
|
||||||
socketNotifier->setEnabled ( true );
|
socketNotifier->setEnabled ( true );
|
||||||
|
|
||||||
|
setSignalHandled ( SIGUSR1, true );
|
||||||
setSignalHandled ( SIGINT, true );
|
setSignalHandled ( SIGINT, true );
|
||||||
setSignalHandled ( SIGTERM, true );
|
setSignalHandled ( SIGTERM, true );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSignalUnix::~CSignalUnix() {
|
CSignalUnix::~CSignalUnix() {
|
||||||
|
setSignalHandled ( SIGUSR1, false );
|
||||||
setSignalHandled ( SIGINT, false );
|
setSignalHandled ( SIGINT, false );
|
||||||
setSignalHandled ( SIGTERM, false );
|
setSignalHandled ( SIGTERM, false );
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,7 @@ public slots:
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void ShutdownSignal ( int sigNum );
|
void HandledSignal ( int sigNum );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QScopedPointer<CSignalBase> pSignalBase;
|
QScopedPointer<CSignalBase> pSignalBase;
|
||||||
|
@ -153,7 +153,7 @@ public:
|
||||||
private:
|
private:
|
||||||
mutable QReadWriteLock lock;
|
mutable QReadWriteLock lock;
|
||||||
|
|
||||||
static BOOL WINAPI signalHandler ( _In_ DWORD sigNum );
|
static BOOL WINAPI signalHandler ( _In_ DWORD );
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
Loading…
Reference in a new issue