Commit 66afc3d9 authored by Philippe Gorley's avatar Philippe Gorley Committed by Adrien Béraud

debug: add wav writer

Helps debug audio woes by writing sound to a file for later analysis.

Change-Id: Iab1c3aff36624024a90af4991c1f5b8ee70ac0bf
parent 6fe4bc49
......@@ -22,7 +22,11 @@
#include "config.h"
#include "libav_deps.h"
#include <chrono>
#include <fstream>
#include <ios>
#include <ratio>
#warning Debug utilities included in build
......@@ -53,4 +57,94 @@ private:
std::chrono::time_point<Clock> start_;
};
/**
* Minimally invasive audio logger. Writes a wav file from raw PCM or AVFrame. Helps debug what goes wrong with audio.
*/
class WavWriter
{
public:
WavWriter(std::string filename, int channels, int sampleRate, int bytesPerSample)
{
f_ = std::ofstream(filename, std::ios::binary);
f_ << "RIFF----WAVEfmt ";
write(16, 4); // no extension data
write(1, 2); // PCM integer samples
write(channels, 2); // channels
write(sampleRate, 4); // sample rate
write(sampleRate * channels * bytesPerSample, 4); // sample size
write(4, 2); // data block size
write(bytesPerSample * 8, 2); // bits per sample
dataChunk_ = f_.tellp();
f_ << "data----";
}
~WavWriter()
{
length_ = f_.tellp();
f_.seekp(dataChunk_ + 4);
write(length_ - dataChunk_ + 8, 4);
f_.seekp(4);
write(length_ - 8, 4);
}
template<typename Word>
void write(Word value, unsigned size)
{
for (; size; --size, value >>= 8)
f_.put(static_cast<char>(value & 0xFF));
}
void write(AVFrame* frame)
{
AVSampleFormat fmt = (AVSampleFormat)frame->format;
int channels = frame->channels;
int depth = av_get_bytes_per_sample(fmt);
int linesize = frame->linesize[0];
int planar = av_sample_fmt_is_planar(fmt);
int step = (planar ? depth : depth * channels);
for (int i = 0; i < linesize; i += step) {
for (int ch = 0; ch < channels; ++ch) {
int c = (planar ? ch : 0);
int offset = (planar ? i : i + depth * ch);
writeSample(&frame->extended_data[c][offset], fmt, depth);
}
}
}
private:
void writeSample(uint8_t* p, AVSampleFormat format, int size)
{
switch (format) {
case AV_SAMPLE_FMT_U8:
case AV_SAMPLE_FMT_U8P:
write(*(uint8_t*)p, size);
break;
case AV_SAMPLE_FMT_S16:
case AV_SAMPLE_FMT_S16P:
write(*(int16_t*)p, size);
break;
case AV_SAMPLE_FMT_S32:
case AV_SAMPLE_FMT_S32P:
case AV_SAMPLE_FMT_FLT:
case AV_SAMPLE_FMT_FLTP:
// float samples are always 32 bits in FFmpeg
write(*(int32_t*)p, size);
break;
case AV_SAMPLE_FMT_S64:
case AV_SAMPLE_FMT_S64P:
case AV_SAMPLE_FMT_DBL:
case AV_SAMPLE_FMT_DBLP:
// dbl samples are always 64 bits in FFmpeg
write(*(int64_t*)p, size);
break;
default:
break;
}
}
std::ofstream f_;
size_t dataChunk_;
size_t length_;
};
}} // namespace ring::debug
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment