refactoring

This commit is contained in:
AlexandreRouma
2023-02-07 08:33:47 +01:00
parent 7758c40bd7
commit 3451edb131
5 changed files with 1 additions and 2 deletions

134
core/src/utils/riff.cpp Normal file
View File

@ -0,0 +1,134 @@
#include "riff.h"
#include <string.h>
#include <stdexcept>
namespace riff {
const char* RIFF_SIGNATURE = "RIFF";
const char* LIST_SIGNATURE = "LIST";
const size_t RIFF_LABEL_SIZE = 4;
bool Writer::open(std::string path, const char form[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Open file
file = std::ofstream(path, std::ios::out | std::ios::binary);
if (!file.is_open()) { return false; }
// Begin RIFF chunk
beginRIFF(form);
return true;
}
bool Writer::isOpen() {
std::lock_guard<std::recursive_mutex> lck(mtx);
return file.is_open();
}
void Writer::close() {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (!isOpen()) { return; }
// Finalize RIFF chunk
endRIFF();
// Close file
file.close();
}
void Writer::beginList(const char id[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Create chunk with the LIST ID and write id
beginChunk(LIST_SIGNATURE);
write((uint8_t*)id, RIFF_LABEL_SIZE);
}
void Writer::endList() {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
throw std::runtime_error("No chunk to end");
}
if (memcmp(chunks.top().hdr.id, LIST_SIGNATURE, RIFF_LABEL_SIZE)) {
throw std::runtime_error("Top chunk not LIST chunk");
}
endChunk();
}
void Writer::beginChunk(const char id[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Create and write header
ChunkDesc desc;
desc.pos = file.tellp();
memcpy(desc.hdr.id, id, sizeof(desc.hdr.id));
desc.hdr.size = 0;
file.write((char*)&desc.hdr, sizeof(ChunkHeader));
// Save descriptor
chunks.push(desc);
}
void Writer::endChunk() {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
throw std::runtime_error("No chunk to end");
}
// Get descriptor
ChunkDesc desc = chunks.top();
chunks.pop();
// Write size
auto pos = file.tellp();
auto npos = desc.pos;
npos += 4;
file.seekp(npos);
file.write((char*)&desc.hdr.size, sizeof(desc.hdr.size));
file.seekp(pos);
// If parent chunk, increment its size
if (!chunks.empty()) {
chunks.top().hdr.size += desc.hdr.size;
}
}
void Writer::write(const uint8_t* data, size_t len) {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
throw std::runtime_error("No chunk to write into");
}
file.write((char*)data, len);
chunks.top().hdr.size += len;
}
void Writer::beginRIFF(const char form[4]) {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (!chunks.empty()) {
throw std::runtime_error("Can't create RIFF chunk on an existing RIFF file");
}
// Create chunk with RIFF ID and write form
beginChunk(RIFF_SIGNATURE);
write((uint8_t*)form, RIFF_LABEL_SIZE);
}
void Writer::endRIFF() {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (chunks.empty()) {
throw std::runtime_error("No chunk to end");
}
if (memcmp(chunks.top().hdr.id, RIFF_SIGNATURE, RIFF_LABEL_SIZE)) {
throw std::runtime_error("Top chunk not RIFF chunk");
}
endChunk();
}
}

43
core/src/utils/riff.h Normal file
View File

@ -0,0 +1,43 @@
#pragma once
#include <mutex>
#include <fstream>
#include <string>
#include <stack>
#include <stdint.h>
namespace riff {
#pragma pack(push, 1)
struct ChunkHeader {
char id[4];
uint32_t size;
};
#pragma pack(pop)
struct ChunkDesc {
ChunkHeader hdr;
std::streampos pos;
};
class Writer {
public:
bool open(std::string path, const char form[4]);
bool isOpen();
void close();
void beginList(const char id[4]);
void endList();
void beginChunk(const char id[4]);
void endChunk();
void write(const uint8_t* data, size_t len);
private:
void beginRIFF(const char form[4]);
void endRIFF();
std::recursive_mutex mtx;
std::ofstream file;
std::stack<ChunkDesc> chunks;
};
}

183
core/src/utils/wav.cpp Normal file
View File

@ -0,0 +1,183 @@
#include "wav.h"
#include <volk/volk.h>
#include <stdexcept>
#include <dsp/buffer/buffer.h>
#include <dsp/stream.h>
#include <map>
namespace wav {
const char* WAVE_FILE_TYPE = "WAVE";
const char* FORMAT_MARKER = "fmt ";
const char* DATA_MARKER = "data";
const uint32_t FORMAT_HEADER_LEN = 16;
const uint16_t SAMPLE_TYPE_PCM = 1;
std::map<SampleType, int> SAMP_BITS = {
{ SAMP_TYPE_UINT8, 8 },
{ SAMP_TYPE_INT16, 16 },
{ SAMP_TYPE_INT32, 32 },
{ SAMP_TYPE_FLOAT32, 32 }
};
Writer::Writer(int channels, uint64_t samplerate, Format format, SampleType type) {
// Validate channels and samplerate
if (channels < 1) { throw std::runtime_error("Channel count must be greater or equal to 1"); }
if (!samplerate) { throw std::runtime_error("Samplerate must be non-zero"); }
// Initialize variables
_channels = channels;
_samplerate = samplerate;
_format = format;
_type = type;
}
Writer::~Writer() { close(); }
bool Writer::open(std::string path) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Close previous file
if (rw.isOpen()) { close(); }
// Reset work values
samplesWritten = 0;
// Fill header
bytesPerSamp = (SAMP_BITS[_type] / 8) * _channels;
hdr.codec = (_type == SAMP_TYPE_FLOAT32) ? CODEC_FLOAT : CODEC_PCM;
hdr.channelCount = _channels;
hdr.sampleRate = _samplerate;
hdr.bitDepth = SAMP_BITS[_type];
hdr.bytesPerSample = bytesPerSamp;
hdr.bytesPerSecond = bytesPerSamp * _samplerate;
// Precompute sizes and allocate buffers
switch (_type) {
case SAMP_TYPE_UINT8:
bufU8 = dsp::buffer::alloc<uint8_t>(STREAM_BUFFER_SIZE * _channels);
break;
case SAMP_TYPE_INT16:
bufI16 = dsp::buffer::alloc<int16_t>(STREAM_BUFFER_SIZE * _channels);
break;
case SAMP_TYPE_INT32:
bufI32 = dsp::buffer::alloc<int32_t>(STREAM_BUFFER_SIZE * _channels);
break;
case SAMP_TYPE_FLOAT32:
break;
default:
return false;
break;
}
// Open file
if (!rw.open(path, WAVE_FILE_TYPE)) { return false; }
// Write format chunk
rw.beginChunk(FORMAT_MARKER);
rw.write((uint8_t*)&hdr, sizeof(FormatHeader));
rw.endChunk();
// Begin data chunk
rw.beginChunk(DATA_MARKER);
return true;
}
bool Writer::isOpen() {
std::lock_guard<std::recursive_mutex> lck(mtx);
return rw.isOpen();
}
void Writer::close() {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Do nothing if the file is not open
if (!rw.isOpen()) { return; }
// Finish data chunk
rw.endChunk();
// Close the file
rw.close();
// Free buffers
if (bufU8) {
dsp::buffer::free(bufU8);
bufU8 = NULL;
}
if (bufI16) {
dsp::buffer::free(bufI16);
bufI16 = NULL;
}
if (bufI32) {
dsp::buffer::free(bufI32);
bufI32 = NULL;
}
}
void Writer::setChannels(int channels) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Do not allow settings to change while open
if (rw.isOpen()) { throw std::runtime_error("Cannot change parameters while file is open"); }
// Validate channel count
if (channels < 1) { throw std::runtime_error("Channel count must be greater or equal to 1"); }
_channels = channels;
}
void Writer::setSamplerate(uint64_t samplerate) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Do not allow settings to change while open
if (rw.isOpen()) { throw std::runtime_error("Cannot change parameters while file is open"); }
// Validate samplerate
if (!samplerate) { throw std::runtime_error("Samplerate must be non-zero"); }
_samplerate = samplerate;
}
void Writer::setFormat(Format format) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Do not allow settings to change while open
if (rw.isOpen()) { throw std::runtime_error("Cannot change parameters while file is open"); }
_format = format;
}
void Writer::setSampleType(SampleType type) {
std::lock_guard<std::recursive_mutex> lck(mtx);
// Do not allow settings to change while open
if (rw.isOpen()) { throw std::runtime_error("Cannot change parameters while file is open"); }
_type = type;
}
void Writer::write(float* samples, int count) {
std::lock_guard<std::recursive_mutex> lck(mtx);
if (!rw.isOpen()) { return; }
// Select different writer function depending on the chose depth
int tcount = count * _channels;
int tbytes = count * bytesPerSamp;
switch (_type) {
case SAMP_TYPE_UINT8:
// Volk doesn't support unsigned ints yet :/
for (int i = 0; i < tcount; i++) {
bufU8[i] = (samples[i] * 127.0f) + 128.0f;
}
rw.write(bufU8, tbytes);
break;
case SAMP_TYPE_INT16:
volk_32f_s32f_convert_16i(bufI16, samples, 32767.0f, tcount);
rw.write((uint8_t*)bufI16, tbytes);
break;
case SAMP_TYPE_INT32:
volk_32f_s32f_convert_32i(bufI32, samples, 2147483647.0f, tcount);
rw.write((uint8_t*)bufI32, tbytes);
break;
case SAMP_TYPE_FLOAT32:
rw.write((uint8_t*)samples, tbytes);
break;
default:
break;
}
// Increment sample counter
samplesWritten += count;
}
}

71
core/src/utils/wav.h Normal file
View File

@ -0,0 +1,71 @@
#pragma once
#include <string>
#include <fstream>
#include <stdint.h>
#include <mutex>
#include "riff.h"
namespace wav {
#pragma pack(push, 1)
struct FormatHeader {
uint16_t codec;
uint16_t channelCount;
uint32_t sampleRate;
uint32_t bytesPerSecond;
uint16_t bytesPerSample;
uint16_t bitDepth;
};
#pragma pack(pop)
enum Format {
FORMAT_WAV,
FORMAT_RF64
};
enum SampleType {
SAMP_TYPE_UINT8,
SAMP_TYPE_INT16,
SAMP_TYPE_INT32,
SAMP_TYPE_FLOAT32
};
enum Codec {
CODEC_PCM = 1,
CODEC_FLOAT = 3
};
class Writer {
public:
Writer(int channels = 2, uint64_t samplerate = 48000, Format format = FORMAT_WAV, SampleType type = SAMP_TYPE_INT16);
~Writer();
bool open(std::string path);
bool isOpen();
void close();
void setChannels(int channels);
void setSamplerate(uint64_t samplerate);
void setFormat(Format format);
void setSampleType(SampleType type);
size_t getSamplesWritten() { return samplesWritten; }
void write(float* samples, int count);
private:
std::recursive_mutex mtx;
FormatHeader hdr;
riff::Writer rw;
int _channels;
uint64_t _samplerate;
Format _format;
SampleType _type;
size_t bytesPerSamp;
uint8_t* bufU8 = NULL;
int16_t* bufI16 = NULL;
int32_t* bufI32 = NULL;
size_t samplesWritten = 0;
};
}