lsnes rr2-β24
[lsnes.git] / src / video / sox.cpp
blob651fd0b74d87775063330f6c95ca2620b253c876
1 #include "video/sox.hpp"
2 #include "library/serialization.hpp"
4 #include <iostream>
6 namespace
8 void write_double(uint8_t* buf, double v)
10 unsigned mag = 1023;
11 while(v >= 2) {
12 mag++;
13 v /= 2;
15 while(v < 1) {
16 mag--;
17 v *= 2;
19 uint64_t v2 = mag;
20 v -= 1;
21 for(unsigned i = 0; i < 52; i++) {
22 v *= 2;
23 v2 = 2 * v2 + ((v >= 1) ? 1 : 0);
24 if(v >= 1)
25 v -= 1;
27 serialization::u64l(buf, v2);
31 sox_dumper::sox_dumper(const std::string& filename, double samplerate, uint32_t channels) throw(std::bad_alloc,
32 std::runtime_error)
34 sox_file.open(filename.c_str(), std::ios::out | std::ios::binary);
35 if(!sox_file)
36 throw std::runtime_error("Can't open sox file for output");
37 try {
38 uint8_t buffer[32] = {0};
39 serialization::u64l(buffer, 0x1C586F532E); //Magic and header size.
40 write_double(buffer + 16, samplerate);
41 serialization::u32l(buffer + 24, channels);
42 sox_file.write(reinterpret_cast<char*>(buffer), 32);
43 if(!sox_file)
44 throw std::runtime_error("Can't write audio header");
45 samplebuffer.resize(channels);
46 databuf.resize(channels << 2);
47 samples_dumped = 0;
48 } catch(...) {
49 sox_file.close();
50 throw;
54 sox_dumper::~sox_dumper() throw()
56 try {
57 close();
58 } catch(...) {
62 void sox_dumper::close() throw(std::bad_alloc, std::runtime_error)
64 sox_file.seekp(8, std::ios::beg);
65 uint8_t buffer[8];
66 uint64_t raw_samples = samples_dumped * samplebuffer.size();
67 serialization::u64l(buffer, raw_samples);
68 sox_file.write(reinterpret_cast<char*>(buffer), 8);
69 if(!sox_file)
70 throw std::runtime_error("Can't fixup audio header");
71 sox_file.close();
74 void sox_dumper::internal_dump_sample()
76 for(size_t i = 0; i < samplebuffer.size(); ++i)
77 serialization::u32l(&databuf[4 * i], static_cast<uint32_t>(samplebuffer[i]));
78 sox_file.write(&databuf[0], databuf.size());
79 if(!sox_file)
80 throw std::runtime_error("Failed to dump sample");
81 samples_dumped++;