jamulus/src/recorder/cwavestream.cpp

149 lines
5.1 KiB
C++
Raw Normal View History

2019-04-10 20:00:54 +02:00
/******************************************************************************\
* Copyright (c) 2020
2019-04-10 20:00:54 +02:00
*
* Author(s):
* pljones
*
******************************************************************************
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
2019-04-10 20:00:54 +02:00
*
\******************************************************************************/
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
#include "cwavestream.h"
/******************************************************************************\
* Overrides in global namespace *
\******************************************************************************/
/**
* @brief operator << Emit a hdr_riff object to a QDataStream
* @param os a QDataStream
* @param obj a hdr_riff object
* @return the QDataStream passed
*/
recorder::CWaveStream& operator<<(recorder::CWaveStream& os, const recorder::HdrRiff& obj)
{
(QDataStream&)os << obj.chunkId << obj.chunkSize << obj.format;
return os;
}
/**
* @brief operator << Emit a fmtSubChunk object to a QDataStream
* @param os a QDataStream
* @param obj a fmtSubChunk object
* @return the QDataStream passed
*/
recorder::CWaveStream& operator<<(recorder::CWaveStream& os, const recorder::FmtSubChunk& obj)
{
(QDataStream&)os << obj.chunkId
<< obj.chunkSize
<< obj.audioFormat
<< obj.numChannels
<< obj.sampleRate
<< obj.byteRate
<< obj.blockAlign
<< obj.bitsPerSample
;
return os;
}
/**
* @brief operator << Emit a dataSubChunkHdr object to a QDataStream
* @param os a QDataStream
* @param obj a dataSubChunkHdr object
* @return the QDataStream passed
*/
recorder::CWaveStream& operator<<(recorder::CWaveStream& os, const recorder::DataSubChunkHdr& obj)
{
(QDataStream&)os << obj.chunkId << obj.chunkSize;
return os;
}
/******************************************************************************\
* Implementations of recorder.CWaveStream methods *
\******************************************************************************/
using namespace recorder;
CWaveStream::CWaveStream(const uint16_t numChannels) :
QDataStream(),
numChannels (numChannels),
initialPos (device()->pos()),
initialByteOrder (byteOrder())
{
waveStreamHeaders();
}
CWaveStream::CWaveStream(QIODevice *iod, const uint16_t numChannels) :
QDataStream(iod),
numChannels (numChannels),
initialPos (device()->pos()),
initialByteOrder (byteOrder())
{
waveStreamHeaders();
}
CWaveStream::CWaveStream(QByteArray *iod, QIODevice::OpenMode flags, const uint16_t numChannels) :
QDataStream(iod, flags),
numChannels (numChannels),
initialPos (device()->pos()),
initialByteOrder (byteOrder())
{
waveStreamHeaders();
}
CWaveStream::CWaveStream(const QByteArray &ba, const uint16_t numChannels) :
QDataStream(ba),
numChannels (numChannels),
initialPos (device()->pos()),
initialByteOrder (byteOrder())
{
waveStreamHeaders();
}
void CWaveStream::waveStreamHeaders()
{
static const HdrRiff scHdrRiff;
const FmtSubChunk cFmtSubChunk (numChannels);
static const DataSubChunkHdr scDataSubChunkHdr;
setByteOrder(LittleEndian);
*this << scHdrRiff << cFmtSubChunk << scDataSubChunkHdr;
}
2019-04-21 23:13:07 +02:00
void CWaveStream::finalise()
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
{
2019-04-21 23:13:07 +02:00
static const uint32_t hdrRiffChunkSize = sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t);
static const uint32_t fmtSubChunkSize = sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t) + sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint16_t) + sizeof(uint16_t);
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
static const uint32_t hdrRiffChunkSizeOffset = sizeof(uint32_t);
2019-04-21 23:13:07 +02:00
static const uint32_t dataSubChunkHdrChunkSizeOffset = hdrRiffChunkSize + fmtSubChunkSize + sizeof (uint32_t);
Add recording support with Reaper Project generation Includes the following changes * Initial .gitignore Administrative * Fix up warning message * Not all Windows file systems are case insensitive Bugfixes * (Qt5) Use QCoreApplication for headless Possible solution to get the application to run as a headless server but it loses the nice history graph, so not ideal. * Avoid ESC closing chat Because ESC shouldn't close the chat window. Or the main app window. * Add console logging support for Windows Whilst looking for the headless support, I found this idea for Windows logging. New improved version. This makes far fewer changes. ---- * Add recording support with Reaper Project generation The main feature! * New -r option to enable recording of PCM files and conversion to Reaper RPP with WAV files * New -R option to set the directory in which to create recording sessions You need to specify the -R option, there's no default... so I guess -r and -R could be combined. * New -T option to convert a session directory with PCM files into a Reaper RPP with WAV files You can use -T on "failed" sessions, if the -r option captures the PCMs but the RPP converter doesn't run for some reaon. (It was useful during development, maybe less so once things seem stable.) The recorder is implemented as a new thread with queuing from the main "real time" server thread. When a new client connects or if its audio format changes (e.g. mono to stereo), a new RIFF WAVE file is started. Each frame of decompressed audio for each client written out as LPCM to the file. When the client disconnects, the RIFF WAVE headers are updated to reflect the file length. Once all clients disconnect, the session is considered ended and a Reaper RPP file is written.
2019-04-03 19:12:45 +02:00
const int64_t currentPos = this->device()->pos();
const uint32_t fileLength = static_cast<uint32_t>(currentPos - initialPos);
QDataStream& out = static_cast<QDataStream&>(*this);
// Overwrite hdr_riff.chunkSize
this->device()->seek(initialPos + hdrRiffChunkSizeOffset);
out << static_cast<uint32_t>(fileLength - (hdrRiffChunkSizeOffset + sizeof (uint32_t)));
// Overwrite dataSubChunkHdr.chunkSize
this->device()->seek(initialPos + dataSubChunkHdrChunkSizeOffset);
out << static_cast<uint32_t>(fileLength - (dataSubChunkHdrChunkSizeOffset + sizeof (uint32_t)));
// and then restore the position and byte order
this->device()->seek(currentPos);
setByteOrder(initialByteOrder);
}