Added #583: add periodic file generation, plus other options:

- Added a Recording menu,
git commit -m Added
This commit is contained in:
vsonnier
2018-01-13 11:50:08 +01:00
parent 4d0f3a794d
commit 26deefd606
14 changed files with 441 additions and 91 deletions
+1 -6
View File
@@ -3,7 +3,6 @@
#include "AudioFile.h"
#include "CubicSDR.h"
#include <iomanip>
#include <sstream>
AudioFile::AudioFile() {
@@ -18,7 +17,7 @@ void AudioFile::setOutputFileName(std::string filename) {
filenameBase = filename;
}
std::string AudioFile::getOutputFileName(int sequenceNumber) {
std::string AudioFile::getOutputFileName() {
std::string recPath = wxGetApp().getConfig()->getRecordingPath();
@@ -36,10 +35,6 @@ std::string AudioFile::getOutputFileName(int sequenceNumber) {
std::stringstream outputFileName;
outputFileName << recPath << filePathSeparator << filenameBaseSafe;
if (sequenceNumber > 0) {
outputFileName << "_" << std::setfill('0') << std::setw(3) << sequenceNumber;
}
int idx = 0;
// If the file exists; then find the next non-existing file in sequence.
+1 -1
View File
@@ -14,7 +14,7 @@ public:
virtual void setOutputFileName(std::string filename);
virtual std::string getExtension() = 0;
virtual std::string getOutputFileName(int sequenceNumber = 0);
virtual std::string getOutputFileName();
virtual bool writeToFile(AudioThreadInputPtr input) = 0;
virtual bool closeFile() = 0;
+40 -2
View File
@@ -2,6 +2,8 @@
// SPDX-License-Identifier: GPL-2.0+
#include "AudioFileWAV.h"
#include "CubicSDR.h"
#include <iomanip>
//limit file size to 2GB (- margin) for maximum compatibility.
#define MAX_WAV_FILE_SIZE (0x7FFFFFFF - 1024)
@@ -63,7 +65,7 @@ std::string AudioFileWAV::getExtension()
bool AudioFileWAV::writeToFile(AudioThreadInputPtr input)
{
if (!outputFileStream.is_open()) {
std::string ofName = getOutputFileName(currentSequenceNumber);
std::string ofName = getOutputFileName();
outputFileStream.open(ofName.c_str(), std::ios::binary);
@@ -85,7 +87,7 @@ bool AudioFileWAV::writeToFile(AudioThreadInputPtr input)
currentSequenceNumber++;
currentFileSize = 0;
std::string ofName = getOutputFileName(currentSequenceNumber);
std::string ofName = getOutputFileName();
outputFileStream.open(ofName.c_str(), std::ios::binary);
writeHeaderToFileStream(input);
@@ -166,3 +168,39 @@ size_t AudioFileWAV::getMaxWritableNumberOfSamples(AudioThreadInputPtr input) {
return (size_t)(remainingBytesInFile / (input->channels * 2));
}
std::string AudioFileWAV::getOutputFileName() {
std::string recPath = wxGetApp().getConfig()->getRecordingPath();
// Strip any invalid characters from the name
std::string stripChars("<>:\"/\\|?*");
std::string filenameBaseSafe = filenameBase;
for (size_t i = 0, iMax = filenameBaseSafe.length(); i < iMax; i++) {
if (stripChars.find(filenameBaseSafe[i]) != std::string::npos) {
filenameBaseSafe.replace(i, 1, "_");
}
}
// Create output file name
std::stringstream outputFileName;
outputFileName << recPath << filePathSeparator << filenameBaseSafe;
//customized part: append a sequence number.
if (currentSequenceNumber > 0) {
outputFileName << "_" << std::setfill('0') << std::setw(3) << currentSequenceNumber;
}
int idx = 0;
// If the file exists; then find the next non-existing file in sequence.
std::string fileNameCandidate = outputFileName.str();
while (FILE *file = fopen((fileNameCandidate + "." + getExtension()).c_str(), "r")) {
fclose(file);
fileNameCandidate = outputFileName.str() + "-" + std::to_string(++idx);
}
return fileNameCandidate + "." + getExtension();
}
+7 -3
View File
@@ -13,10 +13,14 @@ public:
AudioFileWAV();
~AudioFileWAV();
std::string getExtension();
//override of the base method to generate multi-part
//WAV to overcome the WAV format size limit.
virtual std::string getOutputFileName();
bool writeToFile(AudioThreadInputPtr input);
bool closeFile();
virtual std::string getExtension();
virtual bool writeToFile(AudioThreadInputPtr input);
virtual bool closeFile();
protected:
std::ofstream outputFileStream;
+110
View File
@@ -2,6 +2,9 @@
// SPDX-License-Identifier: GPL-2.0+
#include "AudioSinkFileThread.h"
#include <ctime>
#define HEARTBEAT_CHECK_PERIOD_MICROS (50 * 1000)
AudioSinkFileThread::AudioSinkFileThread() : AudioSinkThread() {
@@ -17,6 +20,57 @@ void AudioSinkFileThread::sink(AudioThreadInputPtr input) {
if (!audioFileHandler) {
return;
}
//by default, always write something
bool isSomethingToWrite = true;
if (input->is_squelch_active) {
if (squelchOption == SQUELCH_RECORD_SILENCE) {
//patch with "silence"
input->data.assign(input->data.size(), 0.0f);
input->peak = 0.0f;
}
else if (squelchOption == SQUELCH_SKIP_SILENCE) {
isSomethingToWrite = false;
}
}
//else, nothing to do record as if squelch was not enabled.
if (!isSomethingToWrite) {
return;
}
if (fileTimeLimit > 0) {
durationMeasurement.update();
//duration exeeded, close this file and create another
//with "now" as timestamp.
if (durationMeasurement.getSeconds() > fileTimeLimit) {
audioFileHandler->closeFile();
//initialize the filename of the AudioFile with the current time
time_t t = std::time(nullptr);
tm ltm = *std::localtime(&t);
// GCC 5+
// fileName << "_" << std::put_time(&ltm, "%d-%m-%Y_%H-%M-%S");
char timeStr[512];
//International format: Year.Month.Day, also lexicographically sortable
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d_%H-%M-%S", &ltm);
audioFileHandler->setOutputFileName(fileNameBase + std::string("_") + timeStr);
//reset duration counter
durationMeasurement.start();
//the following writeToFile will take care of creating another file.
}
}
// forward to output file handler
audioFileHandler->writeToFile(input);
}
@@ -28,8 +82,64 @@ void AudioSinkFileThread::inputChanged(AudioThreadInput oldProps, AudioThreadInp
}
audioFileHandler->closeFile();
//reset duration counter
durationMeasurement.start();
}
void AudioSinkFileThread::setAudioFileNameBase(const std::string& baseName) {
fileNameBase = baseName;
}
void AudioSinkFileThread::setAudioFileHandler(AudioFile * output) {
audioFileHandler = output;
//initialize the filename of the AudioFile with the current time
time_t t = std::time(nullptr);
tm ltm = *std::localtime(&t);
// GCC 5+
// fileName << "_" << std::put_time(&ltm, "%d-%m-%Y_%H-%M-%S");
char timeStr[512];
//International format: Year.Month.Day, also lexicographically sortable
strftime(timeStr, sizeof(timeStr), "%Y-%m-%d_%H-%M-%S", &ltm);
audioFileHandler->setOutputFileName(fileNameBase + std::string("_") + timeStr);
// reset Timer
durationMeasurement.start();
}
void AudioSinkFileThread::setSquelchOption(int squelchOptEnumValue) {
if (squelchOptEnumValue == AudioSinkFileThread::SQUELCH_RECORD_SILENCE) {
squelchOption = AudioSinkFileThread::SQUELCH_RECORD_SILENCE;
}
else if (squelchOptEnumValue == AudioSinkFileThread::SQUELCH_SKIP_SILENCE) {
squelchOption = AudioSinkFileThread::SQUELCH_SKIP_SILENCE;
}
else if (squelchOptEnumValue == AudioSinkFileThread::SQUELCH_RECORD_ALWAYS) {
squelchOption = AudioSinkFileThread::SQUELCH_RECORD_ALWAYS;
}
else {
squelchOption = AudioSinkFileThread::SQUELCH_SKIP_SILENCE;
}
}
// Time limit
void AudioSinkFileThread::setFileTimeLimit(int nbSeconds) {
if (nbSeconds > 0) {
fileTimeLimit = nbSeconds;
}
else {
fileTimeLimit = 0;
}
}
+28 -2
View File
@@ -5,6 +5,7 @@
#include "AudioSinkThread.h"
#include "AudioFile.h"
#include "Timer.h"
class AudioSinkFileThread : public AudioSinkThread {
@@ -12,13 +13,38 @@ public:
AudioSinkFileThread();
~AudioSinkFileThread();
void sink(AudioThreadInputPtr input);
void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps);
enum SquelchOption {
SQUELCH_RECORD_SILENCE = 0, // default value, record as a user would hear it.
SQUELCH_SKIP_SILENCE = 1, // skip below-squelch level.
SQUELCH_RECORD_ALWAYS = 2, // record irrespective of the squelch level.
SQUELCH_RECORD_MAX
};
virtual void sink(AudioThreadInputPtr input);
virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps);
void setAudioFileHandler(AudioFile *output);
void setAudioFileNameBase(const std::string& baseName);
//Squelch
void setSquelchOption(int squelchOptEnumValue);
// Time limit
void setFileTimeLimit(int nbSeconds);
protected:
std::string fileNameBase;
AudioFile *audioFileHandler = nullptr;
SquelchOption squelchOption = SQUELCH_RECORD_SILENCE;
int fileTimeLimit = 0;
int fileTimeDurationSeconds = -1;
Timer durationMeasurement;
};
+2 -2
View File
@@ -12,8 +12,8 @@ public:
AudioSinkThread();
virtual ~AudioSinkThread();
virtual void run();
virtual void terminate();
virtual void run();
virtual void terminate();
virtual void sink(AudioThreadInputPtr input) = 0;
virtual void inputChanged(AudioThreadInput oldProps, AudioThreadInputPtr newProps) = 0;
+2
View File
@@ -21,6 +21,8 @@ public:
int channels;
float peak;
int type;
boolean is_squelch_active = false;
std::vector<float> data;
AudioThreadInput() :