198 lines
4.7 KiB
C++
198 lines
4.7 KiB
C++
#include "wrapper.h"
|
|
#include <string>
|
|
|
|
MadHeader * mad_header_create()
|
|
{
|
|
MadHeader* header = new MadHeader;
|
|
mad_header_init(header);
|
|
return header;
|
|
}
|
|
|
|
MadFrame * mad_frame_create()
|
|
{
|
|
MadFrame* frame = new MadFrame;
|
|
mad_frame_init(frame);
|
|
return frame;
|
|
}
|
|
|
|
emscripten::val MadFrame::getOverlap() const
|
|
{
|
|
unsigned char* ptr = (unsigned char(*))*overlap;
|
|
return emscripten::val(typed_memory_view(sizeof *overlap, ptr));
|
|
}
|
|
|
|
emscripten::val MadFrame::getSbsample() const
|
|
{
|
|
unsigned char* ptr = (unsigned char(*))sbsample;
|
|
return emscripten::val(typed_memory_view(sizeof sbsample, ptr));
|
|
}
|
|
|
|
MadStream* mad_stream_create() {
|
|
MadStream* stream = new MadStream;
|
|
mad_stream_init(stream);
|
|
return stream;
|
|
}
|
|
|
|
emscripten::val MadStream::mainData()
|
|
{
|
|
return emscripten::val(typed_memory_view(MAD_BUFFER_MDLEN, (unsigned char(*))main_data));
|
|
}
|
|
|
|
void MadStream::setBuffer(intptr_t bufferPtr, unsigned long length)
|
|
{
|
|
mad_stream_buffer(this, (const unsigned char(*))bufferPtr, length);
|
|
}
|
|
|
|
int MadFrame::decode(mad_stream* stream)
|
|
{
|
|
return mad_frame_decode(this, stream);
|
|
}
|
|
|
|
emscripten::val MadPCM::samples() const
|
|
{
|
|
mad_fixed_t* ptr = (mad_fixed_t(*))mad_pcm::samples;
|
|
return emscripten::val(typed_memory_view(sizeof mad_pcm::samples, ptr));
|
|
}
|
|
|
|
MadPCM* mad_pcm_create() {
|
|
MadPCM* pcm = new MadPCM();
|
|
return pcm;
|
|
}
|
|
|
|
MadSynth* mad_synth_create() {
|
|
MadSynth* synth = new MadSynth();
|
|
mad_synth_init(synth);
|
|
return synth;
|
|
}
|
|
|
|
void MadSynth::frame(const mad_frame* frame)
|
|
{
|
|
mad_synth_frame(this, frame);
|
|
}
|
|
|
|
Decoder::Decoder():
|
|
sampleRate(0),
|
|
channels(0),
|
|
cachedLength(0),
|
|
currentBuffer(0),
|
|
currentBufferLength(0),
|
|
synth(),
|
|
stream(),
|
|
frame(),
|
|
context(0)
|
|
{
|
|
mad_frame_init(&frame);
|
|
mad_stream_init(&stream);
|
|
mad_synth_init(&synth);
|
|
|
|
emscripten::val AudioContext = emscripten::val::global("AudioContext");
|
|
if (!AudioContext.as<bool>()) {
|
|
printf("No global AudioContext, trying webkitAudioContext\n");
|
|
AudioContext = emscripten::val::global("webkitAudioContext");
|
|
}
|
|
|
|
printf("Got an AudioContext\n");
|
|
context = AudioContext.new_();
|
|
}
|
|
|
|
Decoder::~Decoder()
|
|
{
|
|
context.call<void>("close");
|
|
|
|
mad_synth_finish(&synth);
|
|
mad_stream_finish(&stream);
|
|
mad_frame_finish(&frame);
|
|
|
|
if (currentBuffer != 0) {
|
|
free(currentBuffer);
|
|
}
|
|
}
|
|
|
|
void Decoder::addFragment(intptr_t bufferPtr, unsigned long length)
|
|
{
|
|
if (currentBuffer != 0) {
|
|
printf("Adding more then 1 fragment is not supported yet");
|
|
throw 1;
|
|
}
|
|
currentBuffer = (unsigned char(*))bufferPtr;
|
|
currentBufferLength = length;
|
|
|
|
mad_stream_buffer(&stream, currentBuffer, currentBufferLength);
|
|
framesLeft();
|
|
}
|
|
|
|
emscripten::val Decoder::decode(int count)
|
|
{
|
|
emscripten::val ret = emscripten::val::undefined();
|
|
int result = -1;
|
|
|
|
int available = framesLeft(count);
|
|
if (available > 0) {
|
|
ret = context.call<val>("createBuffer", channels, synth.pcm.length, sampleRate);
|
|
}
|
|
|
|
if (result == 0) {
|
|
mad_synth_frame(&synth, &frame);
|
|
ret = context.call<val>("createBuffer", synth.pcm.channels, synth.pcm.length, synth.pcm.samplerate);
|
|
for (int i = 0; i < synth.pcm.channels; ++i) {
|
|
emscripten::val chan = ret.call<val>("getChannelData", i);
|
|
mad_fixed_t* sChan = synth.pcm.samples[i];
|
|
for (int j = 0; j < synth.pcm.length; ++j) {
|
|
float value = mad_f_todouble(sChan[j]);
|
|
chan.set(std::to_string(j), val(value));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Decoder::hasMore() const
|
|
{
|
|
if (currentBuffer == 0) {
|
|
return false;
|
|
}
|
|
|
|
return stream.error != MAD_ERROR_BUFLEN;
|
|
}
|
|
|
|
uint64_t Decoder::framesLeft(uint64_t max)
|
|
{
|
|
if (currentBuffer == 0) {
|
|
return 0;
|
|
}
|
|
|
|
if (!stream.sync) {
|
|
int result = mad_stream_sync(&stream);
|
|
if (result != 0) {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
if (cachedLength == 0) {
|
|
mad_stream probe;
|
|
mad_header ph;
|
|
mad_stream_init(&probe);
|
|
mad_header_init(&ph);
|
|
mad_stream_skip(&probe, stream.skiplen);
|
|
while (probe.error != MAD_ERROR_BUFLEN || cachedLength < max) {
|
|
if (mad_header_decode(&ph, &probe) == 0) {
|
|
if (sampleRate == 0) {
|
|
sampleRate = ph.samplerate;
|
|
channels = MAD_NCHANNELS(&ph);
|
|
} else {
|
|
if (sampleRate != ph.samplerate || channels != MAD_NCHANNELS(&ph)) {
|
|
break;
|
|
}
|
|
}
|
|
++cachedLength;
|
|
}
|
|
}
|
|
}
|
|
|
|
return std::min(cachedLength, max);
|
|
}
|
|
|