lsnes/avi/sox.cpp
2011-11-06 14:41:41 +02:00

107 lines
2.4 KiB
C++

#include "sox.hpp"
#include <iostream>
namespace
{
void write_double(uint8_t* buf, double v)
{
unsigned mag = 1023;
while(v >= 2) {
mag++;
v /= 2;
}
while(v < 1) {
mag--;
v *= 2;
}
uint64_t v2 = mag;
v -= 1;
for(unsigned i = 0; i < 52; i++) {
v *= 2;
v2 = 2 * v2 + ((v >= 1) ? 1 : 0);
if(v >= 1)
v -= 1;
}
buf[0] = v2;
buf[1] = v2 >> 8;
buf[2] = v2 >> 16;
buf[3] = v2 >> 24;
buf[4] = v2 >> 32;
buf[5] = v2 >> 40;
buf[6] = v2 >> 48;
buf[7] = v2 >> 56;
}
}
sox_dumper::sox_dumper(const std::string& filename, double samplerate, uint32_t channels) throw(std::bad_alloc,
std::runtime_error)
{
sox_file.open(filename.c_str(), std::ios::out | std::ios::binary);
if(!sox_file)
throw std::runtime_error("Can't open sox file for output");
try {
uint8_t buffer[32] = {0};
buffer[0] = 0x2E; //Magic.
buffer[1] = 0x53; //Magic.
buffer[2] = 0x6F; //Magic.
buffer[3] = 0x58; //Magic.
buffer[4] = 0x1C; //Header size.
write_double(buffer + 16, samplerate);
buffer[24] = channels;
buffer[25] = channels >> 8;
buffer[26] = channels >> 16;
buffer[27] = channels >> 24;
sox_file.write(reinterpret_cast<char*>(buffer), 32);
if(!sox_file)
throw std::runtime_error("Can't write audio header");
samplebuffer.resize(channels);
databuf.resize(channels << 2);
samples_dumped = 0;
} catch(...) {
sox_file.close();
throw;
}
}
sox_dumper::~sox_dumper() throw()
{
try {
close();
} catch(...) {
}
}
void sox_dumper::close() throw(std::bad_alloc, std::runtime_error)
{
sox_file.seekp(8, std::ios::beg);
uint8_t buffer[8];
uint64_t raw_samples = samples_dumped * samplebuffer.size();
buffer[0] = raw_samples;
buffer[1] = raw_samples >> 8;
buffer[2] = raw_samples >> 16;
buffer[3] = raw_samples >> 24;
buffer[4] = raw_samples >> 32;
buffer[5] = raw_samples >> 40;
buffer[6] = raw_samples >> 48;
buffer[7] = raw_samples >> 56;
sox_file.write(reinterpret_cast<char*>(buffer), 8);
if(!sox_file)
throw std::runtime_error("Can't fixup audio header");
sox_file.close();
}
void sox_dumper::internal_dump_sample()
{
for(size_t i = 0; i < samplebuffer.size(); ++i) {
uint32_t v = samplebuffer[i];
databuf[4 * i + 0] = v;
databuf[4 * i + 1] = v >> 8;
databuf[4 * i + 2] = v >> 16;
databuf[4 * i + 3] = v >> 24;
}
sox_file.write(&databuf[0], databuf.size());
if(!sox_file)
throw std::runtime_error("Failed to dump sample");
samples_dumped++;
}