Skip to content
Snippets Groups Projects

High blue rec

2 files
+ 10
1
Compare changes
  • Side-by-side
  • Inline

Files

src/main.cpp 0 → 100644
+ 216
0
/**
* SMIoT JASON Qualilife sound recorder command line program.
*
* Author: Jan Schlüter <jan.schluter@lis-lab.fr>
* Author: Maxence Ferrari <maxence.ferrari@lis-lab.fr>
*/
#include <iostream>
#include <string>
#include <memory>
#include <cstring>
#include "recorder.h"
#include "filewriter.h"
#include "cleanexit.h"
void print_usage(char *name) {
std::cout << "SMIoT JASON Qualilife sound recorder";
#ifdef JASONREC_VERSION
std::cout << " v" << JASONREC_VERSION;
#endif
std::cout << std::endl;
std::cout << "Usage: " << name << " channels rate filename [--help, -h] [--chunk_len, -c CHUNK_LEN] "
<< "[--total_len, -t TOTAL_LEN] [--device, -d DEVICE] [--bit_depth, -b BIT_DEPTH] "
<< "[--imu, -i IMU] [--filter, -f FILTER] [--verbose, -v]" << std::endl;
std::cout << "Positional arguments:" << std::endl;
std::cout << " CHANNELS:\tnumber of channels to record (1 to 5)" << std::endl;
std::cout << " RATE:\tsample rate in Hz to record at (integral number)" << std::endl;
std::cout << " FILENAME:\toutput file name. should include strftime() format specifiers" << std::endl;
std::cout << " if CHUNK_LEN is specified. For miliseconds, use %z. Example: location/recording_%Y%m%d_%H%M%S_%z.wav" << std::endl;
std::cout << "Optional arguments:" << std::endl;
std::cout << "-h, --help\t\tshow this help message and exit" << std::endl;
std::cout << " --bit_depth, -b\tBIT_DEPTH:\tSize of each samples in bits. Must be a multiple of 8. (Default: 16)" << std::endl;
std::cout << " --imu, -i\tIMU:\tIMU file name. Similar to FILENAME. Disable by default." << std::endl;
std::cout << " --filter, -f\tFILTER:\tNumber of the filter to use. Must be between 0 and 2. (Default: 0)" << std::endl;
std::cout << " --chunk_len, -c\tCHUNK_LEN:\tlength per output file in seconds; will start a new file whenever" << std::endl;
std::cout << " this length is reached. If not given or zero, will record a single file." << std::endl;
std::cout << " --total_len, -t\tTOTAL_LEN:\tTotal recording length; will stop when this length is reached." << std::endl;
std::cout << " If not given or zero, will record continuously until killed." << std::endl;
std::cout << " --device, -d\tDEVICE:\tWhich device to use in case multiple JASON cards are connected," << std::endl;
std::cout << " where 0 is the first, 1 is the second card found (and so on)." << std::endl;
std::cout << " --verbose, -v\t\tEnable the printing of status message " << std::endl;
}
int record(size_t channels, size_t rate, size_t depth, size_t filter, std::string &filename, std::string &imu_name,
float chunklen, float totallen, size_t device, bool verbose) {
JasonRecorder recorder = JasonRecorder(verbose);
std::cout << "Found " << recorder.get_device_count() << " JASON card(s)." << std::endl;
if (recorder.get_device_count() == 0) {
std::cout << "Aborting." << std::endl;
return 2;
}
try {
// prepare the device
std::cout << "Selecting device number " << device << "..." << std::endl;
recorder.set_device(device);
// prepare the file writer
std::unique_ptr<FileWriter> filewriter;
if (chunklen > 0 && imu_name.empty()) {
// implementation note: in C++14 we would use std::make_unique<SplitWavFileWriter>(...)
filewriter.reset(new SplitWavFileWriter(filename, channels, rate, depth, chunklen * rate));
}
else if (chunklen > 0) {
// implementation note: in C++14 we would use std::make_unique<SplitWavFileWriter>(...)
filewriter.reset(new SplitIMUWavFileWriter(filename, imu_name, channels, rate, depth, chunklen * rate));
}
else if (imu_name.empty()){
filewriter.reset(new WavFileWriter(filename, channels, rate, depth, totallen * rate));
}
else{
filewriter.reset(new SplitIMUWavFileWriter(filename, imu_name, channels, rate, depth, totallen * rate));
}
// start the recording loop
std::cout << "Starting to record..." << std::endl;
allow_clean_exit();
size_t total_samples_wanted = totallen * rate;
size_t total_samples_read = 0;
size_t failed_attempts = 0;
size_t sample_size = channels * depth;
std::vector<std::uint8_t> samples;
std::vector<std::uint8_t> imu_data;
try {
std::cout << "Setting recording format to " << channels << " channels at " << rate << " Hz " << (8 * depth) << " bits" << std::endl;
recorder.start_recording(channels, rate, depth, filter);
// we will record until we have enough (or forever, if totallen == 0)
while ((total_samples_wanted == 0) || (total_samples_read < total_samples_wanted)) {
if (exit_requested()) {
std::cout << "Termination requested." << std::endl;
break;
}
recorder.get_samples(samples, imu_data, false, 500);
if (!samples.empty()) {
total_samples_read += samples.size() / sample_size;
// if we have too much now, crop the last packet
if ((total_samples_wanted > 0) && (total_samples_read > total_samples_wanted)) {
samples.resize(samples.size() - (total_samples_read - total_samples_wanted) * sample_size);
}
// pass it on to the file writer
filewriter->write(samples, imu_data);
failed_attempts = 0;
}
else {
// if we received no message or no audio data 20x in a row, abort
failed_attempts += 1;
if (failed_attempts >= 20) {
throw std::runtime_error("Device does not send audio data.");
}
}
}
recorder.stop_recording();
std::cout << "Stopped recording." << std::endl;
}
catch (const std::exception& e) {
recorder.stop_recording();
throw;
}
}
catch (const std::exception& e) {
std::cout << "Error: " << e.what() << std::endl;
return 2;
}
return 0;
}
int main(int argc, char *argv[]) {
if (argc < 4) {
print_usage(argv[0]);
return 2;
}
// parse command line options
int num_channels;
try {
num_channels = std::stoi(argv[1]);
if ((num_channels < 1) || (num_channels > MAX_CHANNELS)) {
std::cout << "Error: CHANNELS must be in 1.." << MAX_CHANNELS << ", got " << num_channels << " instead" << std::endl;
return 2;}
}
catch (const std::exception& e) {
std::cout << "Error: Could not interpret " << argv[1] << " as an integer." << std::endl;
return 2;
}
int rate;
try {
rate = std::stoi(argv[2]);
if (rate!= 32000 && rate!=64000 && rate!=128000 && rate!=256000 && rate!=512000) {
std::cout << "Error: RATE must be a power 2 times 32kHz, got " << rate << " instead" << std::endl;
return 2;
}
}
catch (const std::exception& e) {
std::cout << "Error: Could not interpret " << argv[2] << " as an integer." << std::endl;
return 2;
}
std::string filename = argv[3];
int i=4;
int device(0), bit_depth(16), filter(0);
float chunklen(0), totallen(0);
std::string imu_name;
bool verbose(false);
while (i < argc){
try{
if (strcmp(argv[i], "--chunk_len") == 0 || strcmp(argv[i], "-c") == 0) {
chunklen = atof(argv[++i]);
if ((chunklen < 0)) {
std::cout << "Error: CHUNKLEN must be positive or zero, got " << chunklen << " instead" << std::endl;
return 2;
}}
else if (strcmp(argv[i], "--imu") == 0 || strcmp(argv[i], "-i") == 0) {
imu_name = argv[++i];
}
else if (strcmp(argv[i], "--device") == 0 || strcmp(argv[i], "-d") == 0) {
device = atoi(argv[++i]);
if ((device < 0)) {
std::cout << "Error: DEVICE must be nonnegative, got " << device << " instead" << std::endl;
return 2;
}}
else if (strcmp(argv[i], "--total_len") == 0 || strcmp(argv[i], "-t") == 0) {
totallen = atof(argv[++i]);
if ((totallen < 0)) {
std::cout << "Error: TOTALLEN must be positive or zero, got " << totallen << " instead" << std::endl;
return 2;
}}
else if (strcmp(argv[i], "--bit_depth") == 0 || strcmp(argv[i], "-b") == 0) {
bit_depth = atoi(argv[++i]);
if (bit_depth % 8) {
std::cout << "Error: DEPTH must be a multiple of 8, got " << bit_depth << " instead" << std::endl;
return 2;
}}
else if (strcmp(argv[i], "--filter") == 0 || strcmp(argv[i], "-f") == 0) {
filter = atoi(argv[++i]);
if (filter < 0 || filter > 2 ) {
std::cout << "Error: filter must be between 0 and 2, got " << filter << " instead" << std::endl;
return 2;
}}
else if (strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0){
print_usage(argv[0]);
return 1;
}
else if (strcmp(argv[i], "--verbose") == 0 || strcmp(argv[i], "-v") == 0){
verbose = true;
}
else {
std::cout << "Unrecognized argument " << argv[i] << std::endl;
return 2;
}}
catch (const std::exception& e) {
std::cout << "Error: Could not interpret " << argv[i] << " ( " << argv[i-1] << " ) " " as a number." << std::endl;
return 2;
}
i++;
}
// hand over to the recording function
return record(num_channels, rate, bit_depth/8, filter, filename, imu_name, chunklen, totallen, device, verbose);
}
Loading