From aa8ac249a0f178acc307410c74cb2f2429dec54a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AE=D1=80=D0=B8=D0=B9=20=D0=93=D1=83=D0=B1=D0=B8=D1=87?= Date: Sat, 29 Dec 2018 21:08:22 +0300 Subject: [PATCH] possible to decode portions, possible to find out how much is still available for one stream decoding --- index.html | 36 ++++++++++++++++++------------ wrapper.cpp | 64 ++++++++++++++++++++++++++++++++--------------------- wrapper.h | 9 +++++--- 3 files changed, 67 insertions(+), 42 deletions(-) diff --git a/index.html b/index.html index 3166bd1..2930041 100644 --- a/index.html +++ b/index.html @@ -12,41 +12,49 @@ diff --git a/wrapper.cpp b/wrapper.cpp index 71e690a..8446acd 100644 --- a/wrapper.cpp +++ b/wrapper.cpp @@ -1,5 +1,6 @@ #include "wrapper.h" #include +#include MadHeader * mad_header_create() { @@ -74,6 +75,7 @@ Decoder::Decoder(): sampleRate(0), channels(0), cachedLength(0), + samplesPerFrame(0), currentBuffer(0), currentBufferLength(0), synth(), @@ -121,29 +123,36 @@ void Decoder::addFragment(intptr_t bufferPtr, unsigned long length) framesLeft(); } -emscripten::val Decoder::decode(int count) +emscripten::val Decoder::decode(uint32_t count) { emscripten::val ret = emscripten::val::undefined(); - int result = -1; int available = framesLeft(count); if (available > 0) { - ret = context.call("createBuffer", channels, synth.pcm.length, sampleRate); - } - - if (result == 0) { - mad_synth_frame(&synth, &frame); - ret = context.call("createBuffer", synth.pcm.channels, synth.pcm.length, synth.pcm.samplerate); - for (int i = 0; i < synth.pcm.channels; ++i) { - emscripten::val chan = ret.call("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)); + ret = context.call("createBuffer", channels, available * samplesPerFrame, sampleRate); + + std::vector chans(channels, emscripten::val::undefined()); + for (int i = 0; i < channels; ++i) { + chans[i] = ret.call("getChannelData", i); + } + + for (int i = 0; i < available; ++i) { + mad_frame_decode(&frame, &stream); + mad_synth_frame(&synth, &frame); + + for (int j = 0; j < samplesPerFrame; ++j) { + for (int k = 0; k < channels; ++k) { + float value = mad_f_todouble(synth.pcm.samples[k][j]); + chans[k].set(std::to_string(i * samplesPerFrame + j), val(value)); + } } } - return ret; + cachedLength -= available; + + if (cachedLength == 0) { + framesLeft(); + } } return ret; @@ -158,38 +167,43 @@ bool Decoder::hasMore() const return stream.error != MAD_ERROR_BUFLEN; } -uint64_t Decoder::framesLeft(uint64_t max) +uint32_t Decoder::framesLeft(uint32_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_buffer(&probe, currentBuffer, currentBufferLength); mad_stream_skip(&probe, stream.skiplen); - while (probe.error != MAD_ERROR_BUFLEN || cachedLength < max) { + + while (cachedLength < max) { if (mad_header_decode(&ph, &probe) == 0) { if (sampleRate == 0) { sampleRate = ph.samplerate; channels = MAD_NCHANNELS(&ph); + samplesPerFrame = MAD_NSBSAMPLES(&ph) * 32; //not sure why 32, it's in libmad source } else { - if (sampleRate != ph.samplerate || channels != MAD_NCHANNELS(&ph)) { + if (sampleRate != ph.samplerate || channels != MAD_NCHANNELS(&ph) || samplesPerFrame != MAD_NSBSAMPLES(&ph) * 32) { break; } } ++cachedLength; + } else { + if (!MAD_RECOVERABLE(probe.error)) { + std::cout << "framesLeft::" << probe.error << std::endl; + break; + } } } + + mad_header_finish(&ph); + mad_stream_finish(&probe); } return std::min(cachedLength, max); diff --git a/wrapper.h b/wrapper.h index eb6c366..7dc7d67 100644 --- a/wrapper.h +++ b/wrapper.h @@ -124,14 +124,15 @@ public: ~Decoder(); void addFragment(intptr_t bufferPtr, unsigned long length); - val decode(int count); + val decode(uint32_t count = UINT32_MAX); bool hasMore() const; - uint64_t framesLeft(uint64_t max = UINT64_MAX); + uint32_t framesLeft(uint32_t max = UINT32_MAX); private: uint32_t sampleRate; uint8_t channels; - uint64_t cachedLength; + uint32_t cachedLength; + uint16_t samplesPerFrame; unsigned char* currentBuffer; unsigned long currentBufferLength; @@ -236,6 +237,7 @@ EMSCRIPTEN_BINDINGS(jsmad) { function("mad_stream_init", &mad_stream_init, allow_raw_pointers()); function("mad_stream_finish", &mad_stream_finish, allow_raw_pointers()); function("mad_stream_buffer", &mad_stream_buffer, allow_raw_pointers()); + function("mad_stream_sync", &mad_stream_sync, allow_raw_pointers()); class_("mad_pcm"); class_>("MadPCM") @@ -259,6 +261,7 @@ EMSCRIPTEN_BINDINGS(jsmad) { .constructor<>() .function("addFragment", &Decoder::addFragment) .function("hasMore", &Decoder::hasMore) + .function("framesLeft", &Decoder::framesLeft) .function("decode", &Decoder::decode); }