diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..95d00276 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,75 @@ +name: build + +on: + push: + pull_request: + workflow_dispatch: + +jobs: + build: + name: ${{ matrix.platform }} (${{ matrix.toolchain }}) ${{ matrix.build_type }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + # Full cross-product: every platform in both configurations. The include + # entries key off `os`, an existing matrix value, so they merge into the + # matching combinations rather than creating extra jobs. + matrix: + os: [ubuntu-latest, windows-latest, macos-latest] + build_type: [Debug, Release] + include: + - os: ubuntu-latest + platform: Linux + toolchain: GCC + - os: windows-latest + platform: Windows + toolchain: MSVC + - os: macos-latest + platform: macOS + toolchain: Clang + + steps: + - name: Checkout + uses: actions/checkout@v5 + + # The bundled SDL3 is built from source, so its Linux backends need the + # usual X11/Wayland/audio/GL development headers. + - name: Install Linux dependencies + if: runner.os == 'Linux' + run: | + sudo apt-get update + sudo apt-get install -y \ + libx11-dev libxext-dev libxrandr-dev libxcursor-dev libxi-dev \ + libxfixes-dev libxss-dev libxkbcommon-dev libxtst-dev \ + libwayland-dev wayland-protocols libwayland-egl-backend-dev \ + libegl1-mesa-dev libgles2-mesa-dev libgl1-mesa-dev \ + libasound2-dev libpulse-dev libpipewire-0.3-dev \ + libdbus-1-dev libudev-dev + + - name: Configure + run: > + cmake -S . -B build + -DBSTONE_SDL_BUNDLED=ON + -DBSTONE_TESTS=ON + -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + + # No --target, so this builds every target: the game, the tools, the + # bundled libraries and the test suite. + - name: Build all targets + run: cmake --build build --config ${{ matrix.build_type }} --parallel + + # Run in both configurations on purpose. A Release build defines NDEBUG, + # which compiles BSTONE_ASSERT away, so the Debug run is what exercises + # the assertion-guarded failure paths. + - name: Run tests + shell: bash + run: | + set -euo pipefail + bin=$(find build -type f \( -name bstone_tests -o -name bstone_tests.exe \) | head -1) + if [ -z "$bin" ]; then + echo "::error::bstone_tests binary not found" + find build -name 'bstone_tests*' || true + exit 1 + fi + echo "Running $bin" + "$bin" diff --git a/.gitignore b/.gitignore index 2fe045b8..ddafe0a0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ build/ +build-*/ +data/ .vscode/ .vs/ .DS_Store +test.data diff --git a/README.md b/README.md index 14a2785b..81b98178 100644 --- a/README.md +++ b/README.md @@ -1151,14 +1151,11 @@ Add option `--cheats` to enable these keys. * [Nuked OPL3](http://github.com/nukeykt/Nuked-OPL3) See file `src/lib/nuked_opl3/LICENSE` for license information -* [FLAC](https://xiph.org/flac/) - See file `src/lib/flac/COPYING.Xiph` for license information +* [dr_flac](https://github.com/mackron/dr_libs) + FLAC decoder. See the license statement at the end of file `src/lib/dr_flac/dr_flac.h` (public domain or MIT-0). -* [Ogg](https://www.xiph.org/ogg/) - See file `src/lib/ogg/COPYING` for license information - -* [Vorbis](https://www.xiph.org/vorbis/) - See file `src/lib/vorbis/COPYING` for license information +* [stb_vorbis](https://github.com/nothings/stb) + Ogg Vorbis decoder. See the license statement at the end of file `src/lib/stb_vorbis/stb_vorbis.c` (public domain or MIT). 17 - Credits diff --git a/src/bstone/CMakeLists.txt b/src/bstone/CMakeLists.txt index 1404a9bf..b3fc94e2 100644 --- a/src/bstone/CMakeLists.txt +++ b/src/bstone/CMakeLists.txt @@ -285,13 +285,11 @@ target_link_libraries(bstone ${CMAKE_DL_LIBS} bstone::lib::sdl Threads::Threads - bstone::lib::flac + bstone::lib::dr_flac bstone::lib::khronos bstone::lib::nuked_opl3 - bstone::lib::ogg bstone::lib::openal_soft - bstone::lib::vorbis - bstone::lib::vorbisfile + bstone::lib::stb_vorbis bstone::lib::xbrz bstone::lib::zlib bstone::lib::vulkan @@ -956,10 +954,17 @@ source_group("bstone" FILES ${BSTONE_BSTONE_SOURCES}) if (WIN32) set(BSTONE_RESOURCES_WIN32_SOURCES src/resources/win32/bstone_win32_rc.h - $<$:src/resources/win32/bstone_win32_msvc.manifest> "${PROJECT_BINARY_DIR}/src/resources/win32/bstone_win32.rc" ) + # The manifest is MSVC-only. Use a plain if(MSVC) rather than a + # $ genex in the source list: the Visual Studio generator + # rejects it ("$ may only be used with binary targets"). + if (MSVC) + list(APPEND BSTONE_RESOURCES_WIN32_SOURCES + src/resources/win32/bstone_win32_msvc.manifest) + endif () + target_sources(bstone PRIVATE ${BSTONE_RESOURCES_WIN32_SOURCES}) source_group("resources/win32" FILES ${BSTONE_RESOURCES_WIN32_SOURCES}) endif () diff --git a/src/bstone/src/3d_draw2.cpp b/src/bstone/src/3d_draw2.cpp index bc460181..3350b2d7 100644 --- a/src/bstone/src/3d_draw2.cpp +++ b/src/bstone/src/3d_draw2.cpp @@ -7,6 +7,7 @@ SPDX-License-Identifier: GPL-2.0-or-later #include "3d_def.h" +#include #include "d3_d2.h" #include "id_vl.h" diff --git a/src/bstone/src/bstone_flac_audio_decoder.cpp b/src/bstone/src/bstone_flac_audio_decoder.cpp index bd0134a1..191faf89 100644 --- a/src/bstone/src/bstone_flac_audio_decoder.cpp +++ b/src/bstone/src/bstone_flac_audio_decoder.cpp @@ -1,8 +1,11 @@ #include "bstone_flac_audio_decoder.h" #include "bstone_assert.h" +#include +#include #include #include -#include "FLAC/stream_decoder.h" +#include +#include "dr_flac.h" namespace bstone { @@ -11,7 +14,7 @@ namespace { class FlacAudioDecoder final : public AudioDecoder { public: - FlacAudioDecoder(); + FlacAudioDecoder() = default; ~FlacAudioDecoder() override; bool initialize(const AudioDecoderInitParam& param) override; @@ -23,101 +26,56 @@ class FlacAudioDecoder final : public AudioDecoder bool rewind() override; private: - inline static constexpr int max_channels = 2; + inline static constexpr int cache_capacity = 4096; + inline static constexpr int skip_buffer_size = 4096; - using CacheFrame = float[max_channels]; - using SampleConverter = float (*)(FLAC__int32 sample); using DecodeFramesFunc = int (FlacAudioDecoder::*)(float* samples, int max_frames); - bool is_initialized_{}; const char* error_message_{}; - FLAC__StreamDecoder* decoder_{}; + drflac* flac_{}; VfsInputStreamUPtr stream_{}; + std::int64_t stream_position_{}; + bool is_open_{}; int bit_depth_{}; int channel_count_{}; int src_frame_rate_{}; int dst_frame_rate_{}; - SampleConverter sample_converter_{}; - const FLAC__int32* const* cache_samples_{}; + // Interleaved, normalised float frames; only used by the resampling path. + std::vector cache_{}; int cache_frame_count_{}; int cache_frame_offset_{}; int cache_frame_offset_counter_{}; - CacheFrame cache_frame_{}; DecodeFramesFunc decode_frames_{}; -private: - bool is_error_message_empty() const; - void clear_error_message(); + static std::size_t flac_callback_read(void* user_data, void* buffer, std::size_t size); + static drflac_bool32 flac_callback_seek(void* user_data, int offset, drflac_seek_origin origin); + static drflac_bool32 flac_callback_tell(void* user_data, drflac_int64* position); + std::size_t impl_callback_read(void* buffer, std::size_t size); + bool impl_callback_seek(int offset, drflac_seek_origin origin); + bool impl_skip(std::int64_t size); + void set_error_message(const char* message); - void set_error_message(FLAC__StreamDecoderState state); - void set_error_message(FLAC__StreamDecoderInitStatus status); - void set_error_message(FLAC__StreamDecoderReadStatus status); - void set_error_message(FLAC__StreamDecoderSeekStatus status); - void set_error_message(FLAC__StreamDecoderTellStatus status); - void set_error_message(FLAC__StreamDecoderLengthStatus status); - void set_error_message(FLAC__StreamDecoderErrorStatus status); - - static FLAC__StreamDecoderReadStatus read_callback_proxy( - const FLAC__StreamDecoder* decoder, - FLAC__byte buffer[], - std::size_t* bytes, - void* client_data); - static FLAC__StreamDecoderWriteStatus write_callback_proxy( - const FLAC__StreamDecoder* decoder, - const FLAC__Frame* frame, - const FLAC__int32* const buffer[], - void* client_data); - static void metadata_callback_proxy( - const FLAC__StreamDecoder* decoder, - const FLAC__StreamMetadata* metadata, - void* client_data); - static void error_callback_flac( - const FLAC__StreamDecoder* decoder, - FLAC__StreamDecoderErrorStatus status, - void* client_data); - - FLAC__StreamDecoderReadStatus read_callback(FLAC__byte buffer[], std::size_t* bytes); - FLAC__StreamDecoderWriteStatus write_callback(const FLAC__Frame* frame, const FLAC__int32* const buffer[]); - void metadata_callback(const FLAC__StreamMetadata* metadata); - void error_callback(FLAC__StreamDecoderErrorStatus status); - - static float convert_sample_s8(FLAC__int32 sample); - static float convert_sample_s16(FLAC__int32 sample); - static float convert_sample_s24(FLAC__int32 sample); - static float convert_sample_s32(FLAC__int32 sample); bool impl_is_initialized() const; void impl_close_flac(); bool impl_open_flac(); void impl_terminate(); bool impl_initialize(const AudioDecoderInitParam& param); - int decode_frames_as_is(float* samples, int max_frames); - void cache_update_frame(); bool update_cache(); + int decode_frames_as_is(float* samples, int max_frames); int decode_frames_with_resample(float* samples, int max_frames); }; // ------------------------------------- -FlacAudioDecoder::FlacAudioDecoder() - : - decoder_{FLAC__stream_decoder_new()} -{} - FlacAudioDecoder::~FlacAudioDecoder() { - FLAC__stream_decoder_delete(decoder_); + impl_close_flac(); } bool FlacAudioDecoder::initialize(const AudioDecoderInitParam& param) { - clear_error_message(); - if (decoder_ == nullptr) - { - set_error_message("Failed to allocate a decoder."); - return false; - } - impl_terminate(); + error_message_ = nullptr; if (!impl_initialize(param)) { impl_terminate(); @@ -149,232 +107,162 @@ int FlacAudioDecoder::get_channel_count() const int FlacAudioDecoder::decode_frames(float* samples, int max_frames) { - BSTONE_ASSERT(impl_is_initialized()); BSTONE_ASSERT(max_frames >= 0); - BSTONE_ASSERT(decode_frames_ != nullptr); + BSTONE_ASSERT(impl_is_initialized()); return (this->*decode_frames_)(samples, max_frames); } bool FlacAudioDecoder::rewind() { BSTONE_ASSERT(impl_is_initialized()); - impl_close_flac(); - if (!stream_->rewind()) + if (drflac_seek_to_pcm_frame(flac_, 0) == DRFLAC_FALSE) { set_error_message("Failed to rewind a stream."); return false; } - const int old_bit_depth_ = bit_depth_; - const int old_channel_count_ = channel_count_; - const int old_src_sample_rate_ = src_frame_rate_; - if (!impl_open_flac()) - return false; - if (bit_depth_ != old_bit_depth_ || - channel_count_ != old_channel_count_ || - src_frame_rate_ != old_src_sample_rate_) - { - set_error_message("Parameters mismatch."); - return false; - } cache_frame_count_ = 0; cache_frame_offset_ = 0; + cache_frame_offset_counter_ = 0; return true; } -bool FlacAudioDecoder::is_error_message_empty() const -{ - return error_message_ == nullptr || error_message_[0] == '\0'; -} - -void FlacAudioDecoder::clear_error_message() -{ - error_message_ = nullptr; -} - -void FlacAudioDecoder::set_error_message(const char* message) -{ - error_message_ = message; -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderState state) -{ - set_error_message(FLAC__StreamDecoderStateString[state]); -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderInitStatus status) -{ - set_error_message(FLAC__StreamDecoderInitStatusString[status]); -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderReadStatus status) -{ - set_error_message(FLAC__StreamDecoderReadStatusString[status]); -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderSeekStatus status) -{ - set_error_message(FLAC__StreamDecoderSeekStatusString[status]); -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderTellStatus status) -{ - set_error_message(FLAC__StreamDecoderTellStatusString[status]); -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderLengthStatus status) -{ - set_error_message(FLAC__StreamDecoderLengthStatusString[status]); -} - -void FlacAudioDecoder::set_error_message(FLAC__StreamDecoderErrorStatus status) -{ - set_error_message(FLAC__StreamDecoderErrorStatusString[status]); -} - -FLAC__StreamDecoderReadStatus FlacAudioDecoder::read_callback_proxy( - [[maybe_unused]] const FLAC__StreamDecoder* decoder, - FLAC__byte buffer[], - std::size_t* bytes, - void* client_data) -{ - return static_cast(client_data)->read_callback(buffer, bytes); -} - -FLAC__StreamDecoderWriteStatus FlacAudioDecoder::write_callback_proxy( - [[maybe_unused]] const FLAC__StreamDecoder* decoder, - const FLAC__Frame* frame, - const FLAC__int32* const buffer[], - void* client_data) +std::size_t FlacAudioDecoder::flac_callback_read(void* user_data, void* buffer, std::size_t size) { - return static_cast(client_data)->write_callback(frame, buffer); + return static_cast(user_data)->impl_callback_read(buffer, size); } -void FlacAudioDecoder::metadata_callback_proxy( - [[maybe_unused]] const FLAC__StreamDecoder* decoder, - const FLAC__StreamMetadata* metadata, - void* client_data) +drflac_bool32 FlacAudioDecoder::flac_callback_seek(void* user_data, int offset, drflac_seek_origin origin) { - static_cast(client_data)->metadata_callback(metadata); + return static_cast(user_data)->impl_callback_seek(offset, origin) ? DRFLAC_TRUE : DRFLAC_FALSE; } -void FlacAudioDecoder::error_callback_flac( - [[maybe_unused]] const FLAC__StreamDecoder* decoder, - FLAC__StreamDecoderErrorStatus status, - void* client_data) +drflac_bool32 FlacAudioDecoder::flac_callback_tell(void* user_data, drflac_int64* position) { - static_cast(client_data)->error_callback(status); + *position = static_cast(static_cast(user_data)->stream_position_); + return DRFLAC_TRUE; } -FLAC__StreamDecoderReadStatus FlacAudioDecoder::read_callback(FLAC__byte buffer[], std::size_t* bytes) +std::size_t FlacAudioDecoder::impl_callback_read(void* buffer, std::size_t size) { - const int to_read_size = static_cast(*bytes); - const int read_size = stream_->read(buffer, to_read_size); - *bytes = 0; - if (read_size < 0) - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - if (read_size == 0 && to_read_size > 0) - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - *bytes = static_cast(read_size); - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; -} - -FLAC__StreamDecoderWriteStatus FlacAudioDecoder::write_callback(const FLAC__Frame* frame, const FLAC__int32* const buffer[]) -{ - cache_samples_ = buffer; - cache_frame_count_ = static_cast(frame->header.blocksize); - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; -} - -void FlacAudioDecoder::metadata_callback(const FLAC__StreamMetadata* metadata) -{ - if (metadata->type != FLAC__METADATA_TYPE_STREAMINFO) - return; - const FLAC__StreamMetadata_StreamInfo& info = metadata->data.stream_info; - bit_depth_ = static_cast(info.bits_per_sample); - channel_count_ = static_cast(info.channels); - src_frame_rate_ = static_cast(info.sample_rate); -} - -void FlacAudioDecoder::error_callback(FLAC__StreamDecoderErrorStatus status) -{ - set_error_message(FLAC__StreamDecoderErrorStatusString[status]); -} - -float FlacAudioDecoder::convert_sample_s8(FLAC__int32 sample) -{ - return static_cast(sample) / 128.0F; + constexpr std::size_t max_read_size = 1 << 30; + const int clamped_size = static_cast(std::min(size, max_read_size)); + const auto bytes = static_cast(buffer); + // dr_flac takes a short read for the end of the stream, so fill the whole + // request from however many reads it takes. + int bytes_offset = 0; + while (bytes_offset < clamped_size) + { + const int read_size = stream_->read(bytes + bytes_offset, clamped_size - bytes_offset); + if (read_size <= 0) + { + break; + } + bytes_offset += read_size; + } + stream_position_ += bytes_offset; + return static_cast(bytes_offset); } -float FlacAudioDecoder::convert_sample_s16(FLAC__int32 sample) +bool FlacAudioDecoder::impl_callback_seek(int offset, drflac_seek_origin origin) { - return static_cast(sample) / 32768.0F; + std::int64_t position; + switch (origin) + { + case DRFLAC_SEEK_SET: + position = offset; + break; + case DRFLAC_SEEK_CUR: + position = stream_position_ + offset; + break; + default: + return false; + } + if (position < 0) + { + return false; + } + if (position >= stream_position_) + { + return impl_skip(position - stream_position_); + } + // The VFS stream only rewinds; walk forward from the start. + if (!stream_->rewind()) + { + return false; + } + stream_position_ = 0; + return impl_skip(position); } -float FlacAudioDecoder::convert_sample_s24(FLAC__int32 sample) +bool FlacAudioDecoder::impl_skip(std::int64_t size) { - return static_cast(sample) / 8388608.0F; + unsigned char skip_buffer[skip_buffer_size]; + while (size > 0) + { + const int to_read_size = static_cast(std::min(size, skip_buffer_size)); + const int read_size = stream_->read(skip_buffer, to_read_size); + if (read_size <= 0) + { + return false; + } + stream_position_ += read_size; + size -= read_size; + } + return true; } -float FlacAudioDecoder::convert_sample_s32(FLAC__int32 sample) +void FlacAudioDecoder::set_error_message(const char* message) { - return static_cast(sample) / 2147483648.0F; + error_message_ = message; } bool FlacAudioDecoder::impl_is_initialized() const { - return is_initialized_; + return is_open_; } void FlacAudioDecoder::impl_close_flac() { - FLAC__stream_decoder_finish(decoder_); + if (flac_ != nullptr) + { + drflac_close(flac_); + flac_ = nullptr; + } + is_open_ = false; } bool FlacAudioDecoder::impl_open_flac() { - if (!FLAC__stream_decoder_get_md5_checking(decoder_)) - { - if (!FLAC__stream_decoder_set_md5_checking(decoder_, false)) - { - set_error_message("Failed to disable MD5 checking."); - return false; - } - } - const FLAC__StreamDecoderInitStatus init_status = FLAC__stream_decoder_init_stream( - /* decoder */ decoder_, - /* read_callback */ &FlacAudioDecoder::read_callback_proxy, - /* seek_callback */ nullptr, - /* tell_callback */ nullptr, - /* length_callback */ nullptr, - /* eof_callback */ nullptr, - /* write_callback */ &FlacAudioDecoder::write_callback_proxy, - /* metadata_callback */ &FlacAudioDecoder::metadata_callback_proxy, - /* error_callback */ &FlacAudioDecoder::error_callback_flac, - /* client_data */ this); - if (init_status != FLAC__STREAM_DECODER_INIT_STATUS_OK) + flac_ = drflac_open( + &FlacAudioDecoder::flac_callback_read, + &FlacAudioDecoder::flac_callback_seek, + &FlacAudioDecoder::flac_callback_tell, + this, + nullptr); + if (flac_ == nullptr) { - set_error_message(init_status); - return false; - } - clear_error_message(); - if (!FLAC__stream_decoder_process_until_end_of_metadata(decoder_)) - { - if (is_error_message_empty()) - set_error_message("Failed to process all metadata."); + set_error_message("Failed to open a FLAC stream."); return false; } + bit_depth_ = static_cast(flac_->bitsPerSample); + channel_count_ = static_cast(flac_->channels); + src_frame_rate_ = static_cast(flac_->sampleRate); + is_open_ = true; return true; } void FlacAudioDecoder::impl_terminate() { impl_close_flac(); - is_initialized_ = false; stream_ = nullptr; + stream_position_ = 0; + cache_.clear(); + cache_.shrink_to_fit(); } bool FlacAudioDecoder::impl_initialize(const AudioDecoderInitParam& param) { + impl_terminate(); if (param.vfs_stream == nullptr) { set_error_message("No VFS stream."); @@ -386,22 +274,17 @@ bool FlacAudioDecoder::impl_initialize(const AudioDecoderInitParam& param) return false; } stream_ = std::move(param.vfs_stream); - dst_frame_rate_ = param.dst_rate; + stream_position_ = 0; if (!impl_open_flac()) + { return false; + } switch (bit_depth_) { case 8: - sample_converter_ = &FlacAudioDecoder::convert_sample_s8; - break; case 16: - sample_converter_ = &FlacAudioDecoder::convert_sample_s16; - break; case 24: - sample_converter_ = &FlacAudioDecoder::convert_sample_s24; - break; case 32: - sample_converter_ = &FlacAudioDecoder::convert_sample_s32; break; default: set_error_message("Unsupported bit depth."); @@ -421,80 +304,54 @@ bool FlacAudioDecoder::impl_initialize(const AudioDecoderInitParam& param) set_error_message("Unsupported track's sample rate."); return false; } - cache_samples_ = nullptr; + dst_frame_rate_ = param.dst_rate; cache_frame_count_ = 0; cache_frame_offset_ = 0; cache_frame_offset_counter_ = 0; - std::fill_n(cache_frame_, channel_count_, 0.0F); if (src_frame_rate_ == dst_frame_rate_) + { decode_frames_ = &FlacAudioDecoder::decode_frames_as_is; + } else - decode_frames_ = &FlacAudioDecoder::decode_frames_with_resample; - is_initialized_ = true; - return true; -} - -int FlacAudioDecoder::decode_frames_as_is(float* samples, int max_frames) -{ - int written_frame_count = 0; - while (written_frame_count != max_frames) { - if (cache_frame_offset_ >= cache_frame_count_) - { - cache_frame_count_ = 0; - cache_frame_offset_ = 0; - if (!FLAC__stream_decoder_process_single(decoder_)) - return -1; - if (cache_frame_count_ == 0) - break; - } - const int frame_count = std::min(max_frames - written_frame_count, cache_frame_count_ - cache_frame_offset_); - for (int i_frame = 0; i_frame < frame_count; ++i_frame) - { - for (int i_channel = 0; i_channel < channel_count_; ++i_channel) - { - const FLAC__int32 sample_s32 = cache_samples_[i_channel][cache_frame_offset_ + i_frame]; - samples[i_channel] = sample_converter_(sample_s32); - } - samples += channel_count_; - } - written_frame_count += frame_count; - cache_frame_offset_ += frame_count; + cache_.resize(static_cast(cache_capacity) * channel_count_); + decode_frames_ = &FlacAudioDecoder::decode_frames_with_resample; } - return written_frame_count; + return true; } -void FlacAudioDecoder::cache_update_frame() +bool FlacAudioDecoder::update_cache() { - for (int i_channel = 0; i_channel < channel_count_; ++i_channel) + if (cache_frame_offset_ < cache_frame_count_) { - const FLAC__int32 sample_s32 = cache_samples_[i_channel][cache_frame_offset_]; - cache_frame_[i_channel] = sample_converter_(sample_s32); + return true; } + const drflac_uint64 read_frame_count = drflac_read_pcm_frames_f32( + flac_, static_cast(cache_capacity), cache_.data()); + cache_frame_count_ = static_cast(read_frame_count); + cache_frame_offset_ = 0; + return cache_frame_count_ > 0; } -bool FlacAudioDecoder::update_cache() +int FlacAudioDecoder::decode_frames_as_is(float* samples, int max_frames) { - if (cache_frame_offset_ < cache_frame_count_) - return true; - cache_frame_count_ = 0; - cache_frame_offset_ = 0; - if (!FLAC__stream_decoder_process_single(decoder_)) - return false; - if (cache_frame_offset_ >= cache_frame_count_) - return false; - cache_update_frame(); - return true; + // dr_flac already yields interleaved, normalised float at the source rate. + const drflac_uint64 read_frame_count = drflac_read_pcm_frames_f32( + flac_, static_cast(max_frames), samples); + return static_cast(read_frame_count); } int FlacAudioDecoder::decode_frames_with_resample(float* samples, int max_frames) { int written_frame_count = 0; - while (written_frame_count != max_frames) + while (written_frame_count < max_frames) { if (!update_cache()) + { break; - std::copy_n(cache_frame_, channel_count_, samples); + } + const float* const cache_frame = &cache_[static_cast(cache_frame_offset_) * channel_count_]; + std::copy_n(cache_frame, channel_count_, samples); samples += channel_count_; ++written_frame_count; cache_frame_offset_counter_ += src_frame_rate_; @@ -503,8 +360,9 @@ int FlacAudioDecoder::decode_frames_with_resample(float* samples, int max_frames cache_frame_offset_counter_ -= dst_frame_rate_; ++cache_frame_offset_; if (!update_cache()) + { break; - cache_update_frame(); + } } } return written_frame_count; @@ -520,3 +378,4 @@ AudioDecoderUPtr make_flac_audio_decoder() } } // namespace bstone + diff --git a/src/bstone/src/bstone_hw_texture_mgr.cpp b/src/bstone/src/bstone_hw_texture_mgr.cpp index bd5b990d..57b44b84 100644 --- a/src/bstone/src/bstone_hw_texture_mgr.cpp +++ b/src/bstone/src/bstone_hw_texture_mgr.cpp @@ -13,6 +13,7 @@ SPDX-License-Identifier: GPL-2.0-or-later #include "bstone_hw_texture_mgr.h" +#include #include #include #include diff --git a/src/bstone/src/bstone_image_extractor.cpp b/src/bstone/src/bstone_image_extractor.cpp index 7ef4bedd..9fe00947 100644 --- a/src/bstone/src/bstone_image_extractor.cpp +++ b/src/bstone/src/bstone_image_extractor.cpp @@ -16,6 +16,7 @@ SPDX-License-Identifier: GPL-2.0-or-later #include "bstone_sys_fs.h" #include "id_ca.h" #include "id_vh.h" +#include #include #include #include diff --git a/src/bstone/src/bstone_sha1.cpp b/src/bstone/src/bstone_sha1.cpp index 48366692..ecac3072 100644 --- a/src/bstone/src/bstone_sha1.cpp +++ b/src/bstone/src/bstone_sha1.cpp @@ -8,6 +8,7 @@ SPDX-License-Identifier: MIT // https://www.ietf.org/rfc/rfc3174.txt #include "bstone_sha1.h" +#include #include "bstone_exception.h" namespace bstone { diff --git a/src/bstone/src/bstone_sys_file_sdl.cpp b/src/bstone/src/bstone_sys_file_sdl.cpp index 63bed306..12b1b1b4 100644 --- a/src/bstone/src/bstone_sys_file_sdl.cpp +++ b/src/bstone/src/bstone_sys_file_sdl.cpp @@ -57,7 +57,6 @@ bool File::open(const char* path, FileMode mode) sdl_mode = "wb"; break; default: - BSTONE_ASSERT(false && "Unknown mode."); return false; } handle_ = SDL_IOFromFile(path, sdl_mode); @@ -72,7 +71,6 @@ void File::close() int File::read(void* buffer, int size) const { - BSTONE_ASSERT(is_open()); BSTONE_ASSERT(buffer != nullptr); BSTONE_ASSERT(size >= 0); const std::size_t sdl_read_size = SDL_ReadIO( @@ -90,7 +88,6 @@ int File::read(void* buffer, int size) const bool File::read_exactly(void* buffer, int size) const { - BSTONE_ASSERT(is_open()); BSTONE_ASSERT(buffer != nullptr); BSTONE_ASSERT(size >= 0); for (int offset = 0; offset < size;) @@ -108,7 +105,6 @@ bool File::read_exactly(void* buffer, int size) const int File::write(const void* buffer, int size) const { - BSTONE_ASSERT(is_open()); BSTONE_ASSERT(buffer != nullptr); BSTONE_ASSERT(size >= 0); const std::size_t sdl_written_size = SDL_WriteIO( @@ -126,7 +122,6 @@ int File::write(const void* buffer, int size) const bool File::write_exactly(const void* buffer, int size) const { - BSTONE_ASSERT(is_open()); BSTONE_ASSERT(buffer != nullptr); BSTONE_ASSERT(size >= 0); for (int offset = 0; offset < size;) @@ -144,7 +139,6 @@ bool File::write_exactly(const void* buffer, int size) const std::int64_t File::seek(std::int64_t offset, FileOrigin origin) const { - BSTONE_ASSERT(is_open()); SDL_IOWhence sdl_io_whence; switch (origin) { @@ -166,32 +160,27 @@ std::int64_t File::seek(std::int64_t offset, FileOrigin origin) const std::int64_t File::skip(std::int64_t offset) const { - BSTONE_ASSERT(is_open()); return SDL_SeekIO(static_cast(handle_), offset, SDL_IO_SEEK_CUR); } std::int64_t File::get_position() const { - BSTONE_ASSERT(is_open()); return SDL_TellIO(static_cast(handle_)); } bool File::set_position(std::int64_t position) const { - BSTONE_ASSERT(is_open()); BSTONE_ASSERT(position >= 0); return SDL_SeekIO(static_cast(handle_), position, SDL_IO_SEEK_SET) >= 0; } std::int64_t File::get_size() const { - BSTONE_ASSERT(is_open()); return SDL_GetIOSize(static_cast(handle_)); } bool File::flush() const { - BSTONE_ASSERT(is_open()); return SDL_FlushIO(static_cast(handle_)); } diff --git a/src/bstone/src/bstone_sys_polling_audio_device_sdl.cpp b/src/bstone/src/bstone_sys_polling_audio_device_sdl.cpp index 96119a38..5a4f3775 100644 --- a/src/bstone/src/bstone_sys_polling_audio_device_sdl.cpp +++ b/src/bstone/src/bstone_sys_polling_audio_device_sdl.cpp @@ -10,6 +10,7 @@ SPDX-License-Identifier: MIT #include "bstone_exception.h" #include "bstone_scope_exit.h" #include "bstone_sdl.h" +#include #include #include #include "SDL3/SDL_audio.h" diff --git a/src/bstone/src/bstone_vfs.cpp b/src/bstone/src/bstone_vfs.cpp index 602bd237..b39f0fb7 100644 --- a/src/bstone/src/bstone_vfs.cpp +++ b/src/bstone/src/bstone_vfs.cpp @@ -523,22 +523,6 @@ VfsInputStreamUPtr VfsImpl::open_input_stream_file(const VfsSearchPathImpl& sear // ====================================== -bool VfsInputStream::read_exactly(void* buffer, int buffer_size) -{ - const auto bytes = static_cast(buffer); - int bytes_offset = 0; - while (bytes_offset < buffer_size) - { - const int read_size = read(bytes + bytes_offset, buffer_size - bytes_offset); - if (read_size <= 0) - break; - bytes_offset += read_size; - } - return bytes_offset == buffer_size; -} - -// ====================================== - VfsUPtr make_vfs() { return std::make_unique(); diff --git a/src/bstone/src/bstone_vfs.h b/src/bstone/src/bstone_vfs.h index 7b08dc19..7f21755f 100644 --- a/src/bstone/src/bstone_vfs.h +++ b/src/bstone/src/bstone_vfs.h @@ -37,7 +37,22 @@ class VfsInputStream virtual int get_size() = 0; virtual bool rewind() = 0; virtual int read(void* buffer, int buffer_size) = 0; - virtual bool read_exactly(void* buffer, int buffer_size); + + virtual bool read_exactly(void* buffer, int buffer_size) + { + const auto bytes = static_cast(buffer); + int bytes_offset = 0; + while (bytes_offset < buffer_size) + { + const int read_size = read(bytes + bytes_offset, buffer_size - bytes_offset); + if (read_size <= 0) + { + break; + } + bytes_offset += read_size; + } + return bytes_offset == buffer_size; + } }; using VfsInputStreamUPtr = std::unique_ptr; diff --git a/src/bstone/src/bstone_vorbis_audio_decoder.cpp b/src/bstone/src/bstone_vorbis_audio_decoder.cpp index 6cab530a..c48866f7 100644 --- a/src/bstone/src/bstone_vorbis_audio_decoder.cpp +++ b/src/bstone/src/bstone_vorbis_audio_decoder.cpp @@ -1,10 +1,11 @@ #include "bstone_vorbis_audio_decoder.h" #include "bstone_assert.h" #include +#include #include -#include #include -#include "vorbis/vorbisfile.h" +#include +#include "stb_vorbis.h" namespace bstone { @@ -21,41 +22,49 @@ class VorbisAudioDecoder final : public AudioDecoder bool is_initialized() const override; const char* get_error_message() const override; int get_channel_count() const override; - int decode_frames(float* samples, int sample_count) override; + int decode_frames(float* samples, int max_frames) override; bool rewind() override; private: - inline static constexpr int cache_capacity = 256; + // An Ogg page rarely exceeds 8 KiB; the window doubles if one still does not fit. + inline static constexpr int initial_buffer_capacity = 32 * 1024; + inline static constexpr int max_buffer_capacity = 1024 * 1024; - using DecodeFramesFunc = int (VorbisAudioDecoder::*)(float* samples, int frame_count); + using DecodeFramesFunc = int (VorbisAudioDecoder::*)(float* samples, int max_frames); const char* error_message_{}; - OggVorbis_File vf_{}; + stb_vorbis* vorbis_{}; VfsInputStreamUPtr stream_{}; + // A bounded window over the stream; stb_vorbis consumes it packet by packet. + std::vector buffer_{}; + int buffer_position_{}; + int buffer_end_{}; + bool is_stream_at_end_{}; + bool is_open_{}; int channel_count_{}; int src_frame_rate_{}; int dst_frame_rate_{}; + // Points into stb_vorbis's internal buffer; valid until the next decode call. float** cache_samples_{}; int cache_frame_count_{}; int cache_frame_offset_{}; int cache_frame_offset_counter_{}; DecodeFramesFunc decode_frames_{}; - const char* get_vorbis_error_code_string(int error_code); + static const char* get_vorbis_error_code_string(int error_code); void set_error_message(const char* message); void set_error_message_from_vorbis_code(int error_code); - static std::size_t vorbis_callback_read(void* ptr, std::size_t size, std::size_t nmemb, void* datasource); - bool impl_is_initialized() const; - void impl_terminate_vorbis(); - bool impl_initialize_vorbis(); + void impl_close_vorbis(); + bool refill_buffer(); + bool grow_buffer(); + bool impl_open_vorbis(); void impl_terminate(); bool impl_initialize(const AudioDecoderInitParam& param); - - std::size_t impl_callback_read(void* ptr, std::size_t size, std::size_t nmemb); - int decode_frames_as_is(float* samples, int max_frames); + bool refill_cache(); bool update_cache(); + int decode_frames_as_is(float* samples, int max_frames); int decode_frames_with_resample(float* samples, int max_frames); }; @@ -63,11 +72,12 @@ class VorbisAudioDecoder final : public AudioDecoder VorbisAudioDecoder::~VorbisAudioDecoder() { - impl_terminate_vorbis(); + impl_close_vorbis(); } bool VorbisAudioDecoder::initialize(const AudioDecoderInitParam& param) { + error_message_ = nullptr; if (!impl_initialize(param)) { impl_terminate(); @@ -107,47 +117,59 @@ int VorbisAudioDecoder::decode_frames(float* samples, int max_frames) bool VorbisAudioDecoder::rewind() { BSTONE_ASSERT(impl_is_initialized()); + // Push mode cannot seek; reopen from the rewound stream. if (!stream_->rewind()) { set_error_message("Failed to rewind a stream."); return false; } - const int old_channel_count = channel_count_; - const int old_src_sample_rate = src_frame_rate_; - if (!impl_initialize_vorbis()) + impl_close_vorbis(); + buffer_position_ = 0; + buffer_end_ = 0; + is_stream_at_end_ = false; + if (!refill_buffer()) + { + set_error_message("Empty or invalid stream."); return false; - if (channel_count_ != old_channel_count || - src_frame_rate_ != old_src_sample_rate) + } + if (!impl_open_vorbis()) { - set_error_message("Parameters mismatch."); return false; } + cache_samples_ = nullptr; cache_frame_count_ = 0; cache_frame_offset_ = 0; + cache_frame_offset_counter_ = 0; return true; } const char* VorbisAudioDecoder::get_vorbis_error_code_string(int error_code) { - BSTONE_ASSERT(error_code < 0); #define BSTONE_MACRO(x) case x: return #x; switch (error_code) { - BSTONE_MACRO(OV_FALSE); - BSTONE_MACRO(OV_EOF); - BSTONE_MACRO(OV_HOLE); - BSTONE_MACRO(OV_EREAD); - BSTONE_MACRO(OV_EFAULT); - BSTONE_MACRO(OV_EIMPL); - BSTONE_MACRO(OV_EINVAL); - BSTONE_MACRO(OV_ENOTVORBIS); - BSTONE_MACRO(OV_EBADHEADER); - BSTONE_MACRO(OV_EVERSION); - BSTONE_MACRO(OV_ENOTAUDIO); - BSTONE_MACRO(OV_EBADPACKET); - BSTONE_MACRO(OV_EBADLINK); - BSTONE_MACRO(OV_ENOSEEK); - default: return "OV_???"; + BSTONE_MACRO(VORBIS__no_error); + BSTONE_MACRO(VORBIS_need_more_data); + BSTONE_MACRO(VORBIS_invalid_api_mixing); + BSTONE_MACRO(VORBIS_outofmem); + BSTONE_MACRO(VORBIS_feature_not_supported); + BSTONE_MACRO(VORBIS_too_many_channels); + BSTONE_MACRO(VORBIS_file_open_failure); + BSTONE_MACRO(VORBIS_seek_without_length); + BSTONE_MACRO(VORBIS_unexpected_eof); + BSTONE_MACRO(VORBIS_seek_invalid); + BSTONE_MACRO(VORBIS_invalid_setup); + BSTONE_MACRO(VORBIS_invalid_stream); + BSTONE_MACRO(VORBIS_missing_capture_pattern); + BSTONE_MACRO(VORBIS_invalid_stream_structure_version); + BSTONE_MACRO(VORBIS_continued_packet_flag_invalid); + BSTONE_MACRO(VORBIS_incorrect_stream_serial_number); + BSTONE_MACRO(VORBIS_invalid_first_page); + BSTONE_MACRO(VORBIS_bad_packet_type); + BSTONE_MACRO(VORBIS_cant_find_last_page); + BSTONE_MACRO(VORBIS_seek_failed); + BSTONE_MACRO(VORBIS_ogg_skeleton_not_supported); + default: return "VORBIS_???"; } #undef BSTONE_MACRO } @@ -162,53 +184,102 @@ void VorbisAudioDecoder::set_error_message_from_vorbis_code(int error_code) set_error_message(get_vorbis_error_code_string(error_code)); } -std::size_t VorbisAudioDecoder::vorbis_callback_read(void* ptr, std::size_t size, std::size_t nmemb, void* datasource) -{ - return static_cast(datasource)->impl_callback_read(ptr, size, nmemb); -} - bool VorbisAudioDecoder::impl_is_initialized() const { - return stream_ != nullptr; + return is_open_; } -void VorbisAudioDecoder::impl_terminate_vorbis() +void VorbisAudioDecoder::impl_close_vorbis() { - ov_clear(&vf_); + if (vorbis_ != nullptr) + { + stb_vorbis_close(vorbis_); + vorbis_ = nullptr; + } + is_open_ = false; } -bool VorbisAudioDecoder::impl_initialize_vorbis() +bool VorbisAudioDecoder::refill_buffer() { - ov_callbacks callbacks{ - .read_func = &VorbisAudioDecoder::vorbis_callback_read, - .seek_func = nullptr, - .close_func = nullptr, - .tell_func = nullptr}; - const int ov_open_result = ov_open_callbacks(this, &vf_, nullptr, 0, callbacks); - if (ov_open_result != 0) + if (buffer_position_ > 0) + { + std::memmove(buffer_.data(), buffer_.data() + buffer_position_, buffer_end_ - buffer_position_); + buffer_end_ -= buffer_position_; + buffer_position_ = 0; + } + if (is_stream_at_end_) { - set_error_message_from_vorbis_code(ov_open_result); return false; } - const vorbis_info* const info = ov_info(&vf_, -1); - if (info == nullptr) + const int read_size = stream_->read(buffer_.data() + buffer_end_, static_cast(buffer_.size()) - buffer_end_); + if (read_size <= 0) { - set_error_message("Failed to get Vorbis info."); + is_stream_at_end_ = true; return false; } - if (ov_streams(&vf_) != 1) + buffer_end_ += read_size; + return true; +} + +bool VorbisAudioDecoder::grow_buffer() +{ + if (buffer_.size() >= max_buffer_capacity) { - set_error_message("Multiple logical bitstreams."); + set_error_message("Ogg page too big."); return false; } - channel_count_ = info->channels; - src_frame_rate_ = static_cast(info->rate); + buffer_.resize(buffer_.size() * 2); + return true; +} + +bool VorbisAudioDecoder::impl_open_vorbis() +{ + while (true) + { + int consumed_size = 0; + int error_code = VORBIS__no_error; + vorbis_ = stb_vorbis_open_pushdata( + buffer_.data() + buffer_position_, + buffer_end_ - buffer_position_, + &consumed_size, + &error_code, + nullptr); + if (vorbis_ != nullptr) + { + buffer_position_ += consumed_size; + break; + } + if (error_code != VORBIS_need_more_data) + { + set_error_message_from_vorbis_code(error_code); + return false; + } + if (buffer_end_ - buffer_position_ == static_cast(buffer_.size()) && !grow_buffer()) + { + return false; + } + if (!refill_buffer()) + { + set_error_message_from_vorbis_code(VORBIS_unexpected_eof); + return false; + } + } + const stb_vorbis_info info = stb_vorbis_get_info(vorbis_); + channel_count_ = info.channels; + src_frame_rate_ = static_cast(info.sample_rate); + is_open_ = true; return true; } void VorbisAudioDecoder::impl_terminate() { + impl_close_vorbis(); stream_ = nullptr; + buffer_.clear(); + buffer_.shrink_to_fit(); + buffer_position_ = 0; + buffer_end_ = 0; + is_stream_at_end_ = false; } bool VorbisAudioDecoder::impl_initialize(const AudioDecoderInitParam& param) @@ -225,8 +296,16 @@ bool VorbisAudioDecoder::impl_initialize(const AudioDecoderInitParam& param) return false; } stream_ = std::move(param.vfs_stream); - if (!impl_initialize_vorbis()) + buffer_.resize(initial_buffer_capacity); + if (!refill_buffer()) + { + set_error_message("Empty or invalid stream."); return false; + } + if (!impl_open_vorbis()) + { + return false; + } switch (channel_count_) { case 1: @@ -247,65 +326,88 @@ bool VorbisAudioDecoder::impl_initialize(const AudioDecoderInitParam& param) cache_frame_offset_ = 0; cache_frame_offset_counter_ = 0; if (src_frame_rate_ == dst_frame_rate_) + { decode_frames_ = &VorbisAudioDecoder::decode_frames_as_is; + } else + { decode_frames_ = &VorbisAudioDecoder::decode_frames_with_resample; + } return true; } -std::size_t VorbisAudioDecoder::impl_callback_read(void* ptr, std::size_t size, std::size_t nmemb) -{ - if (const int read_size = stream_->read(ptr, static_cast(size * nmemb)); - read_size > 0) - return read_size; - return 0; -} - -int VorbisAudioDecoder::decode_frames_as_is(float* samples, int max_frames) +bool VorbisAudioDecoder::refill_cache() { - int written_frame_count = 0; - while (written_frame_count < max_frames) + while (true) { - int bitstream; - float** vorbis_samples; - const long read_frame_count = ov_read_float(&vf_, &vorbis_samples, max_frames - written_frame_count, &bitstream); - if (read_frame_count == 0) - break; - if (read_frame_count < 0) + int channels = 0; + float** outputs = nullptr; + int frame_count = 0; + const int consumed_size = stb_vorbis_decode_frame_pushdata( + vorbis_, + buffer_.data() + buffer_position_, + buffer_end_ - buffer_position_, + &channels, + &outputs, + &frame_count); + if (consumed_size > 0) { - if (read_frame_count == OV_HOLE) - continue; - set_error_message_from_vorbis_code(read_frame_count); - return -1; + buffer_position_ += consumed_size; + if (frame_count > 0) + { + cache_samples_ = outputs; + cache_frame_count_ = frame_count; + cache_frame_offset_ = 0; + return true; + } + // A consumed packet with no frames: resynchronisation or a header. + continue; } - for (int i_frame = 0; i_frame < read_frame_count; ++i_frame) + if (buffer_end_ - buffer_position_ == static_cast(buffer_.size()) && !grow_buffer()) { - for (int i_channel = 0; i_channel < channel_count_; ++i_channel) - *samples++ = vorbis_samples[i_channel][i_frame]; + return false; + } + if (!refill_buffer()) + { + return false; } - written_frame_count += read_frame_count; } - return written_frame_count; } bool VorbisAudioDecoder::update_cache() { if (cache_frame_offset_ < cache_frame_count_) + { return true; - cache_frame_count_ = 0; - cache_frame_offset_ = 0; - for (;;) + } + return refill_cache(); +} + +int VorbisAudioDecoder::decode_frames_as_is(float* samples, int max_frames) +{ + int written_frame_count = 0; + while (written_frame_count < max_frames) { - const long read_frame_count = ov_read_float(&vf_, &cache_samples_, cache_capacity, nullptr); - if (read_frame_count < 0) + if (cache_frame_offset_ >= cache_frame_count_) { - if (read_frame_count == OV_HOLE) - continue; - return false; + if (!refill_cache()) + { + break; + } } - cache_frame_count_ = static_cast(read_frame_count); - return cache_frame_offset_ < cache_frame_count_; + const int frame_count = std::min(max_frames - written_frame_count, cache_frame_count_ - cache_frame_offset_); + for (int i_frame = 0; i_frame < frame_count; ++i_frame) + { + for (int i_channel = 0; i_channel < channel_count_; ++i_channel) + { + samples[i_channel] = cache_samples_[i_channel][cache_frame_offset_ + i_frame]; + } + samples += channel_count_; + } + written_frame_count += frame_count; + cache_frame_offset_ += frame_count; } + return written_frame_count; } int VorbisAudioDecoder::decode_frames_with_resample(float* samples, int max_frames) @@ -314,9 +416,13 @@ int VorbisAudioDecoder::decode_frames_with_resample(float* samples, int max_fram while (written_frame_count < max_frames) { if (!update_cache()) + { break; + } for (int i_channel = 0; i_channel < channel_count_; ++i_channel) + { samples[i_channel] = cache_samples_[i_channel][cache_frame_offset_]; + } samples += channel_count_; ++written_frame_count; cache_frame_offset_counter_ += src_frame_rate_; @@ -325,7 +431,9 @@ int VorbisAudioDecoder::decode_frames_with_resample(float* samples, int max_fram cache_frame_offset_counter_ -= dst_frame_rate_; ++cache_frame_offset_; if (!update_cache()) + { break; + } } } return written_frame_count; diff --git a/src/bstone/src/bstone_win32_utility.cpp b/src/bstone/src/bstone_win32_utility.cpp index 5f779821..c36611bf 100644 --- a/src/bstone/src/bstone_win32_utility.cpp +++ b/src/bstone/src/bstone_win32_utility.cpp @@ -6,6 +6,16 @@ SPDX-License-Identifier: MIT // Utilities for Windows +#ifdef _WIN32 + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif + +#ifndef NOMINMAX +#define NOMINMAX +#endif + #include "bstone_win32_utility.h" #include "bstone_assert.h" #include "bstone_win32_os_version.h" @@ -137,3 +147,5 @@ int utf16_to_utf8(const wchar_t* u16_chars, int u16_count) } } // namespace bstone::win32 + +#endif // _WIN32 diff --git a/src/bstone/src/bstone_win32_utility.h b/src/bstone/src/bstone_win32_utility.h index ec36b130..dec1c6ef 100644 --- a/src/bstone/src/bstone_win32_utility.h +++ b/src/bstone/src/bstone_win32_utility.h @@ -6,6 +6,8 @@ SPDX-License-Identifier: MIT // Utilities for Windows +#ifdef _WIN32 + namespace bstone::win32 { int get_string_size(const char* string); @@ -19,3 +21,5 @@ int utf16_to_utf8(const wchar_t* u16_chars, int u16_count, char* u8_chars, int u int utf16_to_utf8(const wchar_t* u16_chars, int u16_count); } // namespace bstone::win32 + +#endif // _WIN32 diff --git a/src/bstone/src/bstone_zip_archive_file.cpp b/src/bstone/src/bstone_zip_archive_file.cpp index 47f296a0..022ce9ac 100644 --- a/src/bstone/src/bstone_zip_archive_file.cpp +++ b/src/bstone/src/bstone_zip_archive_file.cpp @@ -5,6 +5,7 @@ SPDX-License-Identifier: GPL-2.0-or-later */ #include "bstone_zip_archive_file.h" +#include #include "bstone_archive_file_input_stream.h" #include "bstone_assert.h" #include "bstone_endian.h" diff --git a/src/bstone/src/id_in.cpp b/src/bstone/src/id_in.cpp index 06412089..892b1832 100644 --- a/src/bstone/src/id_in.cpp +++ b/src/bstone/src/id_in.cpp @@ -31,6 +31,7 @@ SPDX-License-Identifier: GPL-2.0-or-later #include "bstone_globals.h" #include "bstone_string_builder.h" #include "bstone_sys_keyboard_key.h" +#include #include #include #include diff --git a/src/bstone/src/markhack.cpp b/src/bstone/src/markhack.cpp index 8336fc0c..c116cffd 100644 --- a/src/bstone/src/markhack.cpp +++ b/src/bstone/src/markhack.cpp @@ -12,6 +12,7 @@ SPDX-License-Identifier: GPL-2.0-or-later #include "3d_def.h" +#include #include "id_vl.h" diff --git a/src/lib/CMakeLists.txt b/src/lib/CMakeLists.txt index 04a731c7..4b5378a1 100644 --- a/src/lib/CMakeLists.txt +++ b/src/lib/CMakeLists.txt @@ -1,10 +1,9 @@ cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -add_subdirectory(flac) +add_subdirectory(dr_flac) add_subdirectory(khronos) add_subdirectory(nuked_opl3) -add_subdirectory(ogg) add_subdirectory(openal_soft) -add_subdirectory(vorbis) +add_subdirectory(stb_vorbis) add_subdirectory(vulkan) add_subdirectory(xbrz) add_subdirectory(zlib) diff --git a/src/lib/dr_flac/CMakeLists.txt b/src/lib/dr_flac/CMakeLists.txt new file mode 100644 index 00000000..c2c34bd1 --- /dev/null +++ b/src/lib/dr_flac/CMakeLists.txt @@ -0,0 +1,22 @@ +# bstone +cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) +# ====================================== +project(bstone_lib_dr_flac VERSION 1.0.0 LANGUAGES C) +message(STATUS "[${PROJECT_NAME}] v${PROJECT_VERSION}") +add_library(${PROJECT_NAME} STATIC) +add_library(bstone::lib::dr_flac ALIAS ${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF +) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:_CRT_SECURE_NO_WARNINGS>) +target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W1>) +target_include_directories(${PROJECT_NAME} PUBLIC .) +# Only dr_flac_impl.c defines DR_FLAC_IMPLEMENTATION; dr_flac.h is listed for IDE +# visibility but is a plain header everywhere else. +set_source_files_properties(dr_flac.h PROPERTIES HEADER_FILE_ONLY TRUE) +target_sources(${PROJECT_NAME} PRIVATE + dr_flac_impl.c + dr_flac.h +) diff --git a/src/lib/dr_flac/dr_flac.h b/src/lib/dr_flac/dr_flac.h new file mode 100644 index 00000000..3a234ed2 --- /dev/null +++ b/src/lib/dr_flac/dr_flac.h @@ -0,0 +1,12711 @@ +/* +FLAC audio decoder. Choice of public domain or MIT-0. See license statements at the end of this file. +dr_flac - v0.13.4 - TBD + +David Reid - mackron@gmail.com + +GitHub: https://github.com/mackron/dr_libs +*/ + +/* +Introduction +============ +dr_flac is a single file library. To use it, do something like the following in one .c file. + + ```c + #define DR_FLAC_IMPLEMENTATION + #include "dr_flac.h" + ``` + +You can then #include this file in other parts of the program as you would with any other header file. To decode audio data, do something like the following: + + ```c + drflac* pFlac = drflac_open_file("MySong.flac", NULL); + if (pFlac == NULL) { + // Failed to open FLAC file + } + + drflac_int32* pSamples = malloc(pFlac->totalPCMFrameCount * pFlac->channels * sizeof(drflac_int32)); + drflac_uint64 numberOfInterleavedSamplesActuallyRead = drflac_read_pcm_frames_s32(pFlac, pFlac->totalPCMFrameCount, pSamples); + ``` + +The drflac object represents the decoder. It is a transparent type so all the information you need, such as the number of channels and the bits per sample, +should be directly accessible - just make sure you don't change their values. Samples are always output as interleaved signed 32-bit PCM. In the example above +a native FLAC stream was opened, however dr_flac has seamless support for Ogg encapsulated FLAC streams as well. + +You do not need to decode the entire stream in one go - you just specify how many samples you'd like at any given time and the decoder will give you as many +samples as it can, up to the amount requested. Later on when you need the next batch of samples, just call it again. Example: + + ```c + while (drflac_read_pcm_frames_s32(pFlac, chunkSizeInPCMFrames, pChunkSamples) > 0) { + do_something(); + } + ``` + +You can seek to a specific PCM frame with `drflac_seek_to_pcm_frame()`. + +If you just want to quickly decode an entire FLAC file in one go you can do something like this: + + ```c + unsigned int channels; + unsigned int sampleRate; + drflac_uint64 totalPCMFrameCount; + drflac_int32* pSampleData = drflac_open_file_and_read_pcm_frames_s32("MySong.flac", &channels, &sampleRate, &totalPCMFrameCount, NULL); + if (pSampleData == NULL) { + // Failed to open and decode FLAC file. + } + + ... + + drflac_free(pSampleData, NULL); + ``` + +You can read samples as signed 16-bit integer and 32-bit floating-point PCM with the *_s16() and *_f32() family of APIs respectively, but note that these +should be considered lossy. + + +If you need access to metadata (album art, etc.), use `drflac_open_with_metadata()`, `drflac_open_file_with_metdata()` or `drflac_open_memory_with_metadata()`. +The rationale for keeping these APIs separate is that they're slightly slower than the normal versions and also just a little bit harder to use. dr_flac +reports metadata to the application through the use of a callback, and every metadata block is reported before `drflac_open_with_metdata()` returns. + +The main opening APIs (`drflac_open()`, etc.) will fail if the header is not present. The presents a problem in certain scenarios such as broadcast style +streams or internet radio where the header may not be present because the user has started playback mid-stream. To handle this, use the relaxed APIs: + + `drflac_open_relaxed()` + `drflac_open_with_metadata_relaxed()` + +It is not recommended to use these APIs for file based streams because a missing header would usually indicate a corrupt or perverse file. In addition, these +APIs can take a long time to initialize because they may need to spend a lot of time finding the first frame. + + + +Build Options +============= +#define these options before including this file. + +#define DR_FLAC_NO_STDIO + Disable `drflac_open_file()` and family. + +#define DR_FLAC_NO_OGG + Disables support for Ogg/FLAC streams. + +#define DR_FLAC_BUFFER_SIZE + Defines the size of the internal buffer to store data from onRead(). This buffer is used to reduce the number of calls back to the client for more data. + Larger values means more memory, but better performance. My tests show diminishing returns after about 4KB (which is the default). Consider reducing this if + you have a very efficient implementation of onRead(), or increase it if it's very inefficient. Must be a multiple of 8. + +#define DR_FLAC_NO_CRC + Disables CRC checks. This will offer a performance boost when CRC is unnecessary. This will disable binary search seeking. When seeking, the seek table will + be used if available. Otherwise the seek will be performed using brute force. + +#define DR_FLAC_NO_SIMD + Disables SIMD optimizations (SSE on x86/x64 architectures, NEON on ARM architectures). Use this if you are having compatibility issues with your compiler. + +#define DR_FLAC_NO_WCHAR + Disables all functions ending with `_w`. Use this if your compiler does not provide wchar.h. Not required if DR_FLAC_NO_STDIO is also defined. + + + +Notes +===== +- dr_flac does not support changing the sample rate nor channel count mid stream. +- dr_flac is not thread-safe, but its APIs can be called from any thread so long as you do your own synchronization. +- When using Ogg encapsulation, a corrupted metadata block will result in `drflac_open_with_metadata()` and `drflac_open()` returning inconsistent samples due + to differences in corrupted stream recorvery logic between the two APIs. +*/ + +#ifndef dr_flac_h +#define dr_flac_h + +#ifdef __cplusplus +extern "C" { +#endif + +#define DRFLAC_STRINGIFY(x) #x +#define DRFLAC_XSTRINGIFY(x) DRFLAC_STRINGIFY(x) + +#define DRFLAC_VERSION_MAJOR 0 +#define DRFLAC_VERSION_MINOR 13 +#define DRFLAC_VERSION_REVISION 4 +#define DRFLAC_VERSION_STRING DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MAJOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_MINOR) "." DRFLAC_XSTRINGIFY(DRFLAC_VERSION_REVISION) + +#include /* For size_t. */ + +/* Sized Types */ +typedef signed char drflac_int8; +typedef unsigned char drflac_uint8; +typedef signed short drflac_int16; +typedef unsigned short drflac_uint16; +typedef signed int drflac_int32; +typedef unsigned int drflac_uint32; +#if defined(_MSC_VER) && !defined(__clang__) + typedef signed __int64 drflac_int64; + typedef unsigned __int64 drflac_uint64; +#else + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wlong-long" + #if defined(__clang__) + #pragma GCC diagnostic ignored "-Wc++11-long-long" + #endif + #endif + typedef signed long long drflac_int64; + typedef unsigned long long drflac_uint64; + #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop + #endif +#endif +#if defined(__LP64__) || defined(_WIN64) || (defined(__x86_64__) && !defined(__ILP32__)) || defined(_M_X64) || defined(__ia64) || defined(_M_IA64) || defined(__aarch64__) || defined(_M_ARM64) || defined(__powerpc64__) + typedef drflac_uint64 drflac_uintptr; +#else + typedef drflac_uint32 drflac_uintptr; +#endif +typedef drflac_uint8 drflac_bool8; +typedef drflac_uint32 drflac_bool32; +#define DRFLAC_TRUE 1 +#define DRFLAC_FALSE 0 +/* End Sized Types */ + +/* Decorations */ +#if !defined(DRFLAC_API) + #if defined(DRFLAC_DLL) + #if defined(_WIN32) + #define DRFLAC_DLL_IMPORT __declspec(dllimport) + #define DRFLAC_DLL_EXPORT __declspec(dllexport) + #define DRFLAC_DLL_PRIVATE static + #else + #if defined(__GNUC__) && __GNUC__ >= 4 + #define DRFLAC_DLL_IMPORT __attribute__((visibility("default"))) + #define DRFLAC_DLL_EXPORT __attribute__((visibility("default"))) + #define DRFLAC_DLL_PRIVATE __attribute__((visibility("hidden"))) + #else + #define DRFLAC_DLL_IMPORT + #define DRFLAC_DLL_EXPORT + #define DRFLAC_DLL_PRIVATE static + #endif + #endif + + #if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION) + #define DRFLAC_API DRFLAC_DLL_EXPORT + #else + #define DRFLAC_API DRFLAC_DLL_IMPORT + #endif + #define DRFLAC_PRIVATE DRFLAC_DLL_PRIVATE + #else + #define DRFLAC_API extern + #define DRFLAC_PRIVATE static + #endif +#endif +/* End Decorations */ + +#if defined(_MSC_VER) && _MSC_VER >= 1700 /* Visual Studio 2012 */ + #define DRFLAC_DEPRECATED __declspec(deprecated) +#elif (defined(__GNUC__) && __GNUC__ >= 4) /* GCC 4 */ + #define DRFLAC_DEPRECATED __attribute__((deprecated)) +#elif defined(__has_feature) /* Clang */ + #if __has_feature(attribute_deprecated) + #define DRFLAC_DEPRECATED __attribute__((deprecated)) + #else + #define DRFLAC_DEPRECATED + #endif +#else + #define DRFLAC_DEPRECATED +#endif + +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision); +DRFLAC_API const char* drflac_version_string(void); + +/* Allocation Callbacks */ +typedef struct +{ + void* pUserData; + void* (* onMalloc)(size_t sz, void* pUserData); + void* (* onRealloc)(void* p, size_t sz, void* pUserData); + void (* onFree)(void* p, void* pUserData); +} drflac_allocation_callbacks; +/* End Allocation Callbacks */ + +/* +As data is read from the client it is placed into an internal buffer for fast access. This controls the size of that buffer. Larger values means more speed, +but also more memory. In my testing there is diminishing returns after about 4KB, but you can fiddle with this to suit your own needs. Must be a multiple of 8. +*/ +#ifndef DR_FLAC_BUFFER_SIZE +#define DR_FLAC_BUFFER_SIZE 4096 +#endif + + +/* Architecture Detection */ +#if defined(_WIN64) || defined(_LP64) || defined(__LP64__) +#define DRFLAC_64BIT +#endif + +#if defined(__x86_64__) || (defined(_M_X64) && !defined(_M_ARM64EC)) + #define DRFLAC_X64 +#elif defined(__i386) || defined(_M_IX86) + #define DRFLAC_X86 +#elif defined(__arm__) || defined(_M_ARM) || defined(__arm64) || defined(__arm64__) || defined(__aarch64__) || defined(_M_ARM64) || defined(_M_ARM64EC) + #define DRFLAC_ARM +#endif +/* End Architecture Detection */ + + +#ifdef DRFLAC_64BIT +typedef drflac_uint64 drflac_cache_t; +#else +typedef drflac_uint32 drflac_cache_t; +#endif + +/* The various metadata block types. */ +#define DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO 0 +#define DRFLAC_METADATA_BLOCK_TYPE_PADDING 1 +#define DRFLAC_METADATA_BLOCK_TYPE_APPLICATION 2 +#define DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE 3 +#define DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT 4 +#define DRFLAC_METADATA_BLOCK_TYPE_CUESHEET 5 +#define DRFLAC_METADATA_BLOCK_TYPE_PICTURE 6 +#define DRFLAC_METADATA_BLOCK_TYPE_INVALID 127 + +/* The various picture types specified in the PICTURE block. */ +#define DRFLAC_PICTURE_TYPE_OTHER 0 +#define DRFLAC_PICTURE_TYPE_FILE_ICON 1 +#define DRFLAC_PICTURE_TYPE_OTHER_FILE_ICON 2 +#define DRFLAC_PICTURE_TYPE_COVER_FRONT 3 +#define DRFLAC_PICTURE_TYPE_COVER_BACK 4 +#define DRFLAC_PICTURE_TYPE_LEAFLET_PAGE 5 +#define DRFLAC_PICTURE_TYPE_MEDIA 6 +#define DRFLAC_PICTURE_TYPE_LEAD_ARTIST 7 +#define DRFLAC_PICTURE_TYPE_ARTIST 8 +#define DRFLAC_PICTURE_TYPE_CONDUCTOR 9 +#define DRFLAC_PICTURE_TYPE_BAND 10 +#define DRFLAC_PICTURE_TYPE_COMPOSER 11 +#define DRFLAC_PICTURE_TYPE_LYRICIST 12 +#define DRFLAC_PICTURE_TYPE_RECORDING_LOCATION 13 +#define DRFLAC_PICTURE_TYPE_DURING_RECORDING 14 +#define DRFLAC_PICTURE_TYPE_DURING_PERFORMANCE 15 +#define DRFLAC_PICTURE_TYPE_SCREEN_CAPTURE 16 +#define DRFLAC_PICTURE_TYPE_BRIGHT_COLORED_FISH 17 +#define DRFLAC_PICTURE_TYPE_ILLUSTRATION 18 +#define DRFLAC_PICTURE_TYPE_BAND_LOGOTYPE 19 +#define DRFLAC_PICTURE_TYPE_PUBLISHER_LOGOTYPE 20 + +typedef enum +{ + drflac_container_native, + drflac_container_ogg, + drflac_container_unknown +} drflac_container; + +typedef enum +{ + DRFLAC_SEEK_SET, + DRFLAC_SEEK_CUR, + DRFLAC_SEEK_END +} drflac_seek_origin; + +/* The order of members in this structure is important because we map this directly to the raw data within the SEEKTABLE metadata block. */ +typedef struct +{ + drflac_uint64 firstPCMFrame; + drflac_uint64 flacFrameOffset; /* The offset from the first byte of the header of the first frame. */ + drflac_uint16 pcmFrameCount; +} drflac_seekpoint; + +typedef struct +{ + drflac_uint16 minBlockSizeInPCMFrames; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint32 minFrameSizeInPCMFrames; + drflac_uint32 maxFrameSizeInPCMFrames; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalPCMFrameCount; + drflac_uint8 md5[16]; +} drflac_streaminfo; + +typedef struct +{ + /* + The metadata type. Use this to know how to interpret the data below. Will be set to one of the + DRFLAC_METADATA_BLOCK_TYPE_* tokens. + */ + drflac_uint32 type; + + /* The size in bytes of the block and the buffer pointed to by pRawData if it's non-NULL. */ + drflac_uint32 rawDataSize; + + /* The offset in the stream of the raw data. */ + drflac_uint64 rawDataOffset; + + /* + A pointer to the raw data. This points to a temporary buffer so don't hold on to it. It's best to + not modify the contents of this buffer. Use the structures below for more meaningful and structured + information about the metadata. It's possible for this to be null. + */ + const void* pRawData; + + union + { + drflac_streaminfo streaminfo; + + struct + { + int unused; + } padding; + + struct + { + drflac_uint32 id; + const void* pData; + drflac_uint32 dataSize; + } application; + + struct + { + drflac_uint32 seekpointCount; + const drflac_seekpoint* pSeekpoints; + } seektable; + + struct + { + drflac_uint32 vendorLength; + const char* vendor; + drflac_uint32 commentCount; + const void* pComments; + } vorbis_comment; + + struct + { + char catalog[128]; + drflac_uint64 leadInSampleCount; + drflac_bool32 isCD; + drflac_uint8 trackCount; + const void* pTrackData; + } cuesheet; + + struct + { + drflac_uint32 type; + drflac_uint32 mimeLength; + const char* mime; + drflac_uint32 descriptionLength; + const char* description; + drflac_uint32 width; + drflac_uint32 height; + drflac_uint32 colorDepth; + drflac_uint32 indexColorCount; + drflac_uint32 pictureDataSize; + drflac_uint64 pictureDataOffset; /* Offset from the start of the stream. */ + const drflac_uint8* pPictureData; + } picture; + } data; +} drflac_metadata; + + +/* +Callback for when data needs to be read from the client. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pBufferOut (out) + The output buffer. + +bytesToRead (in) + The number of bytes to read. + + +Return Value +------------ +The number of bytes actually read. + + +Remarks +------- +A return value of less than bytesToRead indicates the end of the stream. Do _not_ return from this callback until either the entire bytesToRead is filled or +you have reached the end of the stream. +*/ +typedef size_t (* drflac_read_proc)(void* pUserData, void* pBufferOut, size_t bytesToRead); + +/* +Callback for when data needs to be seeked. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +offset (in) + The number of bytes to move, relative to the origin. Will never be negative. + +origin (in) + The origin of the seek - the current position, the start of the stream, or the end of the stream. + + +Return Value +------------ +Whether or not the seek was successful. + + +Remarks +------- +Seeking relative to the start and the current position must always be supported. If seeking from the end of the stream is not supported, return DRFLAC_FALSE. + +When seeking to a PCM frame using drflac_seek_to_pcm_frame(), dr_flac may call this with an offset beyond the end of the FLAC stream. This needs to be detected +and handled by returning DRFLAC_FALSE. +*/ +typedef drflac_bool32 (* drflac_seek_proc)(void* pUserData, int offset, drflac_seek_origin origin); + +/* +Callback for when the current position in the stream needs to be retrieved. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pCursor (out) + A pointer to a variable to receive the current position in the stream. + + +Return Value +------------ +Whether or not the operation was successful. +*/ +typedef drflac_bool32 (* drflac_tell_proc)(void* pUserData, drflac_int64* pCursor); + +/* +Callback for when a metadata block is read. + + +Parameters +---------- +pUserData (in) + The user data that was passed to drflac_open() and family. + +pMetadata (in) + A pointer to a structure containing the data of the metadata block. + + +Remarks +------- +Use pMetadata->type to determine which metadata block is being handled and how to read the data. This +will be set to one of the DRFLAC_METADATA_BLOCK_TYPE_* tokens. +*/ +typedef void (* drflac_meta_proc)(void* pUserData, drflac_metadata* pMetadata); + + +/* Structure for internal use. Only used for decoders opened with drflac_open_memory. */ +typedef struct +{ + const drflac_uint8* data; + size_t dataSize; + size_t currentReadPos; +} drflac__memory_stream; + +/* Structure for internal use. Used for bit streaming. */ +typedef struct +{ + /* The function to call when more data needs to be read. */ + drflac_read_proc onRead; + + /* The function to call when the current read position needs to be moved. */ + drflac_seek_proc onSeek; + + /* The function to call when the current read position needs to be retrieved. */ + drflac_tell_proc onTell; + + /* The user data to pass around to onRead and onSeek. */ + void* pUserData; + + + /* + The number of unaligned bytes in the L2 cache. This will always be 0 until the end of the stream is hit. At the end of the + stream there will be a number of bytes that don't cleanly fit in an L1 cache line, so we use this variable to know whether + or not the bistreamer needs to run on a slower path to read those last bytes. This will never be more than sizeof(drflac_cache_t). + */ + size_t unalignedByteCount; + + /* The content of the unaligned bytes. */ + drflac_cache_t unalignedCache; + + /* The index of the next valid cache line in the "L2" cache. */ + drflac_uint32 nextL2Line; + + /* The number of bits that have been consumed by the cache. This is used to determine how many valid bits are remaining. */ + drflac_uint32 consumedBits; + + /* + The cached data which was most recently read from the client. There are two levels of cache. Data flows as such: + Client -> L2 -> L1. The L2 -> L1 movement is aligned and runs on a fast path in just a few instructions. + */ + drflac_cache_t cacheL2[DR_FLAC_BUFFER_SIZE/sizeof(drflac_cache_t)]; + drflac_cache_t cache; + + /* + CRC-16. This is updated whenever bits are read from the bit stream. Manually set this to 0 to reset the CRC. For FLAC, this + is reset to 0 at the beginning of each frame. + */ + drflac_uint16 crc16; + drflac_cache_t crc16Cache; /* A cache for optimizing CRC calculations. This is filled when when the L1 cache is reloaded. */ + drflac_uint32 crc16CacheIgnoredBytes; /* The number of bytes to ignore when updating the CRC-16 from the CRC-16 cache. */ +} drflac_bs; + +typedef struct +{ + /* The type of the subframe: SUBFRAME_CONSTANT, SUBFRAME_VERBATIM, SUBFRAME_FIXED or SUBFRAME_LPC. */ + drflac_uint8 subframeType; + + /* The number of wasted bits per sample as specified by the sub-frame header. */ + drflac_uint8 wastedBitsPerSample; + + /* The order to use for the prediction stage for SUBFRAME_FIXED and SUBFRAME_LPC. */ + drflac_uint8 lpcOrder; + + /* A pointer to the buffer containing the decoded samples in the subframe. This pointer is an offset from drflac::pExtraData. */ + drflac_int32* pSamplesS32; +} drflac_subframe; + +typedef struct +{ + /* + If the stream uses variable block sizes, this will be set to the index of the first PCM frame. If fixed block sizes are used, this will + always be set to 0. This is 64-bit because the decoded PCM frame number will be 36 bits. + */ + drflac_uint64 pcmFrameNumber; + + /* + If the stream uses fixed block sizes, this will be set to the frame number. If variable block sizes are used, this will always be 0. This + is 32-bit because in fixed block sizes, the maximum frame number will be 31 bits. + */ + drflac_uint32 flacFrameNumber; + + /* The sample rate of this frame. */ + drflac_uint32 sampleRate; + + /* The number of PCM frames in each sub-frame within this frame. */ + drflac_uint16 blockSizeInPCMFrames; + + /* + The channel assignment of this frame. This is not always set to the channel count. If interchannel decorrelation is being used this + will be set to DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE, DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE or DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE. + */ + drflac_uint8 channelAssignment; + + /* The number of bits per sample within this frame. */ + drflac_uint8 bitsPerSample; + + /* The frame's CRC. */ + drflac_uint8 crc8; +} drflac_frame_header; + +typedef struct +{ + /* The header. */ + drflac_frame_header header; + + /* + The number of PCM frames left to be read in this FLAC frame. This is initially set to the block size. As PCM frames are read, + this will be decremented. When it reaches 0, the decoder will see this frame as fully consumed and load the next frame. + */ + drflac_uint32 pcmFramesRemaining; + + /* The list of sub-frames within the frame. There is one sub-frame for each channel, and there's a maximum of 8 channels. */ + drflac_subframe subframes[8]; +} drflac_frame; + +typedef struct +{ + /* The function to call when a metadata block is read. */ + drflac_meta_proc onMeta; + + /* The user data posted to the metadata callback function. */ + void* pUserDataMD; + + /* Memory allocation callbacks. */ + drflac_allocation_callbacks allocationCallbacks; + + + /* The sample rate. Will be set to something like 44100. */ + drflac_uint32 sampleRate; + + /* + The number of channels. This will be set to 1 for monaural streams, 2 for stereo, etc. Maximum 8. This is set based on the + value specified in the STREAMINFO block. + */ + drflac_uint8 channels; + + /* The bits per sample. Will be set to something like 16, 24, etc. */ + drflac_uint8 bitsPerSample; + + /* The maximum block size, in samples. This number represents the number of samples in each channel (not combined). */ + drflac_uint16 maxBlockSizeInPCMFrames; + + /* + The total number of PCM Frames making up the stream. Can be 0 in which case it's still a valid stream, but just means + the total PCM frame count is unknown. Likely the case with streams like internet radio. + */ + drflac_uint64 totalPCMFrameCount; + + + /* The container type. This is set based on whether or not the decoder was opened from a native or Ogg stream. */ + drflac_container container; + + /* The number of seekpoints in the seektable. */ + drflac_uint32 seekpointCount; + + + /* Information about the frame the decoder is currently sitting on. */ + drflac_frame currentFLACFrame; + + + /* The index of the PCM frame the decoder is currently sitting on. This is only used for seeking. */ + drflac_uint64 currentPCMFrame; + + /* The position of the first FLAC frame in the stream. This is only ever used for seeking. */ + drflac_uint64 firstFLACFramePosInBytes; + + + /* A hack to avoid a malloc() when opening a decoder with drflac_open_memory(). */ + drflac__memory_stream memoryStream; + + + /* A pointer to the decoded sample data. This is an offset of pExtraData. */ + drflac_int32* pDecodedSamples; + + /* A pointer to the seek table. This is an offset of pExtraData, or NULL if there is no seek table. */ + drflac_seekpoint* pSeekpoints; + + /* Internal use only. Only used with Ogg containers. Points to a drflac_oggbs object. This is an offset of pExtraData. */ + void* _oggbs; + + /* Internal use only. Used for profiling and testing different seeking modes. */ + drflac_bool32 _noSeekTableSeek : 1; + drflac_bool32 _noBinarySearchSeek : 1; + drflac_bool32 _noBruteForceSeek : 1; + + /* The bit streamer. The raw FLAC data is fed through this object. */ + drflac_bs bs; + + /* Variable length extra data. We attach this to the end of the object so we can avoid unnecessary mallocs. */ + drflac_uint8 pExtraData[1]; +} drflac; + + +/* +Opens a FLAC decoder. + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +onTell (in) + The function to call when the read position of the client needs to be queried. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead and onSeek. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +Returns a pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with `drflac_close()`. + +`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`. + +This function will automatically detect whether or not you are attempting to open a native or Ogg encapsulated FLAC, both of which should work seamlessly +without any manual intervention. Ogg encapsulation also works with multiplexed streams which basically means it can play FLAC encoded audio tracks in videos. + +This is the lowest level function for opening a FLAC stream. You can also use `drflac_open_file()` and `drflac_open_memory()` to open the stream from a file or +from a block of memory respectively. + +The STREAMINFO block must be present for this to succeed. Use `drflac_open_relaxed()` to open a FLAC stream where the header may not be present. + +Use `drflac_open_with_metadata()` if you need access to metadata. + + +Seek Also +--------- +drflac_open_file() +drflac_open_memory() +drflac_open_with_metadata() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC stream with relaxed validation of the header block. + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +onTell (in) + The function to call when the read position of the client needs to be queried. + +container (in) + Whether or not the FLAC stream is encapsulated using standard FLAC encapsulation or Ogg encapsulation. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead and onSeek. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +The same as drflac_open(), except attempts to open the stream even when a header block is not present. + +Because the header is not necessarily available, the caller must explicitly define the container (Native or Ogg). Do not set this to `drflac_container_unknown` +as that is for internal use only. + +Opening in relaxed mode will continue reading data from onRead until it finds a valid frame. If a frame is never found it will continue forever. To abort, +force your `onRead` callback to return 0, which dr_flac will use as an indicator that the end of the stream was found. + +Use `drflac_open_with_metadata_relaxed()` if you need access to metadata. +*/ +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder and notifies the caller of the metadata chunks (album art, etc.). + + +Parameters +---------- +onRead (in) + The function to call when data needs to be read from the client. + +onSeek (in) + The function to call when the read position of the client data needs to move. + +onTell (in) + The function to call when the read position of the client needs to be queried. + +onMeta (in) + The function to call for every metadata block. + +pUserData (in, optional) + A pointer to application defined data that will be passed to onRead, onSeek and onMeta. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with `drflac_close()`. + +`pAllocationCallbacks` can be NULL in which case it will use `DRFLAC_MALLOC`, `DRFLAC_REALLOC` and `DRFLAC_FREE`. + +This is slower than `drflac_open()`, so avoid this one if you don't need metadata. Internally, this will allocate and free memory on the heap for every +metadata block except for STREAMINFO and PADDING blocks. + +The caller is notified of the metadata via the `onMeta` callback. All metadata blocks will be handled before the function returns. This callback takes a +pointer to a `drflac_metadata` object which is a union containing the data of all relevant metadata blocks. Use the `type` member to discriminate against +the different metadata types. + +The STREAMINFO block must be present for this to succeed. Use `drflac_open_with_metadata_relaxed()` to open a FLAC stream where the header may not be present. + +Note that this will behave inconsistently with `drflac_open()` if the stream is an Ogg encapsulated stream and a metadata block is corrupted. This is due to +the way the Ogg stream recovers from corrupted pages. When `drflac_open_with_metadata()` is being used, the open routine will try to read the contents of the +metadata block, whereas `drflac_open()` will simply seek past it (for the sake of efficiency). This inconsistency can result in different samples being +returned depending on whether or not the stream is being opened with metadata. + + +Seek Also +--------- +drflac_open_file_with_metadata() +drflac_open_memory_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +The same as drflac_open_with_metadata(), except attempts to open the stream even when a header block is not present. + +See Also +-------- +drflac_open_with_metadata() +drflac_open_relaxed() +*/ +DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Closes the given FLAC decoder. + + +Parameters +---------- +pFlac (in) + The decoder to close. + + +Remarks +------- +This will destroy the decoder object. + + +See Also +-------- +drflac_open() +drflac_open_with_metadata() +drflac_open_file() +drflac_open_file_w() +drflac_open_file_with_metadata() +drflac_open_file_with_metadata_w() +drflac_open_memory() +drflac_open_memory_with_metadata() +*/ +DRFLAC_API void drflac_close(drflac* pFlac); + + +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 32-bit PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut); + + +/* +Reads sample data from the given FLAC decoder, output as interleaved signed 16-bit PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. + +Note that this is lossy for streams where the bits per sample is larger than 16. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut); + +/* +Reads sample data from the given FLAC decoder, output as interleaved 32-bit floating point PCM. + + +Parameters +---------- +pFlac (in) + The decoder. + +framesToRead (in) + The number of PCM frames to read. + +pBufferOut (out, optional) + A pointer to the buffer that will receive the decoded samples. + + +Return Value +------------ +Returns the number of PCM frames actually read. If the return value is less than `framesToRead` it has reached the end. + + +Remarks +------- +pBufferOut can be null, in which case the call will act as a seek, and the return value will be the number of frames seeked. + +Note that this should be considered lossy due to the nature of floating point numbers not being able to exactly represent every possible number. +*/ +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut); + +/* +Seeks to the PCM frame at the given index. + + +Parameters +---------- +pFlac (in) + The decoder. + +pcmFrameIndex (in) + The index of the PCM frame to seek to. See notes below. + + +Return Value +------------- +`DRFLAC_TRUE` if successful; `DRFLAC_FALSE` otherwise. +*/ +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex); + + + +#ifndef DR_FLAC_NO_STDIO +/* +Opens a FLAC decoder from the file at the given path. + + +Parameters +---------- +pFileName (in) + The path of the file to open, either absolute or relative to the current directory. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +Close the decoder with drflac_close(). + + +Remarks +------- +This will hold a handle to the file until the decoder is closed with drflac_close(). Some platforms will restrict the number of files a process can have open +at any given time, so keep this mind if you have many decoders open at the same time. + + +See Also +-------- +drflac_open_file_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder from the file at the given path and notifies the caller of the metadata chunks (album art, etc.) + + +Parameters +---------- +pFileName (in) + The path of the file to open, either absolute or relative to the current directory. + +pAllocationCallbacks (in, optional) + A pointer to application defined callbacks for managing memory allocations. + +onMeta (in) + The callback to fire for each metadata block. + +pUserData (in) + A pointer to the user data to pass to the metadata callback. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Remarks +------- +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. + + +See Also +-------- +drflac_open_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); +#endif + +/* +Opens a FLAC decoder from a pre-allocated block of memory + + +Parameters +---------- +pData (in) + A pointer to the raw encoded FLAC data. + +dataSize (in) + The size in bytes of `data`. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Return Value +------------ +A pointer to an object representing the decoder. + + +Remarks +------- +This does not create a copy of the data. It is up to the application to ensure the buffer remains valid for the lifetime of the decoder. + + +See Also +-------- +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Opens a FLAC decoder from a pre-allocated block of memory and notifies the caller of the metadata chunks (album art, etc.) + + +Parameters +---------- +pData (in) + A pointer to the raw encoded FLAC data. + +dataSize (in) + The size in bytes of `data`. + +onMeta (in) + The callback to fire for each metadata block. + +pUserData (in) + A pointer to the user data to pass to the metadata callback. + +pAllocationCallbacks (in) + A pointer to application defined callbacks for managing memory allocations. + + +Remarks +------- +Look at the documentation for drflac_open_with_metadata() for more information on how metadata is handled. + + +See Also +------- +drflac_open_with_metadata() +drflac_open() +drflac_close() +*/ +DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks); + + + +/* High Level APIs */ + +/* +Opens a FLAC stream from the given callbacks and fully decodes it in a single operation. The return value is a +pointer to the sample data as interleaved signed 32-bit PCM. The returned data must be freed with drflac_free(). + +You can pass in custom memory allocation callbacks via the pAllocationCallbacks parameter. This can be NULL in which +case it will use DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE. + +Sometimes a FLAC file won't keep track of the total sample count. In this situation the function will continuously +read samples into a dynamically sized buffer on the heap until no samples are left. + +Do not call this function on a broadcast type of stream (like internet radio streams and whatnot). +*/ +DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +#ifndef DR_FLAC_NO_STDIO +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a file. */ +DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_file_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); +#endif + +/* Same as drflac_open_and_read_pcm_frames_s32() except opens the decoder from a block of memory. */ +DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns signed 16-bit integer samples. */ +DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* Same as drflac_open_memory_and_read_pcm_frames_s32(), except returns 32-bit floating-point samples. */ +DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks); + +/* +Frees memory that was allocated internally by dr_flac. + +Set pAllocationCallbacks to the same object that was passed to drflac_open_*_and_read_pcm_frames_*(). If you originally passed in NULL, pass in NULL for this. +*/ +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks); + + +/* Structure representing an iterator for vorbis comments in a VORBIS_COMMENT metadata block. */ +typedef struct +{ + drflac_uint32 countRemaining; + const char* pRunningData; +} drflac_vorbis_comment_iterator; + +/* +Initializes a vorbis comment iterator. This can be used for iterating over the vorbis comments in a VORBIS_COMMENT +metadata block. +*/ +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments); + +/* +Goes to the next vorbis comment in the given iterator. If null is returned it means there are no more comments. The +returned string is NOT null terminated. +*/ +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut); + + +/* Structure representing an iterator for cuesheet tracks in a CUESHEET metadata block. */ +typedef struct +{ + drflac_uint32 countRemaining; + const char* pRunningData; +} drflac_cuesheet_track_iterator; + +/* The order of members here is important because we map this directly to the raw data within the CUESHEET metadata block. */ +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 index; + drflac_uint8 reserved[3]; +} drflac_cuesheet_track_index; + +typedef struct +{ + drflac_uint64 offset; + drflac_uint8 trackNumber; + char ISRC[12]; + drflac_bool8 isAudio; + drflac_bool8 preEmphasis; + drflac_uint8 indexCount; + const drflac_cuesheet_track_index* pIndexPoints; +} drflac_cuesheet_track; + +/* +Initializes a cuesheet track iterator. This can be used for iterating over the cuesheet tracks in a CUESHEET metadata +block. +*/ +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData); + +/* Goes to the next cuesheet track in the given iterator. If DRFLAC_FALSE is returned it means there are no more comments. */ +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack); + + +#ifdef __cplusplus +} +#endif +#endif /* dr_flac_h */ + + +/************************************************************************************************************************************************************ + ************************************************************************************************************************************************************ + + IMPLEMENTATION + + ************************************************************************************************************************************************************ + ************************************************************************************************************************************************************/ +#if defined(DR_FLAC_IMPLEMENTATION) || defined(DRFLAC_IMPLEMENTATION) +#ifndef dr_flac_c +#define dr_flac_c + +/* Disable some annoying warnings. */ +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic push + #if __GNUC__ >= 7 + #pragma GCC diagnostic ignored "-Wimplicit-fallthrough" + #endif +#endif + +#ifdef __linux__ + #ifndef _BSD_SOURCE + #define _BSD_SOURCE + #endif + #ifndef _DEFAULT_SOURCE + #define _DEFAULT_SOURCE + #endif + #ifndef __USE_BSD + #define __USE_BSD + #endif + #include +#endif + +#include +#include + +/* Inline */ +#ifdef _MSC_VER + #define DRFLAC_INLINE __forceinline +#elif defined(__GNUC__) + /* + I've had a bug report where GCC is emitting warnings about functions possibly not being inlineable. This warning happens when + the __attribute__((always_inline)) attribute is defined without an "inline" statement. I think therefore there must be some + case where "__inline__" is not always defined, thus the compiler emitting these warnings. When using -std=c89 or -ansi on the + command line, we cannot use the "inline" keyword and instead need to use "__inline__". In an attempt to work around this issue + I am using "__inline__" only when we're compiling in strict ANSI mode. + */ + #if defined(__STRICT_ANSI__) + #define DRFLAC_GNUC_INLINE_HINT __inline__ + #else + #define DRFLAC_GNUC_INLINE_HINT inline + #endif + + #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 2)) || defined(__clang__) + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT __attribute__((always_inline)) + #else + #define DRFLAC_INLINE DRFLAC_GNUC_INLINE_HINT + #endif +#elif defined(__WATCOMC__) + #define DRFLAC_INLINE __inline +#else + #define DRFLAC_INLINE +#endif +/* End Inline */ + +/* +Intrinsics Support + +There's a bug in GCC 4.2.x which results in an incorrect compilation error when using _mm_slli_epi32() where it complains with + + "error: shift must be an immediate" + +Unfortuantely dr_flac depends on this for a few things so we're just going to disable SSE on GCC 4.2 and below. +*/ +#if !defined(DR_FLAC_NO_SIMD) + #if defined(DRFLAC_X64) || defined(DRFLAC_X86) + #if defined(_MSC_VER) && !defined(__clang__) + /* MSVC. */ + #if _MSC_VER >= 1400 && !defined(DRFLAC_NO_SSE2) /* 2005 */ + #define DRFLAC_SUPPORT_SSE2 + #endif + #if _MSC_VER >= 1600 && !defined(DRFLAC_NO_SSE41) /* 2010 */ + #define DRFLAC_SUPPORT_SSE41 + #endif + #elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) + /* Assume GNUC-style. */ + #if defined(__SSE2__) && !defined(DRFLAC_NO_SSE2) + #define DRFLAC_SUPPORT_SSE2 + #endif + #if defined(__SSE4_1__) && !defined(DRFLAC_NO_SSE41) + #define DRFLAC_SUPPORT_SSE41 + #endif + #endif + + /* If at this point we still haven't determined compiler support for the intrinsics just fall back to __has_include. */ + #if !defined(__GNUC__) && !defined(__clang__) && defined(__has_include) + #if !defined(DRFLAC_SUPPORT_SSE2) && !defined(DRFLAC_NO_SSE2) && __has_include() + #define DRFLAC_SUPPORT_SSE2 + #endif + #if !defined(DRFLAC_SUPPORT_SSE41) && !defined(DRFLAC_NO_SSE41) && __has_include() + #define DRFLAC_SUPPORT_SSE41 + #endif + #endif + + #if defined(DRFLAC_SUPPORT_SSE41) + #include + #elif defined(DRFLAC_SUPPORT_SSE2) + #include + #endif + #endif + + #if defined(DRFLAC_ARM) + #if !defined(DRFLAC_NO_NEON) && (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + #define DRFLAC_SUPPORT_NEON + #include + #endif + #endif +#endif + +/* Compile-time CPU feature support. */ +#if !defined(DR_FLAC_NO_SIMD) && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) + #if defined(_MSC_VER) && !defined(__clang__) + #if _MSC_VER >= 1400 + #include + static void drflac__cpuid(int info[4], int fid) + { + __cpuid(info, fid); + } + #else + #define DRFLAC_NO_CPUID + #endif + #else + #if defined(__GNUC__) || defined(__clang__) + static void drflac__cpuid(int info[4], int fid) + { + /* + It looks like the -fPIC option uses the ebx register which GCC complains about. We can work around this by just using a different register, the + specific register of which I'm letting the compiler decide on. The "k" prefix is used to specify a 32-bit register. The {...} syntax is for + supporting different assembly dialects. + + What's basically happening is that we're saving and restoring the ebx register manually. + */ + #if defined(DRFLAC_X86) && defined(__PIC__) + __asm__ __volatile__ ( + "xchg{l} {%%}ebx, %k1;" + "cpuid;" + "xchg{l} {%%}ebx, %k1;" + : "=a"(info[0]), "=&r"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #else + __asm__ __volatile__ ( + "cpuid" : "=a"(info[0]), "=b"(info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(fid), "c"(0) + ); + #endif + } + #else + #define DRFLAC_NO_CPUID + #endif + #endif +#else + #define DRFLAC_NO_CPUID +#endif + +static DRFLAC_INLINE drflac_bool32 drflac_has_sse2(void) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE2) + #if defined(DRFLAC_X64) + return DRFLAC_TRUE; /* 64-bit targets always support SSE2. */ + #elif (defined(_M_IX86_FP) && _M_IX86_FP == 2) || defined(__SSE2__) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE2 code we can assume support. */ + #else + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; + #else + int info[4]; + drflac__cpuid(info, 1); + return (info[3] & (1 << 26)) != 0; + #endif + #endif + #else + return DRFLAC_FALSE; /* SSE2 is only supported on x86 and x64 architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + +static DRFLAC_INLINE drflac_bool32 drflac_has_sse41(void) +{ +#if defined(DRFLAC_SUPPORT_SSE41) + #if (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(DRFLAC_NO_SSE41) + #if defined(__SSE4_1__) || defined(__AVX__) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate SSE41 code we can assume support. */ + #else + #if defined(DRFLAC_NO_CPUID) + return DRFLAC_FALSE; + #else + int info[4]; + drflac__cpuid(info, 1); + return (info[2] & (1 << 19)) != 0; + #endif + #endif + #else + return DRFLAC_FALSE; /* SSE41 is only supported on x86 and x64 architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + + +#if defined(_MSC_VER) && _MSC_VER >= 1500 && (defined(DRFLAC_X86) || defined(DRFLAC_X64)) && !defined(__clang__) + #define DRFLAC_HAS_LZCNT_INTRINSIC +#elif (defined(__GNUC__) && ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))) + #define DRFLAC_HAS_LZCNT_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_clzll) || __has_builtin(__builtin_clzl) + #define DRFLAC_HAS_LZCNT_INTRINSIC + #endif + #endif +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(__clang__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC +#elif defined(__clang__) + #if defined(__has_builtin) + #if __has_builtin(__builtin_bswap16) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap32) + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #endif + #if __has_builtin(__builtin_bswap64) + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + #endif + #endif +#elif defined(__GNUC__) + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + #endif + #if ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #endif +#elif defined(__WATCOMC__) && defined(__386__) + #define DRFLAC_HAS_BYTESWAP16_INTRINSIC + #define DRFLAC_HAS_BYTESWAP32_INTRINSIC + #define DRFLAC_HAS_BYTESWAP64_INTRINSIC + extern __inline drflac_uint16 _watcom_bswap16(drflac_uint16); + extern __inline drflac_uint32 _watcom_bswap32(drflac_uint32); + extern __inline drflac_uint64 _watcom_bswap64(drflac_uint64); +#pragma aux _watcom_bswap16 = \ + "xchg al, ah" \ + parm [ax] \ + value [ax] \ + modify nomemory; +#pragma aux _watcom_bswap32 = \ + "bswap eax" \ + parm [eax] \ + value [eax] \ + modify nomemory; +#pragma aux _watcom_bswap64 = \ + "bswap eax" \ + "bswap edx" \ + "xchg eax,edx" \ + parm [eax edx] \ + value [eax edx] \ + modify nomemory; +#endif + + +/* Standard library stuff. */ +#ifndef DRFLAC_ASSERT +#include +#define DRFLAC_ASSERT(expression) assert(expression) +#endif +#ifndef DRFLAC_MALLOC +#define DRFLAC_MALLOC(sz) malloc((sz)) +#endif +#ifndef DRFLAC_REALLOC +#define DRFLAC_REALLOC(p, sz) realloc((p), (sz)) +#endif +#ifndef DRFLAC_FREE +#define DRFLAC_FREE(p) free((p)) +#endif +#ifndef DRFLAC_COPY_MEMORY +#define DRFLAC_COPY_MEMORY(dst, src, sz) memcpy((dst), (src), (sz)) +#endif +#ifndef DRFLAC_ZERO_MEMORY +#define DRFLAC_ZERO_MEMORY(p, sz) memset((p), 0, (sz)) +#endif +#ifndef DRFLAC_ZERO_OBJECT +#define DRFLAC_ZERO_OBJECT(p) DRFLAC_ZERO_MEMORY((p), sizeof(*(p))) +#endif + +#define DRFLAC_MIN(a, b) (((a) < (b)) ? (a) : (b)) + +#define DRFLAC_MAX_SIMD_VECTOR_SIZE 64 /* 64 for AVX-512 in the future. */ + +/* Result Codes */ +typedef drflac_int32 drflac_result; +#define DRFLAC_SUCCESS 0 +#define DRFLAC_ERROR -1 /* A generic error. */ +#define DRFLAC_INVALID_ARGS -2 +#define DRFLAC_INVALID_OPERATION -3 +#define DRFLAC_OUT_OF_MEMORY -4 +#define DRFLAC_OUT_OF_RANGE -5 +#define DRFLAC_ACCESS_DENIED -6 +#define DRFLAC_DOES_NOT_EXIST -7 +#define DRFLAC_ALREADY_EXISTS -8 +#define DRFLAC_TOO_MANY_OPEN_FILES -9 +#define DRFLAC_INVALID_FILE -10 +#define DRFLAC_TOO_BIG -11 +#define DRFLAC_PATH_TOO_LONG -12 +#define DRFLAC_NAME_TOO_LONG -13 +#define DRFLAC_NOT_DIRECTORY -14 +#define DRFLAC_IS_DIRECTORY -15 +#define DRFLAC_DIRECTORY_NOT_EMPTY -16 +#define DRFLAC_END_OF_FILE -17 +#define DRFLAC_NO_SPACE -18 +#define DRFLAC_BUSY -19 +#define DRFLAC_IO_ERROR -20 +#define DRFLAC_INTERRUPT -21 +#define DRFLAC_UNAVAILABLE -22 +#define DRFLAC_ALREADY_IN_USE -23 +#define DRFLAC_BAD_ADDRESS -24 +#define DRFLAC_BAD_SEEK -25 +#define DRFLAC_BAD_PIPE -26 +#define DRFLAC_DEADLOCK -27 +#define DRFLAC_TOO_MANY_LINKS -28 +#define DRFLAC_NOT_IMPLEMENTED -29 +#define DRFLAC_NO_MESSAGE -30 +#define DRFLAC_BAD_MESSAGE -31 +#define DRFLAC_NO_DATA_AVAILABLE -32 +#define DRFLAC_INVALID_DATA -33 +#define DRFLAC_TIMEOUT -34 +#define DRFLAC_NO_NETWORK -35 +#define DRFLAC_NOT_UNIQUE -36 +#define DRFLAC_NOT_SOCKET -37 +#define DRFLAC_NO_ADDRESS -38 +#define DRFLAC_BAD_PROTOCOL -39 +#define DRFLAC_PROTOCOL_UNAVAILABLE -40 +#define DRFLAC_PROTOCOL_NOT_SUPPORTED -41 +#define DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED -42 +#define DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED -43 +#define DRFLAC_SOCKET_NOT_SUPPORTED -44 +#define DRFLAC_CONNECTION_RESET -45 +#define DRFLAC_ALREADY_CONNECTED -46 +#define DRFLAC_NOT_CONNECTED -47 +#define DRFLAC_CONNECTION_REFUSED -48 +#define DRFLAC_NO_HOST -49 +#define DRFLAC_IN_PROGRESS -50 +#define DRFLAC_CANCELLED -51 +#define DRFLAC_MEMORY_ALREADY_MAPPED -52 +#define DRFLAC_AT_END -53 + +#define DRFLAC_CRC_MISMATCH -100 +/* End Result Codes */ + + +#define DRFLAC_SUBFRAME_CONSTANT 0 +#define DRFLAC_SUBFRAME_VERBATIM 1 +#define DRFLAC_SUBFRAME_FIXED 8 +#define DRFLAC_SUBFRAME_LPC 32 +#define DRFLAC_SUBFRAME_RESERVED 255 + +#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE 0 +#define DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2 1 + +#define DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT 0 +#define DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE 8 +#define DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE 9 +#define DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE 10 + +#define DRFLAC_SEEKPOINT_SIZE_IN_BYTES 18 +#define DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES 36 +#define DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES 12 + +#define drflac_align(x, a) ((((x) + (a) - 1) / (a)) * (a)) + + +DRFLAC_API void drflac_version(drflac_uint32* pMajor, drflac_uint32* pMinor, drflac_uint32* pRevision) +{ + if (pMajor) { + *pMajor = DRFLAC_VERSION_MAJOR; + } + + if (pMinor) { + *pMinor = DRFLAC_VERSION_MINOR; + } + + if (pRevision) { + *pRevision = DRFLAC_VERSION_REVISION; + } +} + +DRFLAC_API const char* drflac_version_string(void) +{ + return DRFLAC_VERSION_STRING; +} + + +/* CPU caps. */ +#if defined(__has_feature) + #if __has_feature(thread_sanitizer) + #define DRFLAC_NO_THREAD_SANITIZE __attribute__((no_sanitize("thread"))) + #else + #define DRFLAC_NO_THREAD_SANITIZE + #endif +#else + #define DRFLAC_NO_THREAD_SANITIZE +#endif + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +static drflac_bool32 drflac__gIsLZCNTSupported = DRFLAC_FALSE; +#endif + +#ifndef DRFLAC_NO_CPUID +static drflac_bool32 drflac__gIsSSE2Supported = DRFLAC_FALSE; +static drflac_bool32 drflac__gIsSSE41Supported = DRFLAC_FALSE; + +/* +I've had a bug report that Clang's ThreadSanitizer presents a warning in this function. Having reviewed this, this does +actually make sense. However, since CPU caps should never differ for a running process, I don't think the trade off of +complicating internal API's by passing around CPU caps versus just disabling the warnings is worthwhile. I'm therefore +just going to disable these warnings. This is disabled via the DRFLAC_NO_THREAD_SANITIZE attribute. +*/ +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) +{ + static drflac_bool32 isCPUCapsInitialized = DRFLAC_FALSE; + + if (!isCPUCapsInitialized) { + /* LZCNT */ +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) + int info[4] = {0}; + drflac__cpuid(info, 0x80000001); + drflac__gIsLZCNTSupported = (info[2] & (1 << 5)) != 0; +#endif + + /* SSE2 */ + drflac__gIsSSE2Supported = drflac_has_sse2(); + + /* SSE4.1 */ + drflac__gIsSSE41Supported = drflac_has_sse41(); + + /* Initialized. */ + isCPUCapsInitialized = DRFLAC_TRUE; + } +} +#else +static drflac_bool32 drflac__gIsNEONSupported = DRFLAC_FALSE; + +static DRFLAC_INLINE drflac_bool32 drflac__has_neon(void) +{ +#if defined(DRFLAC_SUPPORT_NEON) + #if defined(DRFLAC_ARM) && !defined(DRFLAC_NO_NEON) + #if (defined(__ARM_NEON) || defined(__aarch64__) || defined(_M_ARM64)) + return DRFLAC_TRUE; /* If the compiler is allowed to freely generate NEON code we can assume support. */ + #else + /* TODO: Runtime check. */ + return DRFLAC_FALSE; + #endif + #else + return DRFLAC_FALSE; /* NEON is only supported on ARM architectures. */ + #endif +#else + return DRFLAC_FALSE; /* No compiler support. */ +#endif +} + +DRFLAC_NO_THREAD_SANITIZE static void drflac__init_cpu_caps(void) +{ + drflac__gIsNEONSupported = drflac__has_neon(); + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) + drflac__gIsLZCNTSupported = DRFLAC_TRUE; +#endif +} +#endif + + +/* Endian Management */ +static DRFLAC_INLINE drflac_bool32 drflac__is_little_endian(void) +{ +#if defined(DRFLAC_X86) || defined(DRFLAC_X64) + return DRFLAC_TRUE; +#elif defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && __BYTE_ORDER == __LITTLE_ENDIAN + return DRFLAC_TRUE; +#else + int n = 1; + return (*(char*)&n) == 1; +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac__swap_endian_uint16(drflac_uint16 n) +{ +#ifdef DRFLAC_HAS_BYTESWAP16_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_ushort(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap16(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap16(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF00) >> 8) | + ((n & 0x00FF) << 8); +#endif +} + +static DRFLAC_INLINE drflac_uint32 drflac__swap_endian_uint32(drflac_uint32 n) +{ +#ifdef DRFLAC_HAS_BYTESWAP32_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_ulong(n); + #elif defined(__GNUC__) || defined(__clang__) + #if defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 6) && !defined(__ARM_ARCH_6M__) && !defined(DRFLAC_64BIT) /* <-- 64-bit inline assembly has not been tested, so disabling for now. */ + /* Inline assembly optimized implementation for ARM. In my testing, GCC does not generate optimized code with __builtin_bswap32(). */ + drflac_uint32 r; + __asm__ __volatile__ ( + #if defined(DRFLAC_64BIT) + "rev %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(n) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "rev %[out], %[in]" : [out]"=r"(r) : [in]"r"(n) + #endif + ); + return r; + #else + return __builtin_bswap32(n); + #endif + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap32(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + return ((n & 0xFF000000) >> 24) | + ((n & 0x00FF0000) >> 8) | + ((n & 0x0000FF00) << 8) | + ((n & 0x000000FF) << 24); +#endif +} + +static DRFLAC_INLINE drflac_uint64 drflac__swap_endian_uint64(drflac_uint64 n) +{ +#ifdef DRFLAC_HAS_BYTESWAP64_INTRINSIC + #if defined(_MSC_VER) && !defined(__clang__) + return _byteswap_uint64(n); + #elif defined(__GNUC__) || defined(__clang__) + return __builtin_bswap64(n); + #elif defined(__WATCOMC__) && defined(__386__) + return _watcom_bswap64(n); + #else + #error "This compiler does not support the byte swap intrinsic." + #endif +#else + /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + return ((n & ((drflac_uint64)0xFF000000 << 32)) >> 56) | + ((n & ((drflac_uint64)0x00FF0000 << 32)) >> 40) | + ((n & ((drflac_uint64)0x0000FF00 << 32)) >> 24) | + ((n & ((drflac_uint64)0x000000FF << 32)) >> 8) | + ((n & ((drflac_uint64)0xFF000000 )) << 8) | + ((n & ((drflac_uint64)0x00FF0000 )) << 24) | + ((n & ((drflac_uint64)0x0000FF00 )) << 40) | + ((n & ((drflac_uint64)0x000000FF )) << 56); +#endif +} + + +static DRFLAC_INLINE drflac_uint16 drflac__be2host_16(drflac_uint16 n) +{ + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint16(n); + } + + return n; +} + +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32(drflac_uint32 n) +{ + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint32(n); + } + + return n; +} + +static DRFLAC_INLINE drflac_uint32 drflac__be2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *(pNum) << 24 | *(pNum+1) << 16 | *(pNum+2) << 8 | *(pNum+3); +} + +static DRFLAC_INLINE drflac_uint64 drflac__be2host_64(drflac_uint64 n) +{ + if (drflac__is_little_endian()) { + return drflac__swap_endian_uint64(n); + } + + return n; +} + + +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32(drflac_uint32 n) +{ + if (!drflac__is_little_endian()) { + return drflac__swap_endian_uint32(n); + } + + return n; +} + +static DRFLAC_INLINE drflac_uint32 drflac__le2host_32_ptr_unaligned(const void* pData) +{ + const drflac_uint8* pNum = (drflac_uint8*)pData; + return *pNum | *(pNum+1) << 8 | *(pNum+2) << 16 | *(pNum+3) << 24; +} + + +static DRFLAC_INLINE drflac_uint32 drflac__unsynchsafe_32(drflac_uint32 n) +{ + drflac_uint32 result = 0; + result |= (n & 0x7F000000) >> 3; + result |= (n & 0x007F0000) >> 2; + result |= (n & 0x00007F00) >> 1; + result |= (n & 0x0000007F) >> 0; + + return result; +} + + + +/* The CRC code below is based on this document: http://zlib.net/crc_v3.txt */ +static drflac_uint8 drflac__crc8_table[] = { + 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, + 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, + 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, + 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, + 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, + 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, + 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, + 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, + 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, + 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, + 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, + 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, + 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, + 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, + 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, + 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 +}; + +static drflac_uint16 drflac__crc16_table[] = { + 0x0000, 0x8005, 0x800F, 0x000A, 0x801B, 0x001E, 0x0014, 0x8011, + 0x8033, 0x0036, 0x003C, 0x8039, 0x0028, 0x802D, 0x8027, 0x0022, + 0x8063, 0x0066, 0x006C, 0x8069, 0x0078, 0x807D, 0x8077, 0x0072, + 0x0050, 0x8055, 0x805F, 0x005A, 0x804B, 0x004E, 0x0044, 0x8041, + 0x80C3, 0x00C6, 0x00CC, 0x80C9, 0x00D8, 0x80DD, 0x80D7, 0x00D2, + 0x00F0, 0x80F5, 0x80FF, 0x00FA, 0x80EB, 0x00EE, 0x00E4, 0x80E1, + 0x00A0, 0x80A5, 0x80AF, 0x00AA, 0x80BB, 0x00BE, 0x00B4, 0x80B1, + 0x8093, 0x0096, 0x009C, 0x8099, 0x0088, 0x808D, 0x8087, 0x0082, + 0x8183, 0x0186, 0x018C, 0x8189, 0x0198, 0x819D, 0x8197, 0x0192, + 0x01B0, 0x81B5, 0x81BF, 0x01BA, 0x81AB, 0x01AE, 0x01A4, 0x81A1, + 0x01E0, 0x81E5, 0x81EF, 0x01EA, 0x81FB, 0x01FE, 0x01F4, 0x81F1, + 0x81D3, 0x01D6, 0x01DC, 0x81D9, 0x01C8, 0x81CD, 0x81C7, 0x01C2, + 0x0140, 0x8145, 0x814F, 0x014A, 0x815B, 0x015E, 0x0154, 0x8151, + 0x8173, 0x0176, 0x017C, 0x8179, 0x0168, 0x816D, 0x8167, 0x0162, + 0x8123, 0x0126, 0x012C, 0x8129, 0x0138, 0x813D, 0x8137, 0x0132, + 0x0110, 0x8115, 0x811F, 0x011A, 0x810B, 0x010E, 0x0104, 0x8101, + 0x8303, 0x0306, 0x030C, 0x8309, 0x0318, 0x831D, 0x8317, 0x0312, + 0x0330, 0x8335, 0x833F, 0x033A, 0x832B, 0x032E, 0x0324, 0x8321, + 0x0360, 0x8365, 0x836F, 0x036A, 0x837B, 0x037E, 0x0374, 0x8371, + 0x8353, 0x0356, 0x035C, 0x8359, 0x0348, 0x834D, 0x8347, 0x0342, + 0x03C0, 0x83C5, 0x83CF, 0x03CA, 0x83DB, 0x03DE, 0x03D4, 0x83D1, + 0x83F3, 0x03F6, 0x03FC, 0x83F9, 0x03E8, 0x83ED, 0x83E7, 0x03E2, + 0x83A3, 0x03A6, 0x03AC, 0x83A9, 0x03B8, 0x83BD, 0x83B7, 0x03B2, + 0x0390, 0x8395, 0x839F, 0x039A, 0x838B, 0x038E, 0x0384, 0x8381, + 0x0280, 0x8285, 0x828F, 0x028A, 0x829B, 0x029E, 0x0294, 0x8291, + 0x82B3, 0x02B6, 0x02BC, 0x82B9, 0x02A8, 0x82AD, 0x82A7, 0x02A2, + 0x82E3, 0x02E6, 0x02EC, 0x82E9, 0x02F8, 0x82FD, 0x82F7, 0x02F2, + 0x02D0, 0x82D5, 0x82DF, 0x02DA, 0x82CB, 0x02CE, 0x02C4, 0x82C1, + 0x8243, 0x0246, 0x024C, 0x8249, 0x0258, 0x825D, 0x8257, 0x0252, + 0x0270, 0x8275, 0x827F, 0x027A, 0x826B, 0x026E, 0x0264, 0x8261, + 0x0220, 0x8225, 0x822F, 0x022A, 0x823B, 0x023E, 0x0234, 0x8231, + 0x8213, 0x0216, 0x021C, 0x8219, 0x0208, 0x820D, 0x8207, 0x0202 +}; + +static DRFLAC_INLINE drflac_uint8 drflac_crc8_byte(drflac_uint8 crc, drflac_uint8 data) +{ + return drflac__crc8_table[crc ^ data]; +} + +static DRFLAC_INLINE drflac_uint8 drflac_crc8(drflac_uint8 crc, drflac_uint32 data, drflac_uint32 count) +{ +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc8(crc, 0, 8);") */ + drflac_uint8 p = 0x07; + for (int i = count-1; i >= 0; --i) { + drflac_uint8 bit = (data & (1 << i)) >> i; + if (crc & 0x80) { + crc = ((crc << 1) | bit) ^ p; + } else { + crc = ((crc << 1) | bit); + } + } + return crc; +#else + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + + DRFLAC_ASSERT(count <= 32); + + wholeBytes = count >> 3; + leftoverBits = count - (wholeBytes*8); + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + case 4: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc8_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (drflac_uint8)((crc << leftoverBits) ^ drflac__crc8_table[(crc >> (8 - leftoverBits)) ^ (data & leftoverDataMask)]); + } + return crc; +#endif +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_byte(drflac_uint16 crc, drflac_uint8 data) +{ + return (crc << 8) ^ drflac__crc16_table[(drflac_uint8)(crc >> 8) ^ data]; +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_cache(drflac_uint16 crc, drflac_cache_t data) +{ +#ifdef DRFLAC_64BIT + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); +#endif + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); + + return crc; +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16_bytes(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 byteCount) +{ + switch (byteCount) + { +#ifdef DRFLAC_64BIT + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 56) & 0xFF)); + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 48) & 0xFF)); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 40) & 0xFF)); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 32) & 0xFF)); +#endif + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 24) & 0xFF)); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 16) & 0xFF)); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 8) & 0xFF)); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data >> 0) & 0xFF)); + } + + return crc; +} + +#if 0 +static DRFLAC_INLINE drflac_uint16 drflac_crc16__32bit(drflac_uint16 crc, drflac_uint32 data, drflac_uint32 count) +{ +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else +#if 0 + /* REFERENCE (use of this implementation requires an explicit flush by doing "drflac_crc16(crc, 0, 16);") */ + drflac_uint16 p = 0x8005; + for (int i = count-1; i >= 0; --i) { + drflac_uint16 bit = (data & (1ULL << i)) >> i; + if (r & 0x8000) { + r = ((r << 1) | bit) ^ p; + } else { + r = ((r << 1) | bit); + } + } + + return crc; +#else + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + + DRFLAC_ASSERT(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count & 7; + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + default: + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0xFF000000UL << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x00FF0000UL << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x0000FF00UL << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (0x000000FFUL << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +#endif +} + +static DRFLAC_INLINE drflac_uint16 drflac_crc16__64bit(drflac_uint16 crc, drflac_uint64 data, drflac_uint32 count) +{ +#ifdef DR_FLAC_NO_CRC + (void)crc; + (void)data; + (void)count; + return 0; +#else + drflac_uint32 wholeBytes; + drflac_uint32 leftoverBits; + drflac_uint64 leftoverDataMask; + + static drflac_uint64 leftoverDataMaskTable[8] = { + 0x00, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F + }; + + DRFLAC_ASSERT(count <= 64); + + wholeBytes = count >> 3; + leftoverBits = count & 7; + leftoverDataMask = leftoverDataMaskTable[leftoverBits]; + + switch (wholeBytes) { + default: + case 8: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 << 32) << leftoverBits)) >> (56 + leftoverBits))); /* Weird "<< 32" bitshift is required for C89 because it doesn't support 64-bit constants. Should be optimized out by a good compiler. */ + case 7: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 << 32) << leftoverBits)) >> (48 + leftoverBits))); + case 6: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 << 32) << leftoverBits)) >> (40 + leftoverBits))); + case 5: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF << 32) << leftoverBits)) >> (32 + leftoverBits))); + case 4: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0xFF000000 ) << leftoverBits)) >> (24 + leftoverBits))); + case 3: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x00FF0000 ) << leftoverBits)) >> (16 + leftoverBits))); + case 2: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x0000FF00 ) << leftoverBits)) >> ( 8 + leftoverBits))); + case 1: crc = drflac_crc16_byte(crc, (drflac_uint8)((data & (((drflac_uint64)0x000000FF ) << leftoverBits)) >> ( 0 + leftoverBits))); + case 0: if (leftoverBits > 0) crc = (crc << leftoverBits) ^ drflac__crc16_table[(crc >> (16 - leftoverBits)) ^ (data & leftoverDataMask)]; + } + return crc; +#endif +} + + +static DRFLAC_INLINE drflac_uint16 drflac_crc16(drflac_uint16 crc, drflac_cache_t data, drflac_uint32 count) +{ +#ifdef DRFLAC_64BIT + return drflac_crc16__64bit(crc, data, count); +#else + return drflac_crc16__32bit(crc, data, count); +#endif +} +#endif + + +#ifdef DRFLAC_64BIT +#define drflac__be2host__cache_line drflac__be2host_64 +#else +#define drflac__be2host__cache_line drflac__be2host_32 +#endif + +/* +BIT READING ATTEMPT #2 + +This uses a 32- or 64-bit bit-shifted cache - as bits are read, the cache is shifted such that the first valid bit is sitting +on the most significant bit. It uses the notion of an L1 and L2 cache (borrowed from CPU architecture), where the L1 cache +is a 32- or 64-bit unsigned integer (depending on whether or not a 32- or 64-bit build is being compiled) and the L2 is an +array of "cache lines", with each cache line being the same size as the L1. The L2 is a buffer of about 4KB and is where data +from onRead() is read into. +*/ +#define DRFLAC_CACHE_L1_SIZE_BYTES(bs) (sizeof((bs)->cache)) +#define DRFLAC_CACHE_L1_SIZE_BITS(bs) (sizeof((bs)->cache)*8) +#define DRFLAC_CACHE_L1_BITS_REMAINING(bs) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (bs)->consumedBits) +#define DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount) (~((~(drflac_cache_t)0) >> (_bitCount))) +#define DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SIZE_BITS(bs) - (_bitCount)) +#define DRFLAC_CACHE_L1_SELECT(bs, _bitCount) (((bs)->cache) & DRFLAC_CACHE_L1_SELECTION_MASK(_bitCount)) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, _bitCount) (DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount))) +#define DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, _bitCount)(DRFLAC_CACHE_L1_SELECT((bs), (_bitCount)) >> (DRFLAC_CACHE_L1_SELECTION_SHIFT((bs), (_bitCount)) & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1))) +#define DRFLAC_CACHE_L2_SIZE_BYTES(bs) (sizeof((bs)->cacheL2)) +#define DRFLAC_CACHE_L2_LINE_COUNT(bs) (DRFLAC_CACHE_L2_SIZE_BYTES(bs) / sizeof((bs)->cacheL2[0])) +#define DRFLAC_CACHE_L2_LINES_REMAINING(bs) (DRFLAC_CACHE_L2_LINE_COUNT(bs) - (bs)->nextL2Line) + + +#ifndef DR_FLAC_NO_CRC +static DRFLAC_INLINE void drflac__reset_crc16(drflac_bs* bs) +{ + bs->crc16 = 0; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +} + +static DRFLAC_INLINE void drflac__update_crc16(drflac_bs* bs) +{ + if (bs->crc16CacheIgnoredBytes == 0) { + bs->crc16 = drflac_crc16_cache(bs->crc16, bs->crc16Cache); + } else { + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache, DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bs->crc16CacheIgnoredBytes); + bs->crc16CacheIgnoredBytes = 0; + } +} + +static DRFLAC_INLINE drflac_uint16 drflac__flush_crc16(drflac_bs* bs) +{ + /* We should never be flushing in a situation where we are not aligned on a byte boundary. */ + DRFLAC_ASSERT((DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7) == 0); + + /* + The bits that were read from the L1 cache need to be accumulated. The number of bytes needing to be accumulated is determined + by the number of bits that have been consumed. + */ + if (DRFLAC_CACHE_L1_BITS_REMAINING(bs) == 0) { + drflac__update_crc16(bs); + } else { + /* We only accumulate the consumed bits. */ + bs->crc16 = drflac_crc16_bytes(bs->crc16, bs->crc16Cache >> DRFLAC_CACHE_L1_BITS_REMAINING(bs), (bs->consumedBits >> 3) - bs->crc16CacheIgnoredBytes); + + /* + The bits that we just accumulated should never be accumulated again. We need to keep track of how many bytes were accumulated + so we can handle that later. + */ + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; + } + + return bs->crc16; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__reload_l1_cache_from_l2(drflac_bs* bs) +{ + size_t bytesRead; + size_t alignedL1LineCount; + + /* Fast path. Try loading straight from L2. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return DRFLAC_TRUE; + } + + /* + If we get here it means we've run out of data in the L2 cache. We'll need to fetch more from the client, if there's + any left. + */ + if (bs->unalignedByteCount > 0) { + return DRFLAC_FALSE; /* If we have any unaligned bytes it means there's no more aligned bytes left in the client. */ + } + + bytesRead = bs->onRead(bs->pUserData, bs->cacheL2, DRFLAC_CACHE_L2_SIZE_BYTES(bs)); + + bs->nextL2Line = 0; + if (bytesRead == DRFLAC_CACHE_L2_SIZE_BYTES(bs)) { + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return DRFLAC_TRUE; + } + + + /* + If we get here it means we were unable to retrieve enough data to fill the entire L2 cache. It probably + means we've just reached the end of the file. We need to move the valid data down to the end of the buffer + and adjust the index of the next line accordingly. Also keep in mind that the L2 cache must be aligned to + the size of the L1 so we'll need to seek backwards by any misaligned bytes. + */ + alignedL1LineCount = bytesRead / DRFLAC_CACHE_L1_SIZE_BYTES(bs); + + /* We need to keep track of any unaligned bytes for later use. */ + bs->unalignedByteCount = bytesRead - (alignedL1LineCount * DRFLAC_CACHE_L1_SIZE_BYTES(bs)); + if (bs->unalignedByteCount > 0) { + bs->unalignedCache = bs->cacheL2[alignedL1LineCount]; + } + + if (alignedL1LineCount > 0) { + size_t offset = DRFLAC_CACHE_L2_LINE_COUNT(bs) - alignedL1LineCount; + size_t i; + for (i = alignedL1LineCount; i > 0; --i) { + bs->cacheL2[i-1 + offset] = bs->cacheL2[i-1]; + } + + bs->nextL2Line = (drflac_uint32)offset; + bs->cache = bs->cacheL2[bs->nextL2Line++]; + return DRFLAC_TRUE; + } else { + /* If we get into this branch it means we weren't able to load any L1-aligned data. */ + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); + return DRFLAC_FALSE; + } +} + +static drflac_bool32 drflac__reload_cache(drflac_bs* bs) +{ + size_t bytesRead; + +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); +#endif + + /* Fast path. Try just moving the next value in the L2 cache to the L1 cache. */ + if (drflac__reload_l1_cache_from_l2(bs)) { + bs->cache = drflac__be2host__cache_line(bs->cache); + bs->consumedBits = 0; +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + return DRFLAC_TRUE; + } + + /* Slow path. */ + + /* + If we get here it means we have failed to load the L1 cache from the L2. Likely we've just reached the end of the stream and the last + few bytes did not meet the alignment requirements for the L2 cache. In this case we need to fall back to a slower path and read the + data from the unaligned cache. + */ + bytesRead = bs->unalignedByteCount; + if (bytesRead == 0) { + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- The stream has been exhausted, so marked the bits as consumed. */ + return DRFLAC_FALSE; + } + + DRFLAC_ASSERT(bytesRead < DRFLAC_CACHE_L1_SIZE_BYTES(bs)); + bs->consumedBits = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BYTES(bs) - bytesRead) * 8; + + bs->cache = drflac__be2host__cache_line(bs->unalignedCache); + bs->cache &= DRFLAC_CACHE_L1_SELECTION_MASK(DRFLAC_CACHE_L1_BITS_REMAINING(bs)); /* <-- Make sure the consumed bits are always set to zero. Other parts of the library depend on this property. */ + bs->unalignedByteCount = 0; /* <-- At this point the unaligned bytes have been moved into the cache and we thus have no more unaligned bytes. */ + +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache >> bs->consumedBits; + bs->crc16CacheIgnoredBytes = bs->consumedBits >> 3; +#endif + return DRFLAC_TRUE; +} + +static void drflac__reset_cache(drflac_bs* bs) +{ + bs->nextL2Line = DRFLAC_CACHE_L2_LINE_COUNT(bs); /* <-- This clears the L2 cache. */ + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); /* <-- This clears the L1 cache. */ + bs->cache = 0; + bs->unalignedByteCount = 0; /* <-- This clears the trailing unaligned bytes. */ + bs->unalignedCache = 0; + +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = 0; + bs->crc16CacheIgnoredBytes = 0; +#endif +} + + +static DRFLAC_INLINE drflac_bool32 drflac__read_uint32(drflac_bs* bs, unsigned int bitCount, drflac_uint32* pResultOut) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResultOut != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 32); + + if (bs->consumedBits == DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + if (bitCount <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* + If we want to load all 32-bits from a 32-bit cache we need to do it slightly differently because we can't do + a 32-bit shift on a 32-bit integer. This will never be the case on 64-bit caches, so we can have a slightly + more optimal solution for this. + */ +#ifdef DRFLAC_64BIT + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; +#else + if (bitCount < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + *pResultOut = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCount); + bs->consumedBits += bitCount; + bs->cache <<= bitCount; + } else { + /* Cannot shift by 32-bits, so need to do it differently. */ + *pResultOut = (drflac_uint32)bs->cache; + bs->consumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs); + bs->cache = 0; + } +#endif + + return DRFLAC_TRUE; + } else { + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ + drflac_uint32 bitCountHi = DRFLAC_CACHE_L1_BITS_REMAINING(bs); + drflac_uint32 bitCountLo = bitCount - bitCountHi; + drflac_uint32 resultHi; + + DRFLAC_ASSERT(bitCountHi > 0); + DRFLAC_ASSERT(bitCountHi < 32); + resultHi = (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountHi); + + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + *pResultOut = (resultHi << bitCountLo) | (drflac_uint32)DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, bitCountLo); + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + return DRFLAC_TRUE; + } +} + +static drflac_bool32 drflac__read_int32(drflac_bs* bs, unsigned int bitCount, drflac_int32* pResult) +{ + drflac_uint32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 32); + + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + /* Do not attempt to shift by 32 as it's undefined. */ + if (bitCount < 32) { + drflac_uint32 signbit; + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + } + + *pResult = (drflac_int32)result; + return DRFLAC_TRUE; +} + +#ifdef DRFLAC_64BIT +static drflac_bool32 drflac__read_uint64(drflac_bs* bs, unsigned int bitCount, drflac_uint64* pResultOut) +{ + drflac_uint32 resultHi; + drflac_uint32 resultLo; + + DRFLAC_ASSERT(bitCount <= 64); + DRFLAC_ASSERT(bitCount > 32); + + if (!drflac__read_uint32(bs, bitCount - 32, &resultHi)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_uint32(bs, 32, &resultLo)) { + return DRFLAC_FALSE; + } + + *pResultOut = (((drflac_uint64)resultHi) << 32) | ((drflac_uint64)resultLo); + return DRFLAC_TRUE; +} +#endif + +/* Function below is unused, but leaving it here in case I need to quickly add it again. */ +#if 0 +static drflac_bool32 drflac__read_int64(drflac_bs* bs, unsigned int bitCount, drflac_int64* pResultOut) +{ + drflac_uint64 result; + drflac_uint64 signbit; + + DRFLAC_ASSERT(bitCount <= 64); + + if (!drflac__read_uint64(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + signbit = ((result >> (bitCount-1)) & 0x01); + result |= (~signbit + 1) << bitCount; + + *pResultOut = (drflac_int64)result; + return DRFLAC_TRUE; +} +#endif + +static drflac_bool32 drflac__read_uint16(drflac_bs* bs, unsigned int bitCount, drflac_uint16* pResult) +{ + drflac_uint32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 16); + + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_uint16)result; + return DRFLAC_TRUE; +} + +#if 0 +static drflac_bool32 drflac__read_int16(drflac_bs* bs, unsigned int bitCount, drflac_int16* pResult) +{ + drflac_int32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 16); + + if (!drflac__read_int32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_int16)result; + return DRFLAC_TRUE; +} +#endif + +static drflac_bool32 drflac__read_uint8(drflac_bs* bs, unsigned int bitCount, drflac_uint8* pResult) +{ + drflac_uint32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 8); + + if (!drflac__read_uint32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_uint8)result; + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__read_int8(drflac_bs* bs, unsigned int bitCount, drflac_int8* pResult) +{ + drflac_int32 result; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pResult != NULL); + DRFLAC_ASSERT(bitCount > 0); + DRFLAC_ASSERT(bitCount <= 8); + + if (!drflac__read_int32(bs, bitCount, &result)) { + return DRFLAC_FALSE; + } + + *pResult = (drflac_int8)result; + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__seek_bits(drflac_bs* bs, size_t bitsToSeek) +{ + if (bitsToSeek <= DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + bs->consumedBits += (drflac_uint32)bitsToSeek; + bs->cache <<= bitsToSeek; + return DRFLAC_TRUE; + } else { + /* It straddles the cached data. This function isn't called too frequently so I'm favouring simplicity here. */ + bitsToSeek -= DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->consumedBits += DRFLAC_CACHE_L1_BITS_REMAINING(bs); + bs->cache = 0; + + /* Simple case. Seek in groups of the same number as bits that fit within a cache line. */ +#ifdef DRFLAC_64BIT + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint64 bin; + if (!drflac__read_uint64(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); + } +#else + while (bitsToSeek >= DRFLAC_CACHE_L1_SIZE_BITS(bs)) { + drflac_uint32 bin; + if (!drflac__read_uint32(bs, DRFLAC_CACHE_L1_SIZE_BITS(bs), &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= DRFLAC_CACHE_L1_SIZE_BITS(bs); + } +#endif + + /* Whole leftover bytes. */ + while (bitsToSeek >= 8) { + drflac_uint8 bin; + if (!drflac__read_uint8(bs, 8, &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek -= 8; + } + + /* Leftover bits. */ + if (bitsToSeek > 0) { + drflac_uint8 bin; + if (!drflac__read_uint8(bs, (drflac_uint32)bitsToSeek, &bin)) { + return DRFLAC_FALSE; + } + bitsToSeek = 0; /* <-- Necessary for the assert below. */ + } + + DRFLAC_ASSERT(bitsToSeek == 0); + return DRFLAC_TRUE; + } +} + + +/* This function moves the bit streamer to the first bit after the sync code (bit 15 of the of the frame header). It will also update the CRC-16. */ +static drflac_bool32 drflac__find_and_seek_to_next_sync_code(drflac_bs* bs) +{ + DRFLAC_ASSERT(bs != NULL); + + /* + The sync code is always aligned to 8 bits. This is convenient for us because it means we can do byte-aligned movements. The first + thing to do is align to the next byte. + */ + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; + } + + for (;;) { + drflac_uint8 hi; + +#ifndef DR_FLAC_NO_CRC + drflac__reset_crc16(bs); +#endif + + if (!drflac__read_uint8(bs, 8, &hi)) { + return DRFLAC_FALSE; + } + + if (hi == 0xFF) { + drflac_uint8 lo; + if (!drflac__read_uint8(bs, 6, &lo)) { + return DRFLAC_FALSE; + } + + if (lo == 0x3E) { + return DRFLAC_TRUE; + } else { + if (!drflac__seek_bits(bs, DRFLAC_CACHE_L1_BITS_REMAINING(bs) & 7)) { + return DRFLAC_FALSE; + } + } + } + } + + /* Should never get here. */ + /*return DRFLAC_FALSE;*/ +} + + +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) +#define DRFLAC_IMPLEMENT_CLZ_LZCNT +#endif +#if defined(_MSC_VER) && _MSC_VER >= 1400 && (defined(DRFLAC_X64) || defined(DRFLAC_X86)) && !defined(__clang__) +#define DRFLAC_IMPLEMENT_CLZ_MSVC +#endif +#if defined(__WATCOMC__) && defined(__386__) +#define DRFLAC_IMPLEMENT_CLZ_WATCOM +#endif +#ifdef __MRC__ +#include +#define DRFLAC_IMPLEMENT_CLZ_MRC +#endif + +static DRFLAC_INLINE drflac_uint32 drflac__clz_software(drflac_cache_t x) +{ + drflac_uint32 n; + static drflac_uint32 clz_table_4[] = { + 0, + 4, + 3, 3, + 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1 + }; + + if (x == 0) { + return sizeof(x)*8; + } + + n = clz_table_4[x >> (sizeof(x)*8 - 4)]; + if (n == 0) { +#ifdef DRFLAC_64BIT + if ((x & ((drflac_uint64)0xFFFFFFFF << 32)) == 0) { n = 32; x <<= 32; } + if ((x & ((drflac_uint64)0xFFFF0000 << 32)) == 0) { n += 16; x <<= 16; } + if ((x & ((drflac_uint64)0xFF000000 << 32)) == 0) { n += 8; x <<= 8; } + if ((x & ((drflac_uint64)0xF0000000 << 32)) == 0) { n += 4; x <<= 4; } +#else + if ((x & 0xFFFF0000) == 0) { n = 16; x <<= 16; } + if ((x & 0xFF000000) == 0) { n += 8; x <<= 8; } + if ((x & 0xF0000000) == 0) { n += 4; x <<= 4; } +#endif + n += clz_table_4[x >> (sizeof(x)*8 - 4)]; + } + + return n - 1; +} + +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT +static DRFLAC_INLINE drflac_bool32 drflac__is_lzcnt_supported(void) +{ + /* Fast compile time check for ARM. */ +#if defined(DRFLAC_HAS_LZCNT_INTRINSIC) && defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) + return DRFLAC_TRUE; +#elif defined(__MRC__) + return DRFLAC_TRUE; +#else + /* If the compiler itself does not support the intrinsic then we'll need to return false. */ + #ifdef DRFLAC_HAS_LZCNT_INTRINSIC + return drflac__gIsLZCNTSupported; + #else + return DRFLAC_FALSE; + #endif +#endif +} + +static DRFLAC_INLINE drflac_uint32 drflac__clz_lzcnt(drflac_cache_t x) +{ + /* + It's critical for competitive decoding performance that this function be highly optimal. With MSVC we can use the __lzcnt64() and __lzcnt() intrinsics + to achieve good performance, however on GCC and Clang it's a little bit more annoying. The __builtin_clzl() and __builtin_clzll() intrinsics leave + it undefined as to the return value when `x` is 0. We need this to be well defined as returning 32 or 64, depending on whether or not it's a 32- or + 64-bit build. To work around this we would need to add a conditional to check for the x = 0 case, but this creates unnecessary inefficiency. To work + around this problem I have written some inline assembly to emit the LZCNT (x86) or CLZ (ARM) instruction directly which removes the need to include + the conditional. This has worked well in the past, but for some reason Clang's MSVC compatible driver, clang-cl, does not seem to be handling this + in the same way as the normal Clang driver. It seems that `clang-cl` is just outputting the wrong results sometimes, maybe due to some register + getting clobbered? + + I'm not sure if this is a bug with dr_flac's inlined assembly (most likely), a bug in `clang-cl` or just a misunderstanding on my part with inline + assembly rules for `clang-cl`. If somebody can identify an error in dr_flac's inlined assembly I'm happy to get that fixed. + + Fortunately there is an easy workaround for this. Clang implements MSVC-specific intrinsics for compatibility. It also defines _MSC_VER for extra + compatibility. We can therefore just check for _MSC_VER and use the MSVC intrinsic which, fortunately for us, Clang supports. It would still be nice + to know how to fix the inlined assembly for correctness sake, however. + */ + +#if defined(_MSC_VER) /*&& !defined(__clang__)*/ /* <-- Intentionally wanting Clang to use the MSVC __lzcnt64/__lzcnt intrinsics due to above ^. */ + #ifdef DRFLAC_64BIT + return (drflac_uint32)__lzcnt64(x); + #else + return (drflac_uint32)__lzcnt(x); + #endif +#else + #if defined(__GNUC__) || defined(__clang__) + #if defined(DRFLAC_X64) + { + /* + A note on lzcnt. + + We check for the presence of the lzcnt instruction at runtime before calling this function, but we still generate this code. I have had + a report where the assembler does not recognize the lzcnt instruction. To work around this we are going to use `rep; bsr` instead which + has an identical byte encoding as lzcnt, and should hopefully improve compatibility with older assemblers. + */ + drflac_uint64 r; + __asm__ __volatile__ ( + "rep; bsr{q %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + /*"lzcnt{ %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/ + ); + + return (drflac_uint32)r; + } + #elif defined(DRFLAC_X86) + { + drflac_uint32 r; + __asm__ __volatile__ ( + "rep; bsr{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc" + /*"lzcnt{l %1, %0| %0, %1}" : "=r"(r) : "r"(x) : "cc"*/ + ); + + return r; + } + #elif defined(DRFLAC_ARM) && (defined(__ARM_ARCH) && __ARM_ARCH >= 5) && !defined(__ARM_ARCH_6M__) && !(defined(__thumb__) && !defined(__thumb2__)) && !defined(DRFLAC_64BIT) /* <-- I haven't tested 64-bit inline assembly, so only enabling this for the 32-bit build for now. */ + { + unsigned int r; + __asm__ __volatile__ ( + #if defined(DRFLAC_64BIT) + "clz %w[out], %w[in]" : [out]"=r"(r) : [in]"r"(x) /* <-- This is untested. If someone in the community could test this, that would be appreciated! */ + #else + "clz %[out], %[in]" : [out]"=r"(r) : [in]"r"(x) + #endif + ); + + return r; + } + #else + if (x == 0) { + return sizeof(x)*8; + } + #ifdef DRFLAC_64BIT + return (drflac_uint32)__builtin_clzll((drflac_uint64)x); + #else + return (drflac_uint32)__builtin_clzl((drflac_uint32)x); + #endif + #endif + #else + /* Unsupported compiler. */ + #error "This compiler does not support the lzcnt intrinsic." + #endif +#endif +} +#endif + +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC +#include /* For BitScanReverse(). */ + +static DRFLAC_INLINE drflac_uint32 drflac__clz_msvc(drflac_cache_t x) +{ + drflac_uint32 n; + + if (x == 0) { + return sizeof(x)*8; + } + +#ifdef DRFLAC_64BIT + _BitScanReverse64((unsigned long*)&n, x); +#else + _BitScanReverse((unsigned long*)&n, x); +#endif + return sizeof(x)*8 - n - 1; +} +#endif + +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM +static __inline drflac_uint32 drflac__clz_watcom (drflac_uint32); +#ifdef DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT +/* Use the LZCNT instruction (only available on some processors since the 2010s). */ +#pragma aux drflac__clz_watcom_lzcnt = \ + "db 0F3h, 0Fh, 0BDh, 0C0h" /* lzcnt eax, eax */ \ + parm [eax] \ + value [eax] \ + modify nomemory; +#else +/* Use the 386+-compatible implementation. */ +#pragma aux drflac__clz_watcom = \ + "bsr eax, eax" \ + "xor eax, 31" \ + parm [eax] nomemory \ + value [eax] \ + modify exact [eax] nomemory; +#endif +#endif + +static DRFLAC_INLINE drflac_uint32 drflac__clz(drflac_cache_t x) +{ +#ifdef DRFLAC_IMPLEMENT_CLZ_LZCNT + if (drflac__is_lzcnt_supported()) { + return drflac__clz_lzcnt(x); + } else +#endif + { +#ifdef DRFLAC_IMPLEMENT_CLZ_MSVC + return drflac__clz_msvc(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM_LZCNT) + return drflac__clz_watcom_lzcnt(x); +#elif defined(DRFLAC_IMPLEMENT_CLZ_WATCOM) + return (x == 0) ? sizeof(x)*8 : drflac__clz_watcom(x); +#elif defined(__MRC__) + return __cntlzw(x); +#else + return drflac__clz_software(x); +#endif + } +} + + +static DRFLAC_INLINE drflac_bool32 drflac__seek_past_next_set_bit(drflac_bs* bs, unsigned int* pOffsetOut) +{ + drflac_uint32 zeroCounter = 0; + drflac_uint32 setBitOffsetPlus1; + + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + if (bs->cache == 1) { + /* Not catching this would lead to undefined behaviour: a shift of a 32-bit number by 32 or more is undefined */ + *pOffsetOut = zeroCounter + (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs) - 1; + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; + } + + setBitOffsetPlus1 = drflac__clz(bs->cache); + setBitOffsetPlus1 += 1; + + if (setBitOffsetPlus1 > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + bs->consumedBits += setBitOffsetPlus1; + bs->cache <<= setBitOffsetPlus1; + + *pOffsetOut = zeroCounter + setBitOffsetPlus1 - 1; + return DRFLAC_TRUE; +} + + + +static drflac_bool32 drflac__seek_to_byte(drflac_bs* bs, drflac_uint64 offsetFromStart) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(offsetFromStart > 0); + + /* + Seeking from the start is not quite as trivial as it sounds because the onSeek callback takes a signed 32-bit integer (which + is intentional because it simplifies the implementation of the onSeek callbacks), however offsetFromStart is unsigned 64-bit. + To resolve we just need to do an initial seek from the start, and then a series of offset seeks to make up the remainder. + */ + if (offsetFromStart > 0x7FFFFFFF) { + drflac_uint64 bytesRemaining = offsetFromStart; + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) { + return DRFLAC_FALSE; + } + bytesRemaining -= 0x7FFFFFFF; + + while (bytesRemaining > 0x7FFFFFFF) { + if (!bs->onSeek(bs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + bytesRemaining -= 0x7FFFFFFF; + } + + if (bytesRemaining > 0) { + if (!bs->onSeek(bs->pUserData, (int)bytesRemaining, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + } + } else { + if (!bs->onSeek(bs->pUserData, (int)offsetFromStart, DRFLAC_SEEK_SET)) { + return DRFLAC_FALSE; + } + } + + /* The cache should be reset to force a reload of fresh data from the client. */ + drflac__reset_cache(bs); + return DRFLAC_TRUE; +} + + +static drflac_result drflac__read_utf8_coded_number(drflac_bs* bs, drflac_uint64* pNumberOut, drflac_uint8* pCRCOut) +{ + drflac_uint8 crc; + drflac_uint64 result; + drflac_uint8 utf8[7] = {0}; + int byteCount; + int i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pNumberOut != NULL); + DRFLAC_ASSERT(pCRCOut != NULL); + + crc = *pCRCOut; + + if (!drflac__read_uint8(bs, 8, utf8)) { + *pNumberOut = 0; + return DRFLAC_AT_END; + } + crc = drflac_crc8(crc, utf8[0], 8); + + if ((utf8[0] & 0x80) == 0) { + *pNumberOut = utf8[0]; + *pCRCOut = crc; + return DRFLAC_SUCCESS; + } + + /*byteCount = 1;*/ + if ((utf8[0] & 0xE0) == 0xC0) { + byteCount = 2; + } else if ((utf8[0] & 0xF0) == 0xE0) { + byteCount = 3; + } else if ((utf8[0] & 0xF8) == 0xF0) { + byteCount = 4; + } else if ((utf8[0] & 0xFC) == 0xF8) { + byteCount = 5; + } else if ((utf8[0] & 0xFE) == 0xFC) { + byteCount = 6; + } else if ((utf8[0] & 0xFF) == 0xFE) { + byteCount = 7; + } else { + *pNumberOut = 0; + return DRFLAC_CRC_MISMATCH; /* Bad UTF-8 encoding. */ + } + + /* Read extra bytes. */ + DRFLAC_ASSERT(byteCount > 1); + + result = (drflac_uint64)(utf8[0] & (0xFF >> (byteCount + 1))); + for (i = 1; i < byteCount; ++i) { + if (!drflac__read_uint8(bs, 8, utf8 + i)) { + *pNumberOut = 0; + return DRFLAC_AT_END; + } + crc = drflac_crc8(crc, utf8[i], 8); + + result = (result << 6) | (utf8[i] & 0x3F); + } + + *pNumberOut = result; + *pCRCOut = crc; + return DRFLAC_SUCCESS; +} + + +static DRFLAC_INLINE drflac_uint32 drflac__ilog2_u32(drflac_uint32 x) +{ +#if 1 /* Needs optimizing. */ + drflac_uint32 result = 0; + while (x > 0) { + result += 1; + x >>= 1; + } + + return result; +#endif +} + +static DRFLAC_INLINE drflac_bool32 drflac__use_64_bit_prediction(drflac_uint32 bitsPerSample, drflac_uint32 order, drflac_uint32 precision) +{ + /* https://web.archive.org/web/20220205005724/https://github.com/ietf-wg-cellar/flac-specification/blob/37a49aa48ba4ba12e8757badfc59c0df35435fec/rfc_backmatter.md */ + return bitsPerSample + precision + drflac__ilog2_u32(order) > 32; +} + + +/* +The next two functions are responsible for calculating the prediction. + +When the bits per sample is >16 we need to use 64-bit integer arithmetic because otherwise we'll run out of precision. It's +safe to assume this will be slower on 32-bit platforms so we use a more optimal solution when the bits per sample is <=16. +*/ +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_32(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +{ + drflac_int32 prediction = 0; + + DRFLAC_ASSERT(order <= 32); + + /* 32-bit version. */ + + /* VC++ optimizes this to a single jmp. I've not yet verified this for other compilers. */ + switch (order) + { + case 32: prediction += coefficients[31] * pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * pDecodedSamples[- 1]; + } + + return (drflac_int32)(prediction >> shift); +} + +static DRFLAC_INLINE drflac_int32 drflac__calculate_prediction_64(drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +{ + drflac_int64 prediction; + + DRFLAC_ASSERT(order <= 32); + + /* 64-bit version. */ + + /* This method is faster on the 32-bit build when compiling with VC++. See note below. */ +#ifndef DRFLAC_64BIT + if (order == 8) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + } + else if (order == 7) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + } + else if (order == 3) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + } + else if (order == 6) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + } + else if (order == 5) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + } + else if (order == 4) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + } + else if (order == 12) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; + } + else if (order == 2) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + } + else if (order == 1) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + } + else if (order == 10) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + } + else if (order == 9) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + } + else if (order == 11) + { + prediction = coefficients[0] * (drflac_int64)pDecodedSamples[-1]; + prediction += coefficients[1] * (drflac_int64)pDecodedSamples[-2]; + prediction += coefficients[2] * (drflac_int64)pDecodedSamples[-3]; + prediction += coefficients[3] * (drflac_int64)pDecodedSamples[-4]; + prediction += coefficients[4] * (drflac_int64)pDecodedSamples[-5]; + prediction += coefficients[5] * (drflac_int64)pDecodedSamples[-6]; + prediction += coefficients[6] * (drflac_int64)pDecodedSamples[-7]; + prediction += coefficients[7] * (drflac_int64)pDecodedSamples[-8]; + prediction += coefficients[8] * (drflac_int64)pDecodedSamples[-9]; + prediction += coefficients[9] * (drflac_int64)pDecodedSamples[-10]; + prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + } + else + { + int j; + + prediction = 0; + for (j = 0; j < (int)order; ++j) { + prediction += coefficients[j] * (drflac_int64)pDecodedSamples[-j-1]; + } + } +#endif + + /* + VC++ optimizes this to a single jmp instruction, but only the 64-bit build. The 32-bit build generates less efficient code for some + reason. The ugly version above is faster so we'll just switch between the two depending on the target platform. + */ +#ifdef DRFLAC_64BIT + prediction = 0; + switch (order) + { + case 32: prediction += coefficients[31] * (drflac_int64)pDecodedSamples[-32]; + case 31: prediction += coefficients[30] * (drflac_int64)pDecodedSamples[-31]; + case 30: prediction += coefficients[29] * (drflac_int64)pDecodedSamples[-30]; + case 29: prediction += coefficients[28] * (drflac_int64)pDecodedSamples[-29]; + case 28: prediction += coefficients[27] * (drflac_int64)pDecodedSamples[-28]; + case 27: prediction += coefficients[26] * (drflac_int64)pDecodedSamples[-27]; + case 26: prediction += coefficients[25] * (drflac_int64)pDecodedSamples[-26]; + case 25: prediction += coefficients[24] * (drflac_int64)pDecodedSamples[-25]; + case 24: prediction += coefficients[23] * (drflac_int64)pDecodedSamples[-24]; + case 23: prediction += coefficients[22] * (drflac_int64)pDecodedSamples[-23]; + case 22: prediction += coefficients[21] * (drflac_int64)pDecodedSamples[-22]; + case 21: prediction += coefficients[20] * (drflac_int64)pDecodedSamples[-21]; + case 20: prediction += coefficients[19] * (drflac_int64)pDecodedSamples[-20]; + case 19: prediction += coefficients[18] * (drflac_int64)pDecodedSamples[-19]; + case 18: prediction += coefficients[17] * (drflac_int64)pDecodedSamples[-18]; + case 17: prediction += coefficients[16] * (drflac_int64)pDecodedSamples[-17]; + case 16: prediction += coefficients[15] * (drflac_int64)pDecodedSamples[-16]; + case 15: prediction += coefficients[14] * (drflac_int64)pDecodedSamples[-15]; + case 14: prediction += coefficients[13] * (drflac_int64)pDecodedSamples[-14]; + case 13: prediction += coefficients[12] * (drflac_int64)pDecodedSamples[-13]; + case 12: prediction += coefficients[11] * (drflac_int64)pDecodedSamples[-12]; + case 11: prediction += coefficients[10] * (drflac_int64)pDecodedSamples[-11]; + case 10: prediction += coefficients[ 9] * (drflac_int64)pDecodedSamples[-10]; + case 9: prediction += coefficients[ 8] * (drflac_int64)pDecodedSamples[- 9]; + case 8: prediction += coefficients[ 7] * (drflac_int64)pDecodedSamples[- 8]; + case 7: prediction += coefficients[ 6] * (drflac_int64)pDecodedSamples[- 7]; + case 6: prediction += coefficients[ 5] * (drflac_int64)pDecodedSamples[- 6]; + case 5: prediction += coefficients[ 4] * (drflac_int64)pDecodedSamples[- 5]; + case 4: prediction += coefficients[ 3] * (drflac_int64)pDecodedSamples[- 4]; + case 3: prediction += coefficients[ 2] * (drflac_int64)pDecodedSamples[- 3]; + case 2: prediction += coefficients[ 1] * (drflac_int64)pDecodedSamples[- 2]; + case 1: prediction += coefficients[ 0] * (drflac_int64)pDecodedSamples[- 1]; + } +#endif + + return (drflac_int32)(prediction >> shift); +} + + +#if 0 +/* +Reference implementation for reading and decoding samples with residual. This is intentionally left unoptimized for the +sake of readability and should only be used as a reference. +*/ +static drflac_bool32 drflac__decode_samples_with_residual__rice__reference(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + for (i = 0; i < count; ++i) { + drflac_uint32 zeroCounter = 0; + for (;;) { + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; + } + + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + + drflac_uint32 decodedRice; + if (riceParam > 0) { + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; + } + } else { + decodedRice = 0; + } + + decodedRice |= (zeroCounter << riceParam); + if ((decodedRice & 0x01)) { + decodedRice = ~(decodedRice >> 1); + } else { + decodedRice = (decodedRice >> 1); + } + + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] = decodedRice + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } + } + + return DRFLAC_TRUE; +} +#endif + +#if 0 +static drflac_bool32 drflac__read_rice_parts__reference(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_uint32 zeroCounter = 0; + drflac_uint32 decodedRice; + + for (;;) { + drflac_uint8 bit; + if (!drflac__read_uint8(bs, 1, &bit)) { + return DRFLAC_FALSE; + } + + if (bit == 0) { + zeroCounter += 1; + } else { + break; + } + } + + if (riceParam > 0) { + if (!drflac__read_uint32(bs, riceParam, &decodedRice)) { + return DRFLAC_FALSE; + } + } else { + decodedRice = 0; + } + + *pZeroCounterOut = zeroCounter; + *pRiceParamPartOut = decodedRice; + return DRFLAC_TRUE; +} +#endif + +#if 0 +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_cache_t riceParamMask; + drflac_uint32 zeroCounter; + drflac_uint32 setBitOffsetPlus1; + drflac_uint32 riceParamPart; + drflac_uint32 riceLength; + + DRFLAC_ASSERT(riceParam > 0); /* <-- riceParam should never be 0. drflac__read_rice_parts__param_equals_zero() should be used instead for this case. */ + + riceParamMask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParam); + + zeroCounter = 0; + while (bs->cache == 0) { + zeroCounter += (drflac_uint32)DRFLAC_CACHE_L1_BITS_REMAINING(bs); + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + } + + setBitOffsetPlus1 = drflac__clz(bs->cache); + zeroCounter += setBitOffsetPlus1; + setBitOffsetPlus1 += 1; + + riceLength = setBitOffsetPlus1 + riceParam; + if (riceLength < DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + riceParamPart = (drflac_uint32)((bs->cache & (riceParamMask >> setBitOffsetPlus1)) >> DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceLength)); + + bs->consumedBits += riceLength; + bs->cache <<= riceLength; + } else { + drflac_uint32 bitCountLo; + drflac_cache_t resultHi; + + bs->consumedBits += riceLength; + bs->cache <<= setBitOffsetPlus1 & (DRFLAC_CACHE_L1_SIZE_BITS(bs)-1); /* <-- Equivalent to "if (setBitOffsetPlus1 < DRFLAC_CACHE_L1_SIZE_BITS(bs)) { bs->cache <<= setBitOffsetPlus1; }" */ + + /* It straddles the cached data. It will never cover more than the next chunk. We just read the number in two parts and combine them. */ + bitCountLo = bs->consumedBits - DRFLAC_CACHE_L1_SIZE_BITS(bs); + resultHi = DRFLAC_CACHE_L1_SELECT_AND_SHIFT(bs, riceParam); /* <-- Use DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE() if ever this function allows riceParam=0. */ + + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { +#ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); +#endif + bs->cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs->consumedBits = 0; +#ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs->cache; +#endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + if (bitCountLo > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + } + + riceParamPart = (drflac_uint32)(resultHi | DRFLAC_CACHE_L1_SELECT_AND_SHIFT_SAFE(bs, bitCountLo)); + + bs->consumedBits += bitCountLo; + bs->cache <<= bitCountLo; + } + + pZeroCounterOut[0] = zeroCounter; + pRiceParamPartOut[0] = riceParamPart; + + return DRFLAC_TRUE; +} +#endif + +static DRFLAC_INLINE drflac_bool32 drflac__read_rice_parts_x1(drflac_bs* bs, drflac_uint8 riceParam, drflac_uint32* pZeroCounterOut, drflac_uint32* pRiceParamPartOut) +{ + drflac_uint32 riceParamPlus1 = riceParam + 1; + /*drflac_cache_t riceParamPlus1Mask = DRFLAC_CACHE_L1_SELECTION_MASK(riceParamPlus1);*/ + drflac_uint32 riceParamPlus1Shift = DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPlus1); + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ + drflac_uint32 lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + pZeroCounterOut[0] = lzcount; + + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ + pRiceParamPartOut[0] = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + drflac_uint32 riceParamPartHi; + drflac_uint32 riceParamPartLo; + drflac_uint32 riceParamPartLoBitCount; + + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ + + /* Grab the high part of the rice parameter part. */ + riceParamPartHi = (drflac_uint32)(bs_cache >> riceParamPlus1Shift); + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + + /* Now reload the cache. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; + } + + /* We should now have enough information to construct the rice parameter part. */ + riceParamPartLo = (drflac_uint32)(bs_cache >> (DRFLAC_CACHE_L1_SELECTION_SHIFT(bs, riceParamPartLoBitCount))); + pRiceParamPartOut[0] = riceParamPartHi | riceParamPartLo; + + bs_cache <<= riceParamPartLoBitCount; + } + } else { + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ + drflac_uint32 zeroCounter = (drflac_uint32)(DRFLAC_CACHE_L1_SIZE_BITS(bs) - bs_consumedBits); + for (;;) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + + lzcount = drflac__clz(bs_cache); + zeroCounter += lzcount; + + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + + pZeroCounterOut[0] = zeroCounter; + goto extract_rice_param_part; + } + + /* Make sure the cache is restored at the end of it all. */ + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + + return DRFLAC_TRUE; +} + +static DRFLAC_INLINE drflac_bool32 drflac__seek_rice_parts(drflac_bs* bs, drflac_uint8 riceParam) +{ + drflac_uint32 riceParamPlus1 = riceParam + 1; + drflac_uint32 riceParamPlus1MaxConsumedBits = DRFLAC_CACHE_L1_SIZE_BITS(bs) - riceParamPlus1; + + /* + The idea here is to use local variables for the cache in an attempt to encourage the compiler to store them in registers. I have + no idea how this will work in practice... + */ + drflac_cache_t bs_cache = bs->cache; + drflac_uint32 bs_consumedBits = bs->consumedBits; + + /* The first thing to do is find the first unset bit. Most likely a bit will be set in the current cache line. */ + drflac_uint32 lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + /* + It is most likely that the riceParam part (which comes after the zero counter) is also on this cache line. When extracting + this, we include the set bit from the unary coded part because it simplifies cache management. This bit will be handled + outside of this function at a higher level. + */ + extract_rice_param_part: + bs_cache <<= lzcount; + bs_consumedBits += lzcount; + + if (bs_consumedBits <= riceParamPlus1MaxConsumedBits) { + /* Getting here means the rice parameter part is wholly contained within the current cache line. */ + bs_cache <<= riceParamPlus1; + bs_consumedBits += riceParamPlus1; + } else { + /* + Getting here means the rice parameter part straddles the cache line. We need to read from the tail of the current cache + line, reload the cache, and then combine it with the head of the next cache line. + */ + + /* Before reloading the cache we need to grab the size in bits of the low part. */ + drflac_uint32 riceParamPartLoBitCount = bs_consumedBits - riceParamPlus1MaxConsumedBits; + DRFLAC_ASSERT(riceParamPartLoBitCount > 0 && riceParamPartLoBitCount < 32); + + /* Now reload the cache. */ + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = riceParamPartLoBitCount; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + if (riceParamPartLoBitCount > DRFLAC_CACHE_L1_BITS_REMAINING(bs)) { + /* This happens when we get to end of stream */ + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits + riceParamPartLoBitCount; + } + + bs_cache <<= riceParamPartLoBitCount; + } + } else { + /* + Getting here means there are no bits set on the cache line. This is a less optimal case because we just wasted a call + to drflac__clz() and we need to reload the cache. + */ + for (;;) { + if (bs->nextL2Line < DRFLAC_CACHE_L2_LINE_COUNT(bs)) { + #ifndef DR_FLAC_NO_CRC + drflac__update_crc16(bs); + #endif + bs_cache = drflac__be2host__cache_line(bs->cacheL2[bs->nextL2Line++]); + bs_consumedBits = 0; + #ifndef DR_FLAC_NO_CRC + bs->crc16Cache = bs_cache; + #endif + } else { + /* Slow path. We need to fetch more data from the client. */ + if (!drflac__reload_cache(bs)) { + return DRFLAC_FALSE; + } + + bs_cache = bs->cache; + bs_consumedBits = bs->consumedBits; + } + + lzcount = drflac__clz(bs_cache); + if (lzcount < sizeof(bs_cache)*8) { + break; + } + } + + goto extract_rice_param_part; + } + + /* Make sure the cache is restored at the end of it all. */ + bs->cache = bs_cache; + bs->consumedBits = bs_consumedBits; + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar_zeroorder(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0; + drflac_uint32 riceParamPart0; + drflac_uint32 riceParamMask; + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + (void)bitsPerSample; + (void)order; + (void)shift; + (void)coefficients; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + + i = 0; + while (i < count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + + pSamplesOut[i] = riceParamPart0; + + i += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__scalar(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + drflac_uint32 zeroCountPart0 = 0; + drflac_uint32 zeroCountPart1 = 0; + drflac_uint32 zeroCountPart2 = 0; + drflac_uint32 zeroCountPart3 = 0; + drflac_uint32 riceParamPart0 = 0; + drflac_uint32 riceParamPart1 = 0; + drflac_uint32 riceParamPart2 = 0; + drflac_uint32 riceParamPart3 = 0; + drflac_uint32 riceParamMask; + const drflac_int32* pSamplesOutEnd; + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + if (lpcOrder == 0) { + return drflac__decode_samples_with_residual__rice__scalar_zeroorder(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + pSamplesOutEnd = pSamplesOut + (count & ~3); + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + while (pSamplesOut < pSamplesOutEnd) { + /* + Rice extraction. It's faster to do this one at a time against local variables than it is to use the x4 version + against an array. Not sure why, but perhaps it's making more efficient use of registers? + */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; + } + + riceParamPart0 &= riceParamMask; + riceParamPart1 &= riceParamMask; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; + riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; + + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + + pSamplesOut += 4; + } + } else { + while (pSamplesOut < pSamplesOutEnd) { + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart1, &riceParamPart1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart2, &riceParamPart2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart3, &riceParamPart3)) { + return DRFLAC_FALSE; + } + + riceParamPart0 &= riceParamMask; + riceParamPart1 &= riceParamMask; + riceParamPart2 &= riceParamMask; + riceParamPart3 &= riceParamMask; + + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart1 |= (zeroCountPart1 << riceParam); + riceParamPart2 |= (zeroCountPart2 << riceParam); + riceParamPart3 |= (zeroCountPart3 << riceParam); + + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + riceParamPart1 = (riceParamPart1 >> 1) ^ t[riceParamPart1 & 0x01]; + riceParamPart2 = (riceParamPart2 >> 1) ^ t[riceParamPart2 & 0x01]; + riceParamPart3 = (riceParamPart3 >> 1) ^ t[riceParamPart3 & 0x01]; + + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + pSamplesOut[1] = riceParamPart1 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 1); + pSamplesOut[2] = riceParamPart2 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 2); + pSamplesOut[3] = riceParamPart3 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 3); + + pSamplesOut += 4; + } + } + + i = (count & ~3); + while (i < count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountPart0, &riceParamPart0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamPart0 &= riceParamMask; + riceParamPart0 |= (zeroCountPart0 << riceParam); + riceParamPart0 = (riceParamPart0 >> 1) ^ t[riceParamPart0 & 0x01]; + /*riceParamPart0 = (riceParamPart0 >> 1) ^ (~(riceParamPart0 & 0x01) + 1);*/ + + /* Sample reconstruction. */ + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + } else { + pSamplesOut[0] = riceParamPart0 + drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + 0); + } + + i += 1; + pSamplesOut += 1; + } + + return DRFLAC_TRUE; +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE __m128i drflac__mm_packs_interleaved_epi32(__m128i a, __m128i b) +{ + __m128i r; + + /* Pack. */ + r = _mm_packs_epi32(a, b); + + /* a3a2 a1a0 b3b2 b1b0 -> a3a2 b3b2 a1a0 b1b0 */ + r = _mm_shuffle_epi32(r, _MM_SHUFFLE(3, 1, 2, 0)); + + /* a3a2 b3b2 a1a0 b1b0 -> a3b3 a2b2 a1b1 a0b0 */ + r = _mm_shufflehi_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + r = _mm_shufflelo_epi16(r, _MM_SHUFFLE(3, 1, 2, 0)); + + return r; +} +#endif + +#if defined(DRFLAC_SUPPORT_SSE41) +static DRFLAC_INLINE __m128i drflac__mm_not_si128(__m128i a) +{ + return _mm_xor_si128(a, _mm_cmpeq_epi32(_mm_setzero_si128(), _mm_setzero_si128())); +} + +static DRFLAC_INLINE __m128i drflac__mm_hadd_epi32(__m128i x) +{ + __m128i x64 = _mm_add_epi32(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))); + __m128i x32 = _mm_shufflelo_epi16(x64, _MM_SHUFFLE(1, 0, 3, 2)); + return _mm_add_epi32(x64, x32); +} + +static DRFLAC_INLINE __m128i drflac__mm_hadd_epi64(__m128i x) +{ + return _mm_add_epi64(x, _mm_shuffle_epi32(x, _MM_SHUFFLE(1, 0, 3, 2))); +} + +static DRFLAC_INLINE __m128i drflac__mm_srai_epi64(__m128i x, int count) +{ + /* + To simplify this we are assuming count < 32. This restriction allows us to work on a low side and a high side. The low side + is shifted with zero bits, whereas the right side is shifted with sign bits. + */ + __m128i lo = _mm_srli_epi64(x, count); + __m128i hi = _mm_srai_epi32(x, count); + + hi = _mm_and_si128(hi, _mm_set_epi32(0xFFFFFFFF, 0, 0xFFFFFFFF, 0)); /* The high part needs to have the low part cleared. */ + + return _mm_or_si128(lo, hi); +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts0 = 0; + drflac_uint32 zeroCountParts1 = 0; + drflac_uint32 zeroCountParts2 = 0; + drflac_uint32 zeroCountParts3 = 0; + drflac_uint32 riceParamParts0 = 0; + drflac_uint32 riceParamParts1 = 0; + drflac_uint32 riceParamParts2 = 0; + drflac_uint32 riceParamParts3 = 0; + __m128i coefficients128_0; + __m128i coefficients128_4; + __m128i coefficients128_8; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i riceParamMask128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + + /* Pre-load. */ + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); + + /* + Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than + what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results + in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted + so I think there's opportunity for this to be simplified. + */ +#if 1 + { + int runningOrder = order; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#else + /* This causes strict-aliasing warnings with GCC. */ + switch (order) + { + case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12]; + case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11]; + case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10]; + case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; + case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; + case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; + case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; + case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; + case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; + case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; + case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; + case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; + } +#endif + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + __m128i prediction128; + __m128i zeroCountPart128; + __m128i riceParamPart128; + + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); + riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); + + riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); + riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01))), _mm_set1_epi32(0x01))); /* <-- SSE2 compatible */ + /*riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_mullo_epi32(_mm_and_si128(riceParamPart128, _mm_set1_epi32(0x01)), _mm_set1_epi32(0xFFFFFFFF)));*/ /* <-- Only supported from SSE4.1 and is slower in my testing... */ + + if (order <= 4) { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi32(prediction128); + prediction128 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else if (order <= 8) { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_4, samples128_4); + prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0)); + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi32(prediction128); + prediction128 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } else { + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_mullo_epi32(coefficients128_8, samples128_8); + prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_4, samples128_4)); + prediction128 = _mm_add_epi32(prediction128, _mm_mullo_epi32(coefficients128_0, samples128_0)); + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi32(prediction128); + prediction128 = _mm_srai_epi32(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + } + + /* We store samples in groups of 4. */ + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts0 &= riceParamMask; + riceParamParts0 |= (zeroCountParts0 << riceParam); + riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts0 = 0; + drflac_uint32 zeroCountParts1 = 0; + drflac_uint32 zeroCountParts2 = 0; + drflac_uint32 zeroCountParts3 = 0; + drflac_uint32 riceParamParts0 = 0; + drflac_uint32 riceParamParts1 = 0; + drflac_uint32 riceParamParts2 = 0; + drflac_uint32 riceParamParts3 = 0; + __m128i coefficients128_0; + __m128i coefficients128_4; + __m128i coefficients128_8; + __m128i samples128_0; + __m128i samples128_4; + __m128i samples128_8; + __m128i prediction128; + __m128i riceParamMask128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + DRFLAC_ASSERT(order <= 12); + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = _mm_set1_epi32(riceParamMask); + + prediction128 = _mm_setzero_si128(); + + /* Pre-load. */ + coefficients128_0 = _mm_setzero_si128(); + coefficients128_4 = _mm_setzero_si128(); + coefficients128_8 = _mm_setzero_si128(); + + samples128_0 = _mm_setzero_si128(); + samples128_4 = _mm_setzero_si128(); + samples128_8 = _mm_setzero_si128(); + +#if 1 + { + int runningOrder = order; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = _mm_loadu_si128((const __m128i*)(coefficients + 0)); + samples128_0 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 4)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_0 = _mm_set_epi32(0, coefficients[2], coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], pSamplesOut[-3], 0); break; + case 2: coefficients128_0 = _mm_set_epi32(0, 0, coefficients[1], coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], pSamplesOut[-2], 0, 0); break; + case 1: coefficients128_0 = _mm_set_epi32(0, 0, 0, coefficients[0]); samples128_0 = _mm_set_epi32(pSamplesOut[-1], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = _mm_loadu_si128((const __m128i*)(coefficients + 4)); + samples128_4 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 8)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_4 = _mm_set_epi32(0, coefficients[6], coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], pSamplesOut[-7], 0); break; + case 2: coefficients128_4 = _mm_set_epi32(0, 0, coefficients[5], coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], pSamplesOut[-6], 0, 0); break; + case 1: coefficients128_4 = _mm_set_epi32(0, 0, 0, coefficients[4]); samples128_4 = _mm_set_epi32(pSamplesOut[-5], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = _mm_loadu_si128((const __m128i*)(coefficients + 8)); + samples128_8 = _mm_loadu_si128((const __m128i*)(pSamplesOut - 12)); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: coefficients128_8 = _mm_set_epi32(0, coefficients[10], coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], pSamplesOut[-11], 0); break; + case 2: coefficients128_8 = _mm_set_epi32(0, 0, coefficients[9], coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], pSamplesOut[-10], 0, 0); break; + case 1: coefficients128_8 = _mm_set_epi32(0, 0, 0, coefficients[8]); samples128_8 = _mm_set_epi32(pSamplesOut[-9], 0, 0, 0); break; + } + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = _mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_4 = _mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(0, 1, 2, 3)); + coefficients128_8 = _mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(0, 1, 2, 3)); + } +#else + switch (order) + { + case 12: ((drflac_int32*)&coefficients128_8)[0] = coefficients[11]; ((drflac_int32*)&samples128_8)[0] = pDecodedSamples[-12]; + case 11: ((drflac_int32*)&coefficients128_8)[1] = coefficients[10]; ((drflac_int32*)&samples128_8)[1] = pDecodedSamples[-11]; + case 10: ((drflac_int32*)&coefficients128_8)[2] = coefficients[ 9]; ((drflac_int32*)&samples128_8)[2] = pDecodedSamples[-10]; + case 9: ((drflac_int32*)&coefficients128_8)[3] = coefficients[ 8]; ((drflac_int32*)&samples128_8)[3] = pDecodedSamples[- 9]; + case 8: ((drflac_int32*)&coefficients128_4)[0] = coefficients[ 7]; ((drflac_int32*)&samples128_4)[0] = pDecodedSamples[- 8]; + case 7: ((drflac_int32*)&coefficients128_4)[1] = coefficients[ 6]; ((drflac_int32*)&samples128_4)[1] = pDecodedSamples[- 7]; + case 6: ((drflac_int32*)&coefficients128_4)[2] = coefficients[ 5]; ((drflac_int32*)&samples128_4)[2] = pDecodedSamples[- 6]; + case 5: ((drflac_int32*)&coefficients128_4)[3] = coefficients[ 4]; ((drflac_int32*)&samples128_4)[3] = pDecodedSamples[- 5]; + case 4: ((drflac_int32*)&coefficients128_0)[0] = coefficients[ 3]; ((drflac_int32*)&samples128_0)[0] = pDecodedSamples[- 4]; + case 3: ((drflac_int32*)&coefficients128_0)[1] = coefficients[ 2]; ((drflac_int32*)&samples128_0)[1] = pDecodedSamples[- 3]; + case 2: ((drflac_int32*)&coefficients128_0)[2] = coefficients[ 1]; ((drflac_int32*)&samples128_0)[2] = pDecodedSamples[- 2]; + case 1: ((drflac_int32*)&coefficients128_0)[3] = coefficients[ 0]; ((drflac_int32*)&samples128_0)[3] = pDecodedSamples[- 1]; + } +#endif + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + __m128i zeroCountPart128; + __m128i riceParamPart128; + + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts1, &riceParamParts1) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts2, &riceParamParts2) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts3, &riceParamParts3)) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = _mm_set_epi32(zeroCountParts3, zeroCountParts2, zeroCountParts1, zeroCountParts0); + riceParamPart128 = _mm_set_epi32(riceParamParts3, riceParamParts2, riceParamParts1, riceParamParts0); + + riceParamPart128 = _mm_and_si128(riceParamPart128, riceParamMask128); + riceParamPart128 = _mm_or_si128(riceParamPart128, _mm_slli_epi32(zeroCountPart128, riceParam)); + riceParamPart128 = _mm_xor_si128(_mm_srli_epi32(riceParamPart128, 1), _mm_add_epi32(drflac__mm_not_si128(_mm_and_si128(riceParamPart128, _mm_set1_epi32(1))), _mm_set1_epi32(1))); + + for (i = 0; i < 4; i += 1) { + prediction128 = _mm_xor_si128(prediction128, prediction128); /* Reset to 0. */ + + switch (order) + { + case 12: + case 11: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(1, 1, 0, 0)))); + case 10: + case 9: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_8, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_8, _MM_SHUFFLE(3, 3, 2, 2)))); + case 8: + case 7: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(1, 1, 0, 0)))); + case 6: + case 5: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_4, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_4, _MM_SHUFFLE(3, 3, 2, 2)))); + case 4: + case 3: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(1, 1, 0, 0)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(1, 1, 0, 0)))); + case 2: + case 1: prediction128 = _mm_add_epi64(prediction128, _mm_mul_epi32(_mm_shuffle_epi32(coefficients128_0, _MM_SHUFFLE(3, 3, 2, 2)), _mm_shuffle_epi32(samples128_0, _MM_SHUFFLE(3, 3, 2, 2)))); + } + + /* Horizontal add and shift. */ + prediction128 = drflac__mm_hadd_epi64(prediction128); + prediction128 = drflac__mm_srai_epi64(prediction128, shift); + prediction128 = _mm_add_epi32(riceParamPart128, prediction128); + + /* Our value should be sitting in prediction128[0]. We need to combine this with our SSE samples. */ + samples128_8 = _mm_alignr_epi8(samples128_4, samples128_8, 4); + samples128_4 = _mm_alignr_epi8(samples128_0, samples128_4, 4); + samples128_0 = _mm_alignr_epi8(prediction128, samples128_0, 4); + + /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */ + riceParamPart128 = _mm_alignr_epi8(_mm_setzero_si128(), riceParamPart128, 4); + } + + /* We store samples in groups of 4. */ + _mm_storeu_si128((__m128i*)pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts0, &riceParamParts0)) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts0 &= riceParamMask; + riceParamParts0 |= (zeroCountParts0 << riceParam); + riceParamParts0 = (riceParamParts0 >> 1) ^ t[riceParamParts0 & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts0 + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__sse41(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + /* In my testing the order is rarely > 12, so in this case I'm going to simplify the SSE implementation by only handling order <= 12. */ + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__sse41_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } else { + return drflac__decode_samples_with_residual__rice__sse41_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac__vst2q_s32(drflac_int32* p, int32x4x2_t x) +{ + vst1q_s32(p+0, x.val[0]); + vst1q_s32(p+4, x.val[1]); +} + +static DRFLAC_INLINE void drflac__vst2q_u32(drflac_uint32* p, uint32x4x2_t x) +{ + vst1q_u32(p+0, x.val[0]); + vst1q_u32(p+4, x.val[1]); +} + +static DRFLAC_INLINE void drflac__vst2q_f32(float* p, float32x4x2_t x) +{ + vst1q_f32(p+0, x.val[0]); + vst1q_f32(p+4, x.val[1]); +} + +static DRFLAC_INLINE void drflac__vst2q_s16(drflac_int16* p, int16x4x2_t x) +{ + vst1q_s16(p, vcombine_s16(x.val[0], x.val[1])); +} + +static DRFLAC_INLINE void drflac__vst2q_u16(drflac_uint16* p, uint16x4x2_t x) +{ + vst1q_u16(p, vcombine_u16(x.val[0], x.val[1])); +} + +static DRFLAC_INLINE int32x4_t drflac__vdupq_n_s32x4(drflac_int32 x3, drflac_int32 x2, drflac_int32 x1, drflac_int32 x0) +{ + drflac_int32 x[4]; + x[3] = x3; + x[2] = x2; + x[1] = x1; + x[0] = x0; + return vld1q_s32(x); +} + +static DRFLAC_INLINE int32x4_t drflac__valignrq_s32_1(int32x4_t a, int32x4_t b) +{ + /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */ + + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(a, 0), + vgetq_lane_s32(b, 3), + vgetq_lane_s32(b, 2), + vgetq_lane_s32(b, 1) + );*/ + + return vextq_s32(b, a, 1); +} + +static DRFLAC_INLINE uint32x4_t drflac__valignrq_u32_1(uint32x4_t a, uint32x4_t b) +{ + /* Equivalent to SSE's _mm_alignr_epi8(a, b, 4) */ + + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(a, 0), + vgetq_lane_s32(b, 3), + vgetq_lane_s32(b, 2), + vgetq_lane_s32(b, 1) + );*/ + + return vextq_u32(b, a, 1); +} + +static DRFLAC_INLINE int32x2_t drflac__vhaddq_s32(int32x4_t x) +{ + /* The sum must end up in position 0. */ + + /* Reference */ + /*return vdupq_n_s32( + vgetq_lane_s32(x, 3) + + vgetq_lane_s32(x, 2) + + vgetq_lane_s32(x, 1) + + vgetq_lane_s32(x, 0) + );*/ + + int32x2_t r = vadd_s32(vget_high_s32(x), vget_low_s32(x)); + return vpadd_s32(r, r); +} + +static DRFLAC_INLINE int64x1_t drflac__vhaddq_s64(int64x2_t x) +{ + return vadd_s64(vget_high_s64(x), vget_low_s64(x)); +} + +static DRFLAC_INLINE int32x4_t drflac__vrevq_s32(int32x4_t x) +{ + /* Reference */ + /*return drflac__vdupq_n_s32x4( + vgetq_lane_s32(x, 0), + vgetq_lane_s32(x, 1), + vgetq_lane_s32(x, 2), + vgetq_lane_s32(x, 3) + );*/ + + return vrev64q_s32(vcombine_s32(vget_high_s32(x), vget_low_s32(x))); +} + +static DRFLAC_INLINE int32x4_t drflac__vnotq_s32(int32x4_t x) +{ + return veorq_s32(x, vdupq_n_s32(0xFFFFFFFF)); +} + +static DRFLAC_INLINE uint32x4_t drflac__vnotq_u32(uint32x4_t x) +{ + return veorq_u32(x, vdupq_n_u32(0xFFFFFFFF)); +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_32(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts[4]; + drflac_uint32 riceParamParts[4]; + int32x4_t coefficients128_0; + int32x4_t coefficients128_4; + int32x4_t coefficients128_8; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + int32x4_t riceParam128; + int32x2_t shift64; + uint32x4_t one128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = vdupq_n_u32(riceParamMask); + + riceParam128 = vdupq_n_s32(riceParam); + shift64 = vdup_n_s32(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */ + one128 = vdupq_n_u32(1); + + /* + Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than + what's available in the input buffers. It would be conenient to use a fall-through switch to do this, but this results + in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted + so I think there's opportunity for this to be simplified. + */ + { + int runningOrder = order; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */ + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */ + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */ + } + + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */ + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */ + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */ + } + + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */ + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */ + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */ + } + + coefficients128_8 = vld1q_s32(tempC); + samples128_8 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); + } + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + int32x4_t prediction128; + int32x2_t prediction64; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; + + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = vld1q_u32(zeroCountParts); + riceParamPart128 = vld1q_u32(riceParamParts); + + riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128); + riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128)); + riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + + if (order <= 4) { + for (i = 0; i < 4; i += 1) { + prediction128 = vmulq_s32(coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); + + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + } else if (order <= 8) { + for (i = 0; i < 4; i += 1) { + prediction128 = vmulq_s32(coefficients128_4, samples128_4); + prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); + + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + } else { + for (i = 0; i < 4; i += 1) { + prediction128 = vmulq_s32(coefficients128_8, samples128_8); + prediction128 = vmlaq_s32(prediction128, coefficients128_4, samples128_4); + prediction128 = vmlaq_s32(prediction128, coefficients128_0, samples128_0); + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s32(prediction128); + prediction64 = vshl_s32(prediction64, shift64); + prediction64 = vadd_s32(prediction64, vget_low_s32(vreinterpretq_s32_u32(riceParamPart128))); + + samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(prediction64, vdup_n_s32(0)), samples128_0); + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + } + + /* We store samples in groups of 4. */ + vst1q_s32(pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts[0] &= riceParamMask; + riceParamParts[0] |= (zeroCountParts[0] << riceParam); + riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_32(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon_64(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 order, drflac_int32 shift, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + int i; + drflac_uint32 riceParamMask; + drflac_int32* pDecodedSamples = pSamplesOut; + drflac_int32* pDecodedSamplesEnd = pSamplesOut + (count & ~3); + drflac_uint32 zeroCountParts[4]; + drflac_uint32 riceParamParts[4]; + int32x4_t coefficients128_0; + int32x4_t coefficients128_4; + int32x4_t coefficients128_8; + int32x4_t samples128_0; + int32x4_t samples128_4; + int32x4_t samples128_8; + uint32x4_t riceParamMask128; + int32x4_t riceParam128; + int64x1_t shift64; + uint32x4_t one128; + int64x2_t prediction128 = { 0 }; + uint32x4_t zeroCountPart128; + uint32x4_t riceParamPart128; + + const drflac_uint32 t[2] = {0x00000000, 0xFFFFFFFF}; + + riceParamMask = (drflac_uint32)~((~0UL) << riceParam); + riceParamMask128 = vdupq_n_u32(riceParamMask); + + riceParam128 = vdupq_n_s32(riceParam); + shift64 = vdup_n_s64(-shift); /* Negate the shift because we'll be doing a variable shift using vshlq_s32(). */ + one128 = vdupq_n_u32(1); + + /* + Pre-loading the coefficients and prior samples is annoying because we need to ensure we don't try reading more than + what's available in the input buffers. It would be convenient to use a fall-through switch to do this, but this results + in strict aliasing warnings with GCC. To work around this I'm just doing something hacky. This feels a bit convoluted + so I think there's opportunity for this to be simplified. + */ + { + int runningOrder = order; + drflac_int32 tempC[4] = {0, 0, 0, 0}; + drflac_int32 tempS[4] = {0, 0, 0, 0}; + + /* 0 - 3. */ + if (runningOrder >= 4) { + coefficients128_0 = vld1q_s32(coefficients + 0); + samples128_0 = vld1q_s32(pSamplesOut - 4); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[2]; tempS[1] = pSamplesOut[-3]; /* fallthrough */ + case 2: tempC[1] = coefficients[1]; tempS[2] = pSamplesOut[-2]; /* fallthrough */ + case 1: tempC[0] = coefficients[0]; tempS[3] = pSamplesOut[-1]; /* fallthrough */ + } + + coefficients128_0 = vld1q_s32(tempC); + samples128_0 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 4 - 7 */ + if (runningOrder >= 4) { + coefficients128_4 = vld1q_s32(coefficients + 4); + samples128_4 = vld1q_s32(pSamplesOut - 8); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[6]; tempS[1] = pSamplesOut[-7]; /* fallthrough */ + case 2: tempC[1] = coefficients[5]; tempS[2] = pSamplesOut[-6]; /* fallthrough */ + case 1: tempC[0] = coefficients[4]; tempS[3] = pSamplesOut[-5]; /* fallthrough */ + } + + coefficients128_4 = vld1q_s32(tempC); + samples128_4 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* 8 - 11 */ + if (runningOrder == 4) { + coefficients128_8 = vld1q_s32(coefficients + 8); + samples128_8 = vld1q_s32(pSamplesOut - 12); + runningOrder -= 4; + } else { + switch (runningOrder) { + case 3: tempC[2] = coefficients[10]; tempS[1] = pSamplesOut[-11]; /* fallthrough */ + case 2: tempC[1] = coefficients[ 9]; tempS[2] = pSamplesOut[-10]; /* fallthrough */ + case 1: tempC[0] = coefficients[ 8]; tempS[3] = pSamplesOut[- 9]; /* fallthrough */ + } + + coefficients128_8 = vld1q_s32(tempC); + samples128_8 = vld1q_s32(tempS); + runningOrder = 0; + } + + /* Coefficients need to be shuffled for our streaming algorithm below to work. Samples are already in the correct order from the loading routine above. */ + coefficients128_0 = drflac__vrevq_s32(coefficients128_0); + coefficients128_4 = drflac__vrevq_s32(coefficients128_4); + coefficients128_8 = drflac__vrevq_s32(coefficients128_8); + } + + /* For this version we are doing one sample at a time. */ + while (pDecodedSamples < pDecodedSamplesEnd) { + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[1], &riceParamParts[1]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[2], &riceParamParts[2]) || + !drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[3], &riceParamParts[3])) { + return DRFLAC_FALSE; + } + + zeroCountPart128 = vld1q_u32(zeroCountParts); + riceParamPart128 = vld1q_u32(riceParamParts); + + riceParamPart128 = vandq_u32(riceParamPart128, riceParamMask128); + riceParamPart128 = vorrq_u32(riceParamPart128, vshlq_u32(zeroCountPart128, riceParam128)); + riceParamPart128 = veorq_u32(vshrq_n_u32(riceParamPart128, 1), vaddq_u32(drflac__vnotq_u32(vandq_u32(riceParamPart128, one128)), one128)); + + for (i = 0; i < 4; i += 1) { + int64x1_t prediction64; + + prediction128 = veorq_s64(prediction128, prediction128); /* Reset to 0. */ + switch (order) + { + case 12: + case 11: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_8), vget_low_s32(samples128_8))); + case 10: + case 9: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_8), vget_high_s32(samples128_8))); + case 8: + case 7: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_4), vget_low_s32(samples128_4))); + case 6: + case 5: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_4), vget_high_s32(samples128_4))); + case 4: + case 3: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_low_s32(coefficients128_0), vget_low_s32(samples128_0))); + case 2: + case 1: prediction128 = vaddq_s64(prediction128, vmull_s32(vget_high_s32(coefficients128_0), vget_high_s32(samples128_0))); + } + + /* Horizontal add and shift. */ + prediction64 = drflac__vhaddq_s64(prediction128); + prediction64 = vshl_s64(prediction64, shift64); + prediction64 = vadd_s64(prediction64, vdup_n_s64(vgetq_lane_u32(riceParamPart128, 0))); + + /* Our value should be sitting in prediction64[0]. We need to combine this with our SSE samples. */ + samples128_8 = drflac__valignrq_s32_1(samples128_4, samples128_8); + samples128_4 = drflac__valignrq_s32_1(samples128_0, samples128_4); + samples128_0 = drflac__valignrq_s32_1(vcombine_s32(vreinterpret_s32_s64(prediction64), vdup_n_s32(0)), samples128_0); + + /* Slide our rice parameter down so that the value in position 0 contains the next one to process. */ + riceParamPart128 = drflac__valignrq_u32_1(vdupq_n_u32(0), riceParamPart128); + } + + /* We store samples in groups of 4. */ + vst1q_s32(pDecodedSamples, samples128_0); + pDecodedSamples += 4; + } + + /* Make sure we process the last few samples. */ + i = (count & ~3); + while (i < (int)count) { + /* Rice extraction. */ + if (!drflac__read_rice_parts_x1(bs, riceParam, &zeroCountParts[0], &riceParamParts[0])) { + return DRFLAC_FALSE; + } + + /* Rice reconstruction. */ + riceParamParts[0] &= riceParamMask; + riceParamParts[0] |= (zeroCountParts[0] << riceParam); + riceParamParts[0] = (riceParamParts[0] >> 1) ^ t[riceParamParts[0] & 0x01]; + + /* Sample reconstruction. */ + pDecodedSamples[0] = riceParamParts[0] + drflac__calculate_prediction_64(order, shift, coefficients, pDecodedSamples); + + i += 1; + pDecodedSamples += 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples_with_residual__rice__neon(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(pSamplesOut != NULL); + + /* In my testing the order is rarely > 12, so in this case I'm going to simplify the NEON implementation by only handling order <= 12. */ + if (lpcOrder > 0 && lpcOrder <= 12) { + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + return drflac__decode_samples_with_residual__rice__neon_64(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } else { + return drflac__decode_samples_with_residual__rice__neon_32(bs, count, riceParam, lpcOrder, lpcShift, coefficients, pSamplesOut); + } + } else { + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } +} +#endif + +static drflac_bool32 drflac__decode_samples_with_residual__rice(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 riceParam, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ +#if defined(DRFLAC_SUPPORT_SSE41) + if (drflac__gIsSSE41Supported) { + return drflac__decode_samples_with_residual__rice__sse41(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported) { + return drflac__decode_samples_with_residual__rice__neon(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + } else +#endif + { + /* Scalar fallback. */ + #if 0 + return drflac__decode_samples_with_residual__rice__reference(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #else + return drflac__decode_samples_with_residual__rice__scalar(bs, bitsPerSample, count, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pSamplesOut); + #endif + } +} + +/* Reads and seeks past a string of residual values as Rice codes. The decoder should be sitting on the first bit of the Rice codes. */ +static drflac_bool32 drflac__read_and_seek_residual__rice(drflac_bs* bs, drflac_uint32 count, drflac_uint8 riceParam) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + + for (i = 0; i < count; ++i) { + if (!drflac__seek_rice_parts(bs, riceParam)) { + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; +} + +#if defined(__clang__) +__attribute__((no_sanitize("signed-integer-overflow"))) +#endif +static drflac_bool32 drflac__decode_samples_with_residual__unencoded(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 count, drflac_uint8 unencodedBitsPerSample, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pSamplesOut) +{ + drflac_uint32 i; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(unencodedBitsPerSample <= 31); /* <-- unencodedBitsPerSample is a 5 bit number, so cannot exceed 31. */ + DRFLAC_ASSERT(pSamplesOut != NULL); + + for (i = 0; i < count; ++i) { + if (unencodedBitsPerSample > 0) { + if (!drflac__read_int32(bs, unencodedBitsPerSample, pSamplesOut + i)) { + return DRFLAC_FALSE; + } + } else { + pSamplesOut[i] = 0; + } + + if (drflac__use_64_bit_prediction(bitsPerSample, lpcOrder, lpcPrecision)) { + pSamplesOut[i] += drflac__calculate_prediction_64(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } else { + pSamplesOut[i] += drflac__calculate_prediction_32(lpcOrder, lpcShift, coefficients, pSamplesOut + i); + } + } + + return DRFLAC_TRUE; +} + + +/* +Reads and decodes the residual for the sub-frame the decoder is currently sitting on. This function should be called +when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be ignored. The + and parameters are used to determine how many residual values need to be decoded. +*/ +static drflac_bool32 drflac__decode_samples_with_residual(drflac_bs* bs, drflac_uint32 bitsPerSample, drflac_uint32 blockSize, drflac_uint32 lpcOrder, drflac_int32 lpcShift, drflac_uint32 lpcPrecision, const drflac_int32* coefficients, drflac_int32* pDecodedSamples) +{ + drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + DRFLAC_ASSERT(pDecodedSamples != NULL); /* <-- Should we allow NULL, in which case we just seek past the residual rather than do a full decode? */ + + if (!drflac__read_uint8(bs, 2, &residualMethod)) { + return DRFLAC_FALSE; + } + + if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ + } + + /* Ignore the first values. */ + pDecodedSamples += lpcOrder; + + if (!drflac__read_uint8(bs, 4, &partitionOrder)) { + return DRFLAC_FALSE; + } + + /* + From the FLAC spec: + The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + */ + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + /* Validation check. */ + if ((blockSize / (1 << partitionOrder)) < lpcOrder) { + return DRFLAC_FALSE; + } + + samplesInPartition = (blockSize / (1 << partitionOrder)) - lpcOrder; + partitionsRemaining = (1 << partitionOrder); + for (;;) { + drflac_uint8 riceParam = 0; + if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { + if (!drflac__read_uint8(bs, 4, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 15) { + riceParam = 0xFF; + } + } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + if (!drflac__read_uint8(bs, 5, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 31) { + riceParam = 0xFF; + } + } + + if (riceParam != 0xFF) { + if (!drflac__decode_samples_with_residual__rice(bs, bitsPerSample, samplesInPartition, riceParam, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; + } + } else { + drflac_uint8 unencodedBitsPerSample = 0; + if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return DRFLAC_FALSE; + } + + if (!drflac__decode_samples_with_residual__unencoded(bs, bitsPerSample, samplesInPartition, unencodedBitsPerSample, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; + } + } + + pDecodedSamples += samplesInPartition; + + if (partitionsRemaining == 1) { + break; + } + + partitionsRemaining -= 1; + + if (partitionOrder != 0) { + samplesInPartition = blockSize / (1 << partitionOrder); + } + } + + return DRFLAC_TRUE; +} + +/* +Reads and seeks past the residual for the sub-frame the decoder is currently sitting on. This function should be called +when the decoder is sitting at the very start of the RESIDUAL block. The first residuals will be set to 0. The + and parameters are used to determine how many residual values need to be decoded. +*/ +static drflac_bool32 drflac__read_and_seek_residual(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 order) +{ + drflac_uint8 residualMethod; + drflac_uint8 partitionOrder; + drflac_uint32 samplesInPartition; + drflac_uint32 partitionsRemaining; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(blockSize != 0); + + if (!drflac__read_uint8(bs, 2, &residualMethod)) { + return DRFLAC_FALSE; + } + + if (residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE && residualMethod != DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + return DRFLAC_FALSE; /* Unknown or unsupported residual coding method. */ + } + + if (!drflac__read_uint8(bs, 4, &partitionOrder)) { + return DRFLAC_FALSE; + } + + /* + From the FLAC spec: + The Rice partition order in a Rice-coded residual section must be less than or equal to 8. + */ + if (partitionOrder > 8) { + return DRFLAC_FALSE; + } + + /* Validation check. */ + if ((blockSize / (1 << partitionOrder)) <= order) { + return DRFLAC_FALSE; + } + + samplesInPartition = (blockSize / (1 << partitionOrder)) - order; + partitionsRemaining = (1 << partitionOrder); + for (;;) + { + drflac_uint8 riceParam = 0; + if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE) { + if (!drflac__read_uint8(bs, 4, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 15) { + riceParam = 0xFF; + } + } else if (residualMethod == DRFLAC_RESIDUAL_CODING_METHOD_PARTITIONED_RICE2) { + if (!drflac__read_uint8(bs, 5, &riceParam)) { + return DRFLAC_FALSE; + } + if (riceParam == 31) { + riceParam = 0xFF; + } + } + + if (riceParam != 0xFF) { + if (!drflac__read_and_seek_residual__rice(bs, samplesInPartition, riceParam)) { + return DRFLAC_FALSE; + } + } else { + drflac_uint8 unencodedBitsPerSample = 0; + if (!drflac__read_uint8(bs, 5, &unencodedBitsPerSample)) { + return DRFLAC_FALSE; + } + + if (!drflac__seek_bits(bs, unencodedBitsPerSample * samplesInPartition)) { + return DRFLAC_FALSE; + } + } + + + if (partitionsRemaining == 1) { + break; + } + + partitionsRemaining -= 1; + samplesInPartition = blockSize / (1 << partitionOrder); + } + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__decode_samples__constant(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) +{ + drflac_uint32 i; + + /* Only a single sample needs to be decoded here. */ + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + /* + We don't really need to expand this, but it does simplify the process of reading samples. If this becomes a performance issue (unlikely) + we'll want to look at a more efficient way. + */ + for (i = 0; i < blockSize; ++i) { + pDecodedSamples[i] = sample; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples__verbatim(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_int32* pDecodedSamples) +{ + drflac_uint32 i; + + for (i = 0; i < blockSize; ++i) { + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + pDecodedSamples[i] = sample; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples__fixed(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 subframeBitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) +{ + drflac_uint32 i; + + static drflac_int32 lpcCoefficientsTable[5][4] = { + {0, 0, 0, 0}, + {1, 0, 0, 0}, + {2, -1, 0, 0}, + {3, -3, 1, 0}, + {4, -6, 4, -1} + }; + + /* Warm up samples and coefficients. */ + for (i = 0; i < lpcOrder; ++i) { + drflac_int32 sample; + if (!drflac__read_int32(bs, subframeBitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + pDecodedSamples[i] = sample; + } + + if (!drflac__decode_samples_with_residual(bs, subframeBitsPerSample, blockSize, lpcOrder, 0, 4, lpcCoefficientsTable[lpcOrder], pDecodedSamples)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_samples__lpc(drflac_bs* bs, drflac_uint32 blockSize, drflac_uint32 bitsPerSample, drflac_uint8 lpcOrder, drflac_int32* pDecodedSamples) +{ + drflac_uint8 i; + drflac_uint8 lpcPrecision; + drflac_int8 lpcShift; + drflac_int32 coefficients[32]; + + /* Warm up samples. */ + for (i = 0; i < lpcOrder; ++i) { + drflac_int32 sample; + if (!drflac__read_int32(bs, bitsPerSample, &sample)) { + return DRFLAC_FALSE; + } + + pDecodedSamples[i] = sample; + } + + if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { + return DRFLAC_FALSE; + } + if (lpcPrecision == 15) { + return DRFLAC_FALSE; /* Invalid. */ + } + lpcPrecision += 1; + + if (!drflac__read_int8(bs, 5, &lpcShift)) { + return DRFLAC_FALSE; + } + + /* + From the FLAC specification: + + Quantized linear predictor coefficient shift needed in bits (NOTE: this number is signed two's-complement) + + Emphasis on the "signed two's-complement". In practice there does not seem to be any encoders nor decoders supporting negative shifts. For now dr_flac is + not going to support negative shifts as I don't have any reference files. However, when a reference file comes through I will consider adding support. + */ + if (lpcShift < 0) { + return DRFLAC_FALSE; + } + + DRFLAC_ZERO_MEMORY(coefficients, sizeof(coefficients)); + for (i = 0; i < lpcOrder; ++i) { + if (!drflac__read_int32(bs, lpcPrecision, coefficients + i)) { + return DRFLAC_FALSE; + } + } + + if (!drflac__decode_samples_with_residual(bs, bitsPerSample, blockSize, lpcOrder, lpcShift, lpcPrecision, coefficients, pDecodedSamples)) { + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + + +static drflac_bool32 drflac__read_next_flac_frame_header(drflac_bs* bs, drflac_uint8 streaminfoBitsPerSample, drflac_frame_header* header) +{ + const drflac_uint32 sampleRateTable[12] = {0, 88200, 176400, 192000, 8000, 16000, 22050, 24000, 32000, 44100, 48000, 96000}; + const drflac_uint8 bitsPerSampleTable[8] = {0, 8, 12, (drflac_uint8)-1, 16, 20, 24, (drflac_uint8)-1}; /* -1 = reserved. */ + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(header != NULL); + + /* Keep looping until we find a valid sync code. */ + for (;;) { + drflac_uint8 crc8 = 0xCE; /* 0xCE = drflac_crc8(0, 0x3FFE, 14); */ + drflac_uint8 reserved = 0; + drflac_uint8 blockingStrategy = 0; + drflac_uint8 blockSize = 0; + drflac_uint8 sampleRate = 0; + drflac_uint8 channelAssignment = 0; + drflac_uint8 bitsPerSample = 0; + drflac_bool32 isVariableBlockSize; + + if (!drflac__find_and_seek_to_next_sync_code(bs)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; + } + if (reserved == 1) { + continue; + } + crc8 = drflac_crc8(crc8, reserved, 1); + + if (!drflac__read_uint8(bs, 1, &blockingStrategy)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, blockingStrategy, 1); + + if (!drflac__read_uint8(bs, 4, &blockSize)) { + return DRFLAC_FALSE; + } + if (blockSize == 0) { + continue; + } + crc8 = drflac_crc8(crc8, blockSize, 4); + + if (!drflac__read_uint8(bs, 4, &sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, sampleRate, 4); + + if (!drflac__read_uint8(bs, 4, &channelAssignment)) { + return DRFLAC_FALSE; + } + if (channelAssignment > 10) { + continue; + } + crc8 = drflac_crc8(crc8, channelAssignment, 4); + + if (!drflac__read_uint8(bs, 3, &bitsPerSample)) { + return DRFLAC_FALSE; + } + if (bitsPerSample == 3 || bitsPerSample == 7) { + continue; + } + crc8 = drflac_crc8(crc8, bitsPerSample, 3); + + + if (!drflac__read_uint8(bs, 1, &reserved)) { + return DRFLAC_FALSE; + } + if (reserved == 1) { + continue; + } + crc8 = drflac_crc8(crc8, reserved, 1); + + + isVariableBlockSize = blockingStrategy == 1; + if (isVariableBlockSize) { + drflac_uint64 pcmFrameNumber; + drflac_result result = drflac__read_utf8_coded_number(bs, &pcmFrameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_AT_END) { + return DRFLAC_FALSE; + } else { + continue; + } + } + header->flacFrameNumber = 0; + header->pcmFrameNumber = pcmFrameNumber; + } else { + drflac_uint64 flacFrameNumber = 0; + drflac_result result = drflac__read_utf8_coded_number(bs, &flacFrameNumber, &crc8); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_AT_END) { + return DRFLAC_FALSE; + } else { + continue; + } + } + header->flacFrameNumber = (drflac_uint32)flacFrameNumber; /* <-- Safe cast. */ + header->pcmFrameNumber = 0; + } + + + DRFLAC_ASSERT(blockSize > 0); + if (blockSize == 1) { + header->blockSizeInPCMFrames = 192; + } else if (blockSize <= 5) { + DRFLAC_ASSERT(blockSize >= 2); + header->blockSizeInPCMFrames = 576 * (1 << (blockSize - 2)); + } else if (blockSize == 6) { + if (!drflac__read_uint16(bs, 8, &header->blockSizeInPCMFrames)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 8); + header->blockSizeInPCMFrames += 1; + } else if (blockSize == 7) { + if (!drflac__read_uint16(bs, 16, &header->blockSizeInPCMFrames)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->blockSizeInPCMFrames, 16); + if (header->blockSizeInPCMFrames == 0xFFFF) { + return DRFLAC_FALSE; /* Frame is too big. This is the size of the frame minus 1. The STREAMINFO block defines the max block size which is 16-bits. Adding one will make it 17 bits and therefore too big. */ + } + header->blockSizeInPCMFrames += 1; + } else { + DRFLAC_ASSERT(blockSize >= 8); + header->blockSizeInPCMFrames = 256 * (1 << (blockSize - 8)); + } + + + if (sampleRate <= 11) { + header->sampleRate = sampleRateTable[sampleRate]; + } else if (sampleRate == 12) { + if (!drflac__read_uint32(bs, 8, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 8); + header->sampleRate *= 1000; + } else if (sampleRate == 13) { + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 16); + } else if (sampleRate == 14) { + if (!drflac__read_uint32(bs, 16, &header->sampleRate)) { + return DRFLAC_FALSE; + } + crc8 = drflac_crc8(crc8, header->sampleRate, 16); + header->sampleRate *= 10; + } else { + continue; /* Invalid. Assume an invalid block. */ + } + + + header->channelAssignment = channelAssignment; + + header->bitsPerSample = bitsPerSampleTable[bitsPerSample]; + if (header->bitsPerSample == 0) { + header->bitsPerSample = streaminfoBitsPerSample; + } + + if (header->bitsPerSample != streaminfoBitsPerSample) { + /* If this subframe has a different bitsPerSample then streaminfo or the first frame, reject it */ + return DRFLAC_FALSE; + } + + if (!drflac__read_uint8(bs, 8, &header->crc8)) { + return DRFLAC_FALSE; + } + +#ifndef DR_FLAC_NO_CRC + if (header->crc8 != crc8) { + continue; /* CRC mismatch. Loop back to the top and find the next sync code. */ + } +#endif + return DRFLAC_TRUE; + } +} + +static drflac_bool32 drflac__read_subframe_header(drflac_bs* bs, drflac_subframe* pSubframe) +{ + drflac_uint8 header; + int type; + + if (!drflac__read_uint8(bs, 8, &header)) { + return DRFLAC_FALSE; + } + + /* First bit should always be 0. */ + if ((header & 0x80) != 0) { + return DRFLAC_FALSE; + } + + /* + Default to 0 for the LPC order. It's important that we always set this to 0 for non LPC + and FIXED subframes because we'll be using it in a generic validation check later. + */ + pSubframe->lpcOrder = 0; + + type = (header & 0x7E) >> 1; + if (type == 0) { + pSubframe->subframeType = DRFLAC_SUBFRAME_CONSTANT; + } else if (type == 1) { + pSubframe->subframeType = DRFLAC_SUBFRAME_VERBATIM; + } else { + if ((type & 0x20) != 0) { + pSubframe->subframeType = DRFLAC_SUBFRAME_LPC; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x1F) + 1; + } else if ((type & 0x08) != 0) { + pSubframe->subframeType = DRFLAC_SUBFRAME_FIXED; + pSubframe->lpcOrder = (drflac_uint8)(type & 0x07); + if (pSubframe->lpcOrder > 4) { + pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; + pSubframe->lpcOrder = 0; + } + } else { + pSubframe->subframeType = DRFLAC_SUBFRAME_RESERVED; + } + } + + if (pSubframe->subframeType == DRFLAC_SUBFRAME_RESERVED) { + return DRFLAC_FALSE; + } + + /* Wasted bits per sample. */ + pSubframe->wastedBitsPerSample = 0; + if ((header & 0x01) == 1) { + unsigned int wastedBitsPerSample; + if (!drflac__seek_past_next_set_bit(bs, &wastedBitsPerSample)) { + return DRFLAC_FALSE; + } + pSubframe->wastedBitsPerSample = (drflac_uint8)wastedBitsPerSample + 1; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex, drflac_int32* pDecodedSamplesOut) +{ + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; + drflac_bool32 decodeResult; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); + + pSubframe = frame->subframes + subframeIndex; + if (!drflac__read_subframe_header(bs, pSubframe)) { + return DRFLAC_FALSE; + } + + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ + subframeBitsPerSample = frame->header.bitsPerSample; + if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { + subframeBitsPerSample += 1; + } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + subframeBitsPerSample += 1; + } + + if (subframeBitsPerSample > 32) { + /* libFLAC and ffmpeg reject 33-bit subframes as well */ + return DRFLAC_FALSE; + } + + /* Need to handle wasted bits per sample. */ + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return DRFLAC_FALSE; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + + pSubframe->pSamplesS32 = pDecodedSamplesOut; + + /* + pDecodedSamplesOut will be pointing to a buffer that was allocated with enough memory to store + maxBlockSizeInPCMFrames samples (as specified in the FLAC header). We need to guard against an + overflow here. At a higher level we are checking maxBlockSizeInPCMFrames from the header, but + here we need to do an additional check to ensure this frame's block size fully encompasses any + warmup samples which is determined by the LPC order. For non LPC and FIXED subframes, the LPC + order will be have been set to 0 in drflac__read_subframe_header(). + */ + if (frame->header.blockSizeInPCMFrames < pSubframe->lpcOrder) { + return DRFLAC_FALSE; + } + + switch (pSubframe->subframeType) + { + case DRFLAC_SUBFRAME_CONSTANT: + { + decodeResult = drflac__decode_samples__constant(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + } break; + + case DRFLAC_SUBFRAME_VERBATIM: + { + decodeResult = drflac__decode_samples__verbatim(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->pSamplesS32); + } break; + + case DRFLAC_SUBFRAME_FIXED: + { + decodeResult = drflac__decode_samples__fixed(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + } break; + + case DRFLAC_SUBFRAME_LPC: + { + decodeResult = drflac__decode_samples__lpc(bs, frame->header.blockSizeInPCMFrames, subframeBitsPerSample, pSubframe->lpcOrder, pSubframe->pSamplesS32); + } break; + + default: decodeResult = DRFLAC_FALSE; + } + + return decodeResult; +} + +static drflac_bool32 drflac__seek_subframe(drflac_bs* bs, drflac_frame* frame, int subframeIndex) +{ + drflac_subframe* pSubframe; + drflac_uint32 subframeBitsPerSample; + + DRFLAC_ASSERT(bs != NULL); + DRFLAC_ASSERT(frame != NULL); + + pSubframe = frame->subframes + subframeIndex; + if (!drflac__read_subframe_header(bs, pSubframe)) { + return DRFLAC_FALSE; + } + + /* Side channels require an extra bit per sample. Took a while to figure that one out... */ + subframeBitsPerSample = frame->header.bitsPerSample; + if ((frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE || frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE) && subframeIndex == 1) { + subframeBitsPerSample += 1; + } else if (frame->header.channelAssignment == DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE && subframeIndex == 0) { + subframeBitsPerSample += 1; + } + + /* Need to handle wasted bits per sample. */ + if (pSubframe->wastedBitsPerSample >= subframeBitsPerSample) { + return DRFLAC_FALSE; + } + subframeBitsPerSample -= pSubframe->wastedBitsPerSample; + + pSubframe->pSamplesS32 = NULL; + + switch (pSubframe->subframeType) + { + case DRFLAC_SUBFRAME_CONSTANT: + { + if (!drflac__seek_bits(bs, subframeBitsPerSample)) { + return DRFLAC_FALSE; + } + } break; + + case DRFLAC_SUBFRAME_VERBATIM: + { + unsigned int bitsToSeek = frame->header.blockSizeInPCMFrames * subframeBitsPerSample; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + } break; + + case DRFLAC_SUBFRAME_FIXED: + { + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return DRFLAC_FALSE; + } + } break; + + case DRFLAC_SUBFRAME_LPC: + { + drflac_uint8 lpcPrecision; + + unsigned int bitsToSeek = pSubframe->lpcOrder * subframeBitsPerSample; + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_uint8(bs, 4, &lpcPrecision)) { + return DRFLAC_FALSE; + } + if (lpcPrecision == 15) { + return DRFLAC_FALSE; /* Invalid. */ + } + lpcPrecision += 1; + + + bitsToSeek = (pSubframe->lpcOrder * lpcPrecision) + 5; /* +5 for shift. */ + if (!drflac__seek_bits(bs, bitsToSeek)) { + return DRFLAC_FALSE; + } + + if (!drflac__read_and_seek_residual(bs, frame->header.blockSizeInPCMFrames, pSubframe->lpcOrder)) { + return DRFLAC_FALSE; + } + } break; + + default: return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + + +static DRFLAC_INLINE drflac_uint8 drflac__get_channel_count_from_channel_assignment(drflac_int8 channelAssignment) +{ + drflac_uint8 lookup[] = {1, 2, 3, 4, 5, 6, 7, 8, 2, 2, 2}; + + DRFLAC_ASSERT(channelAssignment <= 10); + return lookup[channelAssignment]; +} + +static drflac_result drflac__decode_flac_frame(drflac* pFlac) +{ + int channelCount; + int i; + drflac_uint8 paddingSizeInBits; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; +#endif + + /* This function should be called while the stream is sitting on the first byte after the frame header. */ + DRFLAC_ZERO_MEMORY(pFlac->currentFLACFrame.subframes, sizeof(pFlac->currentFLACFrame.subframes)); + + /* The frame block size must never be larger than the maximum block size defined by the FLAC stream. */ + if (pFlac->currentFLACFrame.header.blockSizeInPCMFrames > pFlac->maxBlockSizeInPCMFrames) { + return DRFLAC_ERROR; + } + + /* The number of channels in the frame must match the channel count from the STREAMINFO block. */ + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + if (channelCount != (int)pFlac->channels) { + return DRFLAC_ERROR; + } + + for (i = 0; i < channelCount; ++i) { + if (!drflac__decode_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i, pFlac->pDecodedSamples + (pFlac->currentFLACFrame.header.blockSizeInPCMFrames * i))) { + return DRFLAC_ERROR; + } + } + + paddingSizeInBits = (drflac_uint8)(DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7); + if (paddingSizeInBits > 0) { + drflac_uint8 padding = 0; + if (!drflac__read_uint8(&pFlac->bs, paddingSizeInBits, &padding)) { + return DRFLAC_AT_END; + } + } + +#ifndef DR_FLAC_NO_CRC + actualCRC16 = drflac__flush_crc16(&pFlac->bs); +#endif + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_AT_END; + } + +#ifndef DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ + } +#endif + + pFlac->currentFLACFrame.pcmFramesRemaining = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + + return DRFLAC_SUCCESS; +} + +static drflac_result drflac__seek_flac_frame(drflac* pFlac) +{ + int channelCount; + int i; + drflac_uint16 desiredCRC16; +#ifndef DR_FLAC_NO_CRC + drflac_uint16 actualCRC16; +#endif + + channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + for (i = 0; i < channelCount; ++i) { + if (!drflac__seek_subframe(&pFlac->bs, &pFlac->currentFLACFrame, i)) { + return DRFLAC_ERROR; + } + } + + /* Padding. */ + if (!drflac__seek_bits(&pFlac->bs, DRFLAC_CACHE_L1_BITS_REMAINING(&pFlac->bs) & 7)) { + return DRFLAC_ERROR; + } + + /* CRC. */ +#ifndef DR_FLAC_NO_CRC + actualCRC16 = drflac__flush_crc16(&pFlac->bs); +#endif + if (!drflac__read_uint16(&pFlac->bs, 16, &desiredCRC16)) { + return DRFLAC_AT_END; + } + +#ifndef DR_FLAC_NO_CRC + if (actualCRC16 != desiredCRC16) { + return DRFLAC_CRC_MISMATCH; /* CRC mismatch. */ + } +#endif + + return DRFLAC_SUCCESS; +} + +static drflac_bool32 drflac__read_and_decode_next_flac_frame(drflac* pFlac) +{ + DRFLAC_ASSERT(pFlac != NULL); + + for (;;) { + drflac_result result; + + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + + result = drflac__decode_flac_frame(pFlac); + if (result != DRFLAC_SUCCESS) { + if (result == DRFLAC_CRC_MISMATCH) { + continue; /* CRC mismatch. Skip to the next frame. */ + } else { + return DRFLAC_FALSE; + } + } + + return DRFLAC_TRUE; + } +} + +static void drflac__get_pcm_frame_range_of_current_flac_frame(drflac* pFlac, drflac_uint64* pFirstPCMFrame, drflac_uint64* pLastPCMFrame) +{ + drflac_uint64 firstPCMFrame; + drflac_uint64 lastPCMFrame; + + DRFLAC_ASSERT(pFlac != NULL); + + firstPCMFrame = pFlac->currentFLACFrame.header.pcmFrameNumber; + if (firstPCMFrame == 0) { + firstPCMFrame = ((drflac_uint64)pFlac->currentFLACFrame.header.flacFrameNumber) * pFlac->maxBlockSizeInPCMFrames; + } + + lastPCMFrame = firstPCMFrame + pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + if (lastPCMFrame > 0) { + lastPCMFrame -= 1; /* Needs to be zero based. */ + } + + if (pFirstPCMFrame) { + *pFirstPCMFrame = firstPCMFrame; + } + if (pLastPCMFrame) { + *pLastPCMFrame = lastPCMFrame; + } +} + +static drflac_bool32 drflac__seek_to_first_frame(drflac* pFlac) +{ + drflac_bool32 result; + + DRFLAC_ASSERT(pFlac != NULL); + + result = drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes); + + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + pFlac->currentPCMFrame = 0; + + return result; +} + +static DRFLAC_INLINE drflac_result drflac__seek_to_next_flac_frame(drflac* pFlac) +{ + /* This function should only ever be called while the decoder is sitting on the first byte past the FRAME_HEADER section. */ + DRFLAC_ASSERT(pFlac != NULL); + return drflac__seek_flac_frame(pFlac); +} + + +static drflac_uint64 drflac__seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 pcmFramesToSeek) +{ + drflac_uint64 pcmFramesRead = 0; + while (pcmFramesToSeek > 0) { + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + if (pFlac->currentFLACFrame.pcmFramesRemaining > pcmFramesToSeek) { + pcmFramesRead += pcmFramesToSeek; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)pcmFramesToSeek; /* <-- Safe cast. Will always be < currentFrame.pcmFramesRemaining < 65536. */ + pcmFramesToSeek = 0; + } else { + pcmFramesRead += pFlac->currentFLACFrame.pcmFramesRemaining; + pcmFramesToSeek -= pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + } + } + } + + pFlac->currentPCMFrame += pcmFramesRead; + return pcmFramesRead; +} + + +static drflac_bool32 drflac__seek_to_pcm_frame__brute_force(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + + DRFLAC_ASSERT(pFlac != NULL); + + /* If we are seeking forward we start from the current position. Otherwise we need to start all the way from the start of the file. */ + if (pcmFrameIndex >= pFlac->currentPCMFrame) { + /* Seeking forward. Need to seek from the current position. */ + runningPCMFrameCount = pFlac->currentPCMFrame; + + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ + if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } else { + isMidFrame = DRFLAC_TRUE; + } + } else { + /* Seeking backwards. Need to seek from the start of the file. */ + runningPCMFrameCount = 0; + + /* Move back to the start. */ + if (!drflac__seek_to_first_frame(pFlac)) { + return DRFLAC_FALSE; + } + + /* Decode the first frame in preparation for sample-exact seeking below. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } + + /* + We need to as quickly as possible find the frame that contains the target sample. To do this, we iterate over each frame and inspect its + header. If based on the header we can determine that the frame contains the sample, we do a full decode of that frame. + */ + for (;;) { + drflac_uint64 pcmFrameCountInThisFLACFrame; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + + pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { + /* + The sample should be in this frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + it never existed and keep iterating. + */ + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + + if (!isMidFrame) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + if (!isMidFrame) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with + drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header. + */ + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = DRFLAC_FALSE; + } + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return DRFLAC_TRUE; + } + } + + next_iteration: + /* Grab the next frame in preparation for the next iteration. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } +} + + +#if !defined(DR_FLAC_NO_CRC) +/* +We use an average compression ratio to determine our approximate start location. FLAC files are generally about 50%-70% the size of their +uncompressed counterparts so we'll use this as a basis. I'm going to split the middle and use a factor of 0.6 to determine the starting +location. +*/ +#define DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO 0.6f + +static drflac_bool32 drflac__seek_to_approximate_flac_frame_to_byte(drflac* pFlac, drflac_uint64 targetByte, drflac_uint64 rangeLo, drflac_uint64 rangeHi, drflac_uint64* pLastSuccessfulSeekOffset) +{ + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pLastSuccessfulSeekOffset != NULL); + DRFLAC_ASSERT(targetByte >= rangeLo); + DRFLAC_ASSERT(targetByte <= rangeHi); + + *pLastSuccessfulSeekOffset = pFlac->firstFLACFramePosInBytes; + + for (;;) { + /* After rangeLo == rangeHi == targetByte fails, we need to break out. */ + drflac_uint64 lastTargetByte = targetByte; + + /* When seeking to a byte, failure probably means we've attempted to seek beyond the end of the stream. To counter this we just halve it each attempt. */ + if (!drflac__seek_to_byte(&pFlac->bs, targetByte)) { + /* If we couldn't even seek to the first byte in the stream we have a problem. Just abandon the whole thing. */ + if (targetByte == 0) { + drflac__seek_to_first_frame(pFlac); /* Try to recover. */ + return DRFLAC_FALSE; + } + + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + /* Getting here should mean that we have seeked to an appropriate byte. */ + + /* Clear the details of the FLAC frame so we don't misreport data. */ + DRFLAC_ZERO_MEMORY(&pFlac->currentFLACFrame, sizeof(pFlac->currentFLACFrame)); + + /* + Now seek to the next FLAC frame. We need to decode the entire frame (not just the header) because it's possible for the header to incorrectly pass the + CRC check and return bad data. We need to decode the entire frame to be more certain. Although this seems unlikely, this has happened to me in testing + so it needs to stay this way for now. + */ +#if 1 + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#else + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + /* Halve the byte location and continue. */ + targetByte = rangeLo + ((rangeHi - rangeLo)/2); + rangeHi = targetByte; + } else { + break; + } +#endif + } + + /* We already tried this byte and there are no more to try, break out. */ + if(targetByte == lastTargetByte) { + return DRFLAC_FALSE; + } + } + + /* The current PCM frame needs to be updated based on the frame we just seeked to. */ + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + + DRFLAC_ASSERT(targetByte <= rangeHi); + + *pLastSuccessfulSeekOffset = targetByte; + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(drflac* pFlac, drflac_uint64 offset) +{ + /* This section of code would be used if we were only decoding the FLAC frame header when calling drflac__seek_to_approximate_flac_frame_to_byte(). */ +#if 0 + if (drflac__decode_flac_frame(pFlac) != DRFLAC_SUCCESS) { + /* We failed to decode this frame which may be due to it being corrupt. We'll just use the next valid FLAC frame. */ + if (drflac__read_and_decode_next_flac_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + } +#endif + + return drflac__seek_forward_by_pcm_frames(pFlac, offset) == offset; +} + + +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search_internal(drflac* pFlac, drflac_uint64 pcmFrameIndex, drflac_uint64 byteRangeLo, drflac_uint64 byteRangeHi) +{ + /* This assumes pFlac->currentPCMFrame is sitting on byteRangeLo upon entry. */ + + drflac_uint64 targetByte; + drflac_uint64 pcmRangeLo = pFlac->totalPCMFrameCount; + drflac_uint64 pcmRangeHi = 0; + drflac_uint64 lastSuccessfulSeekOffset = (drflac_uint64)-1; + drflac_uint64 closestSeekOffsetBeforeTargetPCMFrame = byteRangeLo; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + + targetByte = byteRangeLo + (drflac_uint64)(((drflac_int64)((pcmFrameIndex - pFlac->currentPCMFrame) * pFlac->channels * pFlac->bitsPerSample)/8.0f) * DRFLAC_BINARY_SEARCH_APPROX_COMPRESSION_RATIO); + if (targetByte > byteRangeHi) { + targetByte = byteRangeHi; + } + + for (;;) { + if (drflac__seek_to_approximate_flac_frame_to_byte(pFlac, targetByte, byteRangeLo, byteRangeHi, &lastSuccessfulSeekOffset)) { + /* We found a FLAC frame. We need to check if it contains the sample we're looking for. */ + drflac_uint64 newPCMRangeLo; + drflac_uint64 newPCMRangeHi; + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &newPCMRangeLo, &newPCMRangeHi); + + /* If we selected the same frame, it means we should be pretty close. Just decode the rest. */ + if (pcmRangeLo == newPCMRangeLo) { + if (!drflac__seek_to_approximate_flac_frame_to_byte(pFlac, closestSeekOffsetBeforeTargetPCMFrame, closestSeekOffsetBeforeTargetPCMFrame, byteRangeHi, &lastSuccessfulSeekOffset)) { + break; /* Failed to seek to closest frame. */ + } + + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek forward. */ + } + } + + pcmRangeLo = newPCMRangeLo; + pcmRangeHi = newPCMRangeHi; + + if (pcmRangeLo <= pcmFrameIndex && pcmRangeHi >= pcmFrameIndex) { + /* The target PCM frame is in this FLAC frame. */ + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame) ) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek to FLAC frame. */ + } + } else { + if (pcmRangeLo > pcmFrameIndex) { + /* We seeked too far forward. We need to move our target byte backward and try again. */ + byteRangeHi = lastSuccessfulSeekOffset; + if (byteRangeLo > byteRangeHi) { + byteRangeLo = byteRangeHi; + } + + targetByte = byteRangeLo + ((byteRangeHi - byteRangeLo) / 2); + if (targetByte < byteRangeLo) { + targetByte = byteRangeLo; + } + } else /*if (pcmRangeHi < pcmFrameIndex)*/ { + /* We didn't seek far enough. We need to move our target byte forward and try again. */ + + /* If we're close enough we can just seek forward. */ + if ((pcmFrameIndex - pcmRangeLo) < seekForwardThreshold) { + if (drflac__decode_flac_frame_and_seek_forward_by_pcm_frames(pFlac, pcmFrameIndex - pFlac->currentPCMFrame)) { + return DRFLAC_TRUE; + } else { + break; /* Failed to seek to FLAC frame. */ + } + } else { + const double approxCompressionRatio = (drflac_int64)(lastSuccessfulSeekOffset - pFlac->firstFLACFramePosInBytes) / ((drflac_int64)(pcmRangeLo * pFlac->channels * pFlac->bitsPerSample)/8.0); + + byteRangeLo = lastSuccessfulSeekOffset; + if (byteRangeHi < byteRangeLo) { + byteRangeHi = byteRangeLo; + } + + targetByte = lastSuccessfulSeekOffset + (drflac_uint64)(((drflac_int64)((pcmFrameIndex-pcmRangeLo) * pFlac->channels * pFlac->bitsPerSample)/8.0) * approxCompressionRatio); + if (targetByte > byteRangeHi) { + targetByte = byteRangeHi; + } + + if (closestSeekOffsetBeforeTargetPCMFrame < lastSuccessfulSeekOffset) { + closestSeekOffsetBeforeTargetPCMFrame = lastSuccessfulSeekOffset; + } + } + } + } + } else { + /* Getting here is really bad. We just recover as best we can, but moving to the first frame in the stream, and then abort. */ + break; + } + } + + drflac__seek_to_first_frame(pFlac); /* <-- Try to recover. */ + return DRFLAC_FALSE; +} + +static drflac_bool32 drflac__seek_to_pcm_frame__binary_search(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + drflac_uint32 seekForwardThreshold = (pFlac->maxBlockSizeInPCMFrames != 0) ? pFlac->maxBlockSizeInPCMFrames*2 : 4096; + + /* Our algorithm currently assumes the FLAC stream is currently sitting at the start. */ + if (drflac__seek_to_first_frame(pFlac) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + + /* If we're close enough to the start, just move to the start and seek forward. */ + if (pcmFrameIndex < seekForwardThreshold) { + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFrameIndex) == pcmFrameIndex; + } + + /* + Our starting byte range is the byte position of the first FLAC frame and the approximate end of the file as if it were completely uncompressed. This ensures + the entire file is included, even though most of the time it'll exceed the end of the actual stream. This is OK as the frame searching logic will handle it. + */ + byteRangeLo = pFlac->firstFLACFramePosInBytes; + byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); + + return drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi); +} +#endif /* !DR_FLAC_NO_CRC */ + +static drflac_bool32 drflac__seek_to_pcm_frame__seek_table(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_uint32 iClosestSeekpoint = 0; + drflac_bool32 isMidFrame = DRFLAC_FALSE; + drflac_uint64 runningPCMFrameCount; + drflac_uint32 iSeekpoint; + + + DRFLAC_ASSERT(pFlac != NULL); + + if (pFlac->pSeekpoints == NULL || pFlac->seekpointCount == 0) { + return DRFLAC_FALSE; + } + + /* Do not use the seektable if pcmFramIndex is not coverd by it. */ + if (pFlac->pSeekpoints[0].firstPCMFrame > pcmFrameIndex) { + return DRFLAC_FALSE; + } + + for (iSeekpoint = 0; iSeekpoint < pFlac->seekpointCount; ++iSeekpoint) { + if (pFlac->pSeekpoints[iSeekpoint].firstPCMFrame >= pcmFrameIndex) { + break; + } + + iClosestSeekpoint = iSeekpoint; + } + + /* There's been cases where the seek table contains only zeros. We need to do some basic validation on the closest seekpoint. */ + if (pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount == 0 || pFlac->pSeekpoints[iClosestSeekpoint].pcmFrameCount > pFlac->maxBlockSizeInPCMFrames) { + return DRFLAC_FALSE; + } + if (pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame > pFlac->totalPCMFrameCount && pFlac->totalPCMFrameCount > 0) { + return DRFLAC_FALSE; + } + +#if !defined(DR_FLAC_NO_CRC) + /* At this point we should know the closest seek point. We can use a binary search for this. We need to know the total sample count for this. */ + if (pFlac->totalPCMFrameCount > 0) { + drflac_uint64 byteRangeLo; + drflac_uint64 byteRangeHi; + + byteRangeHi = pFlac->firstFLACFramePosInBytes + (drflac_uint64)((drflac_int64)(pFlac->totalPCMFrameCount * pFlac->channels * pFlac->bitsPerSample)/8.0f); + byteRangeLo = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset; + + /* + If our closest seek point is not the last one, we only need to search between it and the next one. The section below calculates an appropriate starting + value for byteRangeHi which will clamp it appropriately. + + Note that the next seekpoint must have an offset greater than the closest seekpoint because otherwise our binary search algorithm will break down. There + have been cases where a seektable consists of seek points where every byte offset is set to 0 which causes problems. If this happens we need to abort. + */ + if (iClosestSeekpoint < pFlac->seekpointCount-1) { + drflac_uint32 iNextSeekpoint = iClosestSeekpoint + 1; + + /* Basic validation on the seekpoints to ensure they're usable. */ + if (pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset >= pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset || pFlac->pSeekpoints[iNextSeekpoint].pcmFrameCount == 0) { + return DRFLAC_FALSE; /* The next seekpoint doesn't look right. The seek table cannot be trusted from here. Abort. */ + } + + if (pFlac->pSeekpoints[iNextSeekpoint].firstPCMFrame != (((drflac_uint64)0xFFFFFFFF << 32) | 0xFFFFFFFF)) { /* Make sure it's not a placeholder seekpoint. */ + byteRangeHi = pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iNextSeekpoint].flacFrameOffset - 1; /* byteRangeHi must be zero based. */ + } + } + + if (drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + if (drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &pFlac->currentPCMFrame, NULL); + + if (drflac__seek_to_pcm_frame__binary_search_internal(pFlac, pcmFrameIndex, byteRangeLo, byteRangeHi)) { + return DRFLAC_TRUE; + } + } + } + } +#endif /* !DR_FLAC_NO_CRC */ + + /* Getting here means we need to use a slower algorithm because the binary search method failed or cannot be used. */ + + /* + If we are seeking forward and the closest seekpoint is _before_ the current sample, we just seek forward from where we are. Otherwise we start seeking + from the seekpoint's first sample. + */ + if (pcmFrameIndex >= pFlac->currentPCMFrame && pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame <= pFlac->currentPCMFrame) { + /* Optimized case. Just seek forward from where we are. */ + runningPCMFrameCount = pFlac->currentPCMFrame; + + /* The frame header for the first frame may not yet have been read. We need to do that if necessary. */ + if (pFlac->currentPCMFrame == 0 && pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } else { + isMidFrame = DRFLAC_TRUE; + } + } else { + /* Slower case. Seek to the start of the seekpoint and then seek forward from there. */ + runningPCMFrameCount = pFlac->pSeekpoints[iClosestSeekpoint].firstPCMFrame; + + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes + pFlac->pSeekpoints[iClosestSeekpoint].flacFrameOffset)) { + return DRFLAC_FALSE; + } + + /* Grab the frame the seekpoint is sitting on in preparation for the sample-exact seeking below. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } + + for (;;) { + drflac_uint64 pcmFrameCountInThisFLACFrame; + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + + pcmFrameCountInThisFLACFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFLACFrame)) { + /* + The sample should be in this frame. We need to fully decode it, but if it's an invalid frame (a CRC mismatch) we need to pretend + it never existed and keep iterating. + */ + drflac_uint64 pcmFramesToDecode = pcmFrameIndex - runningPCMFrameCount; + + if (!isMidFrame) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* We started seeking mid-frame which means we need to skip the frame decoding part. */ + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + if (!isMidFrame) { + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFLACFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + goto next_iteration; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + We started seeking mid-frame which means we need to seek by reading to the end of the frame instead of with + drflac__seek_to_next_flac_frame() which only works if the decoder is sitting on the byte just after the frame header. + */ + runningPCMFrameCount += pFlac->currentFLACFrame.pcmFramesRemaining; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + isMidFrame = DRFLAC_FALSE; + } + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && runningPCMFrameCount == pFlac->totalPCMFrameCount) { + return DRFLAC_TRUE; + } + } + + next_iteration: + /* Grab the next frame in preparation for the next iteration. */ + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + } +} + + +#ifndef DR_FLAC_NO_OGG +typedef struct +{ + drflac_uint8 capturePattern[4]; /* Should be "OggS" */ + drflac_uint8 structureVersion; /* Always 0. */ + drflac_uint8 headerType; + drflac_uint64 granulePosition; + drflac_uint32 serialNumber; + drflac_uint32 sequenceNumber; + drflac_uint32 checksum; + drflac_uint8 segmentCount; + drflac_uint8 segmentTable[255]; +} drflac_ogg_page_header; +#endif + +typedef struct +{ + drflac_read_proc onRead; + drflac_seek_proc onSeek; + drflac_tell_proc onTell; + drflac_meta_proc onMeta; + drflac_container container; + void* pUserData; + void* pUserDataMD; + drflac_uint32 sampleRate; + drflac_uint8 channels; + drflac_uint8 bitsPerSample; + drflac_uint64 totalPCMFrameCount; + drflac_uint16 maxBlockSizeInPCMFrames; + drflac_uint64 runningFilePos; + drflac_bool32 hasStreamInfoBlock; + drflac_bool32 hasMetadataBlocks; + drflac_bs bs; /* <-- A bit streamer is required for loading data during initialization. */ + drflac_frame_header firstFrameHeader; /* <-- The header of the first frame that was read during relaxed initalization. Only set if there is no STREAMINFO block. */ + +#ifndef DR_FLAC_NO_OGG + drflac_uint32 oggSerial; + drflac_uint64 oggFirstBytePos; + drflac_ogg_page_header oggBosHeader; +#endif +} drflac_init_info; + +static DRFLAC_INLINE void drflac__decode_block_header(drflac_uint32 blockHeader, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) +{ + blockHeader = drflac__be2host_32(blockHeader); + *isLastBlock = (drflac_uint8)((blockHeader & 0x80000000UL) >> 31); + *blockType = (drflac_uint8)((blockHeader & 0x7F000000UL) >> 24); + *blockSize = (blockHeader & 0x00FFFFFFUL); +} + +static DRFLAC_INLINE drflac_bool32 drflac__read_and_decode_block_header(drflac_read_proc onRead, void* pUserData, drflac_uint8* isLastBlock, drflac_uint8* blockType, drflac_uint32* blockSize) +{ + drflac_uint32 blockHeader; + + *blockSize = 0; + if (onRead(pUserData, &blockHeader, 4) != 4) { + return DRFLAC_FALSE; + } + + drflac__decode_block_header(blockHeader, isLastBlock, blockType, blockSize); + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__read_streaminfo(drflac_read_proc onRead, void* pUserData, drflac_streaminfo* pStreamInfo) +{ + drflac_uint32 blockSizes; + drflac_uint64 frameSizes = 0; + drflac_uint64 importantProps; + drflac_uint8 md5[16]; + + /* min/max block size. */ + if (onRead(pUserData, &blockSizes, 4) != 4) { + return DRFLAC_FALSE; + } + + /* min/max frame size. */ + if (onRead(pUserData, &frameSizes, 6) != 6) { + return DRFLAC_FALSE; + } + + /* Sample rate, channels, bits per sample and total sample count. */ + if (onRead(pUserData, &importantProps, 8) != 8) { + return DRFLAC_FALSE; + } + + /* MD5 */ + if (onRead(pUserData, md5, sizeof(md5)) != sizeof(md5)) { + return DRFLAC_FALSE; + } + + blockSizes = drflac__be2host_32(blockSizes); + frameSizes = drflac__be2host_64(frameSizes); + importantProps = drflac__be2host_64(importantProps); + + pStreamInfo->minBlockSizeInPCMFrames = (drflac_uint16)((blockSizes & 0xFFFF0000) >> 16); + pStreamInfo->maxBlockSizeInPCMFrames = (drflac_uint16) (blockSizes & 0x0000FFFF); + pStreamInfo->minFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 24)) >> 40); + pStreamInfo->maxFrameSizeInPCMFrames = (drflac_uint32)((frameSizes & (((drflac_uint64)0x00FFFFFF << 16) << 0)) >> 16); + pStreamInfo->sampleRate = (drflac_uint32)((importantProps & (((drflac_uint64)0x000FFFFF << 16) << 28)) >> 44); + pStreamInfo->channels = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000000E << 16) << 24)) >> 41) + 1; + pStreamInfo->bitsPerSample = (drflac_uint8 )((importantProps & (((drflac_uint64)0x0000001F << 16) << 20)) >> 36) + 1; + pStreamInfo->totalPCMFrameCount = ((importantProps & ((((drflac_uint64)0x0000000F << 16) << 16) | 0xFFFFFFFF))); + DRFLAC_COPY_MEMORY(pStreamInfo->md5, md5, sizeof(md5)); + + return DRFLAC_TRUE; +} + + +static void* drflac__malloc_default(size_t sz, void* pUserData) +{ + (void)pUserData; + return DRFLAC_MALLOC(sz); +} + +static void* drflac__realloc_default(void* p, size_t sz, void* pUserData) +{ + (void)pUserData; + return DRFLAC_REALLOC(p, sz); +} + +static void drflac__free_default(void* p, void* pUserData) +{ + (void)pUserData; + DRFLAC_FREE(p); +} + + +static void* drflac__malloc_from_callbacks(size_t sz, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onMalloc != NULL) { + return pAllocationCallbacks->onMalloc(sz, pAllocationCallbacks->pUserData); + } + + /* Try using realloc(). */ + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(NULL, sz, pAllocationCallbacks->pUserData); + } + + return NULL; +} + +static void* drflac__realloc_from_callbacks(void* p, size_t szNew, size_t szOld, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks == NULL) { + return NULL; + } + + if (pAllocationCallbacks->onRealloc != NULL) { + return pAllocationCallbacks->onRealloc(p, szNew, pAllocationCallbacks->pUserData); + } + + /* Try emulating realloc() in terms of malloc()/free(). */ + if (pAllocationCallbacks->onMalloc != NULL && pAllocationCallbacks->onFree != NULL) { + void* p2; + + p2 = pAllocationCallbacks->onMalloc(szNew, pAllocationCallbacks->pUserData); + if (p2 == NULL) { + return NULL; + } + + if (p != NULL) { + DRFLAC_COPY_MEMORY(p2, p, DRFLAC_MIN(szNew, szOld)); + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } + + return p2; + } + + return NULL; +} + +static void drflac__free_from_callbacks(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (p == NULL || pAllocationCallbacks == NULL) { + return; + } + + if (pAllocationCallbacks->onFree != NULL) { + pAllocationCallbacks->onFree(p, pAllocationCallbacks->pUserData); + } +} + + +static drflac_bool32 drflac__read_and_decode_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_uint64* pFirstFramePos, drflac_uint64* pSeektablePos, drflac_uint32* pSeekpointCount, drflac_allocation_callbacks* pAllocationCallbacks) +{ + /* + We want to keep track of the byte position in the stream of the seektable. At the time of calling this function we know that + we'll be sitting on byte 42. + */ + drflac_uint64 runningFilePos = 42; + drflac_uint64 seektablePos = 0; + drflac_uint32 seektableSize = 0; + drflac_int64 fileSize = 0; + drflac_bool32 hasKnownFileSize = DRFLAC_FALSE; + + /* We'll be doing some memory allocations here against untrusted data. We'll do a basic validation check that they don't exceed the size of the file. */ + if (onTell != NULL && onSeek != NULL) { + if (onSeek(pUserData, 0, DRFLAC_SEEK_END)) { + if (onTell(pUserData, &fileSize)) { + hasKnownFileSize = DRFLAC_TRUE; + } + + onSeek(pUserData, (int)runningFilePos, DRFLAC_SEEK_SET); /* Safe cast because runningFilePos should always be 42 at this point. */ + } + } + + for (;;) { + drflac_metadata metadata; + drflac_uint8 isLastBlock = 0; + drflac_uint8 blockType = 0; + drflac_uint32 blockSize; + if (drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize) == DRFLAC_FALSE) { + return DRFLAC_FALSE; + } + + if (hasKnownFileSize && (blockSize > ((drflac_uint64)fileSize - runningFilePos))) { + return DRFLAC_FALSE; /* Block size exceeds the size of the file. */ + } + + runningFilePos += 4; + + metadata.type = blockType; + metadata.rawDataSize = 0; + metadata.rawDataOffset = runningFilePos; + metadata.pRawData = NULL; + + switch (blockType) + { + case DRFLAC_METADATA_BLOCK_TYPE_APPLICATION: + { + if (blockSize < 4) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + metadata.data.application.id = drflac__be2host_32(*(drflac_uint32*)pRawData); + metadata.data.application.pData = (const void*)((drflac_uint8*)pRawData + sizeof(drflac_uint32)); + metadata.data.application.dataSize = blockSize - sizeof(drflac_uint32); + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_SEEKTABLE: + { + seektablePos = runningFilePos; + seektableSize = blockSize; + + if (onMeta) { + drflac_uint32 seekpointCount; + drflac_uint32 iSeekpoint; + void* pRawData; + size_t rawDataSize; + + seekpointCount = blockSize/DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + rawDataSize = seekpointCount * sizeof(drflac_seekpoint); + + pRawData = drflac__malloc_from_callbacks(rawDataSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + /* We need to read seekpoint by seekpoint and do some processing. */ + for (iSeekpoint = 0; iSeekpoint < seekpointCount; ++iSeekpoint) { + drflac_seekpoint* pSeekpoint = (drflac_seekpoint*)pRawData + iSeekpoint; + + if (onRead(pUserData, pSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) != DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + /* Endian swap. */ + pSeekpoint->firstPCMFrame = drflac__be2host_64(pSeekpoint->firstPCMFrame); + pSeekpoint->flacFrameOffset = drflac__be2host_64(pSeekpoint->flacFrameOffset); + pSeekpoint->pcmFrameCount = drflac__be2host_16(pSeekpoint->pcmFrameCount); + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = rawDataSize; + metadata.data.seektable.seekpointCount = seekpointCount; + metadata.data.seektable.pSeekpoints = (const drflac_seekpoint*)pRawData; + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_VORBIS_COMMENT: + { + if (blockSize < 8) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + drflac_uint32 i; + + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; + + metadata.data.vorbis_comment.vendorLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + + /* Need space for the rest of the block */ + if ((pRunningDataEnd - pRunningData) - 4 < (drflac_int64)metadata.data.vorbis_comment.vendorLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.vendor = pRunningData; pRunningData += metadata.data.vorbis_comment.vendorLength; + metadata.data.vorbis_comment.commentCount = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + + /* Need space for 'commentCount' comments after the block, which at minimum is a drflac_uint32 per comment */ + if ((pRunningDataEnd - pRunningData) / sizeof(drflac_uint32) < metadata.data.vorbis_comment.commentCount) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + metadata.data.vorbis_comment.pComments = pRunningData; + + /* Check that the comments section is valid before passing it to the callback */ + for (i = 0; i < metadata.data.vorbis_comment.commentCount; ++i) { + drflac_uint32 commentLength; + + if (pRunningDataEnd - pRunningData < 4) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + commentLength = drflac__le2host_32_ptr_unaligned(pRunningData); pRunningData += 4; + if (pRunningDataEnd - pRunningData < (drflac_int64)commentLength) { /* <-- Note the order of operations to avoid overflow to a valid value */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + pRunningData += commentLength; + } + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_CUESHEET: + { + if (blockSize < 396) { + return DRFLAC_FALSE; + } + + if (onMeta) { + void* pRawData; + const char* pRunningData; + const char* pRunningDataEnd; + size_t bufferSize; + drflac_uint8 iTrack; + drflac_uint8 iIndex; + void* pTrackData; + + /* + This needs to be loaded in two passes. The first pass is used to calculate the size of the memory allocation + we need for storing the necessary data. The second pass will fill that buffer with usable data. + */ + pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData == NULL) { + return DRFLAC_FALSE; + } + + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + + pRunningData = (const char*)pRawData; + pRunningDataEnd = (const char*)pRawData + blockSize; + + DRFLAC_COPY_MEMORY(metadata.data.cuesheet.catalog, pRunningData, 128); pRunningData += 128; + metadata.data.cuesheet.leadInSampleCount = drflac__be2host_64(*(const drflac_uint64*)pRunningData); pRunningData += 8; + metadata.data.cuesheet.isCD = (pRunningData[0] & 0x80) != 0; pRunningData += 259; + metadata.data.cuesheet.trackCount = pRunningData[0]; pRunningData += 1; + metadata.data.cuesheet.pTrackData = NULL; /* Will be filled later. */ + + /* Pass 1: Calculate the size of the buffer for the track data. */ + { + const char* pRunningDataSaved = pRunningData; /* Will be restored at the end in preparation for the second pass. */ + + bufferSize = metadata.data.cuesheet.trackCount * DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES; + + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + drflac_uint32 indexPointSize; + + if (pRunningDataEnd - pRunningData < DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + /* Skip to the index point count */ + pRunningData += 35; + + indexCount = pRunningData[0]; + pRunningData += 1; + + bufferSize += indexCount * sizeof(drflac_cuesheet_track_index); + + /* Quick validation check. */ + indexPointSize = indexCount * DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; + if (pRunningDataEnd - pRunningData < (drflac_int64)indexPointSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + pRunningData += indexPointSize; + } + + pRunningData = pRunningDataSaved; + } + + /* Pass 2: Allocate a buffer and fill the data. Validation was done in the step above so can be skipped. */ + { + char* pRunningTrackData; + + pTrackData = drflac__malloc_from_callbacks(bufferSize, pAllocationCallbacks); + if (pTrackData == NULL) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + + pRunningTrackData = (char*)pTrackData; + + for (iTrack = 0; iTrack < metadata.data.cuesheet.trackCount; ++iTrack) { + drflac_uint8 indexCount; + + DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES); + pRunningData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; /* Skip forward, but not beyond the last byte in the CUESHEET_TRACK block which is the index count. */ + pRunningTrackData += DRFLAC_CUESHEET_TRACK_SIZE_IN_BYTES-1; + + /* Grab the index count for the next part. */ + indexCount = pRunningData[0]; + pRunningData += 1; + pRunningTrackData += 1; + + /* Extract each track index. */ + for (iIndex = 0; iIndex < indexCount; ++iIndex) { + drflac_cuesheet_track_index* pTrackIndex = (drflac_cuesheet_track_index*)pRunningTrackData; + + DRFLAC_COPY_MEMORY(pRunningTrackData, pRunningData, DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES); + pRunningData += DRFLAC_CUESHEET_TRACK_INDEX_SIZE_IN_BYTES; + pRunningTrackData += sizeof(drflac_cuesheet_track_index); + + pTrackIndex->offset = drflac__be2host_64(pTrackIndex->offset); + } + } + + metadata.data.cuesheet.pTrackData = pTrackData; + } + + /* The original data is no longer needed. */ + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + pRawData = NULL; + + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pTrackData, pAllocationCallbacks); + pTrackData = NULL; + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_PICTURE: + { + if (blockSize < 32) { + return DRFLAC_FALSE; + } + + if (onMeta) { + drflac_bool32 result = DRFLAC_TRUE; + drflac_uint32 blockSizeRemaining = blockSize; + char* pMime = NULL; + char* pDescription = NULL; + void* pPictureData = NULL; + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.type, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.type = drflac__be2host_32(metadata.data.picture.type); + + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.mimeLength, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.mimeLength = drflac__be2host_32(metadata.data.picture.mimeLength); + + if (blockSizeRemaining < metadata.data.picture.mimeLength) { + result = DRFLAC_FALSE; + goto done_flac; + } + + pMime = (char*)drflac__malloc_from_callbacks(metadata.data.picture.mimeLength + 1, pAllocationCallbacks); /* +1 for null terminator. */ + if (pMime == NULL) { + result = DRFLAC_FALSE; + goto done_flac; + } + + if (onRead(pUserData, pMime, metadata.data.picture.mimeLength) != metadata.data.picture.mimeLength) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= metadata.data.picture.mimeLength; + pMime[metadata.data.picture.mimeLength] = '\0'; /* Null terminate for safety. */ + metadata.data.picture.mime = (const char*)pMime; + + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.descriptionLength, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.descriptionLength = drflac__be2host_32(metadata.data.picture.descriptionLength); + + if (blockSizeRemaining < metadata.data.picture.descriptionLength) { + result = DRFLAC_FALSE; + goto done_flac; + } + + pDescription = (char*)drflac__malloc_from_callbacks(metadata.data.picture.descriptionLength + 1, pAllocationCallbacks); /* +1 for null terminator. */ + if (pDescription == NULL) { + result = DRFLAC_FALSE; + goto done_flac; + } + + if (onRead(pUserData, pDescription, metadata.data.picture.descriptionLength) != metadata.data.picture.descriptionLength) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= metadata.data.picture.descriptionLength; + pDescription[metadata.data.picture.descriptionLength] = '\0'; /* Null terminate for safety. */ + metadata.data.picture.description = (const char*)pDescription; + + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.width, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.width = drflac__be2host_32(metadata.data.picture.width); + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.height, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.height = drflac__be2host_32(metadata.data.picture.height); + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.colorDepth, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.colorDepth = drflac__be2host_32(metadata.data.picture.colorDepth); + + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.indexColorCount, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.indexColorCount = drflac__be2host_32(metadata.data.picture.indexColorCount); + + + /* Picture data. */ + if (blockSizeRemaining < 4 || onRead(pUserData, &metadata.data.picture.pictureDataSize, 4) != 4) { + result = DRFLAC_FALSE; + goto done_flac; + } + blockSizeRemaining -= 4; + metadata.data.picture.pictureDataSize = drflac__be2host_32(metadata.data.picture.pictureDataSize); + + if (blockSizeRemaining < metadata.data.picture.pictureDataSize) { + result = DRFLAC_FALSE; + goto done_flac; + } + + /* For the actual image data we want to store the offset to the start of the stream. */ + metadata.data.picture.pictureDataOffset = runningFilePos + (blockSize - blockSizeRemaining); + + /* + For the allocation of image data, we can allow memory allocation to fail, in which case we just leave + the pointer as null. If it fails, we need to fall back to seeking past the image data. + */ + #ifndef DR_FLAC_NO_PICTURE_METADATA_MALLOC + pPictureData = drflac__malloc_from_callbacks(metadata.data.picture.pictureDataSize, pAllocationCallbacks); + if (pPictureData != NULL) { + if (onRead(pUserData, pPictureData, metadata.data.picture.pictureDataSize) != metadata.data.picture.pictureDataSize) { + result = DRFLAC_FALSE; + goto done_flac; + } + } else + #endif + { + /* Allocation failed. We need to seek past the picture data. */ + if (!onSeek(pUserData, metadata.data.picture.pictureDataSize, DRFLAC_SEEK_CUR)) { + result = DRFLAC_FALSE; + goto done_flac; + } + } + + blockSizeRemaining -= metadata.data.picture.pictureDataSize; + (void)blockSizeRemaining; + + metadata.data.picture.pPictureData = (const drflac_uint8*)pPictureData; + + + /* Only fire the callback if we actually have a way to read the image data. We must have either a valid offset, or a valid data pointer. */ + if (metadata.data.picture.pictureDataOffset != 0 || metadata.data.picture.pPictureData != NULL) { + onMeta(pUserDataMD, &metadata); + } else { + /* Don't have a valid offset or data pointer, so just pretend we don't have a picture metadata. */ + } + + done_flac: + drflac__free_from_callbacks(pMime, pAllocationCallbacks); + drflac__free_from_callbacks(pDescription, pAllocationCallbacks); + drflac__free_from_callbacks(pPictureData, pAllocationCallbacks); + + if (result != DRFLAC_TRUE) { + return DRFLAC_FALSE; + } + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_PADDING: + { + if (onMeta) { + metadata.data.padding.unused = 0; + + /* Padding doesn't have anything meaningful in it, so just skip over it, but make sure the caller is aware of it by firing the callback. */ + if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) { + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ + } else { + onMeta(pUserDataMD, &metadata); + } + } + } break; + + case DRFLAC_METADATA_BLOCK_TYPE_INVALID: + { + /* Invalid chunk. Just skip over this one. */ + if (onMeta) { + if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) { + isLastBlock = DRFLAC_TRUE; /* An error occurred while seeking. Attempt to recover by treating this as the last block which will in turn terminate the loop. */ + } + } + } break; + + default: + { + /* + It's an unknown chunk, but not necessarily invalid. There's a chance more metadata blocks might be defined later on, so we + can at the very least report the chunk to the application and let it look at the raw data. + */ + if (onMeta) { + void* pRawData = drflac__malloc_from_callbacks(blockSize, pAllocationCallbacks); + if (pRawData != NULL) { + if (onRead(pUserData, pRawData, blockSize) != blockSize) { + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + return DRFLAC_FALSE; + } + } else { + /* Allocation failed. We need to seek past the block. */ + if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + } + + metadata.pRawData = pRawData; + metadata.rawDataSize = blockSize; + onMeta(pUserDataMD, &metadata); + + drflac__free_from_callbacks(pRawData, pAllocationCallbacks); + } + } break; + } + + /* If we're not handling metadata, just skip over the block. If we are, it will have been handled earlier in the switch statement above. */ + if (onMeta == NULL && blockSize > 0) { + if (!onSeek(pUserData, blockSize, DRFLAC_SEEK_CUR)) { + isLastBlock = DRFLAC_TRUE; + } + } + + runningFilePos += blockSize; + if (isLastBlock) { + break; + } + } + + *pSeektablePos = seektablePos; + *pSeekpointCount = seektableSize / DRFLAC_SEEKPOINT_SIZE_IN_BYTES; + *pFirstFramePos = runningFilePos; + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__init_private__native(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) +{ + /* Pre Condition: The bit stream should be sitting just past the 4-byte id header. */ + + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; + + (void)onSeek; + + pInit->container = drflac_container_native; + + /* The first metadata block should be the STREAMINFO block. */ + if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { + return DRFLAC_FALSE; + } + + if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + if (!relaxed) { + /* We're opening in strict mode and the first block is not the STREAMINFO block. Error. */ + return DRFLAC_FALSE; + } else { + /* + Relaxed mode. To open from here we need to just find the first frame and set the sample rate, etc. to whatever is defined + for that frame. + */ + pInit->hasStreamInfoBlock = DRFLAC_FALSE; + pInit->hasMetadataBlocks = DRFLAC_FALSE; + + if (!drflac__read_next_flac_frame_header(&pInit->bs, 0, &pInit->firstFrameHeader)) { + return DRFLAC_FALSE; /* Couldn't find a frame. */ + } + + if (pInit->firstFrameHeader.bitsPerSample == 0) { + return DRFLAC_FALSE; /* Failed to initialize because the first frame depends on the STREAMINFO block, which does not exist. */ + } + + pInit->sampleRate = pInit->firstFrameHeader.sampleRate; + pInit->channels = drflac__get_channel_count_from_channel_assignment(pInit->firstFrameHeader.channelAssignment); + pInit->bitsPerSample = pInit->firstFrameHeader.bitsPerSample; + pInit->maxBlockSizeInPCMFrames = 65535; /* <-- See notes here: https://xiph.org/flac/format.html#metadata_block_streaminfo */ + return DRFLAC_TRUE; + } + } else { + drflac_streaminfo streaminfo; + if (!drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + return DRFLAC_FALSE; + } + + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; /* Don't care about the min block size - only the max (used for determining the size of the memory allocation). */ + pInit->hasMetadataBlocks = !isLastBlock; + + if (onMeta) { + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + + return DRFLAC_TRUE; + } +} + +#ifndef DR_FLAC_NO_OGG +#define DRFLAC_OGG_MAX_PAGE_SIZE 65307 +#define DRFLAC_OGG_CAPTURE_PATTERN_CRC32 1605413199 /* CRC-32 of "OggS". */ + +typedef enum +{ + drflac_ogg_recover_on_crc_mismatch, + drflac_ogg_fail_on_crc_mismatch +} drflac_ogg_crc_mismatch_recovery; + +#ifndef DR_FLAC_NO_CRC +static drflac_uint32 drflac__crc32_table[] = { + 0x00000000L, 0x04C11DB7L, 0x09823B6EL, 0x0D4326D9L, + 0x130476DCL, 0x17C56B6BL, 0x1A864DB2L, 0x1E475005L, + 0x2608EDB8L, 0x22C9F00FL, 0x2F8AD6D6L, 0x2B4BCB61L, + 0x350C9B64L, 0x31CD86D3L, 0x3C8EA00AL, 0x384FBDBDL, + 0x4C11DB70L, 0x48D0C6C7L, 0x4593E01EL, 0x4152FDA9L, + 0x5F15ADACL, 0x5BD4B01BL, 0x569796C2L, 0x52568B75L, + 0x6A1936C8L, 0x6ED82B7FL, 0x639B0DA6L, 0x675A1011L, + 0x791D4014L, 0x7DDC5DA3L, 0x709F7B7AL, 0x745E66CDL, + 0x9823B6E0L, 0x9CE2AB57L, 0x91A18D8EL, 0x95609039L, + 0x8B27C03CL, 0x8FE6DD8BL, 0x82A5FB52L, 0x8664E6E5L, + 0xBE2B5B58L, 0xBAEA46EFL, 0xB7A96036L, 0xB3687D81L, + 0xAD2F2D84L, 0xA9EE3033L, 0xA4AD16EAL, 0xA06C0B5DL, + 0xD4326D90L, 0xD0F37027L, 0xDDB056FEL, 0xD9714B49L, + 0xC7361B4CL, 0xC3F706FBL, 0xCEB42022L, 0xCA753D95L, + 0xF23A8028L, 0xF6FB9D9FL, 0xFBB8BB46L, 0xFF79A6F1L, + 0xE13EF6F4L, 0xE5FFEB43L, 0xE8BCCD9AL, 0xEC7DD02DL, + 0x34867077L, 0x30476DC0L, 0x3D044B19L, 0x39C556AEL, + 0x278206ABL, 0x23431B1CL, 0x2E003DC5L, 0x2AC12072L, + 0x128E9DCFL, 0x164F8078L, 0x1B0CA6A1L, 0x1FCDBB16L, + 0x018AEB13L, 0x054BF6A4L, 0x0808D07DL, 0x0CC9CDCAL, + 0x7897AB07L, 0x7C56B6B0L, 0x71159069L, 0x75D48DDEL, + 0x6B93DDDBL, 0x6F52C06CL, 0x6211E6B5L, 0x66D0FB02L, + 0x5E9F46BFL, 0x5A5E5B08L, 0x571D7DD1L, 0x53DC6066L, + 0x4D9B3063L, 0x495A2DD4L, 0x44190B0DL, 0x40D816BAL, + 0xACA5C697L, 0xA864DB20L, 0xA527FDF9L, 0xA1E6E04EL, + 0xBFA1B04BL, 0xBB60ADFCL, 0xB6238B25L, 0xB2E29692L, + 0x8AAD2B2FL, 0x8E6C3698L, 0x832F1041L, 0x87EE0DF6L, + 0x99A95DF3L, 0x9D684044L, 0x902B669DL, 0x94EA7B2AL, + 0xE0B41DE7L, 0xE4750050L, 0xE9362689L, 0xEDF73B3EL, + 0xF3B06B3BL, 0xF771768CL, 0xFA325055L, 0xFEF34DE2L, + 0xC6BCF05FL, 0xC27DEDE8L, 0xCF3ECB31L, 0xCBFFD686L, + 0xD5B88683L, 0xD1799B34L, 0xDC3ABDEDL, 0xD8FBA05AL, + 0x690CE0EEL, 0x6DCDFD59L, 0x608EDB80L, 0x644FC637L, + 0x7A089632L, 0x7EC98B85L, 0x738AAD5CL, 0x774BB0EBL, + 0x4F040D56L, 0x4BC510E1L, 0x46863638L, 0x42472B8FL, + 0x5C007B8AL, 0x58C1663DL, 0x558240E4L, 0x51435D53L, + 0x251D3B9EL, 0x21DC2629L, 0x2C9F00F0L, 0x285E1D47L, + 0x36194D42L, 0x32D850F5L, 0x3F9B762CL, 0x3B5A6B9BL, + 0x0315D626L, 0x07D4CB91L, 0x0A97ED48L, 0x0E56F0FFL, + 0x1011A0FAL, 0x14D0BD4DL, 0x19939B94L, 0x1D528623L, + 0xF12F560EL, 0xF5EE4BB9L, 0xF8AD6D60L, 0xFC6C70D7L, + 0xE22B20D2L, 0xE6EA3D65L, 0xEBA91BBCL, 0xEF68060BL, + 0xD727BBB6L, 0xD3E6A601L, 0xDEA580D8L, 0xDA649D6FL, + 0xC423CD6AL, 0xC0E2D0DDL, 0xCDA1F604L, 0xC960EBB3L, + 0xBD3E8D7EL, 0xB9FF90C9L, 0xB4BCB610L, 0xB07DABA7L, + 0xAE3AFBA2L, 0xAAFBE615L, 0xA7B8C0CCL, 0xA379DD7BL, + 0x9B3660C6L, 0x9FF77D71L, 0x92B45BA8L, 0x9675461FL, + 0x8832161AL, 0x8CF30BADL, 0x81B02D74L, 0x857130C3L, + 0x5D8A9099L, 0x594B8D2EL, 0x5408ABF7L, 0x50C9B640L, + 0x4E8EE645L, 0x4A4FFBF2L, 0x470CDD2BL, 0x43CDC09CL, + 0x7B827D21L, 0x7F436096L, 0x7200464FL, 0x76C15BF8L, + 0x68860BFDL, 0x6C47164AL, 0x61043093L, 0x65C52D24L, + 0x119B4BE9L, 0x155A565EL, 0x18197087L, 0x1CD86D30L, + 0x029F3D35L, 0x065E2082L, 0x0B1D065BL, 0x0FDC1BECL, + 0x3793A651L, 0x3352BBE6L, 0x3E119D3FL, 0x3AD08088L, + 0x2497D08DL, 0x2056CD3AL, 0x2D15EBE3L, 0x29D4F654L, + 0xC5A92679L, 0xC1683BCEL, 0xCC2B1D17L, 0xC8EA00A0L, + 0xD6AD50A5L, 0xD26C4D12L, 0xDF2F6BCBL, 0xDBEE767CL, + 0xE3A1CBC1L, 0xE760D676L, 0xEA23F0AFL, 0xEEE2ED18L, + 0xF0A5BD1DL, 0xF464A0AAL, 0xF9278673L, 0xFDE69BC4L, + 0x89B8FD09L, 0x8D79E0BEL, 0x803AC667L, 0x84FBDBD0L, + 0x9ABC8BD5L, 0x9E7D9662L, 0x933EB0BBL, 0x97FFAD0CL, + 0xAFB010B1L, 0xAB710D06L, 0xA6322BDFL, 0xA2F33668L, + 0xBCB4666DL, 0xB8757BDAL, 0xB5365D03L, 0xB1F740B4L +}; +#endif + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_byte(drflac_uint32 crc32, drflac_uint8 data) +{ +#ifndef DR_FLAC_NO_CRC + return (crc32 << 8) ^ drflac__crc32_table[(drflac_uint8)((crc32 >> 24) & 0xFF) ^ data]; +#else + (void)data; + return crc32; +#endif +} + +#if 0 +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint32(drflac_uint32 crc32, drflac_uint32 data) +{ + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 24) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 16) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 8) & 0xFF)); + crc32 = drflac_crc32_byte(crc32, (drflac_uint8)((data >> 0) & 0xFF)); + return crc32; +} + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_uint64(drflac_uint32 crc32, drflac_uint64 data) +{ + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 32) & 0xFFFFFFFF)); + crc32 = drflac_crc32_uint32(crc32, (drflac_uint32)((data >> 0) & 0xFFFFFFFF)); + return crc32; +} +#endif + +static DRFLAC_INLINE drflac_uint32 drflac_crc32_buffer(drflac_uint32 crc32, drflac_uint8* pData, drflac_uint32 dataSize) +{ + /* This can be optimized. */ + drflac_uint32 i; + for (i = 0; i < dataSize; ++i) { + crc32 = drflac_crc32_byte(crc32, pData[i]); + } + return crc32; +} + + +static DRFLAC_INLINE drflac_bool32 drflac_ogg__is_capture_pattern(drflac_uint8 pattern[4]) +{ + return pattern[0] == 'O' && pattern[1] == 'g' && pattern[2] == 'g' && pattern[3] == 'S'; +} + +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_header_size(drflac_ogg_page_header* pHeader) +{ + return 27 + pHeader->segmentCount; +} + +static DRFLAC_INLINE drflac_uint32 drflac_ogg__get_page_body_size(drflac_ogg_page_header* pHeader) +{ + drflac_uint32 pageBodySize = 0; + int i; + + for (i = 0; i < pHeader->segmentCount; ++i) { + pageBodySize += pHeader->segmentTable[i]; + } + + return pageBodySize; +} + +static drflac_result drflac_ogg__read_page_header_after_capture_pattern(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) +{ + drflac_uint8 data[23]; + drflac_uint32 i; + + DRFLAC_ASSERT(*pCRC32 == DRFLAC_OGG_CAPTURE_PATTERN_CRC32); + + if (onRead(pUserData, data, 23) != 23) { + return DRFLAC_AT_END; + } + *pBytesRead += 23; + + /* + It's not actually used, but set the capture pattern to 'OggS' for completeness. Not doing this will cause static analysers to complain about + us trying to access uninitialized data. We could alternatively just comment out this member of the drflac_ogg_page_header structure, but I + like to have it map to the structure of the underlying data. + */ + pHeader->capturePattern[0] = 'O'; + pHeader->capturePattern[1] = 'g'; + pHeader->capturePattern[2] = 'g'; + pHeader->capturePattern[3] = 'S'; + + pHeader->structureVersion = data[0]; + pHeader->headerType = data[1]; + DRFLAC_COPY_MEMORY(&pHeader->granulePosition, &data[ 2], 8); + DRFLAC_COPY_MEMORY(&pHeader->serialNumber, &data[10], 4); + DRFLAC_COPY_MEMORY(&pHeader->sequenceNumber, &data[14], 4); + DRFLAC_COPY_MEMORY(&pHeader->checksum, &data[18], 4); + pHeader->segmentCount = data[22]; + + /* Calculate the CRC. Note that for the calculation the checksum part of the page needs to be set to 0. */ + data[18] = 0; + data[19] = 0; + data[20] = 0; + data[21] = 0; + + for (i = 0; i < 23; ++i) { + *pCRC32 = drflac_crc32_byte(*pCRC32, data[i]); + } + + + if (onRead(pUserData, pHeader->segmentTable, pHeader->segmentCount) != pHeader->segmentCount) { + return DRFLAC_AT_END; + } + *pBytesRead += pHeader->segmentCount; + + for (i = 0; i < pHeader->segmentCount; ++i) { + *pCRC32 = drflac_crc32_byte(*pCRC32, pHeader->segmentTable[i]); + } + + return DRFLAC_SUCCESS; +} + +static drflac_result drflac_ogg__read_page_header(drflac_read_proc onRead, void* pUserData, drflac_ogg_page_header* pHeader, drflac_uint32* pBytesRead, drflac_uint32* pCRC32) +{ + drflac_uint8 id[4]; + + *pBytesRead = 0; + + if (onRead(pUserData, id, 4) != 4) { + return DRFLAC_AT_END; + } + *pBytesRead += 4; + + /* We need to read byte-by-byte until we find the OggS capture pattern. */ + for (;;) { + if (drflac_ogg__is_capture_pattern(id)) { + drflac_result result; + + *pCRC32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + + result = drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, pHeader, pBytesRead, pCRC32); + if (result == DRFLAC_SUCCESS) { + return DRFLAC_SUCCESS; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; + } else { + return result; + } + } + } else { + /* The first 4 bytes did not equal the capture pattern. Read the next byte and try again. */ + id[0] = id[1]; + id[1] = id[2]; + id[2] = id[3]; + if (onRead(pUserData, &id[3], 1) != 1) { + return DRFLAC_AT_END; + } + *pBytesRead += 1; + } + } +} + + +/* +The main part of the Ogg encapsulation is the conversion from the physical Ogg bitstream to the native FLAC bitstream. It works +in three general stages: Ogg Physical Bitstream -> Ogg/FLAC Logical Bitstream -> FLAC Native Bitstream. dr_flac is designed +in such a way that the core sections assume everything is delivered in native format. Therefore, for each encapsulation type +dr_flac is supporting there needs to be a layer sitting on top of the onRead and onSeek callbacks that ensures the bits read from +the physical Ogg bitstream are converted and delivered in native FLAC format. +*/ +typedef struct +{ + drflac_read_proc onRead; /* The original onRead callback from drflac_open() and family. */ + drflac_seek_proc onSeek; /* The original onSeek callback from drflac_open() and family. */ + drflac_tell_proc onTell; /* The original onTell callback from drflac_open() and family. */ + void* pUserData; /* The user data passed on onRead and onSeek. This is the user data that was passed on drflac_open() and family. */ + drflac_uint64 currentBytePos; /* The position of the byte we are sitting on in the physical byte stream. Used for efficient seeking. */ + drflac_uint64 firstBytePos; /* The position of the first byte in the physical bitstream. Points to the start of the "OggS" identifier of the FLAC bos page. */ + drflac_uint32 serialNumber; /* The serial number of the FLAC audio pages. This is determined by the initial header page that was read during initialization. */ + drflac_ogg_page_header bosPageHeader; /* Used for seeking. */ + drflac_ogg_page_header currentPageHeader; + drflac_uint32 bytesRemainingInPage; + drflac_uint32 pageDataSize; + drflac_uint8 pageData[DRFLAC_OGG_MAX_PAGE_SIZE]; +} drflac_oggbs; /* oggbs = Ogg Bitstream */ + +static size_t drflac_oggbs__read_physical(drflac_oggbs* oggbs, void* bufferOut, size_t bytesToRead) +{ + size_t bytesActuallyRead = oggbs->onRead(oggbs->pUserData, bufferOut, bytesToRead); + oggbs->currentBytePos += bytesActuallyRead; + + return bytesActuallyRead; +} + +static drflac_bool32 drflac_oggbs__seek_physical(drflac_oggbs* oggbs, drflac_uint64 offset, drflac_seek_origin origin) +{ + if (origin == DRFLAC_SEEK_SET) { + if (offset <= 0x7FFFFFFF) { + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_SET)) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos = offset; + + return DRFLAC_TRUE; + } else { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_SET)) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos = offset; + + return drflac_oggbs__seek_physical(oggbs, offset - 0x7FFFFFFF, DRFLAC_SEEK_CUR); + } + } else { + while (offset > 0x7FFFFFFF) { + if (!oggbs->onSeek(oggbs->pUserData, 0x7FFFFFFF, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos += 0x7FFFFFFF; + offset -= 0x7FFFFFFF; + } + + if (!oggbs->onSeek(oggbs->pUserData, (int)offset, DRFLAC_SEEK_CUR)) { /* <-- Safe cast thanks to the loop above. */ + return DRFLAC_FALSE; + } + oggbs->currentBytePos += offset; + + return DRFLAC_TRUE; + } +} + +static drflac_bool32 drflac_oggbs__goto_next_page(drflac_oggbs* oggbs, drflac_ogg_crc_mismatch_recovery recoveryMethod) +{ + drflac_ogg_page_header header; + for (;;) { + drflac_uint32 crc32 = 0; + drflac_uint32 bytesRead; + drflac_uint32 pageBodySize; +#ifndef DR_FLAC_NO_CRC + drflac_uint32 actualCRC32; +#endif + + if (drflac_ogg__read_page_header(oggbs->onRead, oggbs->pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; + } + oggbs->currentBytePos += bytesRead; + + pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize > DRFLAC_OGG_MAX_PAGE_SIZE) { + continue; /* Invalid page size. Assume it's corrupted and just move to the next page. */ + } + + if (header.serialNumber != oggbs->serialNumber) { + /* It's not a FLAC page. Skip it. */ + if (pageBodySize > 0 && !drflac_oggbs__seek_physical(oggbs, pageBodySize, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + continue; + } + + + /* We need to read the entire page and then do a CRC check on it. If there's a CRC mismatch we need to skip this page. */ + if (drflac_oggbs__read_physical(oggbs, oggbs->pageData, pageBodySize) != pageBodySize) { + return DRFLAC_FALSE; + } + oggbs->pageDataSize = pageBodySize; + +#ifndef DR_FLAC_NO_CRC + actualCRC32 = drflac_crc32_buffer(crc32, oggbs->pageData, oggbs->pageDataSize); + if (actualCRC32 != header.checksum) { + if (recoveryMethod == drflac_ogg_recover_on_crc_mismatch) { + continue; /* CRC mismatch. Skip this page. */ + } else { + /* + Even though we are failing on a CRC mismatch, we still want our stream to be in a good state. Therefore we + go to the next valid page to ensure we're in a good state, but return false to let the caller know that the + seek did not fully complete. + */ + drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch); + return DRFLAC_FALSE; + } + } +#else + (void)recoveryMethod; /* <-- Silence a warning. */ +#endif + + oggbs->currentPageHeader = header; + oggbs->bytesRemainingInPage = pageBodySize; + return DRFLAC_TRUE; + } +} + +/* Function below is unused at the moment, but I might be re-adding it later. */ +#if 0 +static drflac_uint8 drflac_oggbs__get_current_segment_index(drflac_oggbs* oggbs, drflac_uint8* pBytesRemainingInSeg) +{ + drflac_uint32 bytesConsumedInPage = drflac_ogg__get_page_body_size(&oggbs->currentPageHeader) - oggbs->bytesRemainingInPage; + drflac_uint8 iSeg = 0; + drflac_uint32 iByte = 0; + while (iByte < bytesConsumedInPage) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + if (iByte + segmentSize > bytesConsumedInPage) { + break; + } else { + iSeg += 1; + iByte += segmentSize; + } + } + + *pBytesRemainingInSeg = oggbs->currentPageHeader.segmentTable[iSeg] - (drflac_uint8)(bytesConsumedInPage - iByte); + return iSeg; +} + +static drflac_bool32 drflac_oggbs__seek_to_next_packet(drflac_oggbs* oggbs) +{ + /* The current packet ends when we get to the segment with a lacing value of < 255 which is not at the end of a page. */ + for (;;) { + drflac_bool32 atEndOfPage = DRFLAC_FALSE; + + drflac_uint8 bytesRemainingInSeg; + drflac_uint8 iFirstSeg = drflac_oggbs__get_current_segment_index(oggbs, &bytesRemainingInSeg); + + drflac_uint32 bytesToEndOfPacketOrPage = bytesRemainingInSeg; + for (drflac_uint8 iSeg = iFirstSeg; iSeg < oggbs->currentPageHeader.segmentCount; ++iSeg) { + drflac_uint8 segmentSize = oggbs->currentPageHeader.segmentTable[iSeg]; + if (segmentSize < 255) { + if (iSeg == oggbs->currentPageHeader.segmentCount-1) { + atEndOfPage = DRFLAC_TRUE; + } + + break; + } + + bytesToEndOfPacketOrPage += segmentSize; + } + + /* + At this point we will have found either the packet or the end of the page. If were at the end of the page we'll + want to load the next page and keep searching for the end of the packet. + */ + drflac_oggbs__seek_physical(oggbs, bytesToEndOfPacketOrPage, DRFLAC_SEEK_CUR); + oggbs->bytesRemainingInPage -= bytesToEndOfPacketOrPage; + + if (atEndOfPage) { + /* + We're potentially at the next packet, but we need to check the next page first to be sure because the packet may + straddle pages. + */ + if (!drflac_oggbs__goto_next_page(oggbs)) { + return DRFLAC_FALSE; + } + + /* If it's a fresh packet it most likely means we're at the next packet. */ + if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { + return DRFLAC_TRUE; + } + } else { + /* We're at the next packet. */ + return DRFLAC_TRUE; + } + } +} + +static drflac_bool32 drflac_oggbs__seek_to_next_frame(drflac_oggbs* oggbs) +{ + /* The bitstream should be sitting on the first byte just after the header of the frame. */ + + /* What we're actually doing here is seeking to the start of the next packet. */ + return drflac_oggbs__seek_to_next_packet(oggbs); +} +#endif + +static size_t drflac__on_read_ogg(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; + drflac_uint8* pRunningBufferOut = (drflac_uint8*)bufferOut; + size_t bytesRead = 0; + + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(pRunningBufferOut != NULL); + + /* Reading is done page-by-page. If we've run out of bytes in the page we need to move to the next one. */ + while (bytesRead < bytesToRead) { + size_t bytesRemainingToRead = bytesToRead - bytesRead; + + if (oggbs->bytesRemainingInPage >= bytesRemainingToRead) { + DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), bytesRemainingToRead); + bytesRead += bytesRemainingToRead; + oggbs->bytesRemainingInPage -= (drflac_uint32)bytesRemainingToRead; + break; + } + + /* If we get here it means some of the requested data is contained in the next pages. */ + if (oggbs->bytesRemainingInPage > 0) { + DRFLAC_COPY_MEMORY(pRunningBufferOut, oggbs->pageData + (oggbs->pageDataSize - oggbs->bytesRemainingInPage), oggbs->bytesRemainingInPage); + bytesRead += oggbs->bytesRemainingInPage; + pRunningBufferOut += oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + + DRFLAC_ASSERT(bytesRemainingToRead > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + break; /* Failed to go to the next page. Might have simply hit the end of the stream. */ + } + } + + return bytesRead; +} + +static drflac_bool32 drflac__on_seek_ogg(void* pUserData, int offset, drflac_seek_origin origin) +{ + drflac_oggbs* oggbs = (drflac_oggbs*)pUserData; + int bytesSeeked = 0; + + DRFLAC_ASSERT(oggbs != NULL); + DRFLAC_ASSERT(offset >= 0); /* <-- Never seek backwards. */ + + /* Seeking is always forward which makes things a lot simpler. */ + if (origin == DRFLAC_SEEK_SET) { + if (!drflac_oggbs__seek_physical(oggbs, (int)oggbs->firstBytePos, DRFLAC_SEEK_SET)) { + return DRFLAC_FALSE; + } + + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + return DRFLAC_FALSE; + } + + return drflac__on_seek_ogg(pUserData, offset, DRFLAC_SEEK_CUR); + } else if (origin == DRFLAC_SEEK_CUR) { + while (bytesSeeked < offset) { + int bytesRemainingToSeek = offset - bytesSeeked; + DRFLAC_ASSERT(bytesRemainingToSeek >= 0); + + if (oggbs->bytesRemainingInPage >= (size_t)bytesRemainingToSeek) { + bytesSeeked += bytesRemainingToSeek; + (void)bytesSeeked; /* <-- Silence a dead store warning emitted by Clang Static Analyzer. */ + oggbs->bytesRemainingInPage -= bytesRemainingToSeek; + break; + } + + /* If we get here it means some of the requested data is contained in the next pages. */ + if (oggbs->bytesRemainingInPage > 0) { + bytesSeeked += (int)oggbs->bytesRemainingInPage; + oggbs->bytesRemainingInPage = 0; + } + + DRFLAC_ASSERT(bytesRemainingToSeek > 0); + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_fail_on_crc_mismatch)) { + /* Failed to go to the next page. We either hit the end of the stream or had a CRC mismatch. */ + return DRFLAC_FALSE; + } + } + } else if (origin == DRFLAC_SEEK_END) { + /* Seeking to the end is not supported. */ + return DRFLAC_FALSE; + } + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__on_tell_ogg(void* pUserData, drflac_int64* pCursor) +{ + /* + Not implemented for Ogg containers because we don't currently track the byte position of the logical bitstream. To support this, we'll need + to track the position in drflac__on_read_ogg and drflac__on_seek_ogg. + */ + (void)pUserData; + (void)pCursor; + return DRFLAC_FALSE; +} + + +static drflac_bool32 drflac_ogg__seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + drflac_uint64 originalBytePos; + drflac_uint64 runningGranulePosition; + drflac_uint64 runningFrameBytePos; + drflac_uint64 runningPCMFrameCount; + + DRFLAC_ASSERT(oggbs != NULL); + + originalBytePos = oggbs->currentBytePos; /* For recovery. Points to the OggS identifier. */ + + /* First seek to the first frame. */ + if (!drflac__seek_to_byte(&pFlac->bs, pFlac->firstFLACFramePosInBytes)) { + return DRFLAC_FALSE; + } + oggbs->bytesRemainingInPage = 0; + + runningGranulePosition = 0; + for (;;) { + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + drflac_oggbs__seek_physical(oggbs, originalBytePos, DRFLAC_SEEK_SET); + return DRFLAC_FALSE; /* Never did find that sample... */ + } + + runningFrameBytePos = oggbs->currentBytePos - drflac_ogg__get_page_header_size(&oggbs->currentPageHeader) - oggbs->pageDataSize; + if (oggbs->currentPageHeader.granulePosition >= pcmFrameIndex) { + break; /* The sample is somewhere in the previous page. */ + } + + /* + At this point we know the sample is not in the previous page. It could possibly be in this page. For simplicity we + disregard any pages that do not begin a fresh packet. + */ + if ((oggbs->currentPageHeader.headerType & 0x01) == 0) { /* <-- Is it a fresh page? */ + if (oggbs->currentPageHeader.segmentTable[0] >= 2) { + drflac_uint8 firstBytesInPage[2]; + firstBytesInPage[0] = oggbs->pageData[0]; + firstBytesInPage[1] = oggbs->pageData[1]; + + if ((firstBytesInPage[0] == 0xFF) && (firstBytesInPage[1] & 0xFC) == 0xF8) { /* <-- Does the page begin with a frame's sync code? */ + runningGranulePosition = oggbs->currentPageHeader.granulePosition; + } + + continue; + } + } + } + + /* + We found the page that that is closest to the sample, so now we need to find it. The first thing to do is seek to the + start of that page. In the loop above we checked that it was a fresh page which means this page is also the start of + a new frame. This property means that after we've seeked to the page we can immediately start looping over frames until + we find the one containing the target sample. + */ + if (!drflac_oggbs__seek_physical(oggbs, runningFrameBytePos, DRFLAC_SEEK_SET)) { + return DRFLAC_FALSE; + } + if (!drflac_oggbs__goto_next_page(oggbs, drflac_ogg_recover_on_crc_mismatch)) { + return DRFLAC_FALSE; + } + + /* + At this point we'll be sitting on the first byte of the frame header of the first frame in the page. We just keep + looping over these frames until we find the one containing the sample we're after. + */ + runningPCMFrameCount = runningGranulePosition; + for (;;) { + /* + There are two ways to find the sample and seek past irrelevant frames: + 1) Use the native FLAC decoder. + 2) Use Ogg's framing system. + + Both of these options have their own pros and cons. Using the native FLAC decoder is slower because it needs to + do a full decode of the frame. Using Ogg's framing system is faster, but more complicated and involves some code + duplication for the decoding of frame headers. + + Another thing to consider is that using the Ogg framing system will perform direct seeking of the physical Ogg + bitstream. This is important to consider because it means we cannot read data from the drflac_bs object using the + standard drflac__*() APIs because that will read in extra data for its own internal caching which in turn breaks + the positioning of the read pointer of the physical Ogg bitstream. Therefore, anything that would normally be read + using the native FLAC decoding APIs, such as drflac__read_next_flac_frame_header(), need to be re-implemented so as to + avoid the use of the drflac_bs object. + + Considering these issues, I have decided to use the slower native FLAC decoding method for the following reasons: + 1) Seeking is already partially accelerated using Ogg's paging system in the code block above. + 2) Seeking in an Ogg encapsulated FLAC stream is probably quite uncommon. + 3) Simplicity. + */ + drflac_uint64 firstPCMFrameInFLACFrame = 0; + drflac_uint64 lastPCMFrameInFLACFrame = 0; + drflac_uint64 pcmFrameCountInThisFrame; + + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + return DRFLAC_FALSE; + } + + drflac__get_pcm_frame_range_of_current_flac_frame(pFlac, &firstPCMFrameInFLACFrame, &lastPCMFrameInFLACFrame); + + pcmFrameCountInThisFrame = (lastPCMFrameInFLACFrame - firstPCMFrameInFLACFrame) + 1; + + /* If we are seeking to the end of the file and we've just hit it, we're done. */ + if (pcmFrameIndex == pFlac->totalPCMFrameCount && (runningPCMFrameCount + pcmFrameCountInThisFrame) == pFlac->totalPCMFrameCount) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + pFlac->currentPCMFrame = pcmFrameIndex; + pFlac->currentFLACFrame.pcmFramesRemaining = 0; + return DRFLAC_TRUE; + } else { + return DRFLAC_FALSE; + } + } + + if (pcmFrameIndex < (runningPCMFrameCount + pcmFrameCountInThisFrame)) { + /* + The sample should be in this FLAC frame. We need to fully decode it, however if it's an invalid frame (a CRC mismatch), we need to pretend + it never existed and keep iterating. + */ + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + /* The frame is valid. We just need to skip over some samples to ensure it's sample-exact. */ + drflac_uint64 pcmFramesToDecode = (size_t)(pcmFrameIndex - runningPCMFrameCount); /* <-- Safe cast because the maximum number of samples in a frame is 65535. */ + if (pcmFramesToDecode == 0) { + return DRFLAC_TRUE; + } + + pFlac->currentPCMFrame = runningPCMFrameCount; + + return drflac__seek_forward_by_pcm_frames(pFlac, pcmFramesToDecode) == pcmFramesToDecode; /* <-- If this fails, something bad has happened (it should never fail). */ + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } else { + /* + It's not in this frame. We need to seek past the frame, but check if there was a CRC mismatch. If so, we pretend this + frame never existed and leave the running sample count untouched. + */ + drflac_result result = drflac__seek_to_next_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + runningPCMFrameCount += pcmFrameCountInThisFrame; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + continue; /* CRC mismatch. Pretend this frame never existed. */ + } else { + return DRFLAC_FALSE; + } + } + } + } +} + + + +static drflac_bool32 drflac__init_private__ogg(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_meta_proc onMeta, void* pUserData, void* pUserDataMD, drflac_bool32 relaxed) +{ + drflac_ogg_page_header header; + drflac_uint32 crc32 = DRFLAC_OGG_CAPTURE_PATTERN_CRC32; + drflac_uint32 bytesRead = 0; + + /* Pre Condition: The bit stream should be sitting just past the 4-byte OggS capture pattern. */ + (void)relaxed; + + pInit->container = drflac_container_ogg; + pInit->oggFirstBytePos = 0; + + /* + We'll get here if the first 4 bytes of the stream were the OggS capture pattern, however it doesn't necessarily mean the + stream includes FLAC encoded audio. To check for this we need to scan the beginning-of-stream page markers and check if + any match the FLAC specification. Important to keep in mind that the stream may be multiplexed. + */ + if (drflac_ogg__read_page_header_after_capture_pattern(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; + } + pInit->runningFilePos += bytesRead; + + for (;;) { + int pageBodySize; + + /* Break if we're past the beginning of stream page. */ + if ((header.headerType & 0x02) == 0) { + return DRFLAC_FALSE; + } + + /* Check if it's a FLAC header. */ + pageBodySize = drflac_ogg__get_page_body_size(&header); + if (pageBodySize == 51) { /* 51 = the lacing value of the FLAC header packet. */ + /* It could be a FLAC page... */ + drflac_uint32 bytesRemainingInPage = pageBodySize; + drflac_uint8 packetType; + + if (onRead(pUserData, &packetType, 1) != 1) { + return DRFLAC_FALSE; + } + + bytesRemainingInPage -= 1; + if (packetType == 0x7F) { + /* Increasingly more likely to be a FLAC page... */ + drflac_uint8 sig[4]; + if (onRead(pUserData, sig, 4) != 4) { + return DRFLAC_FALSE; + } + + bytesRemainingInPage -= 4; + if (sig[0] == 'F' && sig[1] == 'L' && sig[2] == 'A' && sig[3] == 'C') { + /* Almost certainly a FLAC page... */ + drflac_uint8 mappingVersion[2]; + if (onRead(pUserData, mappingVersion, 2) != 2) { + return DRFLAC_FALSE; + } + + if (mappingVersion[0] != 1) { + return DRFLAC_FALSE; /* Only supporting version 1.x of the Ogg mapping. */ + } + + /* + The next 2 bytes are the non-audio packets, not including this one. We don't care about this because we're going to + be handling it in a generic way based on the serial number and packet types. + */ + if (!onSeek(pUserData, 2, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + + /* Expecting the native FLAC signature "fLaC". */ + if (onRead(pUserData, sig, 4) != 4) { + return DRFLAC_FALSE; + } + + if (sig[0] == 'f' && sig[1] == 'L' && sig[2] == 'a' && sig[3] == 'C') { + /* The remaining data in the page should be the STREAMINFO block. */ + drflac_streaminfo streaminfo; + drflac_uint8 isLastBlock; + drflac_uint8 blockType; + drflac_uint32 blockSize; + if (!drflac__read_and_decode_block_header(onRead, pUserData, &isLastBlock, &blockType, &blockSize)) { + return DRFLAC_FALSE; + } + + if (blockType != DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO || blockSize != 34) { + return DRFLAC_FALSE; /* Invalid block type. First block must be the STREAMINFO block. */ + } + + if (drflac__read_streaminfo(onRead, pUserData, &streaminfo)) { + /* Success! */ + pInit->hasStreamInfoBlock = DRFLAC_TRUE; + pInit->sampleRate = streaminfo.sampleRate; + pInit->channels = streaminfo.channels; + pInit->bitsPerSample = streaminfo.bitsPerSample; + pInit->totalPCMFrameCount = streaminfo.totalPCMFrameCount; + pInit->maxBlockSizeInPCMFrames = streaminfo.maxBlockSizeInPCMFrames; + pInit->hasMetadataBlocks = !isLastBlock; + + if (onMeta) { + drflac_metadata metadata; + metadata.type = DRFLAC_METADATA_BLOCK_TYPE_STREAMINFO; + metadata.pRawData = NULL; + metadata.rawDataSize = 0; + metadata.data.streaminfo = streaminfo; + onMeta(pUserDataMD, &metadata); + } + + pInit->runningFilePos += pageBodySize; + pInit->oggFirstBytePos = pInit->runningFilePos - 79; /* Subtracting 79 will place us right on top of the "OggS" identifier of the FLAC bos page. */ + pInit->oggSerial = header.serialNumber; + pInit->oggBosHeader = header; + break; + } else { + /* Failed to read STREAMINFO block. Aww, so close... */ + return DRFLAC_FALSE; + } + } else { + /* Invalid file. */ + return DRFLAC_FALSE; + } + } else { + /* Not a FLAC header. Skip it. */ + if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + } + } else { + /* Not a FLAC header. Seek past the entire page and move on to the next. */ + if (!onSeek(pUserData, bytesRemainingInPage, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + } + } else { + if (!onSeek(pUserData, pageBodySize, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; + } + } + + pInit->runningFilePos += pageBodySize; + + + /* Read the header of the next page. */ + if (drflac_ogg__read_page_header(onRead, pUserData, &header, &bytesRead, &crc32) != DRFLAC_SUCCESS) { + return DRFLAC_FALSE; + } + pInit->runningFilePos += bytesRead; + } + + /* + If we get here it means we found a FLAC audio stream. We should be sitting on the first byte of the header of the next page. The next + packets in the FLAC logical stream contain the metadata. The only thing left to do in the initialization phase for Ogg is to create the + Ogg bistream object. + */ + pInit->hasMetadataBlocks = DRFLAC_TRUE; /* <-- Always have at least VORBIS_COMMENT metadata block. */ + return DRFLAC_TRUE; +} +#endif + +static drflac_bool32 drflac__init_private(drflac_init_info* pInit, drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD) +{ + drflac_bool32 relaxed; + drflac_uint8 id[4]; + + if (pInit == NULL || onRead == NULL || onSeek == NULL) { /* <-- onTell is optional. */ + return DRFLAC_FALSE; + } + + DRFLAC_ZERO_MEMORY(pInit, sizeof(*pInit)); + pInit->onRead = onRead; + pInit->onSeek = onSeek; + pInit->onTell = onTell; + pInit->onMeta = onMeta; + pInit->container = container; + pInit->pUserData = pUserData; + pInit->pUserDataMD = pUserDataMD; + + pInit->bs.onRead = onRead; + pInit->bs.onSeek = onSeek; + pInit->bs.onTell = onTell; + pInit->bs.pUserData = pUserData; + drflac__reset_cache(&pInit->bs); + + + /* If the container is explicitly defined then we can try opening in relaxed mode. */ + relaxed = container != drflac_container_unknown; + + /* Skip over any ID3 tags. */ + for (;;) { + if (onRead(pUserData, id, 4) != 4) { + return DRFLAC_FALSE; /* Ran out of data. */ + } + pInit->runningFilePos += 4; + + if (id[0] == 'I' && id[1] == 'D' && id[2] == '3') { + drflac_uint8 header[6]; + drflac_uint8 flags; + drflac_uint32 headerSize; + + if (onRead(pUserData, header, 6) != 6) { + return DRFLAC_FALSE; /* Ran out of data. */ + } + pInit->runningFilePos += 6; + + flags = header[1]; + + DRFLAC_COPY_MEMORY(&headerSize, header+2, 4); + headerSize = drflac__unsynchsafe_32(drflac__be2host_32(headerSize)); + if (flags & 0x10) { + headerSize += 10; + } + + if (!onSeek(pUserData, headerSize, DRFLAC_SEEK_CUR)) { + return DRFLAC_FALSE; /* Failed to seek past the tag. */ + } + pInit->runningFilePos += headerSize; + } else { + break; + } + } + + if (id[0] == 'f' && id[1] == 'L' && id[2] == 'a' && id[3] == 'C') { + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#ifndef DR_FLAC_NO_OGG + if (id[0] == 'O' && id[1] == 'g' && id[2] == 'g' && id[3] == 'S') { + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#endif + + /* If we get here it means we likely don't have a header. Try opening in relaxed mode, if applicable. */ + if (relaxed) { + if (container == drflac_container_native) { + return drflac__init_private__native(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#ifndef DR_FLAC_NO_OGG + if (container == drflac_container_ogg) { + return drflac__init_private__ogg(pInit, onRead, onSeek, onMeta, pUserData, pUserDataMD, relaxed); + } +#endif + } + + /* Unsupported container. */ + return DRFLAC_FALSE; +} + +static void drflac__init_from_info(drflac* pFlac, const drflac_init_info* pInit) +{ + DRFLAC_ASSERT(pFlac != NULL); + DRFLAC_ASSERT(pInit != NULL); + + DRFLAC_ZERO_MEMORY(pFlac, sizeof(*pFlac)); + pFlac->bs = pInit->bs; + pFlac->onMeta = pInit->onMeta; + pFlac->pUserDataMD = pInit->pUserDataMD; + pFlac->maxBlockSizeInPCMFrames = pInit->maxBlockSizeInPCMFrames; + pFlac->sampleRate = pInit->sampleRate; + pFlac->channels = (drflac_uint8)pInit->channels; + pFlac->bitsPerSample = (drflac_uint8)pInit->bitsPerSample; + pFlac->totalPCMFrameCount = pInit->totalPCMFrameCount; + pFlac->container = pInit->container; +} + + +static drflac* drflac_open_with_metadata_private(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, void* pUserDataMD, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac_init_info init; + drflac_uint32 allocationSize; + drflac_uint32 wholeSIMDVectorCountPerChannel; + drflac_uint32 decodedSamplesAllocationSize; +#ifndef DR_FLAC_NO_OGG + drflac_oggbs* pOggbs = NULL; +#endif + drflac_uint64 firstFramePos; + drflac_uint64 seektablePos; + drflac_uint32 seekpointCount; + drflac_allocation_callbacks allocationCallbacks; + drflac* pFlac; + + /* CPU support first. */ + drflac__init_cpu_caps(); + + if (!drflac__init_private(&init, onRead, onSeek, onTell, onMeta, container, pUserData, pUserDataMD)) { + return NULL; + } + + if (pAllocationCallbacks != NULL) { + allocationCallbacks = *pAllocationCallbacks; + if (allocationCallbacks.onFree == NULL || (allocationCallbacks.onMalloc == NULL && allocationCallbacks.onRealloc == NULL)) { + return NULL; /* Invalid allocation callbacks. */ + } + } else { + allocationCallbacks.pUserData = NULL; + allocationCallbacks.onMalloc = drflac__malloc_default; + allocationCallbacks.onRealloc = drflac__realloc_default; + allocationCallbacks.onFree = drflac__free_default; + } + + + /* + The size of the allocation for the drflac object needs to be large enough to fit the following: + 1) The main members of the drflac structure + 2) A block of memory large enough to store the decoded samples of the largest frame in the stream + 3) If the container is Ogg, a drflac_oggbs object + + The complicated part of the allocation is making sure there's enough room the decoded samples, taking into consideration + the different SIMD instruction sets. + */ + allocationSize = sizeof(drflac); + + /* + The allocation size for decoded frames depends on the number of 32-bit integers that fit inside the largest SIMD vector + we are supporting. + */ + if ((init.maxBlockSizeInPCMFrames % (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) == 0) { + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))); + } else { + wholeSIMDVectorCountPerChannel = (init.maxBlockSizeInPCMFrames / (DRFLAC_MAX_SIMD_VECTOR_SIZE / sizeof(drflac_int32))) + 1; + } + + decodedSamplesAllocationSize = wholeSIMDVectorCountPerChannel * DRFLAC_MAX_SIMD_VECTOR_SIZE * init.channels; + + allocationSize += decodedSamplesAllocationSize; + allocationSize += DRFLAC_MAX_SIMD_VECTOR_SIZE; /* Allocate extra bytes to ensure we have enough for alignment. */ + +#ifndef DR_FLAC_NO_OGG + /* There's additional data required for Ogg streams. */ + if (init.container == drflac_container_ogg) { + allocationSize += sizeof(drflac_oggbs); + + pOggbs = (drflac_oggbs*)drflac__malloc_from_callbacks(sizeof(*pOggbs), &allocationCallbacks); + if (pOggbs == NULL) { + return NULL; /*DRFLAC_OUT_OF_MEMORY;*/ + } + + DRFLAC_ZERO_MEMORY(pOggbs, sizeof(*pOggbs)); + pOggbs->onRead = onRead; + pOggbs->onSeek = onSeek; + pOggbs->onTell = onTell; + pOggbs->pUserData = pUserData; + pOggbs->currentBytePos = init.oggFirstBytePos; + pOggbs->firstBytePos = init.oggFirstBytePos; + pOggbs->serialNumber = init.oggSerial; + pOggbs->bosPageHeader = init.oggBosHeader; + pOggbs->bytesRemainingInPage = 0; + } +#endif + + /* + This part is a bit awkward. We need to load the seektable so that it can be referenced in-memory, but I want the drflac object to + consist of only a single heap allocation. To this, the size of the seek table needs to be known, which we determine when reading + and decoding the metadata. + */ + firstFramePos = 42; /* <-- We know we are at byte 42 at this point. */ + seektablePos = 0; + seekpointCount = 0; + if (init.hasMetadataBlocks) { + drflac_read_proc onReadOverride = onRead; + drflac_seek_proc onSeekOverride = onSeek; + drflac_tell_proc onTellOverride = onTell; + void* pUserDataOverride = pUserData; + +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + onReadOverride = drflac__on_read_ogg; + onSeekOverride = drflac__on_seek_ogg; + onTellOverride = drflac__on_tell_ogg; + pUserDataOverride = (void*)pOggbs; + } +#endif + + if (!drflac__read_and_decode_metadata(onReadOverride, onSeekOverride, onTellOverride, onMeta, pUserDataOverride, pUserDataMD, &firstFramePos, &seektablePos, &seekpointCount, &allocationCallbacks)) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif + return NULL; + } + + if ((0xFFFFFFFF - (seekpointCount * sizeof(drflac_seekpoint))) < allocationSize) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif + return NULL; + } + + allocationSize += seekpointCount * sizeof(drflac_seekpoint); + } + + pFlac = (drflac*)drflac__malloc_from_callbacks((size_t)allocationSize, &allocationCallbacks); + if (pFlac == NULL) { + #ifndef DR_FLAC_NO_OGG + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + #endif + return NULL; + } + + drflac__init_from_info(pFlac, &init); + pFlac->allocationCallbacks = allocationCallbacks; + pFlac->pDecodedSamples = (drflac_int32*)drflac_align((size_t)pFlac->pExtraData, DRFLAC_MAX_SIMD_VECTOR_SIZE); + +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) { + drflac_oggbs* pInternalOggbs = (drflac_oggbs*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize + (seekpointCount * sizeof(drflac_seekpoint))); + DRFLAC_COPY_MEMORY(pInternalOggbs, pOggbs, sizeof(*pOggbs)); + + /* At this point the pOggbs object has been handed over to pInternalOggbs and can be freed. */ + drflac__free_from_callbacks(pOggbs, &allocationCallbacks); + pOggbs = NULL; + + /* The Ogg bistream needs to be layered on top of the original bitstream. */ + pFlac->bs.onRead = drflac__on_read_ogg; + pFlac->bs.onSeek = drflac__on_seek_ogg; + pFlac->bs.onTell = drflac__on_tell_ogg; + pFlac->bs.pUserData = (void*)pInternalOggbs; + pFlac->_oggbs = (void*)pInternalOggbs; + } +#endif + + pFlac->firstFLACFramePosInBytes = firstFramePos; + + /* NOTE: Seektables are not currently compatible with Ogg encapsulation (Ogg has its own accelerated seeking system). I may change this later, so I'm leaving this here for now. */ +#ifndef DR_FLAC_NO_OGG + if (init.container == drflac_container_ogg) + { + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + else +#endif + { + /* If we have a seektable we need to load it now, making sure we move back to where we were previously. */ + if (seektablePos != 0) { + pFlac->seekpointCount = seekpointCount; + pFlac->pSeekpoints = (drflac_seekpoint*)((drflac_uint8*)pFlac->pDecodedSamples + decodedSamplesAllocationSize); + + DRFLAC_ASSERT(pFlac->bs.onSeek != NULL); + DRFLAC_ASSERT(pFlac->bs.onRead != NULL); + + /* Seek to the seektable, then just read directly into our seektable buffer. */ + if (pFlac->bs.onSeek(pFlac->bs.pUserData, (int)seektablePos, DRFLAC_SEEK_SET)) { + drflac_uint32 iSeekpoint; + + for (iSeekpoint = 0; iSeekpoint < seekpointCount; iSeekpoint += 1) { + if (pFlac->bs.onRead(pFlac->bs.pUserData, pFlac->pSeekpoints + iSeekpoint, DRFLAC_SEEKPOINT_SIZE_IN_BYTES) == DRFLAC_SEEKPOINT_SIZE_IN_BYTES) { + /* Endian swap. */ + pFlac->pSeekpoints[iSeekpoint].firstPCMFrame = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].firstPCMFrame); + pFlac->pSeekpoints[iSeekpoint].flacFrameOffset = drflac__be2host_64(pFlac->pSeekpoints[iSeekpoint].flacFrameOffset); + pFlac->pSeekpoints[iSeekpoint].pcmFrameCount = drflac__be2host_16(pFlac->pSeekpoints[iSeekpoint].pcmFrameCount); + } else { + /* Failed to read the seektable. Pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + break; + } + } + + /* We need to seek back to where we were. If this fails it's a critical error. */ + if (!pFlac->bs.onSeek(pFlac->bs.pUserData, (int)pFlac->firstFLACFramePosInBytes, DRFLAC_SEEK_SET)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } else { + /* Failed to seek to the seektable. Ominous sign, but for now we can just pretend we don't have one. */ + pFlac->pSeekpoints = NULL; + pFlac->seekpointCount = 0; + } + } + } + + + /* + If we get here, but don't have a STREAMINFO block, it means we've opened the stream in relaxed mode and need to decode + the first frame. + */ + if (!init.hasStreamInfoBlock) { + pFlac->currentFLACFrame.header = init.firstFrameHeader; + for (;;) { + drflac_result result = drflac__decode_flac_frame(pFlac); + if (result == DRFLAC_SUCCESS) { + break; + } else { + if (result == DRFLAC_CRC_MISMATCH) { + if (!drflac__read_next_flac_frame_header(&pFlac->bs, pFlac->bitsPerSample, &pFlac->currentFLACFrame.header)) { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + continue; + } else { + drflac__free_from_callbacks(pFlac, &allocationCallbacks); + return NULL; + } + } + } + } + + return pFlac; +} + + + +#ifndef DR_FLAC_NO_STDIO +#include +#ifndef DR_FLAC_NO_WCHAR +#include /* For wcslen(), wcsrtombs() */ +#endif + +/* Errno */ +/* drflac_result_from_errno() is only used for fopen() and wfopen() so putting it inside DR_WAV_NO_STDIO for now. If something else needs this later we can move it out. */ +#include +static drflac_result drflac_result_from_errno(int e) +{ + switch (e) + { + case 0: return DRFLAC_SUCCESS; + #ifdef EPERM + case EPERM: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef ENOENT + case ENOENT: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef ESRCH + case ESRCH: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef EINTR + case EINTR: return DRFLAC_INTERRUPT; + #endif + #ifdef EIO + case EIO: return DRFLAC_IO_ERROR; + #endif + #ifdef ENXIO + case ENXIO: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef E2BIG + case E2BIG: return DRFLAC_INVALID_ARGS; + #endif + #ifdef ENOEXEC + case ENOEXEC: return DRFLAC_INVALID_FILE; + #endif + #ifdef EBADF + case EBADF: return DRFLAC_INVALID_FILE; + #endif + #ifdef ECHILD + case ECHILD: return DRFLAC_ERROR; + #endif + #ifdef EAGAIN + case EAGAIN: return DRFLAC_UNAVAILABLE; + #endif + #ifdef ENOMEM + case ENOMEM: return DRFLAC_OUT_OF_MEMORY; + #endif + #ifdef EACCES + case EACCES: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef EFAULT + case EFAULT: return DRFLAC_BAD_ADDRESS; + #endif + #ifdef ENOTBLK + case ENOTBLK: return DRFLAC_ERROR; + #endif + #ifdef EBUSY + case EBUSY: return DRFLAC_BUSY; + #endif + #ifdef EEXIST + case EEXIST: return DRFLAC_ALREADY_EXISTS; + #endif + #ifdef EXDEV + case EXDEV: return DRFLAC_ERROR; + #endif + #ifdef ENODEV + case ENODEV: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef ENOTDIR + case ENOTDIR: return DRFLAC_NOT_DIRECTORY; + #endif + #ifdef EISDIR + case EISDIR: return DRFLAC_IS_DIRECTORY; + #endif + #ifdef EINVAL + case EINVAL: return DRFLAC_INVALID_ARGS; + #endif + #ifdef ENFILE + case ENFILE: return DRFLAC_TOO_MANY_OPEN_FILES; + #endif + #ifdef EMFILE + case EMFILE: return DRFLAC_TOO_MANY_OPEN_FILES; + #endif + #ifdef ENOTTY + case ENOTTY: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef ETXTBSY + case ETXTBSY: return DRFLAC_BUSY; + #endif + #ifdef EFBIG + case EFBIG: return DRFLAC_TOO_BIG; + #endif + #ifdef ENOSPC + case ENOSPC: return DRFLAC_NO_SPACE; + #endif + #ifdef ESPIPE + case ESPIPE: return DRFLAC_BAD_SEEK; + #endif + #ifdef EROFS + case EROFS: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef EMLINK + case EMLINK: return DRFLAC_TOO_MANY_LINKS; + #endif + #ifdef EPIPE + case EPIPE: return DRFLAC_BAD_PIPE; + #endif + #ifdef EDOM + case EDOM: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef ERANGE + case ERANGE: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef EDEADLK + case EDEADLK: return DRFLAC_DEADLOCK; + #endif + #ifdef ENAMETOOLONG + case ENAMETOOLONG: return DRFLAC_PATH_TOO_LONG; + #endif + #ifdef ENOLCK + case ENOLCK: return DRFLAC_ERROR; + #endif + #ifdef ENOSYS + case ENOSYS: return DRFLAC_NOT_IMPLEMENTED; + #endif + #if defined(ENOTEMPTY) && ENOTEMPTY != EEXIST /* In AIX, ENOTEMPTY and EEXIST use the same value. */ + case ENOTEMPTY: return DRFLAC_DIRECTORY_NOT_EMPTY; + #endif + #ifdef ELOOP + case ELOOP: return DRFLAC_TOO_MANY_LINKS; + #endif + #ifdef ENOMSG + case ENOMSG: return DRFLAC_NO_MESSAGE; + #endif + #ifdef EIDRM + case EIDRM: return DRFLAC_ERROR; + #endif + #ifdef ECHRNG + case ECHRNG: return DRFLAC_ERROR; + #endif + #ifdef EL2NSYNC + case EL2NSYNC: return DRFLAC_ERROR; + #endif + #ifdef EL3HLT + case EL3HLT: return DRFLAC_ERROR; + #endif + #ifdef EL3RST + case EL3RST: return DRFLAC_ERROR; + #endif + #ifdef ELNRNG + case ELNRNG: return DRFLAC_OUT_OF_RANGE; + #endif + #ifdef EUNATCH + case EUNATCH: return DRFLAC_ERROR; + #endif + #ifdef ENOCSI + case ENOCSI: return DRFLAC_ERROR; + #endif + #ifdef EL2HLT + case EL2HLT: return DRFLAC_ERROR; + #endif + #ifdef EBADE + case EBADE: return DRFLAC_ERROR; + #endif + #ifdef EBADR + case EBADR: return DRFLAC_ERROR; + #endif + #ifdef EXFULL + case EXFULL: return DRFLAC_ERROR; + #endif + #ifdef ENOANO + case ENOANO: return DRFLAC_ERROR; + #endif + #ifdef EBADRQC + case EBADRQC: return DRFLAC_ERROR; + #endif + #ifdef EBADSLT + case EBADSLT: return DRFLAC_ERROR; + #endif + #ifdef EBFONT + case EBFONT: return DRFLAC_INVALID_FILE; + #endif + #ifdef ENOSTR + case ENOSTR: return DRFLAC_ERROR; + #endif + #ifdef ENODATA + case ENODATA: return DRFLAC_NO_DATA_AVAILABLE; + #endif + #ifdef ETIME + case ETIME: return DRFLAC_TIMEOUT; + #endif + #ifdef ENOSR + case ENOSR: return DRFLAC_NO_DATA_AVAILABLE; + #endif + #ifdef ENONET + case ENONET: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENOPKG + case ENOPKG: return DRFLAC_ERROR; + #endif + #ifdef EREMOTE + case EREMOTE: return DRFLAC_ERROR; + #endif + #ifdef ENOLINK + case ENOLINK: return DRFLAC_ERROR; + #endif + #ifdef EADV + case EADV: return DRFLAC_ERROR; + #endif + #ifdef ESRMNT + case ESRMNT: return DRFLAC_ERROR; + #endif + #ifdef ECOMM + case ECOMM: return DRFLAC_ERROR; + #endif + #ifdef EPROTO + case EPROTO: return DRFLAC_ERROR; + #endif + #ifdef EMULTIHOP + case EMULTIHOP: return DRFLAC_ERROR; + #endif + #ifdef EDOTDOT + case EDOTDOT: return DRFLAC_ERROR; + #endif + #ifdef EBADMSG + case EBADMSG: return DRFLAC_BAD_MESSAGE; + #endif + #ifdef EOVERFLOW + case EOVERFLOW: return DRFLAC_TOO_BIG; + #endif + #ifdef ENOTUNIQ + case ENOTUNIQ: return DRFLAC_NOT_UNIQUE; + #endif + #ifdef EBADFD + case EBADFD: return DRFLAC_ERROR; + #endif + #ifdef EREMCHG + case EREMCHG: return DRFLAC_ERROR; + #endif + #ifdef ELIBACC + case ELIBACC: return DRFLAC_ACCESS_DENIED; + #endif + #ifdef ELIBBAD + case ELIBBAD: return DRFLAC_INVALID_FILE; + #endif + #ifdef ELIBSCN + case ELIBSCN: return DRFLAC_INVALID_FILE; + #endif + #ifdef ELIBMAX + case ELIBMAX: return DRFLAC_ERROR; + #endif + #ifdef ELIBEXEC + case ELIBEXEC: return DRFLAC_ERROR; + #endif + #ifdef EILSEQ + case EILSEQ: return DRFLAC_INVALID_DATA; + #endif + #ifdef ERESTART + case ERESTART: return DRFLAC_ERROR; + #endif + #ifdef ESTRPIPE + case ESTRPIPE: return DRFLAC_ERROR; + #endif + #ifdef EUSERS + case EUSERS: return DRFLAC_ERROR; + #endif + #ifdef ENOTSOCK + case ENOTSOCK: return DRFLAC_NOT_SOCKET; + #endif + #ifdef EDESTADDRREQ + case EDESTADDRREQ: return DRFLAC_NO_ADDRESS; + #endif + #ifdef EMSGSIZE + case EMSGSIZE: return DRFLAC_TOO_BIG; + #endif + #ifdef EPROTOTYPE + case EPROTOTYPE: return DRFLAC_BAD_PROTOCOL; + #endif + #ifdef ENOPROTOOPT + case ENOPROTOOPT: return DRFLAC_PROTOCOL_UNAVAILABLE; + #endif + #ifdef EPROTONOSUPPORT + case EPROTONOSUPPORT: return DRFLAC_PROTOCOL_NOT_SUPPORTED; + #endif + #ifdef ESOCKTNOSUPPORT + case ESOCKTNOSUPPORT: return DRFLAC_SOCKET_NOT_SUPPORTED; + #endif + #ifdef EOPNOTSUPP + case EOPNOTSUPP: return DRFLAC_INVALID_OPERATION; + #endif + #ifdef EPFNOSUPPORT + case EPFNOSUPPORT: return DRFLAC_PROTOCOL_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EAFNOSUPPORT + case EAFNOSUPPORT: return DRFLAC_ADDRESS_FAMILY_NOT_SUPPORTED; + #endif + #ifdef EADDRINUSE + case EADDRINUSE: return DRFLAC_ALREADY_IN_USE; + #endif + #ifdef EADDRNOTAVAIL + case EADDRNOTAVAIL: return DRFLAC_ERROR; + #endif + #ifdef ENETDOWN + case ENETDOWN: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENETUNREACH + case ENETUNREACH: return DRFLAC_NO_NETWORK; + #endif + #ifdef ENETRESET + case ENETRESET: return DRFLAC_NO_NETWORK; + #endif + #ifdef ECONNABORTED + case ECONNABORTED: return DRFLAC_NO_NETWORK; + #endif + #ifdef ECONNRESET + case ECONNRESET: return DRFLAC_CONNECTION_RESET; + #endif + #ifdef ENOBUFS + case ENOBUFS: return DRFLAC_NO_SPACE; + #endif + #ifdef EISCONN + case EISCONN: return DRFLAC_ALREADY_CONNECTED; + #endif + #ifdef ENOTCONN + case ENOTCONN: return DRFLAC_NOT_CONNECTED; + #endif + #ifdef ESHUTDOWN + case ESHUTDOWN: return DRFLAC_ERROR; + #endif + #ifdef ETOOMANYREFS + case ETOOMANYREFS: return DRFLAC_ERROR; + #endif + #ifdef ETIMEDOUT + case ETIMEDOUT: return DRFLAC_TIMEOUT; + #endif + #ifdef ECONNREFUSED + case ECONNREFUSED: return DRFLAC_CONNECTION_REFUSED; + #endif + #ifdef EHOSTDOWN + case EHOSTDOWN: return DRFLAC_NO_HOST; + #endif + #ifdef EHOSTUNREACH + case EHOSTUNREACH: return DRFLAC_NO_HOST; + #endif + #ifdef EALREADY + case EALREADY: return DRFLAC_IN_PROGRESS; + #endif + #ifdef EINPROGRESS + case EINPROGRESS: return DRFLAC_IN_PROGRESS; + #endif + #ifdef ESTALE + case ESTALE: return DRFLAC_INVALID_FILE; + #endif + #ifdef EUCLEAN + case EUCLEAN: return DRFLAC_ERROR; + #endif + #ifdef ENOTNAM + case ENOTNAM: return DRFLAC_ERROR; + #endif + #ifdef ENAVAIL + case ENAVAIL: return DRFLAC_ERROR; + #endif + #ifdef EISNAM + case EISNAM: return DRFLAC_ERROR; + #endif + #ifdef EREMOTEIO + case EREMOTEIO: return DRFLAC_IO_ERROR; + #endif + #ifdef EDQUOT + case EDQUOT: return DRFLAC_NO_SPACE; + #endif + #ifdef ENOMEDIUM + case ENOMEDIUM: return DRFLAC_DOES_NOT_EXIST; + #endif + #ifdef EMEDIUMTYPE + case EMEDIUMTYPE: return DRFLAC_ERROR; + #endif + #ifdef ECANCELED + case ECANCELED: return DRFLAC_CANCELLED; + #endif + #ifdef ENOKEY + case ENOKEY: return DRFLAC_ERROR; + #endif + #ifdef EKEYEXPIRED + case EKEYEXPIRED: return DRFLAC_ERROR; + #endif + #ifdef EKEYREVOKED + case EKEYREVOKED: return DRFLAC_ERROR; + #endif + #ifdef EKEYREJECTED + case EKEYREJECTED: return DRFLAC_ERROR; + #endif + #ifdef EOWNERDEAD + case EOWNERDEAD: return DRFLAC_ERROR; + #endif + #ifdef ENOTRECOVERABLE + case ENOTRECOVERABLE: return DRFLAC_ERROR; + #endif + #ifdef ERFKILL + case ERFKILL: return DRFLAC_ERROR; + #endif + #ifdef EHWPOISON + case EHWPOISON: return DRFLAC_ERROR; + #endif + default: return DRFLAC_ERROR; + } +} +/* End Errno */ + +/* fopen */ +static drflac_result drflac_fopen(FILE** ppFile, const char* pFilePath, const char* pOpenMode) +{ +#if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err; +#endif + + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } + +#if defined(_MSC_VER) && _MSC_VER >= 1400 + err = fopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drflac_result_from_errno(err); + } +#else +#if defined(_WIN32) || defined(__APPLE__) + *ppFile = fopen(pFilePath, pOpenMode); +#else + #if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64 && defined(_LARGEFILE64_SOURCE) + *ppFile = fopen64(pFilePath, pOpenMode); + #else + *ppFile = fopen(pFilePath, pOpenMode); + #endif +#endif + if (*ppFile == NULL) { + drflac_result result = drflac_result_from_errno(errno); + if (result == DRFLAC_SUCCESS) { + result = DRFLAC_ERROR; /* Just a safety check to make sure we never ever return success when pFile == NULL. */ + } + + return result; + } +#endif + + return DRFLAC_SUCCESS; +} + +/* +_wfopen() isn't always available in all compilation environments. + + * Windows only. + * MSVC seems to support it universally as far back as VC6 from what I can tell (haven't checked further back). + * MinGW-64 (both 32- and 64-bit) seems to support it. + * MinGW wraps it in !defined(__STRICT_ANSI__). + * OpenWatcom wraps it in !defined(_NO_EXT_KEYS). + +This can be reviewed as compatibility issues arise. The preference is to use _wfopen_s() and _wfopen() as opposed to the wcsrtombs() +fallback, so if you notice your compiler not detecting this properly I'm happy to look at adding support. +*/ +#if defined(_WIN32) + #if defined(_MSC_VER) || defined(__MINGW64__) || (!defined(__STRICT_ANSI__) && !defined(_NO_EXT_KEYS)) + #define DRFLAC_HAS_WFOPEN + #endif +#endif + +#ifndef DR_FLAC_NO_WCHAR +static drflac_result drflac_wfopen(FILE** ppFile, const wchar_t* pFilePath, const wchar_t* pOpenMode, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (ppFile != NULL) { + *ppFile = NULL; /* Safety. */ + } + + if (pFilePath == NULL || pOpenMode == NULL || ppFile == NULL) { + return DRFLAC_INVALID_ARGS; + } + +#if defined(DRFLAC_HAS_WFOPEN) + { + /* Use _wfopen() on Windows. */ + #if defined(_MSC_VER) && _MSC_VER >= 1400 + errno_t err = _wfopen_s(ppFile, pFilePath, pOpenMode); + if (err != 0) { + return drflac_result_from_errno(err); + } + #else + *ppFile = _wfopen(pFilePath, pOpenMode); + if (*ppFile == NULL) { + return drflac_result_from_errno(errno); + } + #endif + (void)pAllocationCallbacks; + } +#else + /* + Use fopen() on anything other than Windows. Requires a conversion. This is annoying because + fopen() is locale specific. The only real way I can think of to do this is with wcsrtombs(). Note + that wcstombs() is apparently not thread-safe because it uses a static global mbstate_t object for + maintaining state. I've checked this with -std=c89 and it works, but if somebody get's a compiler + error I'll look into improving compatibility. + */ + + /* + Some compilers don't support wchar_t or wcsrtombs() which we're using below. In this case we just + need to abort with an error. If you encounter a compiler lacking such support, add it to this list + and submit a bug report and it'll be added to the library upstream. + */ + #if defined(__DJGPP__) + { + /* Nothing to do here. This will fall through to the error check below. */ + } + #else + { + mbstate_t mbs; + size_t lenMB; + const wchar_t* pFilePathTemp = pFilePath; + char* pFilePathMB = NULL; + char pOpenModeMB[32] = {0}; + + /* Get the length first. */ + DRFLAC_ZERO_OBJECT(&mbs); + lenMB = wcsrtombs(NULL, &pFilePathTemp, 0, &mbs); + if (lenMB == (size_t)-1) { + return drflac_result_from_errno(errno); + } + + pFilePathMB = (char*)drflac__malloc_from_callbacks(lenMB + 1, pAllocationCallbacks); + if (pFilePathMB == NULL) { + return DRFLAC_OUT_OF_MEMORY; + } + + pFilePathTemp = pFilePath; + DRFLAC_ZERO_OBJECT(&mbs); + wcsrtombs(pFilePathMB, &pFilePathTemp, lenMB + 1, &mbs); + + /* The open mode should always consist of ASCII characters so we should be able to do a trivial conversion. */ + { + size_t i = 0; + for (;;) { + if (pOpenMode[i] == 0) { + pOpenModeMB[i] = '\0'; + break; + } + + pOpenModeMB[i] = (char)pOpenMode[i]; + i += 1; + } + } + + *ppFile = fopen(pFilePathMB, pOpenModeMB); + + drflac__free_from_callbacks(pFilePathMB, pAllocationCallbacks); + } + #endif + + if (*ppFile == NULL) { + return DRFLAC_ERROR; + } +#endif + + return DRFLAC_SUCCESS; +} +#endif +/* End fopen */ + +static size_t drflac__on_read_stdio(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + return fread(bufferOut, 1, bytesToRead, (FILE*)pUserData); +} + +static drflac_bool32 drflac__on_seek_stdio(void* pUserData, int offset, drflac_seek_origin origin) +{ + int whence = SEEK_SET; + if (origin == DRFLAC_SEEK_CUR) { + whence = SEEK_CUR; + } else if (origin == DRFLAC_SEEK_END) { + whence = SEEK_END; + } + + return fseek((FILE*)pUserData, offset, whence) == 0; +} + +static drflac_bool32 drflac__on_tell_stdio(void* pUserData, drflac_int64* pCursor) +{ + FILE* pFileStdio = (FILE*)pUserData; + drflac_int64 result; + + /* These were all validated at a higher level. */ + DRFLAC_ASSERT(pFileStdio != NULL); + DRFLAC_ASSERT(pCursor != NULL); + +#if defined(_WIN32) && !defined(NXDK) + #if defined(_MSC_VER) && _MSC_VER > 1200 + result = _ftelli64(pFileStdio); + #else + result = ftell(pFileStdio); + #endif +#else + result = ftell(pFileStdio); +#endif + + *pCursor = result; + + return DRFLAC_TRUE; +} + + + +DRFLAC_API drflac* drflac_open_file(const char* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return NULL; + } + + return pFlac; +} + +#ifndef DR_FLAC_NO_WCHAR +DRFLAC_API drflac* drflac_open_file_w(const wchar_t* pFileName, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, (void*)pFile, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return NULL; + } + + return pFlac; +} +#endif + +DRFLAC_API drflac* drflac_open_file_with_metadata(const char* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_fopen(&pFile, pFileName, "rb") != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return pFlac; + } + + return pFlac; +} + +#ifndef DR_FLAC_NO_WCHAR +DRFLAC_API drflac* drflac_open_file_with_metadata_w(const wchar_t* pFileName, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + FILE* pFile; + + if (drflac_wfopen(&pFile, pFileName, L"rb", pAllocationCallbacks) != DRFLAC_SUCCESS) { + return NULL; + } + + pFlac = drflac_open_with_metadata_private(drflac__on_read_stdio, drflac__on_seek_stdio, drflac__on_tell_stdio, onMeta, drflac_container_unknown, (void*)pFile, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + fclose(pFile); + return pFlac; + } + + return pFlac; +} +#endif +#endif /* DR_FLAC_NO_STDIO */ + +static size_t drflac__on_read_memory(void* pUserData, void* bufferOut, size_t bytesToRead) +{ + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + size_t bytesRemaining; + + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(memoryStream->dataSize >= memoryStream->currentReadPos); + + bytesRemaining = memoryStream->dataSize - memoryStream->currentReadPos; + if (bytesToRead > bytesRemaining) { + bytesToRead = bytesRemaining; + } + + if (bytesToRead > 0) { + DRFLAC_COPY_MEMORY(bufferOut, memoryStream->data + memoryStream->currentReadPos, bytesToRead); + memoryStream->currentReadPos += bytesToRead; + } + + return bytesToRead; +} + +static drflac_bool32 drflac__on_seek_memory(void* pUserData, int offset, drflac_seek_origin origin) +{ + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + drflac_int64 newCursor; + + DRFLAC_ASSERT(memoryStream != NULL); + + if (origin == DRFLAC_SEEK_SET) { + newCursor = 0; + } else if (origin == DRFLAC_SEEK_CUR) { + newCursor = (drflac_int64)memoryStream->currentReadPos; + } else if (origin == DRFLAC_SEEK_END) { + newCursor = (drflac_int64)memoryStream->dataSize; + } else { + DRFLAC_ASSERT(!"Invalid seek origin"); + return DRFLAC_FALSE; + } + + newCursor += offset; + + if (newCursor < 0) { + return DRFLAC_FALSE; /* Trying to seek prior to the start of the buffer. */ + } + if ((size_t)newCursor > memoryStream->dataSize) { + return DRFLAC_FALSE; /* Trying to seek beyond the end of the buffer. */ + } + + memoryStream->currentReadPos = (size_t)newCursor; + + return DRFLAC_TRUE; +} + +static drflac_bool32 drflac__on_tell_memory(void* pUserData, drflac_int64* pCursor) +{ + drflac__memory_stream* memoryStream = (drflac__memory_stream*)pUserData; + + DRFLAC_ASSERT(memoryStream != NULL); + DRFLAC_ASSERT(pCursor != NULL); + + *pCursor = (drflac_int64)memoryStream->currentReadPos; + return DRFLAC_TRUE; +} + +DRFLAC_API drflac* drflac_open_memory(const void* pData, size_t dataSize, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac__memory_stream memoryStream; + drflac* pFlac; + + memoryStream.data = (const drflac_uint8*)pData; + memoryStream.dataSize = dataSize; + memoryStream.currentReadPos = 0; + pFlac = drflac_open(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, &memoryStream, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + pFlac->memoryStream = memoryStream; + + /* This is an awful hack... */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + oggbs->pUserData = &pFlac->memoryStream; + } + else +#endif + { + pFlac->bs.pUserData = &pFlac->memoryStream; + } + + return pFlac; +} + +DRFLAC_API drflac* drflac_open_memory_with_metadata(const void* pData, size_t dataSize, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac__memory_stream memoryStream; + drflac* pFlac; + + memoryStream.data = (const drflac_uint8*)pData; + memoryStream.dataSize = dataSize; + memoryStream.currentReadPos = 0; + pFlac = drflac_open_with_metadata_private(drflac__on_read_memory, drflac__on_seek_memory, drflac__on_tell_memory, onMeta, drflac_container_unknown, &memoryStream, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + pFlac->memoryStream = memoryStream; + + /* This is an awful hack... */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + oggbs->pUserData = &pFlac->memoryStream; + } + else +#endif + { + pFlac->bs.pUserData = &pFlac->memoryStream; + } + + return pFlac; +} + + + +DRFLAC_API drflac* drflac_open(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); +} +DRFLAC_API drflac* drflac_open_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onTell, NULL, container, pUserData, pUserData, pAllocationCallbacks); +} + +DRFLAC_API drflac* drflac_open_with_metadata(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, drflac_container_unknown, pUserData, pUserData, pAllocationCallbacks); +} +DRFLAC_API drflac* drflac_open_with_metadata_relaxed(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, drflac_meta_proc onMeta, drflac_container container, void* pUserData, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + return drflac_open_with_metadata_private(onRead, onSeek, onTell, onMeta, container, pUserData, pUserData, pAllocationCallbacks); +} + +DRFLAC_API void drflac_close(drflac* pFlac) +{ + if (pFlac == NULL) { + return; + } + +#ifndef DR_FLAC_NO_STDIO + /* + If we opened the file with drflac_open_file() we will want to close the file handle. We can know whether or not drflac_open_file() + was used by looking at the callbacks. + */ + if (pFlac->bs.onRead == drflac__on_read_stdio) { + fclose((FILE*)pFlac->bs.pUserData); + } + +#ifndef DR_FLAC_NO_OGG + /* Need to clean up Ogg streams a bit differently due to the way the bit streaming is chained. */ + if (pFlac->container == drflac_container_ogg) { + drflac_oggbs* oggbs = (drflac_oggbs*)pFlac->_oggbs; + DRFLAC_ASSERT(pFlac->bs.onRead == drflac__on_read_ogg); + + if (oggbs->onRead == drflac__on_read_stdio) { + fclose((FILE*)oggbs->pUserData); + } + } +#endif +#endif + + drflac__free_from_callbacks(pFlac, &pFlac->allocationCallbacks); +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0; + pOutputSamples[i*8+1] = (drflac_int32)right0; + pOutputSamples[i*8+2] = (drflac_int32)left1; + pOutputSamples[i*8+3] = (drflac_int32)right1; + pOutputSamples[i*8+4] = (drflac_int32)left2; + pOutputSamples[i*8+5] = (drflac_int32)right2; + pOutputSamples[i*8+6] = (drflac_int32)left3; + pOutputSamples[i*8+7] = (drflac_int32)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + + left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + right = vsubq_u32(left, side); + + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0; + pOutputSamples[i*8+1] = (drflac_int32)right0; + pOutputSamples[i*8+2] = (drflac_int32)left1; + pOutputSamples[i*8+3] = (drflac_int32)right1; + pOutputSamples[i*8+4] = (drflac_int32)left2; + pOutputSamples[i*8+5] = (drflac_int32)right2; + pOutputSamples[i*8+6] = (drflac_int32)left3; + pOutputSamples[i*8+7] = (drflac_int32)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + + side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + left = vaddq_u32(right, side); + + drflac__vst2q_u32((drflac_uint32*)pOutputSamples + i*8, vzipq_u32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left; + pOutputSamples[i*2+1] = (drflac_int32)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + + if (shift > 0) { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + pOutputSamples[i*8+0] = (drflac_int32)temp0L; + pOutputSamples[i*8+1] = (drflac_int32)temp0R; + pOutputSamples[i*8+2] = (drflac_int32)temp1L; + pOutputSamples[i*8+3] = (drflac_int32)temp1R; + pOutputSamples[i*8+4] = (drflac_int32)temp2L; + pOutputSamples[i*8+5] = (drflac_int32)temp2R; + pOutputSamples[i*8+6] = (drflac_int32)temp3L; + pOutputSamples[i*8+7] = (drflac_int32)temp3R; + } + } else { + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1); + temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1); + temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1); + temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1); + + temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1); + temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1); + temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1); + temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1); + + pOutputSamples[i*8+0] = (drflac_int32)temp0L; + pOutputSamples[i*8+1] = (drflac_int32)temp0R; + pOutputSamples[i*8+2] = (drflac_int32)temp1L; + pOutputSamples[i*8+3] = (drflac_int32)temp1R; + pOutputSamples[i*8+4] = (drflac_int32)temp2L; + pOutputSamples[i*8+5] = (drflac_int32)temp2R; + pOutputSamples[i*8+6] = (drflac_int32)temp3L; + pOutputSamples[i*8+7] = (drflac_int32)temp3R; + } + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); + } + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_int32 shift = unusedBitsPerSample; + int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */ + int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */ + uint32x4_t one4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + one4 = vdupq_n_u32(1); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4)); + + left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)(mid + side) >> 1; + pOutputSamples[i*2+1] = (drflac_int32)(mid - side) >> 1; + } + } else { + int32x4_t shift4; + + shift -= 1; + shift4 = vdupq_n_s32(shift); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, one4)); + + left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift); + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift); + } + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)); + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + + pOutputSamples[i*8+0] = (drflac_int32)tempL0; + pOutputSamples[i*8+1] = (drflac_int32)tempR0; + pOutputSamples[i*8+2] = (drflac_int32)tempL1; + pOutputSamples[i*8+3] = (drflac_int32)tempR1; + pOutputSamples[i*8+4] = (drflac_int32)tempL2; + pOutputSamples[i*8+5] = (drflac_int32)tempR2; + pOutputSamples[i*8+6] = (drflac_int32)tempL3; + pOutputSamples[i*8+7] = (drflac_int32)tempR3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 0), _mm_unpacklo_epi32(left, right)); + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8 + 4), _mm_unpackhi_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + int32x4_t shift4_0 = vdupq_n_s32(shift0); + int32x4_t shift4_1 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t left; + int32x4_t right; + + left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift4_0)); + right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift4_1)); + + drflac__vst2q_s32(pOutputSamples + i*8, vzipq_s32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0); + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int32* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s32(drflac* pFlac, drflac_uint64 framesToRead, drflac_int32* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; + + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; + } + + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_s32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_s32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_s32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_s32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + pBufferOut[(i*channelCount)+j] = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; + } + } + + return framesRead; +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + + left0 >>= 16; + left1 >>= 16; + left2 >>= 16; + left3 >>= 16; + + right0 >>= 16; + right1 >>= 16; + right2 >>= 16; + right3 >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)left0; + pOutputSamples[i*8+1] = (drflac_int16)right0; + pOutputSamples[i*8+2] = (drflac_int16)left1; + pOutputSamples[i*8+3] = (drflac_int16)right1; + pOutputSamples[i*8+4] = (drflac_int16)left2; + pOutputSamples[i*8+5] = (drflac_int16)right2; + pOutputSamples[i*8+6] = (drflac_int16)left3; + pOutputSamples[i*8+7] = (drflac_int16)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + + left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + right = vsubq_u32(left, side); + + left = vshrq_n_u32(left, 16); + right = vshrq_n_u32(right, 16); + + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + + left0 >>= 16; + left1 >>= 16; + left2 >>= 16; + left3 >>= 16; + + right0 >>= 16; + right1 >>= 16; + right2 >>= 16; + right3 >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)left0; + pOutputSamples[i*8+1] = (drflac_int16)right0; + pOutputSamples[i*8+2] = (drflac_int16)left1; + pOutputSamples[i*8+3] = (drflac_int16)right1; + pOutputSamples[i*8+4] = (drflac_int16)left2; + pOutputSamples[i*8+5] = (drflac_int16)right2; + pOutputSamples[i*8+6] = (drflac_int16)left3; + pOutputSamples[i*8+7] = (drflac_int16)right3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + for (i = 0; i < frameCount4; ++i) { + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + + side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + left = vaddq_u32(right, side); + + left = vshrq_n_u32(left, 16); + right = vshrq_n_u32(right, 16); + + drflac__vst2q_u16((drflac_uint16*)pOutputSamples + i*8, vzip_u16(vmovn_u32(left), vmovn_u32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + left >>= 16; + right >>= 16; + + pOutputSamples[i*2+0] = (drflac_int16)left; + pOutputSamples[i*2+1] = (drflac_int16)right; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + + if (shift > 0) { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + temp0L >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + + temp0R >>= 16; + temp1R >>= 16; + temp2R >>= 16; + temp3R >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)temp0L; + pOutputSamples[i*8+1] = (drflac_int16)temp0R; + pOutputSamples[i*8+2] = (drflac_int16)temp1L; + pOutputSamples[i*8+3] = (drflac_int16)temp1R; + pOutputSamples[i*8+4] = (drflac_int16)temp2L; + pOutputSamples[i*8+5] = (drflac_int16)temp2R; + pOutputSamples[i*8+6] = (drflac_int16)temp3L; + pOutputSamples[i*8+7] = (drflac_int16)temp3R; + } + } else { + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = ((drflac_int32)(mid0 + side0) >> 1); + temp1L = ((drflac_int32)(mid1 + side1) >> 1); + temp2L = ((drflac_int32)(mid2 + side2) >> 1); + temp3L = ((drflac_int32)(mid3 + side3) >> 1); + + temp0R = ((drflac_int32)(mid0 - side0) >> 1); + temp1R = ((drflac_int32)(mid1 - side1) >> 1); + temp2R = ((drflac_int32)(mid2 - side2) >> 1); + temp3R = ((drflac_int32)(mid3 - side3) >> 1); + + temp0L >>= 16; + temp1L >>= 16; + temp2L >>= 16; + temp3L >>= 16; + + temp0R >>= 16; + temp1R >>= 16; + temp2R >>= 16; + temp3R >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)temp0L; + pOutputSamples[i*8+1] = (drflac_int16)temp0R; + pOutputSamples[i*8+2] = (drflac_int16)temp1L; + pOutputSamples[i*8+3] = (drflac_int16)temp1R; + pOutputSamples[i*8+4] = (drflac_int16)temp2L; + pOutputSamples[i*8+5] = (drflac_int16)temp2R; + pOutputSamples[i*8+6] = (drflac_int16)temp3L; + pOutputSamples[i*8+7] = (drflac_int16)temp3R; + } + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) >> 16); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + right = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i left; + __m128i right; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + left = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + right = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); + } + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + int32x4_t wbpsShift0_4; /* wbps = Wasted Bits Per Sample */ + int32x4_t wbpsShift1_4; /* wbps = Wasted Bits Per Sample */ + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + wbpsShift0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbpsShift1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + left = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + right = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((drflac_int32)(mid + side) >> 1) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((drflac_int32)(mid - side) >> 1) >> 16); + } + } else { + int32x4_t shift4; + + shift -= 1; + shift4 = vdupq_n_s32(shift); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t left; + int32x4_t right; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbpsShift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbpsShift1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + left = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + right = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int16)(((mid + side) << shift) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)(((mid - side) << shift) >> 16); + } + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) >> 16); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + + tempL0 >>= 16; + tempL1 >>= 16; + tempL2 >>= 16; + tempL3 >>= 16; + + tempR0 >>= 16; + tempR1 >>= 16; + tempR2 >>= 16; + tempR3 >>= 16; + + pOutputSamples[i*8+0] = (drflac_int16)tempL0; + pOutputSamples[i*8+1] = (drflac_int16)tempR0; + pOutputSamples[i*8+2] = (drflac_int16)tempL1; + pOutputSamples[i*8+3] = (drflac_int16)tempR1; + pOutputSamples[i*8+4] = (drflac_int16)tempL2; + pOutputSamples[i*8+5] = (drflac_int16)tempR2; + pOutputSamples[i*8+6] = (drflac_int16)tempL3; + pOutputSamples[i*8+7] = (drflac_int16)tempR3; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + left = _mm_srai_epi32(left, 16); + right = _mm_srai_epi32(right, 16); + + /* At this point we have results. We can now pack and interleave these into a single __m128i object and then store the in the output buffer. */ + _mm_storeu_si128((__m128i*)(pOutputSamples + i*8), drflac__mm_packs_interleaved_epi32(left, right)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + int32x4_t shift0_4 = vdupq_n_s32(shift0); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t left; + int32x4_t right; + + left = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + right = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4)); + + left = vshrq_n_s32(left, 16); + right = vshrq_n_s32(right, 16); + + drflac__vst2q_s16(pOutputSamples + i*8, vzip_s16(vmovn_s32(left), vmovn_s32(right))); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int16)((pInputSamples0U32[i] << shift0) >> 16); + pOutputSamples[i*2+1] = (drflac_int16)((pInputSamples1U32[i] << shift1) >> 16); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_s16__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, drflac_int16* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_s16__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_s16__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_s16__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_s16(drflac* pFlac, drflac_uint64 framesToRead, drflac_int16* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; + + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; + } + + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_s16__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_s16__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_s16__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_s16__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + pBufferOut[(i*channelCount)+j] = (drflac_int16)(sampleS32 >> 16); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (drflac_uint32)frameCountThisIteration; + } + } + + return framesRead; +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 left = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + float factor = 1 / 2147483648.0; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 left0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 left1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 left2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 left3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 right0 = left0 - side0; + drflac_uint32 right1 = left1 - side1; + drflac_uint32 right2 = left2 - side2; + drflac_uint32 right3 = left3 - side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)right0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)left1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)right1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)left2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)right2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)left3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)right3 * factor; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left * factor; + pOutputSamples[i*2+1] = (drflac_int32)right * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + __m128 factor; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = _mm_set1_ps(1.0f / 8388608.0f); + + for (i = 0; i < frameCount4; ++i) { + __m128i left = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i right = _mm_sub_epi32(left, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + float32x4_t factor4; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor4 = vdupq_n_f32(1.0f / 8388608.0f); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t left; + uint32x4_t side; + uint32x4_t right; + float32x4_t leftf; + float32x4_t rightf; + + left = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + right = vsubq_u32(left, side); + leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 left = pInputSamples0U32[i] << shift0; + drflac_uint32 side = pInputSamples1U32[i] << shift1; + drflac_uint32 right = left - side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_left_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_left_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_left_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_left_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_left_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + for (i = 0; i < frameCount; ++i) { + drflac_uint32 side = (drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + drflac_uint32 right = (drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (float)((drflac_int32)left / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)right / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + float factor = 1 / 2147483648.0; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 side0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 side1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 side2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 side3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 right0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 right1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 right2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 right3 = pInputSamples1U32[i*4+3] << shift1; + + drflac_uint32 left0 = right0 + side0; + drflac_uint32 left1 = right1 + side1; + drflac_uint32 left2 = right2 + side2; + drflac_uint32 left3 = right3 + side3; + + pOutputSamples[i*8+0] = (drflac_int32)left0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)right0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)left1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)right1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)left2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)right2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)left3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)right3 * factor; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left * factor; + pOutputSamples[i*2+1] = (drflac_int32)right * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + __m128 factor; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = _mm_set1_ps(1.0f / 8388608.0f); + + for (i = 0; i < frameCount4; ++i) { + __m128i side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + __m128i right = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + __m128i left = _mm_add_epi32(right, side); + __m128 leftf = _mm_mul_ps(_mm_cvtepi32_ps(left), factor); + __m128 rightf = _mm_mul_ps(_mm_cvtepi32_ps(right), factor); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + float32x4_t factor4; + int32x4_t shift0_4; + int32x4_t shift1_4; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor4 = vdupq_n_f32(1.0f / 8388608.0f); + shift0_4 = vdupq_n_s32(shift0); + shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + uint32x4_t side; + uint32x4_t right; + uint32x4_t left; + float32x4_t leftf; + float32x4_t rightf; + + side = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4); + right = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4); + left = vaddq_u32(right, side); + leftf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(left)), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(vreinterpretq_s32_u32(right)), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 side = pInputSamples0U32[i] << shift0; + drflac_uint32 right = pInputSamples1U32[i] << shift1; + drflac_uint32 left = right + side; + + pOutputSamples[i*2+0] = (drflac_int32)left / 8388608.0f; + pOutputSamples[i*2+1] = (drflac_int32)right / 8388608.0f; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_right_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_right_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_right_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_right_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_right_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + drflac_uint32 mid = (drflac_uint32)pInputSamples0[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = (drflac_uint32)pInputSamples1[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (float)((((drflac_int32)(mid + side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((((drflac_int32)(mid - side) >> 1) << (unusedBitsPerSample)) / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample; + float factor = 1 / 2147483648.0; + + if (shift > 0) { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (mid0 + side0) << shift; + temp1L = (mid1 + side1) << shift; + temp2L = (mid2 + side2) << shift; + temp3L = (mid3 + side3) << shift; + + temp0R = (mid0 - side0) << shift; + temp1R = (mid1 - side1) << shift; + temp2R = (mid2 - side2) << shift; + temp3R = (mid3 - side3) << shift; + + pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor; + pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor; + pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor; + pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor; + pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor; + pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor; + pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor; + pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor; + } + } else { + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 temp0L; + drflac_uint32 temp1L; + drflac_uint32 temp2L; + drflac_uint32 temp3L; + drflac_uint32 temp0R; + drflac_uint32 temp1R; + drflac_uint32 temp2R; + drflac_uint32 temp3R; + + drflac_uint32 mid0 = pInputSamples0U32[i*4+0] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid1 = pInputSamples0U32[i*4+1] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid2 = pInputSamples0U32[i*4+2] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 mid3 = pInputSamples0U32[i*4+3] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + + drflac_uint32 side0 = pInputSamples1U32[i*4+0] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side1 = pInputSamples1U32[i*4+1] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side2 = pInputSamples1U32[i*4+2] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + drflac_uint32 side3 = pInputSamples1U32[i*4+3] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid0 = (mid0 << 1) | (side0 & 0x01); + mid1 = (mid1 << 1) | (side1 & 0x01); + mid2 = (mid2 << 1) | (side2 & 0x01); + mid3 = (mid3 << 1) | (side3 & 0x01); + + temp0L = (drflac_uint32)((drflac_int32)(mid0 + side0) >> 1); + temp1L = (drflac_uint32)((drflac_int32)(mid1 + side1) >> 1); + temp2L = (drflac_uint32)((drflac_int32)(mid2 + side2) >> 1); + temp3L = (drflac_uint32)((drflac_int32)(mid3 + side3) >> 1); + + temp0R = (drflac_uint32)((drflac_int32)(mid0 - side0) >> 1); + temp1R = (drflac_uint32)((drflac_int32)(mid1 - side1) >> 1); + temp2R = (drflac_uint32)((drflac_int32)(mid2 - side2) >> 1); + temp3R = (drflac_uint32)((drflac_int32)(mid3 - side3) >> 1); + + pOutputSamples[i*8+0] = (drflac_int32)temp0L * factor; + pOutputSamples[i*8+1] = (drflac_int32)temp0R * factor; + pOutputSamples[i*8+2] = (drflac_int32)temp1L * factor; + pOutputSamples[i*8+3] = (drflac_int32)temp1R * factor; + pOutputSamples[i*8+4] = (drflac_int32)temp2L * factor; + pOutputSamples[i*8+5] = (drflac_int32)temp2R * factor; + pOutputSamples[i*8+6] = (drflac_int32)temp3L * factor; + pOutputSamples[i*8+7] = (drflac_int32)temp3R * factor; + } + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid + side) >> 1) << unusedBitsPerSample) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((drflac_uint32)((drflac_int32)(mid - side) >> 1) << unusedBitsPerSample) * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample - 8; + float factor; + __m128 factor128; + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = 1.0f / 8388608.0f; + factor128 = _mm_set1_ps(factor); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + tempL = _mm_srai_epi32(_mm_add_epi32(mid, side), 1); + tempR = _mm_srai_epi32(_mm_sub_epi32(mid, side), 1); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; + } + } else { + shift -= 1; + for (i = 0; i < frameCount4; ++i) { + __m128i mid; + __m128i side; + __m128i tempL; + __m128i tempR; + __m128 leftf; + __m128 rightf; + + mid = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + side = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + mid = _mm_or_si128(_mm_slli_epi32(mid, 1), _mm_and_si128(side, _mm_set1_epi32(0x01))); + + tempL = _mm_slli_epi32(_mm_add_epi32(mid, side), shift); + tempR = _mm_slli_epi32(_mm_sub_epi32(mid, side), shift); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(tempL), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(tempR), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; + } + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift = unusedBitsPerSample - 8; + float factor; + float32x4_t factor4; + int32x4_t shift4; + int32x4_t wbps0_4; /* Wasted Bits Per Sample */ + int32x4_t wbps1_4; /* Wasted Bits Per Sample */ + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 24); + + factor = 1.0f / 8388608.0f; + factor4 = vdupq_n_f32(factor); + wbps0_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample); + wbps1_4 = vdupq_n_s32(pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample); + + if (shift == 0) { + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + uint32x4_t mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + uint32x4_t side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + lefti = vshrq_n_s32(vreinterpretq_s32_u32(vaddq_u32(mid, side)), 1); + righti = vshrq_n_s32(vreinterpretq_s32_u32(vsubq_u32(mid, side)), 1); + + leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = ((drflac_int32)(mid + side) >> 1) * factor; + pOutputSamples[i*2+1] = ((drflac_int32)(mid - side) >> 1) * factor; + } + } else { + shift -= 1; + shift4 = vdupq_n_s32(shift); + for (i = 0; i < frameCount4; ++i) { + uint32x4_t mid; + uint32x4_t side; + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + mid = vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), wbps0_4); + side = vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), wbps1_4); + + mid = vorrq_u32(vshlq_n_u32(mid, 1), vandq_u32(side, vdupq_n_u32(1))); + + lefti = vreinterpretq_s32_u32(vshlq_u32(vaddq_u32(mid, side), shift4)); + righti = vreinterpretq_s32_u32(vshlq_u32(vsubq_u32(mid, side), shift4)); + + leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + drflac_uint32 mid = pInputSamples0U32[i] << pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 side = pInputSamples1U32[i] << pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + + mid = (mid << 1) | (side & 0x01); + + pOutputSamples[i*2+0] = (drflac_int32)((mid + side) << shift) * factor; + pOutputSamples[i*2+1] = (drflac_int32)((mid - side) << shift) * factor; + } + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_mid_side(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_mid_side__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_mid_side__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_mid_side__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_mid_side__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +#if 0 +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__reference(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + for (drflac_uint64 i = 0; i < frameCount; ++i) { + pOutputSamples[i*2+0] = (float)((drflac_int32)((drflac_uint32)pInputSamples0[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample)) / 2147483648.0); + pOutputSamples[i*2+1] = (float)((drflac_int32)((drflac_uint32)pInputSamples1[i] << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample)) / 2147483648.0); + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample; + drflac_uint32 shift1 = unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample; + float factor = 1 / 2147483648.0; + + for (i = 0; i < frameCount4; ++i) { + drflac_uint32 tempL0 = pInputSamples0U32[i*4+0] << shift0; + drflac_uint32 tempL1 = pInputSamples0U32[i*4+1] << shift0; + drflac_uint32 tempL2 = pInputSamples0U32[i*4+2] << shift0; + drflac_uint32 tempL3 = pInputSamples0U32[i*4+3] << shift0; + + drflac_uint32 tempR0 = pInputSamples1U32[i*4+0] << shift1; + drflac_uint32 tempR1 = pInputSamples1U32[i*4+1] << shift1; + drflac_uint32 tempR2 = pInputSamples1U32[i*4+2] << shift1; + drflac_uint32 tempR3 = pInputSamples1U32[i*4+3] << shift1; + + pOutputSamples[i*8+0] = (drflac_int32)tempL0 * factor; + pOutputSamples[i*8+1] = (drflac_int32)tempR0 * factor; + pOutputSamples[i*8+2] = (drflac_int32)tempL1 * factor; + pOutputSamples[i*8+3] = (drflac_int32)tempR1 * factor; + pOutputSamples[i*8+4] = (drflac_int32)tempL2 * factor; + pOutputSamples[i*8+5] = (drflac_int32)tempR2 * factor; + pOutputSamples[i*8+6] = (drflac_int32)tempL3 * factor; + pOutputSamples[i*8+7] = (drflac_int32)tempR3 * factor; + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} + +#if defined(DRFLAC_SUPPORT_SSE2) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + + float factor = 1.0f / 8388608.0f; + __m128 factor128 = _mm_set1_ps(factor); + + for (i = 0; i < frameCount4; ++i) { + __m128i lefti; + __m128i righti; + __m128 leftf; + __m128 rightf; + + lefti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples0 + i), shift0); + righti = _mm_slli_epi32(_mm_loadu_si128((const __m128i*)pInputSamples1 + i), shift1); + + leftf = _mm_mul_ps(_mm_cvtepi32_ps(lefti), factor128); + rightf = _mm_mul_ps(_mm_cvtepi32_ps(righti), factor128); + + _mm_storeu_ps(pOutputSamples + i*8 + 0, _mm_unpacklo_ps(leftf, rightf)); + _mm_storeu_ps(pOutputSamples + i*8 + 4, _mm_unpackhi_ps(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} +#endif + +#if defined(DRFLAC_SUPPORT_NEON) +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo__neon(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ + drflac_uint64 i; + drflac_uint64 frameCount4 = frameCount >> 2; + const drflac_uint32* pInputSamples0U32 = (const drflac_uint32*)pInputSamples0; + const drflac_uint32* pInputSamples1U32 = (const drflac_uint32*)pInputSamples1; + drflac_uint32 shift0 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[0].wastedBitsPerSample) - 8; + drflac_uint32 shift1 = (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[1].wastedBitsPerSample) - 8; + + float factor = 1.0f / 8388608.0f; + float32x4_t factor4 = vdupq_n_f32(factor); + int32x4_t shift0_4 = vdupq_n_s32(shift0); + int32x4_t shift1_4 = vdupq_n_s32(shift1); + + for (i = 0; i < frameCount4; ++i) { + int32x4_t lefti; + int32x4_t righti; + float32x4_t leftf; + float32x4_t rightf; + + lefti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples0U32 + i*4), shift0_4)); + righti = vreinterpretq_s32_u32(vshlq_u32(vld1q_u32(pInputSamples1U32 + i*4), shift1_4)); + + leftf = vmulq_f32(vcvtq_f32_s32(lefti), factor4); + rightf = vmulq_f32(vcvtq_f32_s32(righti), factor4); + + drflac__vst2q_f32(pOutputSamples + i*8, vzipq_f32(leftf, rightf)); + } + + for (i = (frameCount4 << 2); i < frameCount; ++i) { + pOutputSamples[i*2+0] = (drflac_int32)(pInputSamples0U32[i] << shift0) * factor; + pOutputSamples[i*2+1] = (drflac_int32)(pInputSamples1U32[i] << shift1) * factor; + } +} +#endif + +static DRFLAC_INLINE void drflac_read_pcm_frames_f32__decode_independent_stereo(drflac* pFlac, drflac_uint64 frameCount, drflac_uint32 unusedBitsPerSample, const drflac_int32* pInputSamples0, const drflac_int32* pInputSamples1, float* pOutputSamples) +{ +#if defined(DRFLAC_SUPPORT_SSE2) + if (drflac__gIsSSE2Supported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_independent_stereo__sse2(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#elif defined(DRFLAC_SUPPORT_NEON) + if (drflac__gIsNEONSupported && pFlac->bitsPerSample <= 24) { + drflac_read_pcm_frames_f32__decode_independent_stereo__neon(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); + } else +#endif + { + /* Scalar fallback. */ +#if 0 + drflac_read_pcm_frames_f32__decode_independent_stereo__reference(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#else + drflac_read_pcm_frames_f32__decode_independent_stereo__scalar(pFlac, frameCount, unusedBitsPerSample, pInputSamples0, pInputSamples1, pOutputSamples); +#endif + } +} + +DRFLAC_API drflac_uint64 drflac_read_pcm_frames_f32(drflac* pFlac, drflac_uint64 framesToRead, float* pBufferOut) +{ + drflac_uint64 framesRead; + drflac_uint32 unusedBitsPerSample; + + if (pFlac == NULL || framesToRead == 0) { + return 0; + } + + if (pBufferOut == NULL) { + return drflac__seek_forward_by_pcm_frames(pFlac, framesToRead); + } + + DRFLAC_ASSERT(pFlac->bitsPerSample <= 32); + unusedBitsPerSample = 32 - pFlac->bitsPerSample; + + framesRead = 0; + while (framesToRead > 0) { + /* If we've run out of samples in this frame, go to the next. */ + if (pFlac->currentFLACFrame.pcmFramesRemaining == 0) { + if (!drflac__read_and_decode_next_flac_frame(pFlac)) { + break; /* Couldn't read the next frame, so just break from the loop and return. */ + } + } else { + unsigned int channelCount = drflac__get_channel_count_from_channel_assignment(pFlac->currentFLACFrame.header.channelAssignment); + drflac_uint64 iFirstPCMFrame = pFlac->currentFLACFrame.header.blockSizeInPCMFrames - pFlac->currentFLACFrame.pcmFramesRemaining; + drflac_uint64 frameCountThisIteration = framesToRead; + + if (frameCountThisIteration > pFlac->currentFLACFrame.pcmFramesRemaining) { + frameCountThisIteration = pFlac->currentFLACFrame.pcmFramesRemaining; + } + + if (channelCount == 2) { + const drflac_int32* pDecodedSamples0 = pFlac->currentFLACFrame.subframes[0].pSamplesS32 + iFirstPCMFrame; + const drflac_int32* pDecodedSamples1 = pFlac->currentFLACFrame.subframes[1].pSamplesS32 + iFirstPCMFrame; + + switch (pFlac->currentFLACFrame.header.channelAssignment) + { + case DRFLAC_CHANNEL_ASSIGNMENT_LEFT_SIDE: + { + drflac_read_pcm_frames_f32__decode_left_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_RIGHT_SIDE: + { + drflac_read_pcm_frames_f32__decode_right_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_MID_SIDE: + { + drflac_read_pcm_frames_f32__decode_mid_side(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + + case DRFLAC_CHANNEL_ASSIGNMENT_INDEPENDENT: + default: + { + drflac_read_pcm_frames_f32__decode_independent_stereo(pFlac, frameCountThisIteration, unusedBitsPerSample, pDecodedSamples0, pDecodedSamples1, pBufferOut); + } break; + } + } else { + /* Generic interleaving. */ + drflac_uint64 i; + for (i = 0; i < frameCountThisIteration; ++i) { + unsigned int j; + for (j = 0; j < channelCount; ++j) { + drflac_int32 sampleS32 = (drflac_int32)((drflac_uint32)(pFlac->currentFLACFrame.subframes[j].pSamplesS32[iFirstPCMFrame + i]) << (unusedBitsPerSample + pFlac->currentFLACFrame.subframes[j].wastedBitsPerSample)); + pBufferOut[(i*channelCount)+j] = (float)(sampleS32 / 2147483648.0); + } + } + } + + framesRead += frameCountThisIteration; + pBufferOut += frameCountThisIteration * channelCount; + framesToRead -= frameCountThisIteration; + pFlac->currentPCMFrame += frameCountThisIteration; + pFlac->currentFLACFrame.pcmFramesRemaining -= (unsigned int)frameCountThisIteration; + } + } + + return framesRead; +} + + +DRFLAC_API drflac_bool32 drflac_seek_to_pcm_frame(drflac* pFlac, drflac_uint64 pcmFrameIndex) +{ + if (pFlac == NULL) { + return DRFLAC_FALSE; + } + + /* Don't do anything if we're already on the seek point. */ + if (pFlac->currentPCMFrame == pcmFrameIndex) { + return DRFLAC_TRUE; + } + + /* + If we don't know where the first frame begins then we can't seek. This will happen when the STREAMINFO block was not present + when the decoder was opened. + */ + if (pFlac->firstFLACFramePosInBytes == 0) { + return DRFLAC_FALSE; + } + + if (pcmFrameIndex == 0) { + pFlac->currentPCMFrame = 0; + return drflac__seek_to_first_frame(pFlac); + } else { + drflac_bool32 wasSuccessful = DRFLAC_FALSE; + drflac_uint64 originalPCMFrame = pFlac->currentPCMFrame; + + /* Clamp the sample to the end. */ + if (pcmFrameIndex > pFlac->totalPCMFrameCount) { + pcmFrameIndex = pFlac->totalPCMFrameCount; + } + + /* If the target sample and the current sample are in the same frame we just move the position forward. */ + if (pcmFrameIndex > pFlac->currentPCMFrame) { + /* Forward. */ + drflac_uint32 offset = (drflac_uint32)(pcmFrameIndex - pFlac->currentPCMFrame); + if (pFlac->currentFLACFrame.pcmFramesRemaining > offset) { + pFlac->currentFLACFrame.pcmFramesRemaining -= offset; + pFlac->currentPCMFrame = pcmFrameIndex; + return DRFLAC_TRUE; + } + } else { + /* Backward. */ + drflac_uint32 offsetAbs = (drflac_uint32)(pFlac->currentPCMFrame - pcmFrameIndex); + drflac_uint32 currentFLACFramePCMFrameCount = pFlac->currentFLACFrame.header.blockSizeInPCMFrames; + drflac_uint32 currentFLACFramePCMFramesConsumed = currentFLACFramePCMFrameCount - pFlac->currentFLACFrame.pcmFramesRemaining; + if (currentFLACFramePCMFramesConsumed > offsetAbs) { + pFlac->currentFLACFrame.pcmFramesRemaining += offsetAbs; + pFlac->currentPCMFrame = pcmFrameIndex; + return DRFLAC_TRUE; + } + } + + /* + Different techniques depending on encapsulation. Using the native FLAC seektable with Ogg encapsulation is a bit awkward so + we'll instead use Ogg's natural seeking facility. + */ +#ifndef DR_FLAC_NO_OGG + if (pFlac->container == drflac_container_ogg) + { + wasSuccessful = drflac_ogg__seek_to_pcm_frame(pFlac, pcmFrameIndex); + } + else +#endif + { + /* First try seeking via the seek table. If this fails, fall back to a brute force seek which is much slower. */ + if (/*!wasSuccessful && */!pFlac->_noSeekTableSeek) { + wasSuccessful = drflac__seek_to_pcm_frame__seek_table(pFlac, pcmFrameIndex); + } + +#if !defined(DR_FLAC_NO_CRC) + /* Fall back to binary search if seek table seeking fails. This requires the length of the stream to be known. */ + if (!wasSuccessful && !pFlac->_noBinarySearchSeek && pFlac->totalPCMFrameCount > 0) { + wasSuccessful = drflac__seek_to_pcm_frame__binary_search(pFlac, pcmFrameIndex); + } +#endif + + /* Fall back to brute force if all else fails. */ + if (!wasSuccessful && !pFlac->_noBruteForceSeek) { + wasSuccessful = drflac__seek_to_pcm_frame__brute_force(pFlac, pcmFrameIndex); + } + } + + if (wasSuccessful) { + pFlac->currentPCMFrame = pcmFrameIndex; + } else { + /* Seek failed. Try putting the decoder back to it's original state. */ + if (drflac_seek_to_pcm_frame(pFlac, originalPCMFrame) == DRFLAC_FALSE) { + /* Failed to seek back to the original PCM frame. Fall back to 0. */ + drflac_seek_to_pcm_frame(pFlac, 0); + } + } + + return wasSuccessful; + } +} + + + +/* High Level APIs */ + +/* SIZE_MAX */ +#if defined(SIZE_MAX) + #define DRFLAC_SIZE_MAX SIZE_MAX +#else + #if defined(DRFLAC_64BIT) + #define DRFLAC_SIZE_MAX ((drflac_uint64)0xFFFFFFFFFFFFFFFF) + #else + #define DRFLAC_SIZE_MAX 0xFFFFFFFF + #endif +#endif +/* End SIZE_MAX */ + + +/* Using a macro as the definition of the drflac__full_decode_and_close_*() API family. Sue me. */ +#define DRFLAC_DEFINE_FULL_READ_AND_CLOSE(extension, type) \ +static type* drflac__full_read_and_close_ ## extension (drflac* pFlac, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut)\ +{ \ + type* pSampleData = NULL; \ + drflac_uint64 totalPCMFrameCount; \ + type buffer[4096]; \ + drflac_uint64 pcmFramesRead; \ + size_t sampleDataBufferSize = sizeof(buffer); \ + \ + DRFLAC_ASSERT(pFlac != NULL); \ + \ + totalPCMFrameCount = 0; \ + \ + pSampleData = (type*)drflac__malloc_from_callbacks(sampleDataBufferSize, &pFlac->allocationCallbacks); \ + if (pSampleData == NULL) { \ + goto on_error; \ + } \ + \ + while ((pcmFramesRead = (drflac_uint64)drflac_read_pcm_frames_##extension(pFlac, sizeof(buffer)/sizeof(buffer[0])/pFlac->channels, buffer)) > 0) { \ + if (((totalPCMFrameCount + pcmFramesRead) * pFlac->channels * sizeof(type)) > sampleDataBufferSize) { \ + type* pNewSampleData; \ + size_t newSampleDataBufferSize; \ + \ + newSampleDataBufferSize = sampleDataBufferSize * 2; \ + pNewSampleData = (type*)drflac__realloc_from_callbacks(pSampleData, newSampleDataBufferSize, sampleDataBufferSize, &pFlac->allocationCallbacks); \ + if (pNewSampleData == NULL) { \ + drflac__free_from_callbacks(pSampleData, &pFlac->allocationCallbacks); \ + goto on_error; \ + } \ + \ + sampleDataBufferSize = newSampleDataBufferSize; \ + pSampleData = pNewSampleData; \ + } \ + \ + DRFLAC_COPY_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), buffer, (size_t)(pcmFramesRead*pFlac->channels*sizeof(type))); \ + totalPCMFrameCount += pcmFramesRead; \ + } \ + \ + /* At this point everything should be decoded, but we just want to fill the unused part buffer with silence - need to \ + protect those ears from random noise! */ \ + DRFLAC_ZERO_MEMORY(pSampleData + (totalPCMFrameCount*pFlac->channels), (size_t)(sampleDataBufferSize - totalPCMFrameCount*pFlac->channels*sizeof(type))); \ + \ + if (sampleRateOut) *sampleRateOut = pFlac->sampleRate; \ + if (channelsOut) *channelsOut = pFlac->channels; \ + if (totalPCMFrameCountOut) *totalPCMFrameCountOut = totalPCMFrameCount; \ + \ + drflac_close(pFlac); \ + return pSampleData; \ + \ +on_error: \ + drflac_close(pFlac); \ + return NULL; \ +} + +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s32, drflac_int32) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(s16, drflac_int16) +DRFLAC_DEFINE_FULL_READ_AND_CLOSE(f32, float) + +DRFLAC_API drflac_int32* drflac_open_and_read_pcm_frames_s32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); +} + +DRFLAC_API drflac_int16* drflac_open_and_read_pcm_frames_s16(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s16(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); +} + +DRFLAC_API float* drflac_open_and_read_pcm_frames_f32(drflac_read_proc onRead, drflac_seek_proc onSeek, drflac_tell_proc onTell, void* pUserData, unsigned int* channelsOut, unsigned int* sampleRateOut, drflac_uint64* totalPCMFrameCountOut, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (channelsOut) { + *channelsOut = 0; + } + if (sampleRateOut) { + *sampleRateOut = 0; + } + if (totalPCMFrameCountOut) { + *totalPCMFrameCountOut = 0; + } + + pFlac = drflac_open(onRead, onSeek, onTell, pUserData, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_f32(pFlac, channelsOut, sampleRateOut, totalPCMFrameCountOut); +} + +#ifndef DR_FLAC_NO_STDIO +DRFLAC_API drflac_int32* drflac_open_file_and_read_pcm_frames_s32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API drflac_int16* drflac_open_file_and_read_pcm_frames_s16(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API float* drflac_open_file_and_read_pcm_frames_f32(const char* filename, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_file(filename, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); +} +#endif + +DRFLAC_API drflac_int32* drflac_open_memory_and_read_pcm_frames_s32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s32(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API drflac_int16* drflac_open_memory_and_read_pcm_frames_s16(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_s16(pFlac, channels, sampleRate, totalPCMFrameCount); +} + +DRFLAC_API float* drflac_open_memory_and_read_pcm_frames_f32(const void* data, size_t dataSize, unsigned int* channels, unsigned int* sampleRate, drflac_uint64* totalPCMFrameCount, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + drflac* pFlac; + + if (sampleRate) { + *sampleRate = 0; + } + if (channels) { + *channels = 0; + } + if (totalPCMFrameCount) { + *totalPCMFrameCount = 0; + } + + pFlac = drflac_open_memory(data, dataSize, pAllocationCallbacks); + if (pFlac == NULL) { + return NULL; + } + + return drflac__full_read_and_close_f32(pFlac, channels, sampleRate, totalPCMFrameCount); +} + + +DRFLAC_API void drflac_free(void* p, const drflac_allocation_callbacks* pAllocationCallbacks) +{ + if (pAllocationCallbacks != NULL) { + drflac__free_from_callbacks(p, pAllocationCallbacks); + } else { + drflac__free_default(p, NULL); + } +} + + + + +DRFLAC_API void drflac_init_vorbis_comment_iterator(drflac_vorbis_comment_iterator* pIter, drflac_uint32 commentCount, const void* pComments) +{ + if (pIter == NULL) { + return; + } + + pIter->countRemaining = commentCount; + pIter->pRunningData = (const char*)pComments; +} + +DRFLAC_API const char* drflac_next_vorbis_comment(drflac_vorbis_comment_iterator* pIter, drflac_uint32* pCommentLengthOut) +{ + drflac_int32 length; + const char* pComment; + + /* Safety. */ + if (pCommentLengthOut) { + *pCommentLengthOut = 0; + } + + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return NULL; + } + + length = drflac__le2host_32_ptr_unaligned(pIter->pRunningData); + pIter->pRunningData += 4; + + pComment = pIter->pRunningData; + pIter->pRunningData += length; + pIter->countRemaining -= 1; + + if (pCommentLengthOut) { + *pCommentLengthOut = length; + } + + return pComment; +} + + + + +DRFLAC_API void drflac_init_cuesheet_track_iterator(drflac_cuesheet_track_iterator* pIter, drflac_uint32 trackCount, const void* pTrackData) +{ + if (pIter == NULL) { + return; + } + + pIter->countRemaining = trackCount; + pIter->pRunningData = (const char*)pTrackData; +} + +DRFLAC_API drflac_bool32 drflac_next_cuesheet_track(drflac_cuesheet_track_iterator* pIter, drflac_cuesheet_track* pCuesheetTrack) +{ + drflac_cuesheet_track cuesheetTrack; + const char* pRunningData; + drflac_uint64 offsetHi; + drflac_uint64 offsetLo; + + if (pIter == NULL || pIter->countRemaining == 0 || pIter->pRunningData == NULL) { + return DRFLAC_FALSE; + } + + pRunningData = pIter->pRunningData; + + offsetHi = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + offsetLo = drflac__be2host_32(*(const drflac_uint32*)pRunningData); pRunningData += 4; + cuesheetTrack.offset = offsetLo | (offsetHi << 32); + cuesheetTrack.trackNumber = pRunningData[0]; pRunningData += 1; + DRFLAC_COPY_MEMORY(cuesheetTrack.ISRC, pRunningData, sizeof(cuesheetTrack.ISRC)); pRunningData += 12; + cuesheetTrack.isAudio = (pRunningData[0] & 0x80) != 0; + cuesheetTrack.preEmphasis = (pRunningData[0] & 0x40) != 0; pRunningData += 14; + cuesheetTrack.indexCount = pRunningData[0]; pRunningData += 1; + cuesheetTrack.pIndexPoints = (const drflac_cuesheet_track_index*)pRunningData; pRunningData += cuesheetTrack.indexCount * sizeof(drflac_cuesheet_track_index); + + pIter->pRunningData = pRunningData; + pIter->countRemaining -= 1; + + if (pCuesheetTrack) { + *pCuesheetTrack = cuesheetTrack; + } + + return DRFLAC_TRUE; +} + +#if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))) + #pragma GCC diagnostic pop +#endif +#endif /* dr_flac_c */ +#endif /* DR_FLAC_IMPLEMENTATION */ + + +/* +REVISION HISTORY +================ +v0.13.4 - TBD + - Add a bounds check when allocating memory during metadata processing. + - Fix a possible overflow error when parsing picture metadata. + - Fix an with seek point parsing. + +v0.13.3 - 2026-01-17 + - Fix a compiler compatibility issue with some inlined assembly. + - Fix a compilation warning. + +v0.13.2 - 2025-12-02 + - Improve robustness of the parsing of picture metadata to improve support for memory constrained embedded devices. + - Fix a warning about an assigned by unused variable. + - Improvements to drflac_open_and_read_pcm_frames_*() and family to avoid excessively large memory allocations from malformed files. + +v0.13.1 - 2025-09-10 + - Fix an error with the NXDK build. + +v0.13.0 - 2025-07-23 + - API CHANGE: Seek origin enums have been renamed to match the naming convention used by other dr_libs libraries: + - drflac_seek_origin_start -> DRFLAC_SEEK_SET + - drflac_seek_origin_current -> DRFLAC_SEEK_CUR + - DRFLAC_SEEK_END (new) + - API CHANGE: A new seek origin has been added to allow seeking from the end of the file. If you implement your own `onSeek` callback, you should now detect and handle `DRFLAC_SEEK_END`. If seeking to the end is not supported, return `DRFLAC_FALSE`. If you only use `*_open_file()` or `*_open_memory()`, you need not change anything. + - API CHANGE: An `onTell` callback has been added to the following functions: + - drflac_open() + - drflac_open_relaxed() + - drflac_open_with_metadata() + - drflac_open_with_metadata_relaxed() + - drflac_open_and_read_pcm_frames_s32() + - drflac_open_and_read_pcm_frames_s16() + - drflac_open_and_read_pcm_frames_f32() + - Fix compilation for AIX OS. + +v0.12.43 - 2024-12-17 + - Fix a possible buffer overflow during decoding. + - Improve detection of ARM64EC + +v0.12.42 - 2023-11-02 + - Fix build for ARMv6-M. + - Fix a compilation warning with GCC. + +v0.12.41 - 2023-06-17 + - Fix an incorrect date in revision history. No functional change. + +v0.12.40 - 2023-05-22 + - Minor code restructure. No functional change. + +v0.12.39 - 2022-09-17 + - Fix compilation with DJGPP. + - Fix compilation error with Visual Studio 2019 and the ARM build. + - Fix an error with SSE 4.1 detection. + - Add support for disabling wchar_t with DR_WAV_NO_WCHAR. + - Improve compatibility with compilers which lack support for explicit struct packing. + - Improve compatibility with low-end and embedded hardware by reducing the amount of stack + allocation when loading an Ogg encapsulated file. + +v0.12.38 - 2022-04-10 + - Fix compilation error on older versions of GCC. + +v0.12.37 - 2022-02-12 + - Improve ARM detection. + +v0.12.36 - 2022-02-07 + - Fix a compilation error with the ARM build. + +v0.12.35 - 2022-02-06 + - Fix a bug due to underestimating the amount of precision required for the prediction stage. + - Fix some bugs found from fuzz testing. + +v0.12.34 - 2022-01-07 + - Fix some misalignment bugs when reading metadata. + +v0.12.33 - 2021-12-22 + - Fix a bug with seeking when the seek table does not start at PCM frame 0. + +v0.12.32 - 2021-12-11 + - Fix a warning with Clang. + +v0.12.31 - 2021-08-16 + - Silence some warnings. + +v0.12.30 - 2021-07-31 + - Fix platform detection for ARM64. + +v0.12.29 - 2021-04-02 + - Fix a bug where the running PCM frame index is set to an invalid value when over-seeking. + - Fix a decoding error due to an incorrect validation check. + +v0.12.28 - 2021-02-21 + - Fix a warning due to referencing _MSC_VER when it is undefined. + +v0.12.27 - 2021-01-31 + - Fix a static analysis warning. + +v0.12.26 - 2021-01-17 + - Fix a compilation warning due to _BSD_SOURCE being deprecated. + +v0.12.25 - 2020-12-26 + - Update documentation. + +v0.12.24 - 2020-11-29 + - Fix ARM64/NEON detection when compiling with MSVC. + +v0.12.23 - 2020-11-21 + - Fix compilation with OpenWatcom. + +v0.12.22 - 2020-11-01 + - Fix an error with the previous release. + +v0.12.21 - 2020-11-01 + - Fix a possible deadlock when seeking. + - Improve compiler support for older versions of GCC. + +v0.12.20 - 2020-09-08 + - Fix a compilation error on older compilers. + +v0.12.19 - 2020-08-30 + - Fix a bug due to an undefined 32-bit shift. + +v0.12.18 - 2020-08-14 + - Fix a crash when compiling with clang-cl. + +v0.12.17 - 2020-08-02 + - Simplify sized types. + +v0.12.16 - 2020-07-25 + - Fix a compilation warning. + +v0.12.15 - 2020-07-06 + - Check for negative LPC shifts and return an error. + +v0.12.14 - 2020-06-23 + - Add include guard for the implementation section. + +v0.12.13 - 2020-05-16 + - Add compile-time and run-time version querying. + - DRFLAC_VERSION_MINOR + - DRFLAC_VERSION_MAJOR + - DRFLAC_VERSION_REVISION + - DRFLAC_VERSION_STRING + - drflac_version() + - drflac_version_string() + +v0.12.12 - 2020-04-30 + - Fix compilation errors with VC6. + +v0.12.11 - 2020-04-19 + - Fix some pedantic warnings. + - Fix some undefined behaviour warnings. + +v0.12.10 - 2020-04-10 + - Fix some bugs when trying to seek with an invalid seek table. + +v0.12.9 - 2020-04-05 + - Fix warnings. + +v0.12.8 - 2020-04-04 + - Add drflac_open_file_w() and drflac_open_file_with_metadata_w(). + - Fix some static analysis warnings. + - Minor documentation updates. + +v0.12.7 - 2020-03-14 + - Fix compilation errors with VC6. + +v0.12.6 - 2020-03-07 + - Fix compilation error with Visual Studio .NET 2003. + +v0.12.5 - 2020-01-30 + - Silence some static analysis warnings. + +v0.12.4 - 2020-01-29 + - Silence some static analysis warnings. + +v0.12.3 - 2019-12-02 + - Fix some warnings when compiling with GCC and the -Og flag. + - Fix a crash in out-of-memory situations. + - Fix potential integer overflow bug. + - Fix some static analysis warnings. + - Fix a possible crash when using custom memory allocators without a custom realloc() implementation. + - Fix a bug with binary search seeking where the bits per sample is not a multiple of 8. + +v0.12.2 - 2019-10-07 + - Internal code clean up. + +v0.12.1 - 2019-09-29 + - Fix some Clang Static Analyzer warnings. + - Fix an unused variable warning. + +v0.12.0 - 2019-09-23 + - API CHANGE: Add support for user defined memory allocation routines. This system allows the program to specify their own memory allocation + routines with a user data pointer for client-specific contextual data. This adds an extra parameter to the end of the following APIs: + - drflac_open() + - drflac_open_relaxed() + - drflac_open_with_metadata() + - drflac_open_with_metadata_relaxed() + - drflac_open_file() + - drflac_open_file_with_metadata() + - drflac_open_memory() + - drflac_open_memory_with_metadata() + - drflac_open_and_read_pcm_frames_s32() + - drflac_open_and_read_pcm_frames_s16() + - drflac_open_and_read_pcm_frames_f32() + - drflac_open_file_and_read_pcm_frames_s32() + - drflac_open_file_and_read_pcm_frames_s16() + - drflac_open_file_and_read_pcm_frames_f32() + - drflac_open_memory_and_read_pcm_frames_s32() + - drflac_open_memory_and_read_pcm_frames_s16() + - drflac_open_memory_and_read_pcm_frames_f32() + Set this extra parameter to NULL to use defaults which is the same as the previous behaviour. Setting this NULL will use + DRFLAC_MALLOC, DRFLAC_REALLOC and DRFLAC_FREE. + - Remove deprecated APIs: + - drflac_read_s32() + - drflac_read_s16() + - drflac_read_f32() + - drflac_seek_to_sample() + - drflac_open_and_decode_s32() + - drflac_open_and_decode_s16() + - drflac_open_and_decode_f32() + - drflac_open_and_decode_file_s32() + - drflac_open_and_decode_file_s16() + - drflac_open_and_decode_file_f32() + - drflac_open_and_decode_memory_s32() + - drflac_open_and_decode_memory_s16() + - drflac_open_and_decode_memory_f32() + - Remove drflac.totalSampleCount which is now replaced with drflac.totalPCMFrameCount. You can emulate drflac.totalSampleCount + by doing pFlac->totalPCMFrameCount*pFlac->channels. + - Rename drflac.currentFrame to drflac.currentFLACFrame to remove ambiguity with PCM frames. + - Fix errors when seeking to the end of a stream. + - Optimizations to seeking. + - SSE improvements and optimizations. + - ARM NEON optimizations. + - Optimizations to drflac_read_pcm_frames_s16(). + - Optimizations to drflac_read_pcm_frames_s32(). + +v0.11.10 - 2019-06-26 + - Fix a compiler error. + +v0.11.9 - 2019-06-16 + - Silence some ThreadSanitizer warnings. + +v0.11.8 - 2019-05-21 + - Fix warnings. + +v0.11.7 - 2019-05-06 + - C89 fixes. + +v0.11.6 - 2019-05-05 + - Add support for C89. + - Fix a compiler warning when CRC is disabled. + - Change license to choice of public domain or MIT-0. + +v0.11.5 - 2019-04-19 + - Fix a compiler error with GCC. + +v0.11.4 - 2019-04-17 + - Fix some warnings with GCC when compiling with -std=c99. + +v0.11.3 - 2019-04-07 + - Silence warnings with GCC. + +v0.11.2 - 2019-03-10 + - Fix a warning. + +v0.11.1 - 2019-02-17 + - Fix a potential bug with seeking. + +v0.11.0 - 2018-12-16 + - API CHANGE: Deprecated drflac_read_s32(), drflac_read_s16() and drflac_read_f32() and replaced them with + drflac_read_pcm_frames_s32(), drflac_read_pcm_frames_s16() and drflac_read_pcm_frames_f32(). The new APIs take + and return PCM frame counts instead of sample counts. To upgrade you will need to change the input count by + dividing it by the channel count, and then do the same with the return value. + - API_CHANGE: Deprecated drflac_seek_to_sample() and replaced with drflac_seek_to_pcm_frame(). Same rules as + the changes to drflac_read_*() apply. + - API CHANGE: Deprecated drflac_open_and_decode_*() and replaced with drflac_open_*_and_read_*(). Same rules as + the changes to drflac_read_*() apply. + - Optimizations. + +v0.10.0 - 2018-09-11 + - Remove the DR_FLAC_NO_WIN32_IO option and the Win32 file IO functionality. If you need to use Win32 file IO you + need to do it yourself via the callback API. + - Fix the clang build. + - Fix undefined behavior. + - Fix errors with CUESHEET metdata blocks. + - Add an API for iterating over each cuesheet track in the CUESHEET metadata block. This works the same way as the + Vorbis comment API. + - Other miscellaneous bug fixes, mostly relating to invalid FLAC streams. + - Minor optimizations. + +v0.9.11 - 2018-08-29 + - Fix a bug with sample reconstruction. + +v0.9.10 - 2018-08-07 + - Improve 64-bit detection. + +v0.9.9 - 2018-08-05 + - Fix C++ build on older versions of GCC. + +v0.9.8 - 2018-07-24 + - Fix compilation errors. + +v0.9.7 - 2018-07-05 + - Fix a warning. + +v0.9.6 - 2018-06-29 + - Fix some typos. + +v0.9.5 - 2018-06-23 + - Fix some warnings. + +v0.9.4 - 2018-06-14 + - Optimizations to seeking. + - Clean up. + +v0.9.3 - 2018-05-22 + - Bug fix. + +v0.9.2 - 2018-05-12 + - Fix a compilation error due to a missing break statement. + +v0.9.1 - 2018-04-29 + - Fix compilation error with Clang. + +v0.9 - 2018-04-24 + - Fix Clang build. + - Start using major.minor.revision versioning. + +v0.8g - 2018-04-19 + - Fix build on non-x86/x64 architectures. + +v0.8f - 2018-02-02 + - Stop pretending to support changing rate/channels mid stream. + +v0.8e - 2018-02-01 + - Fix a crash when the block size of a frame is larger than the maximum block size defined by the FLAC stream. + - Fix a crash the the Rice partition order is invalid. + +v0.8d - 2017-09-22 + - Add support for decoding streams with ID3 tags. ID3 tags are just skipped. + +v0.8c - 2017-09-07 + - Fix warning on non-x86/x64 architectures. + +v0.8b - 2017-08-19 + - Fix build on non-x86/x64 architectures. + +v0.8a - 2017-08-13 + - A small optimization for the Clang build. + +v0.8 - 2017-08-12 + - API CHANGE: Rename dr_* types to drflac_*. + - Optimizations. This brings dr_flac back to about the same class of efficiency as the reference implementation. + - Add support for custom implementations of malloc(), realloc(), etc. + - Add CRC checking to Ogg encapsulated streams. + - Fix VC++ 6 build. This is only for the C++ compiler. The C compiler is not currently supported. + - Bug fixes. + +v0.7 - 2017-07-23 + - Add support for opening a stream without a header block. To do this, use drflac_open_relaxed() / drflac_open_with_metadata_relaxed(). + +v0.6 - 2017-07-22 + - Add support for recovering from invalid frames. With this change, dr_flac will simply skip over invalid frames as if they + never existed. Frames are checked against their sync code, the CRC-8 of the frame header and the CRC-16 of the whole frame. + +v0.5 - 2017-07-16 + - Fix typos. + - Change drflac_bool* types to unsigned. + - Add CRC checking. This makes dr_flac slower, but can be disabled with #define DR_FLAC_NO_CRC. + +v0.4f - 2017-03-10 + - Fix a couple of bugs with the bitstreaming code. + +v0.4e - 2017-02-17 + - Fix some warnings. + +v0.4d - 2016-12-26 + - Add support for 32-bit floating-point PCM decoding. + - Use drflac_int* and drflac_uint* sized types to improve compiler support. + - Minor improvements to documentation. + +v0.4c - 2016-12-26 + - Add support for signed 16-bit integer PCM decoding. + +v0.4b - 2016-10-23 + - A minor change to drflac_bool8 and drflac_bool32 types. + +v0.4a - 2016-10-11 + - Rename drBool32 to drflac_bool32 for styling consistency. + +v0.4 - 2016-09-29 + - API/ABI CHANGE: Use fixed size 32-bit booleans instead of the built-in bool type. + - API CHANGE: Rename drflac_open_and_decode*() to drflac_open_and_decode*_s32(). + - API CHANGE: Swap the order of "channels" and "sampleRate" parameters in drflac_open_and_decode*(). Rationale for this is to + keep it consistent with drflac_audio. + +v0.3f - 2016-09-21 + - Fix a warning with GCC. + +v0.3e - 2016-09-18 + - Fixed a bug where GCC 4.3+ was not getting properly identified. + - Fixed a few typos. + - Changed date formats to ISO 8601 (YYYY-MM-DD). + +v0.3d - 2016-06-11 + - Minor clean up. + +v0.3c - 2016-05-28 + - Fixed compilation error. + +v0.3b - 2016-05-16 + - Fixed Linux/GCC build. + - Updated documentation. + +v0.3a - 2016-05-15 + - Minor fixes to documentation. + +v0.3 - 2016-05-11 + - Optimizations. Now at about parity with the reference implementation on 32-bit builds. + - Lots of clean up. + +v0.2b - 2016-05-10 + - Bug fixes. + +v0.2a - 2016-05-10 + - Made drflac_open_and_decode() more robust. + - Removed an unused debugging variable + +v0.2 - 2016-05-09 + - Added support for Ogg encapsulation. + - API CHANGE. Have the onSeek callback take a third argument which specifies whether or not the seek + should be relative to the start or the current position. Also changes the seeking rules such that + seeking offsets will never be negative. + - Have drflac_open_and_decode() fail gracefully if the stream has an unknown total sample count. + +v0.1b - 2016-05-07 + - Properly close the file handle in drflac_open_file() and family when the decoder fails to initialize. + - Removed a stale comment. + +v0.1a - 2016-05-05 + - Minor formatting changes. + - Fixed a warning on the GCC build. + +v0.1 - 2016-05-03 + - Initial versioned release. +*/ + +/* +This software is available as a choice of the following licenses. Choose +whichever you prefer. + +=============================================================================== +ALTERNATIVE 1 - Public Domain (www.unlicense.org) +=============================================================================== +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. + +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to + +=============================================================================== +ALTERNATIVE 2 - MIT No Attribution +=============================================================================== +Copyright 2023 David Reid + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ diff --git a/src/lib/dr_flac/dr_flac_impl.c b/src/lib/dr_flac/dr_flac_impl.c new file mode 100644 index 00000000..955dd6ad --- /dev/null +++ b/src/lib/dr_flac/dr_flac_impl.c @@ -0,0 +1,14 @@ +/* +Implementation translation unit for dr_flac. + +dr_flac.h is a normal header unless DR_FLAC_IMPLEMENTATION is defined in exactly +one translation unit; this is that unit. DR_FLAC_NO_STDIO drops the FILE*-based +helpers bstone does not use (it decodes from an in-memory buffer), and +DR_FLAC_NO_OGG drops Ogg-encapsulated FLAC, which bstone does not support. +*/ + +#define DR_FLAC_IMPLEMENTATION +#define DR_FLAC_NO_STDIO +#define DR_FLAC_NO_OGG + +#include "dr_flac.h" diff --git a/src/lib/flac/CMakeLists.txt b/src/lib/flac/CMakeLists.txt deleted file mode 100644 index 3772918d..00000000 --- a/src/lib/flac/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# bstone -cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -add_subdirectory(src) diff --git a/src/lib/flac/COPYING.Xiph b/src/lib/flac/COPYING.Xiph deleted file mode 100644 index f42f48b3..00000000 --- a/src/lib/flac/COPYING.Xiph +++ /dev/null @@ -1,29 +0,0 @@ -Copyright (C) 2000-2009 Josh Coalson -Copyright (C) 2011-2025 Xiph.Org Foundation - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -- Neither the name of the Xiph.Org Foundation nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/lib/flac/bstone_flac_changelog.txt b/src/lib/flac/bstone_flac_changelog.txt deleted file mode 100644 index cd0713e2..00000000 --- a/src/lib/flac/bstone_flac_changelog.txt +++ /dev/null @@ -1,12 +0,0 @@ -Based on https://downloads.xiph.org/releases/flac/flac-1.5.0.tar.xz -Lookup "/* bstone */" for changes. - -- Essential files related to decoding only. -- Custom CMake scripts. -- No assembler code. -- No file API, only callbacks. -- No Ogg support. -- No standard error/input/output. - -Next upgrade notes -- Synchronize PACKAGE_VERSION value in src/libFLAC/CMakeLists.txt on upgrade. diff --git a/src/lib/flac/include/FLAC/assert.h b/src/lib/flac/include/FLAC/assert.h deleted file mode 100644 index 7b98526d..00000000 --- a/src/lib/flac/include/FLAC/assert.h +++ /dev/null @@ -1,51 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ASSERT_H -#define FLAC__ASSERT_H - -/* we need this since some compilers (like MSVC) leave assert()s on release code (and we don't want to use their ASSERT) */ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -#define FLAC__ASSERT(x) if(!(x)) __builtin_abort(); -#define FLAC__ASSERT_DECLARATION(x) x -#else -#ifndef NDEBUG -#include -#define FLAC__ASSERT(x) assert(x) -#define FLAC__ASSERT_DECLARATION(x) x -#else -#define FLAC__ASSERT(x) -#define FLAC__ASSERT_DECLARATION(x) -#endif -#endif - -#endif diff --git a/src/lib/flac/include/FLAC/callback.h b/src/lib/flac/include/FLAC/callback.h deleted file mode 100644 index a3b65cae..00000000 --- a/src/lib/flac/include/FLAC/callback.h +++ /dev/null @@ -1,190 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__CALLBACK_H -#define FLAC__CALLBACK_H - -#include "ordinals.h" -#include /* for size_t */ - -/** \file include/FLAC/callback.h - * - * \brief - * This module defines the structures for describing I/O callbacks - * to the other FLAC interfaces. - * - * See the detailed documentation for callbacks in the - * \link flac_callbacks callbacks \endlink module. - */ - -/** \defgroup flac_callbacks FLAC/callback.h: I/O callback structures - * \ingroup flac - * - * \brief - * This module defines the structures for describing I/O callbacks - * to the other FLAC interfaces. - * - * The purpose of the I/O callback functions is to create a common way - * for the metadata interfaces to handle I/O. - * - * Originally the metadata interfaces required filenames as the way of - * specifying FLAC files to operate on. This is problematic in some - * environments so there is an additional option to specify a set of - * callbacks for doing I/O on the FLAC file, instead of the filename. - * - * In addition to the callbacks, a FLAC__IOHandle type is defined as an - * opaque structure for a data source. - * - * The callback function prototypes are similar (but not identical) to the - * stdio functions fread, fwrite, fseek, ftell, feof, and fclose. If you use - * stdio streams to implement the callbacks, you can pass fread, fwrite, and - * fclose anywhere a FLAC__IOCallback_Read, FLAC__IOCallback_Write, or - * FLAC__IOCallback_Close is required, and a FILE* anywhere a FLAC__IOHandle - * is required. \warning You generally CANNOT directly use fseek or ftell - * for FLAC__IOCallback_Seek or FLAC__IOCallback_Tell since on most systems - * these use 32-bit offsets and FLAC requires 64-bit offsets to deal with - * large files. You will have to find an equivalent function (e.g. ftello), - * or write a wrapper. The same is true for feof() since this is usually - * implemented as a macro, not as a function whose address can be taken. - * - * \{ - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** This is the opaque handle type used by the callbacks. Typically - * this is a \c FILE* or address of a file descriptor. - */ -typedef void* FLAC__IOHandle; - -/** Signature for the read callback. - * The signature and semantics match POSIX fread() implementations - * and can generally be used interchangeably. Note that the global - * variable errno from errno.h is read by some libFLAC functions to - * detect read errors. - * - * \param ptr The address of the read buffer. - * \param size The size of the records to be read. - * \param nmemb The number of records to be read. - * \param handle The handle to the data source. - * \retval size_t - * The number of records read. - */ -typedef size_t (*FLAC__IOCallback_Read) (void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); - -/** Signature for the write callback. - * The signature and semantics match POSIX fwrite() implementations - * and can generally be used interchangeably. - * - * \param ptr The address of the write buffer. - * \param size The size of the records to be written. - * \param nmemb The number of records to be written. - * \param handle The handle to the data source. - * \retval size_t - * The number of records written. - */ -typedef size_t (*FLAC__IOCallback_Write) (const void *ptr, size_t size, size_t nmemb, FLAC__IOHandle handle); - -/** Signature for the seek callback. - * The signature and semantics mostly match POSIX fseek() WITH ONE IMPORTANT - * EXCEPTION: the offset is a 64-bit type whereas fseek() is generally 'long' - * and 32-bits wide. - * - * \param handle The handle to the data source. - * \param offset The new position, relative to \a whence - * \param whence \c SEEK_SET, \c SEEK_CUR, or \c SEEK_END - * \retval int - * \c 0 on success, \c -1 on error. - */ -typedef int (*FLAC__IOCallback_Seek) (FLAC__IOHandle handle, FLAC__int64 offset, int whence); - -/** Signature for the tell callback. - * The signature and semantics mostly match POSIX ftell() WITH ONE IMPORTANT - * EXCEPTION: the offset is a 64-bit type whereas ftell() is generally 'long' - * and 32-bits wide. - * - * \param handle The handle to the data source. - * \retval FLAC__int64 - * The current position on success, \c -1 on error. - */ -typedef FLAC__int64 (*FLAC__IOCallback_Tell) (FLAC__IOHandle handle); - -/** Signature for the EOF callback. - * The signature and semantics mostly match POSIX feof() but WATCHOUT: - * on many systems, feof() is a macro, so in this case a wrapper function - * must be provided instead. - * - * \param handle The handle to the data source. - * \retval int - * \c 0 if not at end of file, nonzero if at end of file. - */ -typedef int (*FLAC__IOCallback_Eof) (FLAC__IOHandle handle); - -/** Signature for the close callback. - * The signature and semantics match POSIX fclose() implementations - * and can generally be used interchangeably. - * - * \param handle The handle to the data source. - * \retval int - * \c 0 on success, \c EOF on error. - */ -typedef int (*FLAC__IOCallback_Close) (FLAC__IOHandle handle); - -/** A structure for holding a set of callbacks. - * Each FLAC interface that requires a FLAC__IOCallbacks structure will - * describe which of the callbacks are required. The ones that are not - * required may be set to NULL. - * - * If the seek requirement for an interface is optional, you can signify that - * a data source is not seekable by setting the \a seek field to \c NULL. - * - * See the detailed documentation for callbacks in the - * \link flac_callbacks callbacks \endlink module. - */ -typedef struct { - FLAC__IOCallback_Read read; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Write write; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Seek seek; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Tell tell; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Eof eof; /**< See FLAC__IOCallbacks */ - FLAC__IOCallback_Close close; /**< See FLAC__IOCallbacks */ -} FLAC__IOCallbacks; - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/lib/flac/include/FLAC/export.h b/src/lib/flac/include/FLAC/export.h deleted file mode 100644 index b5203392..00000000 --- a/src/lib/flac/include/FLAC/export.h +++ /dev/null @@ -1,115 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__EXPORT_H -#define FLAC__EXPORT_H - -/** \file include/FLAC/export.h - * - * \brief - * This module contains \#defines and symbols for exporting function - * calls, and providing version information and compiled-in features. - * - * See the \link flac_export export \endlink module. - */ - -/** \defgroup flac_export FLAC/export.h: export symbols - * \ingroup flac - * - * \brief - * This module contains \#defines and symbols for exporting function - * calls, and providing version information and compiled-in features. - * - * If you are compiling for Windows (with Visual Studio or MinGW for - * example) and will link to the static library (libFLAC++.lib) you - * should define FLAC__NO_DLL in your project to make sure the symbols - * are exported properly. - * - * \{ - */ - -/** This \#define is used internally in libFLAC and its headers to make - * sure the correct symbols are exported when working with shared - * libraries. On Windows, this \#define is set to __declspec(dllexport) - * when compiling libFLAC into a library and to __declspec(dllimport) - * when the headers are used to link to that DLL. On non-Windows systems - * it is used to set symbol visibility. - * - * Because of this, the define FLAC__NO_DLL must be defined when linking - * to libFLAC statically or linking will fail. - */ -/* This has grown quite complicated. FLAC__NO_DLL is used by MSVC sln - * files and CMake, which build either static or shared. autotools can - * build static, shared or **both**. Therefore, DLL_EXPORT, which is set - * by libtool, must override FLAC__NO_DLL on building shared components - */ -#if defined(_WIN32) - -#if defined(FLAC__NO_DLL) && !(defined(DLL_EXPORT)) -#define FLAC_API -#else -#ifdef FLAC_API_EXPORTS -#define FLAC_API __declspec(dllexport) -#else -#define FLAC_API __declspec(dllimport) -#endif -#endif - -#elif defined(FLAC__USE_VISIBILITY_ATTR) -#define FLAC_API __attribute__ ((visibility ("default"))) - -#else -#define FLAC_API - -#endif - -/** These \#defines will mirror the libtool-based library version number, see - * http://www.gnu.org/software/libtool/manual/libtool.html#Libtool-versioning - */ -#define FLAC_API_VERSION_CURRENT 14 -#define FLAC_API_VERSION_REVISION 0 /**< see above */ -#define FLAC_API_VERSION_AGE 0 /**< see above */ - -#ifdef __cplusplus -extern "C" { -#endif - -/** \c 1 if the library has been compiled with support for Ogg FLAC, else \c 0. */ -extern FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC; - -#ifdef __cplusplus -} -#endif - -/* \} */ - -#endif diff --git a/src/lib/flac/include/FLAC/format.h b/src/lib/flac/include/FLAC/format.h deleted file mode 100644 index 48876d67..00000000 --- a/src/lib/flac/include/FLAC/format.h +++ /dev/null @@ -1,1032 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__FORMAT_H -#define FLAC__FORMAT_H - -#include "export.h" -#include "ordinals.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** \file include/FLAC/format.h - * - * \brief - * This module contains structure definitions for the representation - * of FLAC format components in memory. These are the basic - * structures used by the rest of the interfaces. - * - * See the detailed documentation in the - * \link flac_format format \endlink module. - */ - -/** \defgroup flac_format FLAC/format.h: format components - * \ingroup flac - * - * \brief - * This module contains structure definitions for the representation - * of FLAC format components in memory. These are the basic - * structures used by the rest of the interfaces. - * - * First, you should be familiar with the - * FLAC format. Many of the values here - * follow directly from the specification. As a user of libFLAC, the - * interesting parts really are the structures that describe the frame - * header and metadata blocks. - * - * The format structures here are very primitive, designed to store - * information in an efficient way. Reading information from the - * structures is easy but creating or modifying them directly is - * more complex. For the most part, as a user of a library, editing - * is not necessary; however, for metadata blocks it is, so there are - * convenience functions provided in the \link flac_metadata metadata - * module \endlink to simplify the manipulation of metadata blocks. - * - * \note - * It's not the best convention, but symbols ending in _LEN are in bits - * and _LENGTH are in bytes. _LENGTH symbols are \#defines instead of - * global variables because they are usually used when declaring byte - * arrays and some compilers require compile-time knowledge of array - * sizes when declared on the stack. - * - * \{ - */ - - -/* - Most of the values described in this file are defined by the FLAC - format specification. There is nothing to tune here. -*/ - -/** The largest legal metadata type code. */ -#define FLAC__MAX_METADATA_TYPE_CODE (126u) - -/** The minimum block size, in samples, permitted by the format. */ -#define FLAC__MIN_BLOCK_SIZE (16u) - -/** The maximum block size, in samples, permitted by the format. */ -#define FLAC__MAX_BLOCK_SIZE (65535u) - -/** The maximum block size, in samples, permitted by the FLAC subset for - * sample rates up to 48kHz. */ -#define FLAC__SUBSET_MAX_BLOCK_SIZE_48000HZ (4608u) - -/** The maximum number of channels permitted by the format. */ -#define FLAC__MAX_CHANNELS (8u) - -/** The minimum sample resolution permitted by the format. */ -#define FLAC__MIN_BITS_PER_SAMPLE (4u) - -/** The maximum sample resolution permitted by the format. */ -#define FLAC__MAX_BITS_PER_SAMPLE (32u) - -/** The maximum sample resolution permitted by libFLAC. - * - * FLAC__MAX_BITS_PER_SAMPLE is the limit of the FLAC format. However, - * the reference encoder/decoder used to be limited to 24 bits. This - * value was used to signal that limit. - */ -#define FLAC__REFERENCE_CODEC_MAX_BITS_PER_SAMPLE (32u) - -/** The maximum sample rate permitted by the format. The value is - * ((2 ^ 20) - 1) - */ -#define FLAC__MAX_SAMPLE_RATE (1048575u) - -/** The maximum LPC order permitted by the format. */ -#define FLAC__MAX_LPC_ORDER (32u) - -/** The maximum LPC order permitted by the FLAC subset for sample rates - * up to 48kHz. */ -#define FLAC__SUBSET_MAX_LPC_ORDER_48000HZ (12u) - -/** The minimum quantized linear predictor coefficient precision - * permitted by the format. - */ -#define FLAC__MIN_QLP_COEFF_PRECISION (5u) - -/** The maximum quantized linear predictor coefficient precision - * permitted by the format. - */ -#define FLAC__MAX_QLP_COEFF_PRECISION (15u) - -/** The maximum order of the fixed predictors permitted by the format. */ -#define FLAC__MAX_FIXED_ORDER (4u) - -/** The maximum Rice partition order permitted by the format. */ -#define FLAC__MAX_RICE_PARTITION_ORDER (15u) - -/** The maximum Rice partition order permitted by the FLAC Subset. */ -#define FLAC__SUBSET_MAX_RICE_PARTITION_ORDER (8u) - -/** The version string of the release, stamped onto the libraries and binaries. - * - * \note - * This does not correspond to the shared library version number, which - * is used to determine binary compatibility. - */ -extern FLAC_API const char *FLAC__VERSION_STRING; - -/** The vendor string inserted by the encoder into the VORBIS_COMMENT block. - * This is a NUL-terminated ASCII string; when inserted into the - * VORBIS_COMMENT the trailing null is stripped. - */ -extern FLAC_API const char *FLAC__VENDOR_STRING; - -/** The byte string representation of the beginning of a FLAC stream. */ -extern FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4]; /* = "fLaC" */ - -/** The 32-bit integer big-endian representation of the beginning of - * a FLAC stream. - */ -extern FLAC_API const uint32_t FLAC__STREAM_SYNC; /* = 0x664C6143 */ - -/** The length of the FLAC signature in bits. */ -extern FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN; /* = 32 bits */ - -/** The length of the FLAC signature in bytes. */ -#define FLAC__STREAM_SYNC_LENGTH (4u) - - -/***************************************************************************** - * - * Subframe structures - * - *****************************************************************************/ - -/*****************************************************************************/ - -/** An enumeration of the available entropy coding methods. */ -typedef enum { - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE = 0, - /**< Residual is coded by partitioning into contexts, each with it's own - * 4-bit Rice parameter. */ - - FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2 = 1 - /**< Residual is coded by partitioning into contexts, each with it's own - * 5-bit Rice parameter. */ -} FLAC__EntropyCodingMethodType; - -/** Maps a FLAC__EntropyCodingMethodType to a C string. - * - * Using a FLAC__EntropyCodingMethodType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__EntropyCodingMethodTypeString[]; - - -/** Contents of a Rice partitioned residual - */ -typedef struct { - - uint32_t *parameters; - /**< The Rice parameters for each context. */ - - uint32_t *raw_bits; - /**< Widths for escape-coded partitions. Will be non-zero for escaped - * partitions and zero for unescaped partitions. - */ - - uint32_t capacity_by_order; - /**< The capacity of the \a parameters and \a raw_bits arrays - * specified as an order, i.e. the number of array elements - * allocated is 2 ^ \a capacity_by_order. - */ -} FLAC__EntropyCodingMethod_PartitionedRiceContents; - -/** Header for a Rice partitioned residual. (c.f. format specification) - */ -typedef struct { - - uint32_t order; - /**< The partition order, i.e. # of contexts = 2 ^ \a order. */ - - const FLAC__EntropyCodingMethod_PartitionedRiceContents *contents; - /**< The context's Rice parameters and/or raw bits. */ - -} FLAC__EntropyCodingMethod_PartitionedRice; - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN; /**< == 5 (bits) */ -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN; /**< == 5 (bits) */ - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; -/**< == (1<format specification) - */ -typedef struct { - FLAC__EntropyCodingMethodType type; - union { - FLAC__EntropyCodingMethod_PartitionedRice partitioned_rice; - } data; -} FLAC__EntropyCodingMethod; - -extern FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN; /**< == 2 (bits) */ - -/*****************************************************************************/ - -/** An enumeration of the available subframe types. */ -typedef enum { - FLAC__SUBFRAME_TYPE_CONSTANT = 0, /**< constant signal */ - FLAC__SUBFRAME_TYPE_VERBATIM = 1, /**< uncompressed signal */ - FLAC__SUBFRAME_TYPE_FIXED = 2, /**< fixed polynomial prediction */ - FLAC__SUBFRAME_TYPE_LPC = 3 /**< linear prediction */ -} FLAC__SubframeType; - -/** Maps a FLAC__SubframeType to a C string. - * - * Using a FLAC__SubframeType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__SubframeTypeString[]; - - -/** CONSTANT subframe. (c.f. format specification) - */ -typedef struct { - FLAC__int64 value; /**< The constant signal value. */ -} FLAC__Subframe_Constant; - -/** An enumeration of the possible verbatim subframe data types. */ -typedef enum { - FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32, /**< verbatim subframe has 32-bit int */ - FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64 /**< verbatim subframe has 64-bit int */ -} FLAC__VerbatimSubframeDataType; - - -/** VERBATIM subframe. (c.f. format specification) - */ -typedef struct { - union { - const FLAC__int32 *int32; /**< A FLAC__int32 pointer to verbatim signal. */ - const FLAC__int64 *int64; /**< A FLAC__int64 pointer to verbatim signal. */ - } data; - FLAC__VerbatimSubframeDataType data_type; -} FLAC__Subframe_Verbatim; - - -/** FIXED subframe. (c.f. format specification) - */ -typedef struct { - FLAC__EntropyCodingMethod entropy_coding_method; - /**< The residual coding method. */ - - uint32_t order; - /**< The polynomial order. */ - - FLAC__int64 warmup[FLAC__MAX_FIXED_ORDER]; - /**< Warmup samples to prime the predictor, length == order. */ - - const FLAC__int32 *residual; - /**< The residual signal, length == (blocksize minus order) samples. */ -} FLAC__Subframe_Fixed; - - -/** LPC subframe. (c.f. format specification) - */ -typedef struct { - FLAC__EntropyCodingMethod entropy_coding_method; - /**< The residual coding method. */ - - uint32_t order; - /**< The FIR order. */ - - uint32_t qlp_coeff_precision; - /**< Quantized FIR filter coefficient precision in bits. */ - - int quantization_level; - /**< The qlp coeff shift needed. */ - - FLAC__int32 qlp_coeff[FLAC__MAX_LPC_ORDER]; - /**< FIR filter coefficients. */ - - FLAC__int64 warmup[FLAC__MAX_LPC_ORDER]; - /**< Warmup samples to prime the predictor, length == order. */ - - const FLAC__int32 *residual; - /**< The residual signal, length == (blocksize minus order) samples. */ -} FLAC__Subframe_LPC; - -extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN; /**< == 5 (bits) */ - - -/** FLAC subframe structure. (c.f. format specification) - */ -typedef struct { - FLAC__SubframeType type; - union { - FLAC__Subframe_Constant constant; - FLAC__Subframe_Fixed fixed; - FLAC__Subframe_LPC lpc; - FLAC__Subframe_Verbatim verbatim; - } data; - uint32_t wasted_bits; -} FLAC__Subframe; - -/** == 1 (bit) - * - * This used to be a zero-padding bit (hence the name - * FLAC__SUBFRAME_ZERO_PAD_LEN) but is now a reserved bit. It still has a - * mandatory value of \c 0 but in the future may take on the value \c 0 or \c 1 - * to mean something else. - */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_ZERO_PAD_LEN; -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LEN; /**< == 6 (bits) */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_WASTED_BITS_FLAG_LEN; /**< == 1 (bit) */ - -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_CONSTANT_BYTE_ALIGNED_MASK; /**< = 0x00 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_VERBATIM_BYTE_ALIGNED_MASK; /**< = 0x02 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_FIXED_BYTE_ALIGNED_MASK; /**< = 0x10 */ -extern FLAC_API const uint32_t FLAC__SUBFRAME_TYPE_LPC_BYTE_ALIGNED_MASK; /**< = 0x40 */ - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Frame structures - * - *****************************************************************************/ - -/** An enumeration of the available channel assignments. */ -typedef enum { - FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT = 0, /**< independent channels */ - FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE = 1, /**< left+side stereo */ - FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE = 2, /**< right+side stereo */ - FLAC__CHANNEL_ASSIGNMENT_MID_SIDE = 3 /**< mid+side stereo */ -} FLAC__ChannelAssignment; - -/** Maps a FLAC__ChannelAssignment to a C string. - * - * Using a FLAC__ChannelAssignment as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__ChannelAssignmentString[]; - -/** An enumeration of the possible frame numbering methods. */ -typedef enum { - FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER, /**< number contains the frame number */ - FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER /**< number contains the sample number of first sample in frame */ -} FLAC__FrameNumberType; - -/** Maps a FLAC__FrameNumberType to a C string. - * - * Using a FLAC__FrameNumberType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__FrameNumberTypeString[]; - - -/** FLAC frame header structure. (c.f. format specification) - */ -typedef struct { - uint32_t blocksize; - /**< The number of samples per subframe. */ - - uint32_t sample_rate; - /**< The sample rate in Hz. */ - - uint32_t channels; - /**< The number of channels (== number of subframes). */ - - FLAC__ChannelAssignment channel_assignment; - /**< The channel assignment for the frame. */ - - uint32_t bits_per_sample; - /**< The sample resolution. */ - - FLAC__FrameNumberType number_type; - /**< The numbering scheme used for the frame. As a convenience, the - * decoder will always convert a frame number to a sample number because - * the rules are complex. */ - - union { - FLAC__uint32 frame_number; - FLAC__uint64 sample_number; - } number; - /**< The frame number or sample number of first sample in frame; - * use the \a number_type value to determine which to use. */ - - FLAC__uint8 crc; - /**< CRC-8 (polynomial = x^8 + x^2 + x^1 + x^0, initialized with 0) - * of the raw frame header bytes, meaning everything before the CRC byte - * including the sync code. - */ -} FLAC__FrameHeader; - -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC; /**< == 0x3ffe; the frame header sync code */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN; /**< == 14 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN; /**< == 1 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN; /**< == 1 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN; /**< == 4 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN; /**< == 3 (bits) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN; /**< == 8 (bits) */ - - -/** FLAC frame footer structure. (c.f. format specification) - */ -typedef struct { - FLAC__uint16 crc; - /**< CRC-16 (polynomial = x^16 + x^15 + x^2 + x^0, initialized with - * 0) of the bytes before the crc, back to and including the frame header - * sync code. - */ -} FLAC__FrameFooter; - -extern FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN; /**< == 16 (bits) */ - - -/** FLAC frame structure. (c.f. format specification) - */ -typedef struct { - FLAC__FrameHeader header; - FLAC__Subframe subframes[FLAC__MAX_CHANNELS]; - FLAC__FrameFooter footer; -} FLAC__Frame; - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Meta-data structures - * - *****************************************************************************/ - -/** An enumeration of the available metadata block types. */ -typedef enum { - - FLAC__METADATA_TYPE_STREAMINFO = 0, - /**< STREAMINFO block */ - - FLAC__METADATA_TYPE_PADDING = 1, - /**< PADDING block */ - - FLAC__METADATA_TYPE_APPLICATION = 2, - /**< APPLICATION block */ - - FLAC__METADATA_TYPE_SEEKTABLE = 3, - /**< SEEKTABLE block */ - - FLAC__METADATA_TYPE_VORBIS_COMMENT = 4, - /**< VORBISCOMMENT block (a.k.a. FLAC tags) */ - - FLAC__METADATA_TYPE_CUESHEET = 5, - /**< CUESHEET block */ - - FLAC__METADATA_TYPE_PICTURE = 6, - /**< PICTURE block */ - - FLAC__METADATA_TYPE_UNDEFINED = 7, - /**< marker to denote beginning of undefined type range; this number will increase as new metadata types are added */ - - FLAC__MAX_METADATA_TYPE = FLAC__MAX_METADATA_TYPE_CODE, - /**< No type will ever be greater than this. There is not enough room in the protocol block. */ -} FLAC__MetadataType; - -/** Maps a FLAC__MetadataType to a C string. - * - * Using a FLAC__MetadataType as the index to this array will - * give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__MetadataTypeString[]; - - -/** FLAC STREAMINFO structure. (c.f. format specification) - */ -typedef struct { - uint32_t min_blocksize, max_blocksize; - uint32_t min_framesize, max_framesize; - uint32_t sample_rate; - uint32_t channels; - uint32_t bits_per_sample; - FLAC__uint64 total_samples; - FLAC__byte md5sum[16]; -} FLAC__StreamMetadata_StreamInfo; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; /**< == 16 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; /**< == 16 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; /**< == 24 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; /**< == 24 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; /**< == 20 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; /**< == 3 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; /**< == 5 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; /**< == 36 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN; /**< == 128 (bits) */ - -/** The total stream length of the STREAMINFO block in bytes. */ -#define FLAC__STREAM_METADATA_STREAMINFO_LENGTH (34u) - -/** FLAC PADDING structure. (c.f. format specification) - */ -typedef struct { - int dummy; - /**< Conceptually this is an empty struct since we don't store the - * padding bytes. Empty structs are not allowed by some C compilers, - * hence the dummy. - */ -} FLAC__StreamMetadata_Padding; - - -/** FLAC APPLICATION structure. (c.f. format specification) - */ -typedef struct { - FLAC__byte id[4]; - FLAC__byte *data; -} FLAC__StreamMetadata_Application; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN; /**< == 32 (bits) */ - -/** SeekPoint structure used in SEEKTABLE blocks. (c.f. format specification) - */ -typedef struct { - FLAC__uint64 sample_number; - /**< The sample number of the target frame. */ - - FLAC__uint64 stream_offset; - /**< The offset, in bytes, of the target frame with respect to - * beginning of the first frame. */ - - uint32_t frame_samples; - /**< The number of samples in the target frame. */ -} FLAC__StreamMetadata_SeekPoint; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN; /**< == 16 (bits) */ - -/** The total stream length of a seek point in bytes. */ -#define FLAC__STREAM_METADATA_SEEKPOINT_LENGTH (18u) - -/** The value used in the \a sample_number field of - * FLAC__StreamMetadataSeekPoint used to indicate a placeholder - * point (== 0xffffffffffffffff). - */ -extern FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - - -/** FLAC SEEKTABLE structure. (c.f. format specification) - * - * \note From the format specification: - * - The seek points must be sorted by ascending sample number. - * - Each seek point's sample number must be the first sample of the - * target frame. - * - Each seek point's sample number must be unique within the table. - * - Existence of a SEEKTABLE block implies a correct setting of - * total_samples in the stream_info block. - * - Behavior is undefined when more than one SEEKTABLE block is - * present in a stream. - */ -typedef struct { - uint32_t num_points; - FLAC__StreamMetadata_SeekPoint *points; -} FLAC__StreamMetadata_SeekTable; - - -/** Vorbis comment entry structure used in VORBIS_COMMENT blocks. (c.f. format specification) - * - * For convenience, the APIs maintain a trailing NUL character at the end of - * \a entry which is not counted toward \a length, i.e. - * \code strlen(entry) == length \endcode - */ -typedef struct { - FLAC__uint32 length; - FLAC__byte *entry; -} FLAC__StreamMetadata_VorbisComment_Entry; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN; /**< == 32 (bits) */ - - -/** FLAC VORBIS_COMMENT structure. (c.f. format specification) - */ -typedef struct { - FLAC__StreamMetadata_VorbisComment_Entry vendor_string; - FLAC__uint32 num_comments; - FLAC__StreamMetadata_VorbisComment_Entry *comments; -} FLAC__StreamMetadata_VorbisComment; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN; /**< == 32 (bits) */ - - -/** FLAC CUESHEET track index structure. (See the - * format specification for - * the full description of each field.) - */ -typedef struct { - FLAC__uint64 offset; - /**< Offset in samples, relative to the track offset, of the index - * point. - */ - - FLAC__byte number; - /**< The index point number. */ -} FLAC__StreamMetadata_CueSheet_Index; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN; /**< == 8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN; /**< == 3*8 (bits) */ - - -/** FLAC CUESHEET track structure. (See the - * format specification for - * the full description of each field.) - */ -typedef struct { - FLAC__uint64 offset; - /**< Track offset in samples, relative to the beginning of the FLAC audio stream. */ - - FLAC__byte number; - /**< The track number. */ - - char isrc[13]; - /**< Track ISRC. This is a 12-digit alphanumeric code plus a trailing \c NUL byte */ - - uint32_t type:1; - /**< The track type: 0 for audio, 1 for non-audio. */ - - uint32_t pre_emphasis:1; - /**< The pre-emphasis flag: 0 for no pre-emphasis, 1 for pre-emphasis. */ - - FLAC__byte num_indices; - /**< The number of track index points. */ - - FLAC__StreamMetadata_CueSheet_Index *indices; - /**< NULL if num_indices == 0, else pointer to array of index points. */ - -} FLAC__StreamMetadata_CueSheet_Track; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN; /**< == 8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN; /**< == 12*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN; /**< == 6+13*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN; /**< == 8 (bits) */ - - -/** FLAC CUESHEET structure. (See the - * format specification - * for the full description of each field.) - */ -typedef struct { - char media_catalog_number[129]; - /**< Media catalog number, in ASCII printable characters 0x20-0x7e. In - * general, the media catalog number may be 0 to 128 bytes long; any - * unused characters should be right-padded with NUL characters. - */ - - FLAC__uint64 lead_in; - /**< The number of lead-in samples. */ - - FLAC__bool is_cd; - /**< \c true if CUESHEET corresponds to a Compact Disc, else \c false. */ - - uint32_t num_tracks; - /**< The number of tracks. */ - - FLAC__StreamMetadata_CueSheet_Track *tracks; - /**< NULL if num_tracks == 0, else pointer to array of tracks. */ - -} FLAC__StreamMetadata_CueSheet; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN; /**< == 128*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN; /**< == 64 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN; /**< == 7+258*8 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN; /**< == 8 (bits) */ - - -/** An enumeration of the PICTURE types (see FLAC__StreamMetadataPicture and id3 v2.4 APIC tag). */ -typedef enum { - FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER = 0, /**< Other */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON_STANDARD = 1, /**< 32x32 pixels 'file icon' (PNG only) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FILE_ICON = 2, /**< Other file icon */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FRONT_COVER = 3, /**< Cover (front) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BACK_COVER = 4, /**< Cover (back) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LEAFLET_PAGE = 5, /**< Leaflet page */ - FLAC__STREAM_METADATA_PICTURE_TYPE_MEDIA = 6, /**< Media (e.g. label side of CD) */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LEAD_ARTIST = 7, /**< Lead artist/lead performer/soloist */ - FLAC__STREAM_METADATA_PICTURE_TYPE_ARTIST = 8, /**< Artist/performer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_CONDUCTOR = 9, /**< Conductor */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BAND = 10, /**< Band/Orchestra */ - FLAC__STREAM_METADATA_PICTURE_TYPE_COMPOSER = 11, /**< Composer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_LYRICIST = 12, /**< Lyricist/text writer */ - FLAC__STREAM_METADATA_PICTURE_TYPE_RECORDING_LOCATION = 13, /**< Recording Location */ - FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_RECORDING = 14, /**< During recording */ - FLAC__STREAM_METADATA_PICTURE_TYPE_DURING_PERFORMANCE = 15, /**< During performance */ - FLAC__STREAM_METADATA_PICTURE_TYPE_VIDEO_SCREEN_CAPTURE = 16, /**< Movie/video screen capture */ - FLAC__STREAM_METADATA_PICTURE_TYPE_FISH = 17, /**< A bright coloured fish */ - FLAC__STREAM_METADATA_PICTURE_TYPE_ILLUSTRATION = 18, /**< Illustration */ - FLAC__STREAM_METADATA_PICTURE_TYPE_BAND_LOGOTYPE = 19, /**< Band/artist logotype */ - FLAC__STREAM_METADATA_PICTURE_TYPE_PUBLISHER_LOGOTYPE = 20, /**< Publisher/Studio logotype */ - FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED -} FLAC__StreamMetadata_Picture_Type; - -/** Maps a FLAC__StreamMetadata_Picture_Type to a C string. - * - * Using a FLAC__StreamMetadata_Picture_Type as the index to this array - * will give the string equivalent. The contents should not be - * modified. - */ -extern FLAC_API const char * const FLAC__StreamMetadata_Picture_TypeString[]; - -/** FLAC PICTURE structure. (See the - * format specification - * for the full description of each field.) - */ -typedef struct { - FLAC__StreamMetadata_Picture_Type type; - /**< The kind of picture stored. */ - - char *mime_type; - /**< Picture data's MIME type, in ASCII printable characters - * 0x20-0x7e, NUL terminated. For best compatibility with players, - * use picture data of MIME type \c image/jpeg or \c image/png. A - * MIME type of '-->' is also allowed, in which case the picture - * data should be a complete URL. In file storage, the MIME type is - * stored as a 32-bit length followed by the ASCII string with no NUL - * terminator, but is converted to a plain C string in this structure - * for convenience. - */ - - FLAC__byte *description; - /**< Picture's description in UTF-8, NUL terminated. In file storage, - * the description is stored as a 32-bit length followed by the UTF-8 - * string with no NUL terminator, but is converted to a plain C string - * in this structure for convenience. - */ - - FLAC__uint32 width; - /**< Picture's width in pixels. */ - - FLAC__uint32 height; - /**< Picture's height in pixels. */ - - FLAC__uint32 depth; - /**< Picture's color depth in bits-per-pixel. */ - - FLAC__uint32 colors; - /**< For indexed palettes (like GIF), picture's number of colors (the - * number of palette entries), or \c 0 for non-indexed (i.e. 2^depth). - */ - - FLAC__uint32 data_length; - /**< Length of binary picture data in bytes. */ - - FLAC__byte *data; - /**< Binary picture data. */ - -} FLAC__StreamMetadata_Picture; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN; /**< == 32 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN; /**< == 32 (bits) */ - - -/** Structure that is used when a metadata block of unknown type is loaded. - * The contents are opaque. The structure is used only internally to - * correctly handle unknown metadata. - */ -typedef struct { - FLAC__byte *data; -} FLAC__StreamMetadata_Unknown; - - -/** FLAC metadata block structure. (c.f. format specification) - */ -typedef struct FLAC__StreamMetadata { - FLAC__MetadataType type; - /**< The type of the metadata block; used determine which member of the - * \a data union to dereference. If type >= FLAC__METADATA_TYPE_UNDEFINED - * then \a data.unknown must be used. */ - - FLAC__bool is_last; - /**< \c true if this metadata block is the last, else \a false */ - - uint32_t length; - /**< Length, in bytes, of the block data as it appears in the stream. */ - - union { - FLAC__StreamMetadata_StreamInfo stream_info; - FLAC__StreamMetadata_Padding padding; - FLAC__StreamMetadata_Application application; - FLAC__StreamMetadata_SeekTable seek_table; - FLAC__StreamMetadata_VorbisComment vorbis_comment; - FLAC__StreamMetadata_CueSheet cue_sheet; - FLAC__StreamMetadata_Picture picture; - FLAC__StreamMetadata_Unknown unknown; - } data; - /**< Polymorphic block data; use the \a type value to determine which - * to use. */ -} FLAC__StreamMetadata; - -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN; /**< == 1 (bit) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN; /**< == 7 (bits) */ -extern FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN; /**< == 24 (bits) */ - -/** The total stream length of a metadata block header in bytes. */ -#define FLAC__STREAM_METADATA_HEADER_LENGTH (4u) - -/*****************************************************************************/ - - -/***************************************************************************** - * - * Utility functions - * - *****************************************************************************/ - -/** Tests that a sample rate is valid for FLAC. - * - * \param sample_rate The sample rate to test for compliance. - * \retval FLAC__bool - * \c true if the given sample rate conforms to the specification, else - * \c false. - */ -FLAC_API FLAC__bool FLAC__format_sample_rate_is_valid(uint32_t sample_rate); - -/** Tests that a blocksize at the given sample rate is valid for the FLAC - * subset. - * - * \param blocksize The blocksize to test for compliance. - * \param sample_rate The sample rate is needed, since the valid subset - * blocksize depends on the sample rate. - * \retval FLAC__bool - * \c true if the given blocksize conforms to the specification for the - * subset at the given sample rate, else \c false. - */ -FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate); - -/** Tests that a sample rate is valid for the FLAC subset. The subset rules - * for valid sample rates are slightly more complex since the rate has to - * be expressible completely in the frame header. - * - * \param sample_rate The sample rate to test for compliance. - * \retval FLAC__bool - * \c true if the given sample rate conforms to the specification for the - * subset, else \c false. - */ -FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate); - -/** Check a Vorbis comment entry name to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment names must be composed only of characters from - * [0x20-0x3C,0x3E-0x7D]. - * - * \param name A NUL-terminated string to be checked. - * \assert - * \code name != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name); - -/** Check a Vorbis comment entry value to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment values must be valid UTF-8 sequences. - * - * \param value A string to be checked. - * \param length A the length of \a value in bytes. May be - * \c (uint32_t)(-1) to indicate that \a value is a plain - * UTF-8 NUL-terminated string. - * \assert - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length); - -/** Check a Vorbis comment entry to see if it conforms to the Vorbis - * comment specification. - * - * Vorbis comment entries must be of the form 'name=value', and 'name' and - * 'value' must be legal according to - * FLAC__format_vorbiscomment_entry_name_is_legal() and - * FLAC__format_vorbiscomment_entry_value_is_legal() respectively. - * - * \param entry An entry to be checked. - * \param length The length of \a entry in bytes. - * \assert - * \code value != NULL \endcode - * \retval FLAC__bool - * \c false if entry name is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length); - -/** Check a seek table to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * seek table. - * - * \param seek_table A pointer to a seek table to be checked. - * \assert - * \code seek_table != NULL \endcode - * \retval FLAC__bool - * \c false if seek table is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table); - -/** Sort a seek table's seek points according to the format specification. - * This includes a "unique-ification" step to remove duplicates, i.e. - * seek points with identical \a sample_number values. Duplicate seek - * points are converted into placeholder points and sorted to the end of - * the table. - * - * \param seek_table A pointer to a seek table to be sorted. - * \assert - * \code seek_table != NULL \endcode - * \retval uint32_t - * The number of duplicate seek points converted into placeholders. - */ -FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table); - -/** Check a cue sheet to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * cue sheet. - * - * \param cue_sheet A pointer to an existing cue sheet to be checked. - * \param check_cd_da_subset If \c true, check CUESHEET against more - * stringent requirements for a CD-DA (audio) disc. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code cue_sheet != NULL \endcode - * \retval FLAC__bool - * \c false if cue sheet is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation); - -/** Check picture data to see if it conforms to the FLAC specification. - * See the format specification for limits on the contents of the - * PICTURE block. - * - * \param picture A pointer to existing picture data to be checked. - * \param violation Address of a pointer to a string. If there is a - * violation, a pointer to a string explanation of the - * violation will be returned here. \a violation may be - * \c NULL if you don't need the returned string. Do not - * free the returned string; it will always point to static - * data. - * \assert - * \code picture != NULL \endcode - * \retval FLAC__bool - * \c false if picture data is illegal, else \c true. - */ -FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/lib/flac/include/FLAC/ordinals.h b/src/lib/flac/include/FLAC/ordinals.h deleted file mode 100644 index 1a413158..00000000 --- a/src/lib/flac/include/FLAC/ordinals.h +++ /dev/null @@ -1,55 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__ORDINALS_H -#define FLAC__ORDINALS_H - -/* This of course assumes C99 headers */ - -#include -#include - -typedef int8_t FLAC__int8; -typedef uint8_t FLAC__uint8; - -typedef int16_t FLAC__int16; -typedef int32_t FLAC__int32; -typedef int64_t FLAC__int64; -typedef uint16_t FLAC__uint16; -typedef uint32_t FLAC__uint32; -typedef uint64_t FLAC__uint64; - -typedef int FLAC__bool; - -typedef FLAC__uint8 FLAC__byte; - -#endif diff --git a/src/lib/flac/include/FLAC/stream_decoder.h b/src/lib/flac/include/FLAC/stream_decoder.h deleted file mode 100644 index 00d85bc3..00000000 --- a/src/lib/flac/include/FLAC/stream_decoder.h +++ /dev/null @@ -1,1792 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__STREAM_DECODER_H -#define FLAC__STREAM_DECODER_H - -#if 0 /* bstone */ -#include /* for FILE */ -#endif /* bstone */ -#include "export.h" -#include "format.h" - -#ifdef __cplusplus -extern "C" { -#endif - - -/** \file include/FLAC/stream_decoder.h - * - * \brief - * This module contains the functions which implement the stream - * decoder. - * - * See the detailed documentation in the - * \link flac_stream_decoder stream decoder \endlink module. - */ - -/** \defgroup flac_decoder FLAC/ \*_decoder.h: decoder interfaces - * \ingroup flac - * - * \brief - * This module describes the decoder layers provided by libFLAC. - * - * The stream decoder can be used to decode complete streams either from - * the client via callbacks, or directly from a file, depending on how - * it is initialized. When decoding via callbacks, the client provides - * callbacks for reading FLAC data and writing decoded samples, and - * handling metadata and errors. If the client also supplies seek-related - * callback, the decoder function for sample-accurate seeking within the - * FLAC input is also available. When decoding from a file, the client - * needs only supply a filename or open \c FILE* and write/metadata/error - * callbacks; the rest of the callbacks are supplied internally. For more - * info see the \link flac_stream_decoder stream decoder \endlink module. - */ - -/** \defgroup flac_stream_decoder FLAC/stream_decoder.h: stream decoder interface - * \ingroup flac_decoder - * - * \brief - * This module contains the functions which implement the stream - * decoder. - * - * The stream decoder can decode native FLAC, and optionally Ogg FLAC - * (check FLAC_API_SUPPORTS_OGG_FLAC) streams and files. - * - * The basic usage of this decoder is as follows: - * - The program creates an instance of a decoder using - * FLAC__stream_decoder_new(). - * - The program overrides the default settings using - * FLAC__stream_decoder_set_*() functions. - * - The program initializes the instance to validate the settings and - * prepare for decoding using - * - FLAC__stream_decoder_init_stream() or FLAC__stream_decoder_init_FILE() - * or FLAC__stream_decoder_init_file() for native FLAC, - * - FLAC__stream_decoder_init_ogg_stream() or FLAC__stream_decoder_init_ogg_FILE() - * or FLAC__stream_decoder_init_ogg_file() for Ogg FLAC - * - The program calls the FLAC__stream_decoder_process_*() functions - * to decode data, which subsequently calls the callbacks. - * - The program finishes the decoding with FLAC__stream_decoder_finish(), - * which flushes the input and output and resets the decoder to the - * uninitialized state. - * - The instance may be used again or deleted with - * FLAC__stream_decoder_delete(). - * - * In more detail, the program will create a new instance by calling - * FLAC__stream_decoder_new(), then call FLAC__stream_decoder_set_*() - * functions to override the default decoder options, and call - * one of the FLAC__stream_decoder_init_*() functions. - * - * There are three initialization functions for native FLAC, one for - * setting up the decoder to decode FLAC data from the client via - * callbacks, and two for decoding directly from a FLAC file. - * - * For decoding via callbacks, use FLAC__stream_decoder_init_stream(). - * You must also supply several callbacks for handling I/O. Some (like - * seeking) are optional, depending on the capabilities of the input. - * - * For decoding directly from a file, use FLAC__stream_decoder_init_FILE() - * or FLAC__stream_decoder_init_file(). Then you must only supply an open - * \c FILE* or filename and fewer callbacks; the decoder will handle - * the other callbacks internally. - * - * There are three similarly-named init functions for decoding from Ogg - * FLAC streams. Check \c FLAC_API_SUPPORTS_OGG_FLAC to find out if the - * library has been built with Ogg support. - * - * Once the decoder is initialized, your program will call one of several - * functions to start the decoding process: - * - * - FLAC__stream_decoder_process_single() - Tells the decoder to process at - * most one metadata block or audio frame and return, calling either the - * metadata callback or write callback, respectively, once. If the decoder - * loses sync it will return with only the error callback being called. - * - FLAC__stream_decoder_process_until_end_of_metadata() - Tells the decoder - * to process the stream from the current location and stop upon reaching - * the first audio frame. The client will get one metadata, write, or error - * callback per metadata block, audio frame, or sync error, respectively. - * - FLAC__stream_decoder_process_until_end_of_stream() - Tells the decoder - * to process the stream from the current location until the read callback - * returns FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM or - * FLAC__STREAM_DECODER_READ_STATUS_ABORT. The client will get one metadata, - * write, or error callback per metadata block, audio frame, or sync error, - * respectively. - * - * When the decoder has finished decoding (normally or through an abort), - * the instance is finished by calling FLAC__stream_decoder_finish(), which - * ensures the decoder is in the correct state and frees memory. Then the - * instance may be deleted with FLAC__stream_decoder_delete() or initialized - * again to decode another stream. - * - * Seeking is exposed through the FLAC__stream_decoder_seek_absolute() method. - * At any point after the stream decoder has been initialized, the client can - * call this function to seek to an exact sample within the stream. - * Subsequently, the first time the write callback is called it will be - * passed a (possibly partial) block starting at that sample. - * - * If the client cannot seek via the callback interface provided, but still - * has another way of seeking, it can flush the decoder using - * FLAC__stream_decoder_flush() and start feeding data from the new position - * through the read callback. - * - * The stream decoder also provides MD5 signature checking. If this is - * turned on before initialization, FLAC__stream_decoder_finish() will - * report when the decoded MD5 signature does not match the one stored - * in the STREAMINFO block. MD5 checking is automatically turned off - * (until the next FLAC__stream_decoder_reset()) if there is no signature - * in the STREAMINFO block or when a seek is attempted. - * - * The FLAC__stream_decoder_set_metadata_*() functions deserve special - * attention. By default, the decoder only calls the metadata_callback for - * the STREAMINFO block. These functions allow you to tell the decoder - * explicitly which blocks to parse and return via the metadata_callback - * and/or which to skip. Use a FLAC__stream_decoder_set_metadata_respond_all(), - * FLAC__stream_decoder_set_metadata_ignore() ... or FLAC__stream_decoder_set_metadata_ignore_all(), - * FLAC__stream_decoder_set_metadata_respond() ... sequence to exactly specify - * which blocks to return. Remember that metadata blocks can potentially - * be big (for example, cover art) so filtering out the ones you don't - * use can reduce the memory requirements of the decoder. Also note the - * special forms FLAC__stream_decoder_set_metadata_respond_application(id) - * and FLAC__stream_decoder_set_metadata_ignore_application(id) for - * filtering APPLICATION blocks based on the application ID. - * - * STREAMINFO and SEEKTABLE blocks are always parsed and used internally, but - * they still can legally be filtered from the metadata_callback. - * - * \note - * The "set" functions may only be called when the decoder is in the - * state FLAC__STREAM_DECODER_UNINITIALIZED, i.e. after - * FLAC__stream_decoder_new() or FLAC__stream_decoder_finish(), but - * before FLAC__stream_decoder_init_*(). If this is the case they will - * return \c true, otherwise \c false. - * - * \note - * FLAC__stream_decoder_finish() resets all settings to the constructor - * defaults, including the callbacks. - * - * \{ - */ - - -/** State values for a FLAC__StreamDecoder - * - * The decoder's state can be obtained by calling FLAC__stream_decoder_get_state(). - */ -typedef enum { - - FLAC__STREAM_DECODER_SEARCH_FOR_METADATA = 0, - /**< The decoder is ready to search for metadata. */ - - FLAC__STREAM_DECODER_READ_METADATA, - /**< The decoder is ready to or is in the process of reading metadata. */ - - FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC, - /**< The decoder is ready to or is in the process of searching for the - * frame sync code. - */ - - FLAC__STREAM_DECODER_READ_FRAME, - /**< The decoder is ready to or is in the process of reading a frame. */ - - FLAC__STREAM_DECODER_END_OF_STREAM, - /**< The decoder has reached the end of the stream. */ - - FLAC__STREAM_DECODER_OGG_ERROR, - /**< An error occurred in the underlying Ogg layer. */ - - FLAC__STREAM_DECODER_SEEK_ERROR, - /**< An error occurred while seeking. The decoder must be flushed - * with FLAC__stream_decoder_flush() or reset with - * FLAC__stream_decoder_reset() before decoding can continue. - */ - - FLAC__STREAM_DECODER_ABORTED, - /**< The decoder was aborted by the read or write callback. */ - - FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. The decoder is in an invalid - * state and can no longer be used. - */ - - FLAC__STREAM_DECODER_UNINITIALIZED, - /**< The decoder is in the uninitialized state; one of the - * FLAC__stream_decoder_init_*() functions must be called before samples - * can be processed. - */ - - FLAC__STREAM_DECODER_END_OF_LINK - /**< The decoder has reached the end of an Ogg FLAC chain link and a new - * link follows; FLAC__stream_decoder_finish_link() has to be called to - * progress. This state is only returned when decoding of chained - * streams is enabled with - * FLAC__stream_decoder_set_decode_chained_stream() - */ - -} FLAC__StreamDecoderState; - -/** Maps a FLAC__StreamDecoderState to a C string. - * - * Using a FLAC__StreamDecoderState as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderStateString[]; - - -/** Possible return values for the FLAC__stream_decoder_init_*() functions. - */ -typedef enum { - - FLAC__STREAM_DECODER_INIT_STATUS_OK = 0, - /**< Initialization was successful. */ - - FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER, - /**< The library was not compiled with support for the given container - * format. - */ - - FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS, - /**< A required callback was not supplied. */ - - FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR, - /**< An error occurred allocating memory. */ - - FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE, - /**< fopen() failed in FLAC__stream_decoder_init_file() or - * FLAC__stream_decoder_init_ogg_file(). */ - - FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED - /**< FLAC__stream_decoder_init_*() was called when the decoder was - * already initialized, usually because - * FLAC__stream_decoder_finish() was not called. - */ - -} FLAC__StreamDecoderInitStatus; - -/** Maps a FLAC__StreamDecoderInitStatus to a C string. - * - * Using a FLAC__StreamDecoderInitStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderInitStatusString[]; - - -/** Return values for the FLAC__StreamDecoder read callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, - /**< The read was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM, - /**< The read was attempted while at the end of the stream. Note that - * the client must only return this value when the read callback was - * called when already at the end of the stream. Otherwise, if the read - * itself moves to the end of the stream, the client should still return - * the data and \c FLAC__STREAM_DECODER_READ_STATUS_CONTINUE, and then on - * the next read callback it should return - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM with a byte count - * of \c 0. - */ - - FLAC__STREAM_DECODER_READ_STATUS_ABORT, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_READ_STATUS_END_OF_LINK - /**< The read was attempted while at the end of the link. The semantics - * are the same as for FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - */ - -} FLAC__StreamDecoderReadStatus; - -/** Maps a FLAC__StreamDecoderReadStatus to a C string. - * - * Using a FLAC__StreamDecoderReadStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderReadStatusString[]; - - -/** Return values for the FLAC__StreamDecoder seek callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_SEEK_STATUS_OK, - /**< The seek was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_SEEK_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - /**< Client does not support seeking. */ - -} FLAC__StreamDecoderSeekStatus; - -/** Maps a FLAC__StreamDecoderSeekStatus to a C string. - * - * Using a FLAC__StreamDecoderSeekStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[]; - - -/** Return values for the FLAC__StreamDecoder tell callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_TELL_STATUS_OK, - /**< The tell was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_TELL_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - /**< Client does not support telling the position. */ - -} FLAC__StreamDecoderTellStatus; - -/** Maps a FLAC__StreamDecoderTellStatus to a C string. - * - * Using a FLAC__StreamDecoderTellStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderTellStatusString[]; - - -/** Return values for the FLAC__StreamDecoder length callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_LENGTH_STATUS_OK, - /**< The length call was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR, - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - - FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - /**< Client does not support reporting the length. */ - -} FLAC__StreamDecoderLengthStatus; - -/** Maps a FLAC__StreamDecoderLengthStatus to a C string. - * - * Using a FLAC__StreamDecoderLengthStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[]; - - -/** Return values for the FLAC__StreamDecoder write callback. - */ -typedef enum { - - FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE, - /**< The write was OK and decoding can continue. */ - - FLAC__STREAM_DECODER_WRITE_STATUS_ABORT - /**< An unrecoverable error occurred. The decoder will return from the process call. */ - -} FLAC__StreamDecoderWriteStatus; - -/** Maps a FLAC__StreamDecoderWriteStatus to a C string. - * - * Using a FLAC__StreamDecoderWriteStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[]; - - -/** Possible values passed back to the FLAC__StreamDecoder error callback. - * \c FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC is the generic catch- - * all. The rest could be caused by bad sync (false synchronization on - * data that is not the start of a frame) or corrupted data. The error - * itself is the decoder's best guess at what happened assuming a correct - * sync. For example \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER - * could be caused by a correct sync on the start of a frame, but some - * data in the frame header was corrupted. Or it could be the result of - * syncing on a point the stream that looked like the starting of a frame - * but was not. \c FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM - * could be because the decoder encountered a valid frame made by a future - * version of the encoder which it cannot parse, or because of a false - * sync making it appear as though an encountered frame was generated by - * a future encoder. \c FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA is - * caused by finding data that doesn't fit a metadata block (too large - * or too small) or finding inconsistencies in the metadata, for example - * a PICTURE block with an image that exceeds the size of the metadata - * block. - */ -typedef enum { - - FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC, - /**< An error in the stream caused the decoder to lose synchronization. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER, - /**< The decoder encountered a corrupted frame header. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH, - /**< The frame's data did not match the CRC in the footer. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM, - /**< The decoder encountered reserved fields in use in the stream. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA, - /**< The decoder encountered a corrupted metadata block. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_OUT_OF_BOUNDS, - /**< The decoder encountered a otherwise valid frame in which - * the decoded samples exceeded the range offered by the stated - * bit depth. */ - - FLAC__STREAM_DECODER_ERROR_STATUS_MISSING_FRAME - /**< Two adjacent frames had frame numbers increasing by more than - * 1 or sample numbers increasing by more than the blocksize, - * indicating that one or more frame/frames was missing between - * them. The decoder will sent out one or more ´fake' constant - * subframes to fill up the gap. */ - -} FLAC__StreamDecoderErrorStatus; - -/** Maps a FLAC__StreamDecoderErrorStatus to a C string. - * - * Using a FLAC__StreamDecoderErrorStatus as the index to this array - * will give the string equivalent. The contents should not be modified. - */ -extern FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[]; - - -/*********************************************************************** - * - * class FLAC__StreamDecoder - * - ***********************************************************************/ - -struct FLAC__StreamDecoderProtected; -struct FLAC__StreamDecoderPrivate; -/** The opaque structure definition for the stream decoder type. - * See the \link flac_stream_decoder stream decoder module \endlink - * for a detailed description. - */ -typedef struct { - struct FLAC__StreamDecoderProtected *protected_; /* avoid the C++ keyword 'protected' */ - struct FLAC__StreamDecoderPrivate *private_; /* avoid the C++ keyword 'private' */ -} FLAC__StreamDecoder; - -/** Signature for the read callback. - * - * A function pointer matching this signature must be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs more input data. The address of the - * buffer to be filled is supplied, along with the number of bytes the - * buffer can hold. The callback may choose to supply less data and - * modify the byte count but must be careful not to overflow the buffer. - * The callback then returns a status code chosen from - * FLAC__StreamDecoderReadStatus. - * - * Here is an example of a read callback for stdio streams: - * \code - * FLAC__StreamDecoderReadStatus read_cb(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(*bytes > 0) { - * *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, file); - * if(ferror(file)) - * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - * else if(*bytes == 0) - * return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - * else - * return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - * } - * else - * return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param buffer A pointer to a location for the callee to store - * data to be decoded. - * \param bytes A pointer to the size of the buffer. On entry - * to the callback, it contains the maximum number - * of bytes that may be stored in \a buffer. The - * callee must set it to the actual number of bytes - * stored (0 in case of error or end-of-stream) before - * returning. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderReadStatus - * The callee's return status. Note that the callback should return - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM if and only if - * zero bytes were read and there is no more data to be read. - */ -typedef FLAC__StreamDecoderReadStatus (*FLAC__StreamDecoderReadCallback)(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); - -/** Signature for the seek callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs to seek the input stream. The decoder - * will pass the absolute byte offset to seek to, 0 meaning the - * beginning of the stream. - * - * Here is an example of a seek callback for stdio streams: - * \code - * FLAC__StreamDecoderSeekStatus seek_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * if(file == stdin) - * return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; - * else if(fseeko(file, (off_t)absolute_byte_offset, SEEK_SET) < 0) - * return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; - * else - * return FLAC__STREAM_DECODER_SEEK_STATUS_OK; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset The offset from the beginning of the stream - * to seek to. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderSeekStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderSeekStatus (*FLAC__StreamDecoderSeekCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); - -/** Signature for the tell callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder wants to know the current position of the - * stream. The callback should return the byte offset from the - * beginning of the stream. - * - * Here is an example of a tell callback for stdio streams: - * \code - * FLAC__StreamDecoderTellStatus tell_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * off_t pos; - * if(file == stdin) - * return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; - * else if((pos = ftello(file)) < 0) - * return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; - * else { - * *absolute_byte_offset = (FLAC__uint64)pos; - * return FLAC__STREAM_DECODER_TELL_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param absolute_byte_offset A pointer to storage for the current offset - * from the beginning of the stream. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderTellStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderTellStatus (*FLAC__StreamDecoderTellCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); - -/** Signature for the length callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder wants to know the total length of the stream - * in bytes. - * - * Here is an example of a length callback for stdio streams: - * \code - * FLAC__StreamDecoderLengthStatus length_cb(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) - * { - * FILE *file = ((MyClientData*)client_data)->file; - * struct stat filestats; - * - * if(file == stdin) - * return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; - * else if(fstat(fileno(file), &filestats) != 0) - * return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; - * else { - * *stream_length = (FLAC__uint64)filestats.st_size; - * return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; - * } - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param stream_length A pointer to storage for the length of the stream - * in bytes. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderLengthStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderLengthStatus (*FLAC__StreamDecoderLengthCallback)(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); - -/** Signature for the EOF callback. - * - * A function pointer matching this signature may be passed to - * FLAC__stream_decoder_init*_stream(). The supplied function will be - * called when the decoder needs to know if the end of the stream has - * been reached. - * - * Here is an example of a EOF callback for stdio streams: - * FLAC__bool eof_cb(const FLAC__StreamDecoder *decoder, void *client_data) - * \code - * { - * FILE *file = ((MyClientData*)client_data)->file; - * return feof(file)? true : false; - * } - * \endcode - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__bool - * \c true if the currently at the end of the stream, else \c false. - */ -typedef FLAC__bool (*FLAC__StreamDecoderEofCallback)(const FLAC__StreamDecoder *decoder, void *client_data); - -/** Signature for the write callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called when the decoder has decoded a - * single audio frame. The decoder will pass the frame metadata as well - * as an array of pointers (one for each channel) pointing to the - * decoded audio. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param frame The description of the decoded frame. See - * FLAC__Frame. - * \param buffer An array of pointers to decoded channels of data. - * Each pointer will point to an array of signed - * samples of length \a frame->header.blocksize. - * Channels will be ordered according to the FLAC - * specification; see the documentation for the - * frame header. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - * \retval FLAC__StreamDecoderWriteStatus - * The callee's return status. - */ -typedef FLAC__StreamDecoderWriteStatus (*FLAC__StreamDecoderWriteCallback)(const FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[], void *client_data); - -/** Signature for the metadata callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called when the decoder has decoded a - * metadata block. In a valid FLAC file there will always be one - * \c STREAMINFO block, followed by zero or more other metadata blocks. - * These will be supplied by the decoder in the same order as they - * appear in the stream and always before the first audio frame (i.e. - * write callback). The metadata block that is passed in must not be - * modified, and it doesn't live beyond the callback, so you should make - * a copy of it with FLAC__metadata_object_clone() if you will need it - * elsewhere. Since metadata blocks can potentially be large, by - * default the decoder only calls the metadata callback for the - * \c STREAMINFO block; you can instruct the decoder to pass or filter - * other blocks with FLAC__stream_decoder_set_metadata_*() calls. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param metadata The decoded metadata block. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - */ -typedef void (*FLAC__StreamDecoderMetadataCallback)(const FLAC__StreamDecoder *decoder, const FLAC__StreamMetadata *metadata, void *client_data); - -/** Signature for the error callback. - * - * A function pointer matching this signature must be passed to one of - * the FLAC__stream_decoder_init_*() functions. - * The supplied function will be called whenever an error occurs during - * decoding. - * - * \note In general, FLAC__StreamDecoder functions which change the - * state should not be called on the \a decoder while in the callback. - * - * \param decoder The decoder instance calling the callback. - * \param status The error encountered by the decoder. - * \param client_data The callee's client data set through - * FLAC__stream_decoder_init_*(). - */ -typedef void (*FLAC__StreamDecoderErrorCallback)(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status, void *client_data); - - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -/** Create a new stream decoder instance. The instance is created with - * default settings; see the individual FLAC__stream_decoder_set_*() - * functions for each setting's default. - * - * \retval FLAC__StreamDecoder* - * \c NULL if there was an error allocating memory, else the new instance. - */ -FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void); - -/** Free a decoder instance. Deletes the object pointed to by \a decoder. - * - * \param decoder A pointer to an existing decoder. - * \assert - * \code decoder != NULL \endcode - */ -FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder); - - -/*********************************************************************** - * - * Public class method prototypes - * - ***********************************************************************/ - -/** Set the serial number for the FLAC stream within the Ogg container. - * The default behavior is to use the serial number of the first Ogg - * page. Setting a serial number here will explicitly specify which - * stream is to be decoded. - * - * \note - * This does not need to be set for native FLAC decoding. - * - * \default \c use serial number of first page - * \param decoder A decoder instance to set. - * \param serial_number See above. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long serial_number); - -/** Set the "decode chained stream" flag. If set to \c false, the - * decoder will stop decoding when it encounters the end-of-stream - * of the first link in the chain. If set to \c true, decoding will - * continue: at the start of each link, FLAC__stream_decoder_get_state - * will return FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. - * - * This function was made to decode chained Ogg streams, but it should - * be possible to chain regular FLAC files through the read callback - * by using FLAC__STREAM_DECODER_READ_STATUS_END_OF_LINK - * appropriately. - * - * Note that when this flag is set to true, the serial number set - * with FLAC__stream_decoder_set_ogg_serial_number is ignored. - * - * \note - * This function has no effect with native FLAC decoding. - * - * \default \c false - * \param decoder A decoder instance to set. - * \param allow Whether to allow chained streams. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_decode_chained_stream(FLAC__StreamDecoder* decoder, FLAC__bool value); - -/** Set the "MD5 signature checking" flag. If \c true, the decoder will - * compute the MD5 signature of the unencoded audio data while decoding - * and compare it to the signature from the STREAMINFO block, if it - * exists, during FLAC__stream_decoder_finish(). - * - * MD5 signature checking will be turned off (until the next - * FLAC__stream_decoder_reset()) if there is no signature in the - * STREAMINFO block or when a seek is attempted. - * - * Clients that do not use the MD5 check should leave this off to speed - * up decoding. - * - * \default \c false - * \param decoder A decoder instance to set. - * \param value Flag value (see above). - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if the decoder is already initialized, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value); - -/** Direct the decoder to pass on all metadata blocks of type \a type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if type is invalid, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); - -/** Direct the decoder to pass on all APPLICATION metadata blocks of the - * given \a id. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false when memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); - -/** Direct the decoder to pass on all metadata blocks of any type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c always \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder); - -/** Direct the decoder to filter out all metadata blocks of type \a type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param type See above. - * \assert - * \code decoder != NULL \endcode - * \a type is valid - * \retval FLAC__bool - * \c false if type is invalid, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type); - -/** Direct the decoder to filter out all APPLICATION metadata blocks of - * the given \a id. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \param id See above. - * \assert - * \code decoder != NULL \endcode - * \code id != NULL \endcode - * \retval FLAC__bool - * \c false if memory allocation fails, else \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]); - -/** Direct the decoder to filter out all metadata blocks of any type. - * - * \default By default, only the \c STREAMINFO block is returned via the - * metadata callback. - * \param decoder A decoder instance to set. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c always \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder); - -/** Get the current decoder state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderState - * The current decoder state. - */ -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder); - -/** Get the current decoder state as a C string. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval const char * - * The decoder state as a C string. Do not modify the contents. - */ -FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder); - -/** Get the "decode chained stream" flag as described in - * \code FLAC__stream_decoder_set_decode_chained_stream \endcode. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_chained_stream(const FLAC__StreamDecoder* decoder); - -/** Get the "MD5 signature checking" flag. - * This is the value of the setting, not whether or not the decoder is - * currently checking the MD5 (remember, it can be turned off automatically - * by a seek). When the decoder is reset the flag will be restored to the - * value returned by this function. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * See above. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder); - -/** Get the total number of samples in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the \c STREAMINFO block. A value of \c 0 means "unknown". - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder); - -/** Seek to the end of the file being decoded to find the total number - * of samples. This will return a number of samples even if - * FLAC__stream_decoder_get_total_samples() returns 0. It can also - * be used to find the total number of samples of a chained stream, - * as it returns the total number of samples in all chain links - * combined. See FLAC__stream_decoder_set_decode_chained_stream() - * - * For this function to work, the stream must be seekable. Also, as - * seeking can fail, this function returns 0 when it was unable to - * find the total number of samples. Use - * FLAC__stream_decoder_get_state() in that case to find out whether - * the decoder is still valid. - * - * The state in which the decoder is left after calling this function - * is undefined and might change in the future. Use - * FLAC__stream_decoder_reset() to return the decoder to a defined - * state. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API FLAC__uint64 FLAC__stream_decoder_find_total_samples(FLAC__StreamDecoder *decoder); - -/** Get the current number of channels in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder); - -/** Get the current channel assignment in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__ChannelAssignment - * See above. - */ -FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder); - -/** Get the current sample resolution in the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder); - -/** Get the current sample rate in Hz of the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder); - -/** Get the current blocksize of the stream being decoded. - * Will only be valid after decoding has started and will contain the - * value from the most recently decoded frame header. - * - * \param decoder A decoder instance to query. - * \assert - * \code decoder != NULL \endcode - * \retval uint32_t - * See above. - */ -FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder); - -/** Returns the decoder's current read position within the stream. - * The position is the byte offset from the start of the stream. - * Bytes before this position have been fully decoded. Note that - * there may still be undecoded bytes in the decoder's read FIFO. - * The returned position is correct even after a seek. - * - * \warning This function currently only works for native FLAC, - * not Ogg FLAC streams. - * - * \param decoder A decoder instance to query. - * \param position Address at which to return the desired position. - * \assert - * \code decoder != NULL \endcode - * \code position != NULL \endcode - * \retval FLAC__bool - * \c true if successful, \c false if the stream is not native FLAC, - * or there was an error from the 'tell' callback or it returned - * \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position); - -/** Return client_data from decoder. - * The data pointed to by the pointer should not be modified. - * - * \param decoder A decoder instance. - * \retval const void * - * The callee's client data set through FLAC__stream_decoder_init_*(). - * Do not modify the contents. - */ -FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder); - -#define FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID -1 -#define FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED -2 -#define FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR -3 - -/** Get the link lengths in samples in a chained stream - * - * After either processing the whole file or using - * FLAC__stream_decoder_find_total_samples, this function - * returns an array with link lengths in samples. If it fails, - * it returns a negative number as error code, currently either - * FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID if the current - * decoder is not in a valid state or not processing a chained - * stream, FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED if - * the stream hasn't been indexed yet, and - * FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR - * if allocating memory failed. - * - * If the function succeeds, the return value is the number of - * links. The link_lengths parameter is a FLAC__uint64 pointer - * which is allocated by the call, and must be freed by the user. - * If a null pointer is passed, the function only returns the - * number of links, not their lengths. The length of the returned - * array is equal to the number of links and thus to the return - * value of the function. - * - * \param decoder A decoder instance to query. - * \param link_lengths Address at which to return the link lengths - * array. - * \assert - * \code decoder != NULL \endcode - * \retval int32_t - * \c the number of links if successful, zero or a negative - * number if unsuccessful - */ - -FLAC_API int32_t FLAC__stream_decoder_get_link_lengths(FLAC__StreamDecoder *decoder, FLAC__uint64 **link_lengths); - -/** Initialize the decoder instance to decode native FLAC streams. - * - * This flavor of initialization sets up the decoder to decode from a - * native FLAC stream. I/O is performed via callbacks to the client. - * For decoding from a plain file via filename or open FILE*, - * FLAC__stream_decoder_init_file() and FLAC__stream_decoder_init_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param read_callback See FLAC__StreamDecoderReadCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamDecoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is not \c NULL then a - * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param tell_callback See FLAC__StreamDecoderTellCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param length_callback See FLAC__StreamDecoderLengthCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a length_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param eof_callback See FLAC__StreamDecoderEofCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a eof_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c false - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC streams. - * - * This flavor of initialization sets up the decoder to decode from a - * FLAC stream in an Ogg container. I/O is performed via callbacks to the - * client. For decoding from a plain file via filename or open FILE*, - * FLAC__stream_decoder_init_ogg_file() and FLAC__stream_decoder_init_ogg_FILE() - * provide a simpler interface. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param read_callback See FLAC__StreamDecoderReadCallback. This - * pointer must not be \c NULL. - * \param seek_callback See FLAC__StreamDecoderSeekCallback. This - * pointer may be \c NULL if seeking is not - * supported. If \a seek_callback is not \c NULL then a - * \a tell_callback, \a length_callback, and \a eof_callback must also be supplied. - * Alternatively, a dummy seek callback that just - * returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param tell_callback See FLAC__StreamDecoderTellCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a tell_callback must also be supplied. - * Alternatively, a dummy tell callback that just - * returns \c FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param length_callback See FLAC__StreamDecoderLengthCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a length_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param eof_callback See FLAC__StreamDecoderEofCallback. This - * pointer may be \c NULL if not supported by the client. If - * \a seek_callback is not \c NULL then a - * \a eof_callback must also be supplied. - * Alternatively, a dummy length callback that just - * returns \c false - * may also be supplied, all though this is slightly - * less efficient for the decoder. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -#if 0 /* bstone */ -/** Initialize the decoder instance to decode native FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a - * plain native FLAC file. For non-stdio streams, you must use - * FLAC__stream_decoder_init_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param file An open FLAC file. The file should have been - * opened with mode \c "rb" and rewound. The file - * becomes owned by the decoder and should not be - * manipulated by the client while decoding. - * Unless \a file is \c stdin, it will be closed - * when FLAC__stream_decoder_finish() is called. - * Note however that seeking will not work when - * decoding from \c stdin since it is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a - * plain Ogg FLAC file. For non-stdio streams, you must use - * FLAC__stream_decoder_init_ogg_stream() and provide callbacks for the I/O. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param file An open FLAC file. The file should have been - * opened with mode \c "rb" and rewound. The file - * becomes owned by the decoder and should not be - * manipulated by the client while decoding. - * Unless \a file is \c stdin, it will be closed - * when FLAC__stream_decoder_finish() is called. - * Note however that seeking will not work when - * decoding from \c stdin since it is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \code file != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode native FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a plain - * native FLAC file. If POSIX fopen() semantics are not sufficient, you must - * use FLAC__stream_decoder_init_FILE(), or FLAC__stream_decoder_init_stream() - * and provide callbacks for the I/O. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \param decoder An uninitialized decoder instance. - * \param filename The name of the file to decode from. The file will - * be opened with fopen(). Use \c NULL to decode from - * \c stdin. Note that \c stdin is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); - -/** Initialize the decoder instance to decode Ogg FLAC files. - * - * This flavor of initialization sets up the decoder to decode from a plain - * Ogg FLAC file. If POSIX fopen() semantics are not sufficient, you must use - * FLAC__stream_decoder_init_ogg_FILE(), or FLAC__stream_decoder_init_ogg_stream() - * and provide callbacks for the I/O. - * - * On Windows, filename must be a UTF-8 encoded filename, which libFLAC - * internally translates to an appropriate representation to use with - * _wfopen. On all other systems, filename is passed to fopen without - * any translation. - * - * This function should be called after FLAC__stream_decoder_new() and - * FLAC__stream_decoder_set_*() but before any of the - * FLAC__stream_decoder_process_*() functions. Will set and return the - * decoder state, which will be FLAC__STREAM_DECODER_SEARCH_FOR_METADATA - * if initialization succeeded. - * - * \note Support for Ogg FLAC in the library is optional. If this - * library has been built without support for Ogg FLAC, this function - * will return \c FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER. - * - * \param decoder An uninitialized decoder instance. - * \param filename The name of the file to decode from. The file will - * be opened with fopen(). Use \c NULL to decode from - * \c stdin. Note that \c stdin is not seekable. - * \param write_callback See FLAC__StreamDecoderWriteCallback. This - * pointer must not be \c NULL. - * \param metadata_callback See FLAC__StreamDecoderMetadataCallback. This - * pointer may be \c NULL if the callback is not - * desired. - * \param error_callback See FLAC__StreamDecoderErrorCallback. This - * pointer must not be \c NULL. - * \param client_data This value will be supplied to callbacks in their - * \a client_data argument. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__StreamDecoderInitStatus - * \c FLAC__STREAM_DECODER_INIT_STATUS_OK if initialization was successful; - * see FLAC__StreamDecoderInitStatus for the meanings of other return values. - */ -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -); -#endif /* bstone */ - -/** Finish the decoding process. - * Flushes the decoding buffer, releases resources, resets the decoder - * settings to their defaults, and returns the decoder state to - * FLAC__STREAM_DECODER_UNINITIALIZED. - * - * In the event of a prematurely-terminated decode, it is not strictly - * necessary to call this immediately before FLAC__stream_decoder_delete() - * but it is good practice to match every FLAC__stream_decoder_init_*() - * with a FLAC__stream_decoder_finish(). - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if MD5 checking is on AND a STREAMINFO block was available - * AND the MD5 signature in the STREAMINFO block was non-zero AND the - * signature does not match the one computed by the decoder; else - * \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder); - -/** Finish the decoding process of the current link. - * Checks MD5 for current link and start processing of the next link. This - * function should only be used when the decoder state is - * FLAC__STREAM_DECODER_END_OF_LINK. After calling this function, the state - * is set to FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. - * - * \param decoder An uninitialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if MD5 checking is on AND a STREAMINFO block was available - * AND the MD5 signature in the STREAMINFO block was non-zero AND the - * signature does not match the one computed by the decoder; else - * \c true. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_finish_link(FLAC__StreamDecoder *decoder); - -/** Flush the stream input. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC. This will also turn - * off MD5 checking. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation - * error occurs (in which case the state will be set to - * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder); - -/** Reset the decoding process. - * The decoder's input buffer will be cleared and the state set to - * \c FLAC__STREAM_DECODER_SEARCH_FOR_METADATA. This is similar to - * FLAC__stream_decoder_finish() except that the settings are - * preserved; there is no need to call FLAC__stream_decoder_init_*() - * before decoding again. MD5 checking will be restored to its original - * setting. - * - * If the decoder is seekable, or was initialized with - * FLAC__stream_decoder_init*_FILE() or FLAC__stream_decoder_init*_file(), - * the decoder will also attempt to seek to the beginning of the file. - * If this rewind fails, this function will return \c false. It follows - * that FLAC__stream_decoder_reset() cannot be used when decoding from - * \c stdin. - * - * If the decoder was initialized with FLAC__stream_encoder_init*_stream() - * and is not seekable (i.e. no seek callback was provided or the seek - * callback returns \c FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED), it - * is the duty of the client to start feeding data from the beginning of - * the stream on the next FLAC__stream_decoder_process_*() call. - * - * \param decoder A decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false if a memory allocation occurs - * (in which case the state will be set to - * \c FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) or a seek error - * occurs (the state will be unchanged). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder); - -/** Decode one metadata block or audio frame. - * This version instructs the decoder to decode a either a single metadata - * block or a single frame and stop, unless the callbacks return a fatal - * error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * As the decoder needs more input it will call the read callback. - * Depending on what was decoded, the metadata or write callback will be - * called with the decoded metadata block or audio frame. - * - * Unless there is a fatal read error or end of stream, this function - * will return once one whole frame is decoded. In other words, if the - * stream is not synchronized or points to a corrupt frame header, the - * decoder will continue to try and resync until it gets to a valid - * frame, then decode one frame, then return. If the decoder points to - * a frame whose frame CRC in the frame footer does not match the - * computed frame CRC, this function will issue a - * FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH error to the - * error callback, and return, having decoded one complete, although - * corrupt, frame. (Such corrupted frames are sent as silence of the - * correct length to the write callback.) - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the metadata. - * This version instructs the decoder to decode from the current position - * and continue until all the metadata has been read, or until the - * callbacks return a fatal error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * As the decoder needs more input it will call the read callback. - * As each metadata block is decoded, the metadata callback will be called - * with the decoded metadata. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the Ogg chain link. - * This version instructs the decoder to decode from the current - * position and continue until the end of link or until the - * callbacks return a fatal error. This function should not be - * used without enabling decoding of chained streams with - * FLAC__stream_decoder_set_decode_chained_stream() - * - * To start processing the next link after calling this function, - * call FLAC__stream_decoder_finish_link() - * - * As the decoder needs more input it will call the read callback. - * As each metadata block and frame is decoded, the metadata or write - * callback will be called with the decoded metadata or frame. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_link(FLAC__StreamDecoder *decoder); - -/** Decode until the end of the stream. - * This version instructs the decoder to decode from the current position - * and continue until the end of stream (the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM), or until the - * callbacks return a fatal error. - * - * As the decoder needs more input it will call the read callback. - * As each metadata block and frame is decoded, the metadata or write - * callback will be called with the decoded metadata or frame. - * - * \param decoder An initialized decoder instance. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder); - -/** Skip one audio frame. - * This version instructs the decoder to 'skip' a single frame and stop, - * unless the callbacks return a fatal error or the read callback returns - * \c FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM. - * - * The decoding flow is the same as what occurs when - * FLAC__stream_decoder_process_single() is called to process an audio - * frame, except that this function does not decode the parsed data into - * PCM or call the write callback. The integrity of the frame is still - * checked the same way as in the other process functions. - * - * This function will return once one whole frame is skipped, in the - * same way that FLAC__stream_decoder_process_single() will return once - * one whole frame is decoded. - * - * This function can be used in more quickly determining FLAC frame - * boundaries when decoding of the actual data is not needed, for - * example when an application is separating a FLAC stream into frames - * for editing or storing in a container. To do this, the application - * can use FLAC__stream_decoder_skip_single_frame() to quickly advance - * to the next frame, then use - * FLAC__stream_decoder_get_decode_position() to find the new frame - * boundary. - * - * This function should only be called when the stream has advanced - * past all the metadata, otherwise it will return \c false. - * - * \param decoder An initialized decoder instance not in a metadata - * state. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), or if the decoder - * is in the FLAC__STREAM_DECODER_SEARCH_FOR_METADATA or - * FLAC__STREAM_DECODER_READ_METADATA state, else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder); - -/** Skip one Ogg chain link. - * This version instructs the decoder to 'skip' the current ogg chain - * link. This function should not be used without enabling decoding - * of chained streams with - * FLAC__stream_decoder_set_decode_chained_stream() - * - * When the location ot the next link is already known (for example, - * because there has already been a seek in the stream) this function - * will seek to the end of the link and start processing, but when it - * is not, it will do various seeks (when possible) to find the end - * of the link. If seeking is not possible (or the tell and length - * callback do not work) it will simply read forward instead of - * seeking, much like a muted (but faster) version of - * FLAC__stream_decoder_process_until_end_of_link(). - * - * \param decoder An initialized decoder instance not in a metadata - * state. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c false if any fatal read, write, or memory allocation error - * occurred (meaning decoding must stop), or when decoding a format - * that does not support chaining, else \c true; for more - * information about the decoder, check the decoder state with - * FLAC__stream_decoder_get_state(). - */ -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_link(FLAC__StreamDecoder *decoder); - -/** Flush the input and seek to an absolute sample. - * Decoding will resume at the given sample. Note that because of - * this, the next write callback may contain a partial block. The - * client must support seeking the input or this function will fail - * and return \c false. Furthermore, if the decoder state is - * \c FLAC__STREAM_DECODER_SEEK_ERROR, then the decoder must be flushed - * with FLAC__stream_decoder_flush() or reset with - * FLAC__stream_decoder_reset() before decoding can continue. - * - * When seeking in a chained stream with decoding of such streams - * enabled with FLAC__stream_decoder_set_decode_chained_stream(), - * this function seeks in the whole stream, over all links. When - * a seek to another link is performed, the decoder will also - * return metadata blocks of that link. If this is not desired, - * use FLAC__stream_decoder_set_metadata_ignore_all() before - * seeking. - * - * \param decoder A decoder instance. - * \param sample The target sample number to seek to. - * \assert - * \code decoder != NULL \endcode - * \retval FLAC__bool - * \c true if successful, else \c false. - */ -FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample); - -/* \} */ - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/src/lib/flac/include/share/alloc.h b/src/lib/flac/include/share/alloc.h deleted file mode 100644 index ed53babd..00000000 --- a/src/lib/flac/include/share/alloc.h +++ /dev/null @@ -1,322 +0,0 @@ -/* alloc - Convenience routines for safely allocating memory - * Copyright (C) 2007-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__SHARE__ALLOC_H -#define FLAC__SHARE__ALLOC_H - -#ifdef HAVE_CONFIG_H -# include -#endif - -/* WATCHOUT: for c++ you may have to #define __STDC_LIMIT_MACROS 1 real early - * before #including this file, otherwise SIZE_MAX might not be defined - */ - -#include /* for SIZE_MAX */ -#ifdef HAVE_STDINT_H -#include /* for SIZE_MAX in case limits.h didn't get it */ -#endif -#include /* for size_t, malloc(), etc */ -#include "share/compat.h" - -#ifndef SIZE_MAX -# ifndef SIZE_T_MAX -# ifdef _MSC_VER -# ifdef _WIN64 -# define SIZE_T_MAX FLAC__U64L(0xffffffffffffffff) -# else -# define SIZE_T_MAX 0xffffffff -# endif -# else -# error -# endif -# endif -# define SIZE_MAX SIZE_T_MAX -#endif - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - -extern int alloc_check_threshold, alloc_check_counter, alloc_check_keep_failing; - -static inline int alloc_check(void) { - if(alloc_check_threshold == INT32_MAX) - return 0; - else if(alloc_check_counter++ == alloc_check_threshold) - return 1; - else if(alloc_check_keep_failing && (alloc_check_counter > alloc_check_threshold)) - return 1; - else { - return 0; - } -} - -#endif - -/* avoid malloc()ing 0 bytes, see: - * https://www.securecoding.cert.org/confluence/display/seccode/MEM04-A.+Do+not+make+assumptions+about+the+result+of+allocating+0+bytes?focusedCommentId=5407003 -*/ - -static inline void *safe_malloc_(size_t size) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Fail if requested */ - if(alloc_check()) - return NULL; -#endif - /* malloc(0) is undefined; FLAC src convention is to always allocate */ - if(!size) - size++; - return malloc(size); -} - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -static inline void *malloc_(size_t size) -{ - /* Fail if requested */ - if(alloc_check()) - return NULL; - return malloc(size); -} -#else -#define malloc_ malloc -#endif - - - -static inline void *safe_calloc_(size_t nmemb, size_t size) -{ -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Fail if requested */ - if(alloc_check()) - return NULL; -#endif - if(!nmemb || !size) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - return calloc(nmemb, size); -} - -/*@@@@ there's probably a better way to prevent overflows when allocating untrusted sums but this works for now */ - -static inline void *safe_malloc_add_2op_(size_t size1, size_t size2) -{ - size2 += size1; - if(size2 < size1) - return 0; - return safe_malloc_(size2); -} - -static inline void *safe_malloc_add_3op_(size_t size1, size_t size2, size_t size3) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - return safe_malloc_(size3); -} - -static inline void *safe_malloc_add_4op_(size_t size1, size_t size2, size_t size3, size_t size4) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - size4 += size3; - if(size4 < size3) - return 0; - return safe_malloc_(size4); -} - -void *safe_malloc_mul_2op_(size_t size1, size_t size2) ; - -static inline void *safe_malloc_mul_3op_(size_t size1, size_t size2, size_t size3) -{ - if(!size1 || !size2 || !size3) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - if(size1 > SIZE_MAX / size2) - return 0; - size1 *= size2; - if(size1 > SIZE_MAX / size3) - return 0; - return malloc_(size1*size3); -} - -/* size1*size2 + size3 */ -static inline void *safe_malloc_mul2add_(size_t size1, size_t size2, size_t size3) -{ - if(!size1 || !size2) - return safe_malloc_(size3); - if(size1 > SIZE_MAX / size2) - return 0; - return safe_malloc_add_2op_(size1*size2, size3); -} - -/* size1 * (size2 + size3) */ -static inline void *safe_malloc_muladd2_(size_t size1, size_t size2, size_t size3) -{ - if(!size1 || (!size2 && !size3)) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - size2 += size3; - if(size2 < size3) - return 0; - if(size1 > SIZE_MAX / size2) - return 0; - return malloc_(size1*size2); -} - -static inline void *safe_realloc_(void *ptr, size_t size) -{ - void *oldptr; - void *newptr; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* Fail if requested */ - if(alloc_check() && size > 0) { - free(ptr); - return NULL; - } -#endif - oldptr = ptr; - newptr = realloc(ptr, size); - if(size > 0 && newptr == 0) - free(oldptr); - return newptr; -} - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -static inline void *realloc_(void *ptr, size_t size) -{ - /* Fail if requested */ - if(alloc_check()) - return NULL; - return realloc(ptr, size); -} -#else -#define realloc_ realloc -#endif - - -static inline void *safe_realloc_nofree_add_2op_(void *ptr, size_t size1, size_t size2) -{ - size2 += size1; - if(size2 < size1) - return 0; - return realloc_(ptr, size2); -} - -static inline void *safe_realloc_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) -{ - size2 += size1; - if(size2 < size1) { - free(ptr); - return 0; - } - size3 += size2; - if(size3 < size2) { - free(ptr); - return 0; - } - return safe_realloc_(ptr, size3); -} - -static inline void *safe_realloc_nofree_add_3op_(void *ptr, size_t size1, size_t size2, size_t size3) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - return realloc_(ptr, size3); -} - -static inline void *safe_realloc_nofree_add_4op_(void *ptr, size_t size1, size_t size2, size_t size3, size_t size4) -{ - size2 += size1; - if(size2 < size1) - return 0; - size3 += size2; - if(size3 < size2) - return 0; - size4 += size3; - if(size4 < size3) - return 0; - return realloc_(ptr, size4); -} - -static inline void *safe_realloc_mul_2op_(void *ptr, size_t size1, size_t size2) -{ - if(!size1 || !size2) - return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ - if(size1 > SIZE_MAX / size2) { - free(ptr); - return 0; - } - return safe_realloc_(ptr, size1*size2); -} - -static inline void *safe_realloc_nofree_mul_2op_(void *ptr, size_t size1, size_t size2) -{ - if(!size1 || !size2) - return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ - if(size1 > SIZE_MAX / size2) - return 0; - return realloc_(ptr, size1*size2); -} - -/* size1 * (size2 + size3) */ -static inline void *safe_realloc_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) -{ - if(!size1 || (!size2 && !size3)) - return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ - size2 += size3; - if(size2 < size3) { - free(ptr); - return 0; - } - return safe_realloc_mul_2op_(ptr, size1, size2); -} - -/* size1 * (size2 + size3) */ -static inline void *safe_realloc_nofree_muladd2_(void *ptr, size_t size1, size_t size2, size_t size3) -{ - if(!size1 || (!size2 && !size3)) - return realloc(ptr, 0); /* preserve POSIX realloc(ptr, 0) semantics */ - size2 += size3; - if(size2 < size3) - return 0; - return safe_realloc_nofree_mul_2op_(ptr, size1, size2); -} - -#endif diff --git a/src/lib/flac/include/share/compat.h b/src/lib/flac/include/share/compat.h deleted file mode 100644 index 0a9a4bd2..00000000 --- a/src/lib/flac/include/share/compat.h +++ /dev/null @@ -1,264 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2012-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* This is the preferred location of all CPP hackery to make $random_compiler - * work like something approaching a C99 (or maybe more accurately GNU99) - * compiler. - * - * It is assumed that this header will be included after "config.h". - */ - -#ifndef FLAC__SHARE__COMPAT_H -#define FLAC__SHARE__COMPAT_H - -#if 0 /* bstone */ -#include -#include - -#if defined _WIN32 && !defined __CYGWIN__ -/* where MSVC puts unlink() */ -# include -#else -# include -#endif - -#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ -#include /* for off_t */ -#define FLAC__off_t __int64 /* use this instead of off_t to fix the 2 GB limit */ -#define FLAC__OFF_T_MAX INT64_MAX -#if !defined __MINGW32__ -#define fseeko _fseeki64 -#define ftello _ftelli64 -#else /* MinGW */ -#if !defined(HAVE_FSEEKO) -#define fseeko fseeko64 -#define ftello ftello64 -#endif -#endif -#else -#ifndef HAVE_FSEEKO -#define fseeko fseek -#define ftello ftell -#define FLAC__off_t long -#define FLAC__OFF_T_MAX LONG_MAX -#else -#define FLAC__off_t off_t -#define FLAC__OFF_T_MAX (sizeof(off_t) == sizeof(int64_t) ? INT64_MAX : sizeof(off_t) == sizeof(int32_t) ? INT32_MAX : -999999) -#endif -#endif - - - -#ifdef HAVE_INTTYPES_H -#define __STDC_FORMAT_MACROS -#include -#endif - -#if defined(_MSC_VER) -#define strtoll _strtoi64 -#define strtoull _strtoui64 -#endif - -#if defined(_MSC_VER) && !defined(__cplusplus) -#define inline __inline -#endif - -#if defined __INTEL_COMPILER || (defined _MSC_VER && defined _WIN64) -/* MSVS generates VERY slow 32-bit code with __restrict */ -#define flac_restrict __restrict -#elif defined __GNUC__ -#define flac_restrict __restrict__ -#else -#define flac_restrict -#endif - -#define FLAC__U64L(x) x##ULL - -#if defined _MSC_VER || defined __MINGW32__ -#define FLAC__STRCASECMP _stricmp -#define FLAC__STRNCASECMP _strnicmp -#elif defined __BORLANDC__ -#define FLAC__STRCASECMP stricmp -#define FLAC__STRNCASECMP strnicmp -#else -#define FLAC__STRCASECMP strcasecmp -#define FLAC__STRNCASECMP strncasecmp -#endif - -#if defined _MSC_VER || defined __MINGW32__ || defined __EMX__ -#include /* for _setmode(), chmod() */ -#include /* for _O_BINARY */ -#else -#include /* for chown(), unlink() */ -#endif - -#if defined _MSC_VER || defined __BORLANDC__ || defined __MINGW32__ -#if defined __BORLANDC__ -#include /* for utime() */ -#else -#include /* for utime() */ -#endif -#else -#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) -#include -#else -#include /* some flavors of BSD (like OS X) require this to get time_t */ -#include /* for utime() */ -#endif -#endif - -#if defined _MSC_VER -# if _MSC_VER >= 1800 -# include -# elif _MSC_VER >= 1600 -/* Visual Studio 2010 has decent C99 support */ -# include -# define PRIu64 "llu" -# define PRId64 "lld" -# define PRIx64 "llx" -# else -# include -# ifndef UINT32_MAX -# define UINT32_MAX _UI32_MAX -# endif -# define PRIu64 "I64u" -# define PRId64 "I64d" -# define PRIx64 "I64x" -# endif -# if defined(_USING_V110_SDK71_) && !defined(_DLL) -# pragma message("WARNING: This compile will NOT FUNCTION PROPERLY on Windows XP. See comments in include/share/compat.h for details") -#define FLAC__USE_FILELENGTHI64 -/* - ************************************************************************************* - * V110_SDK71, in MSVC 2017 also known as v141_xp, is a platform toolset that is supposed - * to target Windows XP. It turns out however that certain functions provided silently fail - * on Windows XP only, which makes debugging challenging. This only occurs when building with - * /MT. This problem has been reported to Microsoft, but there hasn't been a fix for years. See - * https://web.archive.org/web/20170327195018/https://connect.microsoft.com/VisualStudio/feedback/details/1557168/wstat64-returns-1-on-xp-always - * - * It is known that this problem affects the functions _wstat64 (used by flac_stat i.e. - * stat64_utf8) and _fstat64 (i.e. flac_fstat) and therefore affects both libFLAC in - * several places as well as the flac and metaflac command line tools - * - * As the extent of this problem is unknown and Microsoft seems unwilling to fix it, - * users of libFLAC building with Visual Studio are encouraged to not use the /MT compile - * switch when explicitly targeting Windows XP. When use of /MT is deemed necessary with - * this toolset, be sure to check whether your application works properly on Windows XP. - * It is also possible to build for Windows XP with MinGW instead. - ************************************************************************************* -*/ -# endif -#endif /* defined _MSC_VER */ - -#ifdef _WIN32 -/* All char* strings are in UTF-8 format. Added to support Unicode files on Windows */ - -#include "share/win_utf8_io.h" -#define flac_printf printf_utf8 -#define flac_fprintf fprintf_utf8 -#define flac_vfprintf vfprintf_utf8 -#define flac_fopen fopen_utf8 -#define flac_chmod chmod_utf8 -#define flac_utime utime_utf8 -#define flac_unlink unlink_utf8 -#define flac_rename rename_utf8 -#define flac_stat stat64_utf8 - -#else - -#define flac_printf printf -#define flac_fprintf fprintf -#define flac_vfprintf vfprintf - -#define flac_fopen fopen -#define flac_chmod chmod -#define flac_unlink unlink -#define flac_rename rename -#define flac_stat stat - -#if defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200809L) -#define flac_utime(a, b) utimensat (AT_FDCWD, a, *b, 0) -#else -#define flac_utime utime -#endif -#endif - -#ifdef _WIN32 -#define flac_stat_s __stat64 /* stat struct */ -#define flac_fstat _fstat64 -#else -#define flac_stat_s stat /* stat struct */ -#define flac_fstat fstat -#endif - -#ifdef ANDROID -#include -#endif - -#ifndef M_LN2 -#define M_LN2 0.69314718055994530942 -#endif -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif - -/* FLAC needs to compile and work correctly on systems with a normal ISO C99 - * snprintf as well as Microsoft Visual Studio which has an non-standards - * conformant snprint_s function. - * - * This function wraps the MS version to behave more like the ISO version. - */ -#ifdef __cplusplus -extern "C" { -#endif -int flac_snprintf(char *str, size_t size, const char *fmt, ...); -int flac_vsnprintf(char *str, size_t size, const char *fmt, va_list va); -#ifdef __cplusplus -}; -#endif -#else /* bstone */ -#ifdef ANDROID -#include -#endif - -#define flac_fprintf(...) -#define flac_restrict -#define FLAC__U64L(x) x##ULL - -#ifndef M_LN2 -#define M_LN2 0.69314718055994530942 -#endif -#ifndef M_PI -#define M_PI 3.14159265358979323846 -#endif -#endif /* bstone */ - -#endif /* FLAC__SHARE__COMPAT_H */ diff --git a/src/lib/flac/include/share/endswap.h b/src/lib/flac/include/share/endswap.h deleted file mode 100644 index 3831c509..00000000 --- a/src/lib/flac/include/share/endswap.h +++ /dev/null @@ -1,84 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2012-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -/* It is assumed that this header will be included after "config.h". */ - -#ifdef HAVE_BSWAP32 /* GCC and Clang */ - -/* GCC prior to 4.8 didn't provide bswap16 on x86_64 */ -#ifndef HAVE_BSWAP16 -static inline unsigned short __builtin_bswap16(unsigned short a) -{ - return (a<<8)|(a>>8); -} -#endif - -#define ENDSWAP_16(x) (__builtin_bswap16 (x)) -#define ENDSWAP_32(x) (__builtin_bswap32 (x)) -#define ENDSWAP_64(x) (__builtin_bswap64 (x)) - -#elif defined _MSC_VER /* Windows */ - -#include - -#define ENDSWAP_16(x) (_byteswap_ushort (x)) -#define ENDSWAP_32(x) (_byteswap_ulong (x)) -#define ENDSWAP_64(x) (_byteswap_uint64 (x)) - -#elif defined HAVE_BYTESWAP_H /* Linux */ - -#include - -#define ENDSWAP_16(x) (bswap_16 (x)) -#define ENDSWAP_32(x) (bswap_32 (x)) -#define ENDSWAP_64(x) (bswap_64 (x)) - -#else - -#define ENDSWAP_16(x) ((((x) >> 8) & 0xFF) | (((x) & 0xFF) << 8)) -#define ENDSWAP_32(x) ((((x) >> 24) & 0xFF) | (((x) >> 8) & 0xFF00) | (((x) & 0xFF00) << 8) | (((x) & 0xFF) << 24)) -#define ENDSWAP_64(x) ((ENDSWAP_32(((x) >> 32) & 0xFFFFFFFF)) | (ENDSWAP_32((x) & 0xFFFFFFFF) << 32)) - -#endif - - -/* Host to little-endian byte swapping (for MD5 calculation) */ -#if CPU_IS_BIG_ENDIAN - -#define H2LE_16(x) ENDSWAP_16 (x) -#define H2LE_32(x) ENDSWAP_32 (x) - -#else - -#define H2LE_16(x) (x) -#define H2LE_32(x) (x) - -#endif diff --git a/src/lib/flac/src/CMakeLists.txt b/src/lib/flac/src/CMakeLists.txt deleted file mode 100644 index 9e8ca66c..00000000 --- a/src/lib/flac/src/CMakeLists.txt +++ /dev/null @@ -1,3 +0,0 @@ -# bstone -cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -add_subdirectory(libFLAC) diff --git a/src/lib/flac/src/libFLAC/CMakeLists.txt b/src/lib/flac/src/libFLAC/CMakeLists.txt deleted file mode 100644 index b707ba5f..00000000 --- a/src/lib/flac/src/libFLAC/CMakeLists.txt +++ /dev/null @@ -1,76 +0,0 @@ -# bstone -cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -project(bstone_lib_flac VERSION 1.0.0 LANGUAGES C) -message(STATUS "[${PROJECT_NAME}] v${PROJECT_VERSION}") -add_library(${PROJECT_NAME} STATIC) -add_library(bstone::lib::flac ALIAS ${PROJECT_NAME}) -set_target_properties(${PROJECT_NAME} PROPERTIES - C_STANDARD 99 - C_STANDARD_REQUIRED ON - C_EXTENSIONS OFF -) -target_compile_definitions(${PROJECT_NAME} PUBLIC FLAC__NO_DLL) -target_compile_definitions(${PROJECT_NAME} PRIVATE - FLAC__NO_ASM - FLAC__HAS_OGG=0 - PACKAGE_VERSION=\"v1.5.0\" -) -target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W1>) -target_include_directories(${PROJECT_NAME} PUBLIC ../../include) -target_include_directories(${PROJECT_NAME} PRIVATE include) -# -------------------------------------- -set(bstone_flac_include_flac_sources - ../../include/FLAC/assert.h - ../../include/FLAC/callback.h - ../../include/FLAC/export.h - ../../include/FLAC/format.h - ../../include/FLAC/ordinals.h - ../../include/FLAC/stream_decoder.h -) -source_group("include/FLAC" FILES ${bstone_flac_include_flac_sources}) -target_sources(${PROJECT_NAME} PRIVATE ${bstone_flac_include_flac_sources}) -# -------------------------------------- -set(bstone_flac_include_share_sources - ../../include/share/alloc.h - ../../include/share/compat.h - ../../include/share/endswap.h -) -source_group("include/share" FILES ${bstone_flac_include_share_sources}) -target_sources(${PROJECT_NAME} PRIVATE ${bstone_flac_include_share_sources}) -# -------------------------------------- -set(bstone_flac_include_private_sources - include/private/bitmath.h - include/private/bitreader.h - include/private/cpu.h - include/private/crc.h - include/private/fixed.h - include/private/float.h - include/private/format.h - include/private/lpc.h - include/private/macros.h - include/private/md5.h - include/private/memory.h -) -source_group("include/private" FILES ${bstone_flac_include_private_sources}) -target_sources(${PROJECT_NAME} PRIVATE ${bstone_flac_include_private_sources}) -# -------------------------------------- -set(bstone_flac_include_protected_sources - include/protected/stream_decoder.h -) -source_group("include/protected" FILES ${bstone_flac_include_protected_sources}) -target_sources(${PROJECT_NAME} PRIVATE ${bstone_flac_include_protected_sources}) -# -------------------------------------- -set(bstone_flac_include_src_sources - src/bitmath.c - src/bitreader.c - src/cpu.c - src/crc.c - src/fixed.c - src/format.c - src/lpc.c - src/md5.c - src/memory.c - src/stream_decoder.c -) -source_group("src" FILES ${bstone_flac_include_src_sources}) -target_sources(${PROJECT_NAME} PRIVATE ${bstone_flac_include_src_sources}) diff --git a/src/lib/flac/src/libFLAC/include/private/bitmath.h b/src/lib/flac/src/libFLAC/include/private/bitmath.h deleted file mode 100644 index 5241462f..00000000 --- a/src/lib/flac/src/libFLAC/include/private/bitmath.h +++ /dev/null @@ -1,211 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__BITMATH_H -#define FLAC__PRIVATE__BITMATH_H - -#include "FLAC/ordinals.h" -#include "FLAC/assert.h" - -#include "share/compat.h" - -#if defined(_MSC_VER) -#include /* for _BitScanReverse* */ -#endif - -/* Will never be emitted for MSVC, GCC, Intel compilers */ -static inline uint32_t FLAC__clz_soft_uint32(FLAC__uint32 word) -{ - static const uint8_t byte_to_unary_table[] = { - 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - }; - - return word > 0xffffff ? byte_to_unary_table[word >> 24] : - word > 0xffff ? byte_to_unary_table[word >> 16] + 8 : - word > 0xff ? byte_to_unary_table[word >> 8] + 16 : - byte_to_unary_table[word] + 24; -} - -static inline uint32_t FLAC__clz_uint32(FLAC__uint32 v) -{ -/* Never used with input 0 */ - FLAC__ASSERT(v > 0); -#if defined(__INTEL_COMPILER) - return _bit_scan_reverse(v) ^ 31U; -#elif defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) -/* This will translate either to (bsr ^ 31U), clz , ctlz, cntlz, lzcnt depending on - * -march= setting or to a software routine in exotic machines. */ - return __builtin_clz(v); -#elif defined(_MSC_VER) - { - unsigned long idx; - _BitScanReverse(&idx, v); - return idx ^ 31U; - } -#else - return FLAC__clz_soft_uint32(v); -#endif -} - -/* Used when 64-bit bsr/clz is unavailable; can use 32-bit bsr/clz when possible */ -static inline uint32_t FLAC__clz_soft_uint64(FLAC__uint64 word) -{ - return (FLAC__uint32)(word>>32) ? FLAC__clz_uint32((FLAC__uint32)(word>>32)) : - FLAC__clz_uint32((FLAC__uint32)word) + 32; -} - -static inline uint32_t FLAC__clz_uint64(FLAC__uint64 v) -{ - /* Never used with input 0 */ - FLAC__ASSERT(v > 0); -#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) - return __builtin_clzll(v); -#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64)) - { - unsigned long idx; - _BitScanReverse64(&idx, v); - return idx ^ 63U; - } -#else - return FLAC__clz_soft_uint64(v); -#endif -} - -/* These two functions work with input 0 */ -static inline uint32_t FLAC__clz2_uint32(FLAC__uint32 v) -{ - if (!v) - return 32; - return FLAC__clz_uint32(v); -} - -static inline uint32_t FLAC__clz2_uint64(FLAC__uint64 v) -{ - if (!v) - return 64; - return FLAC__clz_uint64(v); -} - -/* An example of what FLAC__bitmath_ilog2() computes: - * - * ilog2( 0) = assertion failure - * ilog2( 1) = 0 - * ilog2( 2) = 1 - * ilog2( 3) = 1 - * ilog2( 4) = 2 - * ilog2( 5) = 2 - * ilog2( 6) = 2 - * ilog2( 7) = 2 - * ilog2( 8) = 3 - * ilog2( 9) = 3 - * ilog2(10) = 3 - * ilog2(11) = 3 - * ilog2(12) = 3 - * ilog2(13) = 3 - * ilog2(14) = 3 - * ilog2(15) = 3 - * ilog2(16) = 4 - * ilog2(17) = 4 - * ilog2(18) = 4 - */ - -static inline uint32_t FLAC__bitmath_ilog2(FLAC__uint32 v) -{ - FLAC__ASSERT(v > 0); -#if defined(__INTEL_COMPILER) - return _bit_scan_reverse(v); -#elif defined(_MSC_VER) - { - unsigned long idx; - _BitScanReverse(&idx, v); - return idx; - } -#else - return FLAC__clz_uint32(v) ^ 31U; -#endif -} - -static inline uint32_t FLAC__bitmath_ilog2_wide(FLAC__uint64 v) -{ - FLAC__ASSERT(v > 0); -#if defined(__GNUC__) && (__GNUC__ >= 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) - return __builtin_clzll(v) ^ 63U; -/* Sorry, only supported in x64/Itanium.. and both have fast FPU which makes integer-only encoder pointless */ -#elif (defined(__INTEL_COMPILER) || defined(_MSC_VER)) && (defined(_M_IA64) || defined(_M_X64)) - { - unsigned long idx; - _BitScanReverse64(&idx, v); - return idx; - } -#else -/* Brain-damaged compilers will use the fastest possible way that is, - de Bruijn sequences (http://supertech.csail.mit.edu/papers/debruijn.pdf) - (C) Timothy B. Terriberry (tterribe@xiph.org) 2001-2009 CC0 (Public domain). -*/ - { - static const uint8_t DEBRUIJN_IDX64[64]={ - 0, 1, 2, 7, 3,13, 8,19, 4,25,14,28, 9,34,20,40, - 5,17,26,38,15,46,29,48,10,31,35,54,21,50,41,57, - 63, 6,12,18,24,27,33,39,16,37,45,47,30,53,49,56, - 62,11,23,32,36,44,52,55,61,22,43,51,60,42,59,58 - }; - v|= v>>1; - v|= v>>2; - v|= v>>4; - v|= v>>8; - v|= v>>16; - v|= v>>32; - v= (v>>1)+1; - return DEBRUIJN_IDX64[v*FLAC__U64L(0x218A392CD3D5DBF)>>58&0x3F]; - } -#endif -} - -uint32_t FLAC__bitmath_silog2(FLAC__int64 v); -uint32_t FLAC__bitmath_extra_mulbits_unsigned(FLAC__uint32 v); - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/bitreader.h b/src/lib/flac/src/libFLAC/include/private/bitreader.h deleted file mode 100644 index 770fb899..00000000 --- a/src/lib/flac/src/libFLAC/include/private/bitreader.h +++ /dev/null @@ -1,103 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__BITREADER_H -#define FLAC__PRIVATE__BITREADER_H - -#if 0 /* bstone */ -#include /* for FILE */ -#endif /* bstone */ -#include "FLAC/ordinals.h" -#include "cpu.h" - -/* - * opaque structure definition - */ -struct FLAC__BitReader; -typedef struct FLAC__BitReader FLAC__BitReader; - -typedef FLAC__bool (*FLAC__BitReaderReadCallback)(FLAC__byte buffer[], size_t *bytes, void *client_data); - -/* - * construction, deletion, initialization, etc functions - */ -FLAC__BitReader *FLAC__bitreader_new(void); -void FLAC__bitreader_delete(FLAC__BitReader *br); -FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd); -void FLAC__bitreader_free(FLAC__BitReader *br); /* does not 'free(br)' */ -FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br); -void FLAC__bitreader_set_framesync_location(FLAC__BitReader *br); -FLAC__bool FLAC__bitreader_rewind_to_after_last_seen_framesync(FLAC__BitReader *br); - -/* - * CRC functions - */ -void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed); -FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br); - -/* - * info functions - */ -FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); -uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); -uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); -void FLAC__bitreader_set_limit(FLAC__BitReader *br, uint32_t limit); -void FLAC__bitreader_remove_limit(FLAC__BitReader *br); -uint32_t FLAC__bitreader_limit_remaining(FLAC__BitReader *br); -void FLAC__bitreader_limit_invalidate(FLAC__BitReader *br); - -/* - * read functions - */ - -FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_raw_int64(FLAC__BitReader *br, FLAC__int64 *val, uint32_t bits); -FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); /*only for bits=32*/ -FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits); /* WATCHOUT: does not CRC the skipped data! */ /*@@@@ add to unit tests */ -FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */ -FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals); /* WATCHOUT: does not CRC the read data! */ -FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val); -FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter); -FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); -#ifdef FLAC__BMI2_SUPPORTED -FLAC__bool FLAC__bitreader_read_rice_signed_block_bmi2(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); -#endif - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter); -FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter); -#endif -FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen); -FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen); -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/cpu.h b/src/lib/flac/src/libFLAC/include/private/cpu.h deleted file mode 100644 index 2d9687bc..00000000 --- a/src/lib/flac/src/libFLAC/include/private/cpu.h +++ /dev/null @@ -1,198 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__CPU_H -#define FLAC__PRIVATE__CPU_H - -#include "FLAC/ordinals.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifndef FLAC__CPU_X86_64 - -#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) -#define FLAC__CPU_X86_64 -#endif - -#endif - -#ifndef FLAC__CPU_IA32 - -#if defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) ||defined( __i386) || defined(_M_IX86) -#define FLAC__CPU_IA32 -#endif - -#endif - -#ifndef __has_attribute -#define __has_attribute(x) 0 -#endif - -#if FLAC__HAS_X86INTRIN -/* SSE intrinsics support by ICC/MSVC/GCC */ -#if defined __INTEL_COMPILER - #define FLAC__SSE_TARGET(x) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #if (__INTEL_COMPILER >= 1000) /* Intel C++ Compiler 10.0 */ - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #define FLAC__SSE4_2_SUPPORTED 1 - #endif - #ifdef FLAC__USE_AVX - #if (__INTEL_COMPILER >= 1110) /* Intel C++ Compiler 11.1 */ - #define FLAC__AVX_SUPPORTED 1 - #endif - #if (__INTEL_COMPILER >= 1300) /* Intel C++ Compiler 13.0 */ - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #endif - #endif -#elif defined __clang__ && __has_attribute(__target__) /* clang */ - #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #define FLAC__SSE4_2_SUPPORTED 1 - #ifdef FLAC__USE_AVX - #define FLAC__AVX_SUPPORTED 1 - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #define FLAC__BMI2_SUPPORTED 1 - #endif -#elif defined __GNUC__ && !defined __clang__ && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) /* GCC 4.9+ */ - #define FLAC__SSE_TARGET(x) __attribute__ ((__target__ (x))) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #define FLAC__SSE4_2_SUPPORTED 1 - #ifdef FLAC__USE_AVX - #define FLAC__AVX_SUPPORTED 1 - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #define FLAC__BMI2_SUPPORTED 1 - #endif -#elif defined _MSC_VER - #define FLAC__SSE_TARGET(x) - #define FLAC__SSE_SUPPORTED 1 - #define FLAC__SSE2_SUPPORTED 1 - #if (_MSC_VER >= 1500) /* MS Visual Studio 2008 */ - #define FLAC__SSSE3_SUPPORTED 1 - #define FLAC__SSE4_1_SUPPORTED 1 - #define FLAC__SSE4_2_SUPPORTED 1 - #endif - #ifdef FLAC__USE_AVX - #if (_MSC_FULL_VER >= 160040219) /* MS Visual Studio 2010 SP1 */ - #define FLAC__AVX_SUPPORTED 1 - #endif - #if (_MSC_VER >= 1700) /* MS Visual Studio 2012 */ - #define FLAC__AVX2_SUPPORTED 1 - #define FLAC__FMA_SUPPORTED 1 - #endif - #endif -#else - #define FLAC__SSE_TARGET(x) - #ifdef __SSE__ - #define FLAC__SSE_SUPPORTED 1 - #endif - #ifdef __SSE2__ - #define FLAC__SSE2_SUPPORTED 1 - #endif - #ifdef __SSSE3__ - #define FLAC__SSSE3_SUPPORTED 1 - #endif - #ifdef __SSE4_1__ - #define FLAC__SSE4_1_SUPPORTED 1 - #endif - #ifdef __SSE4_2__ - #define FLAC__SSE4_2_SUPPORTED 1 - #endif - #ifdef FLAC__USE_AVX - #ifdef __AVX__ - #define FLAC__AVX_SUPPORTED 1 - #endif - #ifdef __AVX2__ - #define FLAC__AVX2_SUPPORTED 1 - #endif - #ifdef __FMA__ - #define FLAC__FMA_SUPPORTED 1 - #endif - #endif -#endif /* compiler version */ -#endif /* intrinsics support */ - - -#ifndef FLAC__AVX_SUPPORTED -#define FLAC__AVX_SUPPORTED 0 -#endif - -typedef enum { - FLAC__CPUINFO_TYPE_IA32, - FLAC__CPUINFO_TYPE_X86_64, - FLAC__CPUINFO_TYPE_UNKNOWN -} FLAC__CPUInfo_Type; - -typedef struct { - FLAC__bool intel; - - FLAC__bool cmov; - FLAC__bool mmx; - FLAC__bool sse; - FLAC__bool sse2; - - FLAC__bool sse3; - FLAC__bool ssse3; - FLAC__bool sse41; - FLAC__bool sse42; - FLAC__bool avx; - FLAC__bool avx2; - FLAC__bool fma; - FLAC__bool bmi2; -} FLAC__CPUInfo_x86; - -typedef struct { - FLAC__bool use_asm; - FLAC__CPUInfo_Type type; - FLAC__CPUInfo_x86 x86; -} FLAC__CPUInfo; - -void FLAC__cpu_info(FLAC__CPUInfo *info); - -FLAC__uint32 FLAC__cpu_have_cpuid_asm_ia32(void); - -void FLAC__cpu_info_asm_ia32(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx); - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/crc.h b/src/lib/flac/src/libFLAC/include/private/crc.h deleted file mode 100644 index 9e8ed4f2..00000000 --- a/src/lib/flac/src/libFLAC/include/private/crc.h +++ /dev/null @@ -1,60 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__CRC_H -#define FLAC__PRIVATE__CRC_H - -#include "FLAC/ordinals.h" - -/* 8 bit CRC generator, MSB shifted first -** polynomial = x^8 + x^2 + x^1 + x^0 -** init = 0 -*/ -FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len); - -/* 16 bit CRC generator, MSB shifted first -** polynomial = x^16 + x^15 + x^2 + x^0 -** init = 0 -*/ -extern FLAC__uint16 const FLAC__crc16_table[8][256]; - -#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) & 0xffff) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) -/* this alternate may be faster on some systems/compilers */ -#if 0 -#define FLAC__CRC16_UPDATE(data, crc) ((((crc)<<8) ^ FLAC__crc16_table[0][((crc)>>8) ^ (data)]) & 0xffff) -#endif - -FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len); -FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc); -FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc); - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/fixed.h b/src/lib/flac/src/libFLAC/include/private/fixed.h deleted file mode 100644 index 85d5e008..00000000 --- a/src/lib/flac/src/libFLAC/include/private/fixed.h +++ /dev/null @@ -1,117 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__FIXED_H -#define FLAC__PRIVATE__FIXED_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "private/cpu.h" -#include "private/float.h" -#include "FLAC/format.h" - -/* - * FLAC__fixed_compute_best_predictor() - * -------------------------------------------------------------------- - * Compute the best fixed predictor and the expected bits-per-sample - * of the residual signal for each order. The _wide() version uses - * 64-bit integers which is statistically necessary when bits-per- - * sample + log2(blocksize) > 30 - * - * IN data[0,data_len-1] - * IN data_len - * OUT residual_bits_per_sample[0,FLAC__MAX_FIXED_ORDER] - */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -# ifndef FLAC__NO_ASM -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE2_SUPPORTED -uint32_t FLAC__fixed_compute_best_predictor_intrin_sse2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER + 1]); -# endif -# ifdef FLAC__SSSE3_SUPPORTED -uint32_t FLAC__fixed_compute_best_predictor_intrin_ssse3(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -# endif -# ifdef FLAC__SSE4_2_SUPPORTED -uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_sse42(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -# endif -# ifdef FLAC__AVX2_SUPPORTED -uint32_t FLAC__fixed_compute_best_predictor_wide_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_limit_residual_intrin_avx2(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -# endif -# endif -# endif -#else -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]); -#endif - -/* - * FLAC__fixed_compute_residual() - * -------------------------------------------------------------------- - * Compute the residual signal obtained from sutracting the predicted - * signal from the original. - * - * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) - * IN data_len length of original signal - * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order - * OUT residual[0,data_len-1] residual signal - */ -void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); -void FLAC__fixed_compute_residual_wide(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); -void FLAC__fixed_compute_residual_wide_33bit(const FLAC__int64 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]); - -/* - * FLAC__fixed_restore_signal() - * -------------------------------------------------------------------- - * Restore the original signal by summing the residual and the - * predictor. - * - * IN residual[0,data_len-1] residual signal - * IN data_len length of original signal - * IN order <= FLAC__MAX_FIXED_ORDER fixed-predictor order - * *** IMPORTANT: the caller must pass in the historical samples: - * IN data[-order,-1] previously-reconstructed historical samples - * OUT data[0,data_len-1] original signal - */ -void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]); -void FLAC__fixed_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]); -void FLAC__fixed_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int64 data[]); - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/float.h b/src/lib/flac/src/libFLAC/include/private/float.h deleted file mode 100644 index 98aff30c..00000000 --- a/src/lib/flac/src/libFLAC/include/private/float.h +++ /dev/null @@ -1,95 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2004-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__FLOAT_H -#define FLAC__PRIVATE__FLOAT_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include "FLAC/ordinals.h" - -/* - * All the code in libFLAC that uses float and double - * should be protected by checks of the macro - * FLAC__INTEGER_ONLY_LIBRARY. - * - */ -#ifndef FLAC__INTEGER_ONLY_LIBRARY -/* - * FLAC__real is the basic floating point type used in LPC analysis. - * - * WATCHOUT: changing FLAC__real will change the signatures of many - * functions that have assembly language equivalents and break them. - */ -typedef float FLAC__real; -#else -/* - * The convention for FLAC__fixedpoint is to use the upper 16 bits - * for the integer part and lower 16 bits for the fractional part. - */ -typedef FLAC__int32 FLAC__fixedpoint; -extern const FLAC__fixedpoint FLAC__FP_ZERO; -extern const FLAC__fixedpoint FLAC__FP_ONE_HALF; -extern const FLAC__fixedpoint FLAC__FP_ONE; -extern const FLAC__fixedpoint FLAC__FP_LN2; -extern const FLAC__fixedpoint FLAC__FP_E; - -#define FLAC__fixedpoint_trunc(x) ((x)>>16) - -#define FLAC__fixedpoint_mul(x, y) ( (FLAC__fixedpoint) ( ((FLAC__int64)(x)*(FLAC__int64)(y)) >> 16 ) ) - -#define FLAC__fixedpoint_div(x, y) ( (FLAC__fixedpoint) ( ( ((FLAC__int64)(x)<<32) / (FLAC__int64)(y) ) >> 16 ) ) - -/* - * FLAC__fixedpoint_log2() - * -------------------------------------------------------------------- - * Returns the base-2 logarithm of the fixed-point number 'x' using an - * algorithm by Knuth for x >= 1.0 - * - * 'fracbits' is the number of fractional bits of 'x'. 'fracbits' must - * be < 32 and evenly divisible by 4 (0 is OK but not very precise). - * - * 'precision' roughly limits the number of iterations that are done; - * use (uint32_t)(-1) for maximum precision. - * - * If 'x' is less than one -- that is, x < (1< -#endif - -#include "private/cpu.h" -#include "private/float.h" -#include "FLAC/format.h" - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -/* - * FLAC__lpc_window_data() - * -------------------------------------------------------------------- - * Applies the given window to the data. - * OPT: asm implementation - * - * IN in[0,data_len-1] - * IN window[0,data_len-1] - * OUT out[0,lag-1] - * IN data_len - */ -void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len); -void FLAC__lpc_window_data_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len); -void FLAC__lpc_window_data_partial(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift); -void FLAC__lpc_window_data_partial_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift); - -/* - * FLAC__lpc_compute_autocorrelation() - * -------------------------------------------------------------------- - * Compute the autocorrelation for lags between 0 and lag-1. - * Assumes data[] outside of [0,data_len-1] == 0. - * Asserts that lag > 0. - * - * IN data[0,data_len-1] - * IN data_len - * IN 0 < lag <= data_len - * OUT autoc[0,lag-1] - */ -void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -#ifndef FLAC__NO_ASM -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE2_SUPPORTED -void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_sse2_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -# endif -# endif -# if defined FLAC__CPU_X86_64 && FLAC__HAS_X86INTRIN -# ifdef FLAC__FMA_SUPPORTED -void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_12(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_fma_lag_16(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -# endif -# endif -#if defined FLAC__CPU_ARM64 && FLAC__HAS_NEONINTRIN && FLAC__HAS_A64NEONINTRIN -void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_8(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_10(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -void FLAC__lpc_compute_autocorrelation_intrin_neon_lag_14(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]); -#endif -#endif /* FLAC__NO_ASM */ - -/* - * FLAC__lpc_compute_lp_coefficients() - * -------------------------------------------------------------------- - * Computes LP coefficients for orders 1..max_order. - * Do not call if autoc[0] == 0.0. This means the signal is zero - * and there is no point in calculating a predictor. - * - * IN autoc[0,max_order] autocorrelation values - * IN 0 < max_order <= FLAC__MAX_LPC_ORDER max LP order to compute - * OUT lp_coeff[0,max_order-1][0,max_order-1] LP coefficients for each order - * *** IMPORTANT: - * *** lp_coeff[0,max_order-1][max_order,FLAC__MAX_LPC_ORDER-1] are untouched - * OUT error[0,max_order-1] error for each order (more - * specifically, the variance of - * the error signal times # of - * samples in the signal) - * - * Example: if max_order is 9, the LP coefficients for order 9 will be - * in lp_coeff[8][0,8], the LP coefficients for order 8 will be - * in lp_coeff[7][0,7], etc. - */ -void FLAC__lpc_compute_lp_coefficients(const double autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]); - -/* - * FLAC__lpc_quantize_coefficients() - * -------------------------------------------------------------------- - * Quantizes the LP coefficients. NOTE: precision + bits_per_sample - * must be less than 32 (sizeof(FLAC__int32)*8). - * - * IN lp_coeff[0,order-1] LP coefficients - * IN order LP order - * IN FLAC__MIN_QLP_COEFF_PRECISION < precision - * desired precision (in bits, including sign - * bit) of largest coefficient - * OUT qlp_coeff[0,order-1] quantized coefficients - * OUT shift # of bits to shift right to get approximated - * LP coefficients. NOTE: could be negative. - * RETURN 0 => quantization OK - * 1 => coefficients require too much shifting for *shift to - * fit in the LPC subframe header. 'shift' is unset. - * 2 => coefficients are all zero, which is bad. 'shift' is - * unset. - */ -int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift); - -/* - * FLAC__lpc_compute_residual_from_qlp_coefficients() - * -------------------------------------------------------------------- - * Compute the residual signal obtained from sutracting the predicted - * signal from the original. - * - * IN data[-order,data_len-1] original signal (NOTE THE INDICES!) - * IN data_len length of original signal - * IN qlp_coeff[0,order-1] quantized LP coefficients - * IN order > 0 LP order - * IN lp_quantization quantization of LP coefficients in bits - * OUT residual[0,data_len-1] residual signal - */ -void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(const FLAC__int64 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -#ifndef FLAC__NO_ASM -# ifdef FLAC__CPU_ARM64 -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_neon(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif - -# if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN -# ifdef FLAC__SSE2_SUPPORTED -void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# ifdef FLAC__SSE4_1_SUPPORTED -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_sse41(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# ifdef FLAC__AVX2_SUPPORTED -void FLAC__lpc_compute_residual_from_qlp_coefficients_16_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide_intrin_avx2(const FLAC__int32 *data, uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 residual[]); -# endif -# endif -#endif - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -FLAC__uint64 FLAC__lpc_max_prediction_value_before_shift(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order); -uint32_t FLAC__lpc_max_prediction_before_shift_bps(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order); -uint32_t FLAC__lpc_max_residual_bps(uint32_t subframe_bps, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization); - -/* - * FLAC__lpc_restore_signal() - * -------------------------------------------------------------------- - * Restore the original signal by summing the residual and the - * predictor. - * - * IN residual[0,data_len-1] residual signal - * IN data_len length of original signal - * IN qlp_coeff[0,order-1] quantized LP coefficients - * IN order > 0 LP order - * IN lp_quantization quantization of LP coefficients in bits - * *** IMPORTANT: the caller must pass in the historical samples: - * IN data[-order,-1] previously-reconstructed historical samples - * OUT data[0,data_len-1] original signal - */ -void FLAC__lpc_restore_signal(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int32 data[]); -void FLAC__lpc_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, const FLAC__int32 qlp_coeff[], uint32_t order, int lp_quantization, FLAC__int64 data[]); - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -/* - * FLAC__lpc_compute_expected_bits_per_residual_sample() - * -------------------------------------------------------------------- - * Compute the expected number of bits per residual signal sample - * based on the LP error (which is related to the residual variance). - * - * IN lpc_error >= 0.0 error returned from calculating LP coefficients - * IN total_samples > 0 # of samples in residual signal - * RETURN expected bits per sample - */ -double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples); -double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale); - -/* - * FLAC__lpc_compute_best_order() - * -------------------------------------------------------------------- - * Compute the best order from the array of signal errors returned - * during coefficient computation. - * - * IN lpc_error[0,max_order-1] >= 0.0 error returned from calculating LP coefficients - * IN max_order > 0 max LP order - * IN total_samples > 0 # of samples in residual signal - * IN overhead_bits_per_order # of bits overhead for each increased LP order - * (includes warmup sample size and quantized LP coefficient) - * RETURN [1,max_order] best order - */ -uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order); - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/macros.h b/src/lib/flac/src/libFLAC/include/private/macros.h deleted file mode 100644 index cce91543..00000000 --- a/src/lib/flac/src/libFLAC/include/private/macros.h +++ /dev/null @@ -1,74 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2012-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__MACROS_H -#define FLAC__PRIVATE__MACROS_H - -#if defined(__GNUC__) && (__GNUC__ > 4 || ( __GNUC__ == 4 && __GNUC_MINOR__ >= 3)) - -#define flac_max(a,b) \ - ({ __typeof__ (a) _a = (a); \ - __typeof__ (b) _b = (b); \ - _a > _b ? _a : _b; }) - -#define MIN_PASTE(A,B) A##B -#define MIN_IMPL(A,B,L) ({ \ - __typeof__(A) MIN_PASTE(__a,L) = (A); \ - __typeof__(B) MIN_PASTE(__b,L) = (B); \ - MIN_PASTE(__a,L) < MIN_PASTE(__b,L) ? MIN_PASTE(__a,L) : MIN_PASTE(__b,L); \ - }) - -#define flac_min(A,B) MIN_IMPL(A,B,__COUNTER__) - -/* Whatever other unix that has sys/param.h */ -#elif defined(HAVE_SYS_PARAM_H) -#include -#if defined(MIN) && defined(MAX) -#define flac_max(a,b) MAX(a,b) -#define flac_min(a,b) MIN(a,b) -#endif - -/* Windows VS has them in stdlib.h.. XXX:Untested */ -#elif defined(_MSC_VER) -#include -#define flac_max(a,b) __max(a,b) -#define flac_min(a,b) __min(a,b) -#endif - -#ifndef flac_min -#define flac_min(x,y) ((x) <= (y) ? (x) : (y)) -#endif - -#ifndef flac_max -#define flac_max(x,y) ((x) >= (y) ? (x) : (y)) -#endif - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/md5.h b/src/lib/flac/src/libFLAC/include/private/md5.h deleted file mode 100644 index f9d79c3e..00000000 --- a/src/lib/flac/src/libFLAC/include/private/md5.h +++ /dev/null @@ -1,50 +0,0 @@ -#ifndef FLAC__PRIVATE__MD5_H -#define FLAC__PRIVATE__MD5_H - -/* - * This is the header file for the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - * Changed so as no longer to depend on Colin Plumb's `usual.h' - * header definitions; now uses stuff from dpkg's config.h - * - Ian Jackson . - * Still in the public domain. - * - * Josh Coalson: made some changes to integrate with libFLAC. - * Still in the public domain, with no warranty. - */ - -#include "FLAC/ordinals.h" - -typedef union { - FLAC__byte *p8; - FLAC__int16 *p16; - FLAC__int32 *p32; -} FLAC__multibyte; - -typedef struct { - FLAC__uint32 in[16]; - FLAC__uint32 buf[4]; - FLAC__uint32 bytes[2]; - FLAC__multibyte internal_buf; - size_t capacity; -} FLAC__MD5Context; - -void FLAC__MD5Init(FLAC__MD5Context *context); -void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *context); - -FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample); - -#endif diff --git a/src/lib/flac/src/libFLAC/include/private/memory.h b/src/lib/flac/src/libFLAC/include/private/memory.h deleted file mode 100644 index 1a84a015..00000000 --- a/src/lib/flac/src/libFLAC/include/private/memory.h +++ /dev/null @@ -1,58 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PRIVATE__MEMORY_H -#define FLAC__PRIVATE__MEMORY_H - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include /* for size_t */ - -#include "private/float.h" -#include "FLAC/ordinals.h" /* for FLAC__bool */ - -/* Returns the unaligned address returned by malloc. - * Use free() on this address to deallocate. - */ -void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address); -FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_int64_array(size_t elements, FLAC__int64 **unaligned_pointer, FLAC__int64 **aligned_pointer); -FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer); -#ifndef FLAC__INTEGER_ONLY_LIBRARY -FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer); -#endif -void *safe_malloc_mul_2op_p(size_t size1, size_t size2); - -#endif diff --git a/src/lib/flac/src/libFLAC/include/protected/stream_decoder.h b/src/lib/flac/src/libFLAC/include/protected/stream_decoder.h deleted file mode 100644 index 1bf5edea..00000000 --- a/src/lib/flac/src/libFLAC/include/protected/stream_decoder.h +++ /dev/null @@ -1,60 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef FLAC__PROTECTED__STREAM_DECODER_H -#define FLAC__PROTECTED__STREAM_DECODER_H - -#include "FLAC/stream_decoder.h" -#if FLAC__HAS_OGG -#include "private/ogg_decoder_aspect.h" -#endif - -typedef struct FLAC__StreamDecoderProtected { - FLAC__StreamDecoderState state; - FLAC__StreamDecoderInitStatus initstate; - uint32_t channels; - FLAC__ChannelAssignment channel_assignment; - uint32_t bits_per_sample; - uint32_t sample_rate; /* in Hz */ - uint32_t blocksize; /* in samples (per channel) */ - FLAC__bool md5_checking; /* if true, generate MD5 signature of decoded data and compare against signature in the STREAMINFO metadata block */ -#if FLAC__HAS_OGG - FLAC__OggDecoderAspect ogg_decoder_aspect; -#endif -} FLAC__StreamDecoderProtected; - -/* - * Return the number of input bytes consumed - */ -uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder); - -#endif diff --git a/src/lib/flac/src/libFLAC/src/bitmath.c b/src/lib/flac/src/libFLAC/src/bitmath.c deleted file mode 100644 index 470c03b8..00000000 --- a/src/lib/flac/src/libFLAC/src/bitmath.c +++ /dev/null @@ -1,115 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "private/bitmath.h" - -/* An example of what FLAC__bitmath_silog2() computes: - * - * silog2(-10) = 5 - * silog2(- 9) = 5 - * silog2(- 8) = 4 - * silog2(- 7) = 4 - * silog2(- 6) = 4 - * silog2(- 5) = 4 - * silog2(- 4) = 3 - * silog2(- 3) = 3 - * silog2(- 2) = 2 - * silog2(- 1) = 2 - * silog2( 0) = 0 - * silog2( 1) = 2 - * silog2( 2) = 3 - * silog2( 3) = 3 - * silog2( 4) = 4 - * silog2( 5) = 4 - * silog2( 6) = 4 - * silog2( 7) = 4 - * silog2( 8) = 5 - * silog2( 9) = 5 - * silog2( 10) = 5 - */ -uint32_t FLAC__bitmath_silog2(FLAC__int64 v) -{ - if(v == 0) - return 0; - - if(v == -1) - return 2; - - v = (v < 0) ? (-(v+1)) : v; - return FLAC__bitmath_ilog2_wide(v)+2; -} - -/* An example of what FLAC__bitmath_extra_mulbits_unsigned() computes: - * - * extra_mulbits_unsigned( 0) = 0 - * extra_mulbits_unsigned( 1) = 0 - * extra_mulbits_unsigned( 2) = 1 - * extra_mulbits_unsigned( 3) = 2 - * extra_mulbits_unsigned( 4) = 2 - * extra_mulbits_unsigned( 5) = 3 - * extra_mulbits_unsigned( 6) = 3 - * extra_mulbits_unsigned( 7) = 3 - * extra_mulbits_unsigned( 8) = 3 - * extra_mulbits_unsigned( 9) = 4 - * extra_mulbits_unsigned(10) = 4 - * extra_mulbits_unsigned(11) = 4 - * extra_mulbits_unsigned(12) = 4 - * extra_mulbits_unsigned(13) = 4 - * extra_mulbits_unsigned(14) = 4 - * extra_mulbits_unsigned(15) = 4 - * extra_mulbits_unsigned(16) = 4 - * extra_mulbits_unsigned(17) = 5 - * extra_mulbits_unsigned(18) = 5 - * - * The intent of this is to calculate how many extra bits multiplication - * by a certain number requires. So, if a signal fits in a certain number - * of bits (for example 16) than multiplying by a number (for example 1024) - * grows that storage requirement (to 26 in this example). In effect this is - * is the log2 rounded up. - */ -uint32_t FLAC__bitmath_extra_mulbits_unsigned(FLAC__uint32 v) -{ - uint32_t ilog2; - if(v == 0) - return 0; - ilog2 = FLAC__bitmath_ilog2(v); - if(((v >> ilog2) << ilog2) == v) - /* v is power of 2 */ - return ilog2; - else - /* v is not a power of 2, return one higher */ - return ilog2 + 1; -} diff --git a/src/lib/flac/src/libFLAC/src/bitreader.c b/src/lib/flac/src/libFLAC/src/bitreader.c deleted file mode 100644 index 3ebe37c8..00000000 --- a/src/lib/flac/src/libFLAC/src/bitreader.c +++ /dev/null @@ -1,1052 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include "private/bitmath.h" -#include "private/bitreader.h" -#include "private/crc.h" -#include "private/cpu.h" -#include "private/macros.h" -#include "FLAC/assert.h" -#include "share/compat.h" -#include "share/endswap.h" - -/* Things should be fastest when this matches the machine word size */ -/* WATCHOUT: if you change this you must also change the following #defines down to COUNT_ZERO_MSBS2 below to match */ -/* WATCHOUT: there are a few places where the code will not work unless brword is >= 32 bits wide */ -/* also, some sections currently only have fast versions for 4 or 8 bytes per word */ - -#if (ENABLE_64_BIT_WORDS == 0) - -typedef FLAC__uint32 brword; -#define FLAC__BYTES_PER_WORD 4 /* sizeof brword */ -#define FLAC__BITS_PER_WORD 32 -#define FLAC__WORD_ALL_ONES ((FLAC__uint32)0xffffffff) -/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */ -#if WORDS_BIGENDIAN -#define SWAP_BE_WORD_TO_HOST(x) (x) -#else -#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_32(x) -#endif -/* counts the # of zero MSBs in a word */ -#define COUNT_ZERO_MSBS(word) FLAC__clz_uint32(word) -#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint32(word) - -#else - -typedef FLAC__uint64 brword; -#define FLAC__BYTES_PER_WORD 8 /* sizeof brword */ -#define FLAC__BITS_PER_WORD 64 -#define FLAC__WORD_ALL_ONES ((FLAC__uint64)FLAC__U64L(0xffffffffffffffff)) -/* SWAP_BE_WORD_TO_HOST swaps bytes in a brword (which is always big-endian) if necessary to match host byte order */ -#if WORDS_BIGENDIAN -#define SWAP_BE_WORD_TO_HOST(x) (x) -#else -#define SWAP_BE_WORD_TO_HOST(x) ENDSWAP_64(x) -#endif -/* counts the # of zero MSBs in a word */ -#define COUNT_ZERO_MSBS(word) FLAC__clz_uint64(word) -#define COUNT_ZERO_MSBS2(word) FLAC__clz2_uint64(word) - -#endif - -/* - * This should be at least twice as large as the largest number of words - * required to represent any 'number' (in any encoding) you are going to - * read. With FLAC this is on the order of maybe a few hundred bits. - * If the buffer is smaller than that, the decoder won't be able to read - * in a whole number that is in a variable length encoding (e.g. Rice). - * But to be practical it should be at least 1K bytes. - * - * Increase this number to decrease the number of read callbacks, at the - * expense of using more memory. Or decrease for the reverse effect, - * keeping in mind the limit from the first paragraph. The optimal size - * also depends on the CPU cache size and other factors; some twiddling - * may be necessary to squeeze out the best performance. - */ -static const uint32_t FLAC__BITREADER_DEFAULT_CAPACITY = 65536u / FLAC__BITS_PER_WORD; /* in words */ - -struct FLAC__BitReader { - /* any partially-consumed word at the head will stay right-justified as bits are consumed from the left */ - /* any incomplete word at the tail will be left-justified, and bytes from the read callback are added on the right */ - brword *buffer; - uint32_t capacity; /* in words */ - uint32_t words; /* # of completed words in buffer */ - uint32_t bytes; /* # of bytes in incomplete word at buffer[words] */ - uint32_t consumed_words; /* #words ... */ - uint32_t consumed_bits; /* ... + (#bits of head word) already consumed from the front of buffer */ - uint32_t read_crc16; /* the running frame CRC */ - uint32_t crc16_offset; /* the number of words in the current buffer that should not be CRC'd */ - uint32_t crc16_align; /* the number of bits in the current consumed word that should not be CRC'd */ - FLAC__bool read_limit_set; /* whether reads are limited */ - uint32_t read_limit; /* the remaining size of what can be read */ - uint32_t last_seen_framesync; /* the location of the last seen framesync, if it is in the buffer, in bits from front of buffer */ - FLAC__BitReaderReadCallback read_callback; - void *client_data; -}; - -static inline void crc16_update_word_(FLAC__BitReader *br, brword word) -{ - register uint32_t crc = br->read_crc16; - - for ( ; br->crc16_align < FLAC__BITS_PER_WORD ; br->crc16_align += 8) { - uint32_t shift = FLAC__BITS_PER_WORD - 8 - br->crc16_align ; - crc = FLAC__CRC16_UPDATE ((uint32_t) (shift < FLAC__BITS_PER_WORD ? (word >> shift) & 0xff : 0), crc); - } - - br->read_crc16 = crc; - br->crc16_align = 0; -} - -static inline void crc16_update_block_(FLAC__BitReader *br) -{ - if(br->consumed_words > br->crc16_offset && br->crc16_align) - crc16_update_word_(br, br->buffer[br->crc16_offset++]); - - /* Prevent OOB read due to wrap-around. */ - if (br->consumed_words > br->crc16_offset) { -#if FLAC__BYTES_PER_WORD == 4 - br->read_crc16 = FLAC__crc16_update_words32(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16); -#elif FLAC__BYTES_PER_WORD == 8 - br->read_crc16 = FLAC__crc16_update_words64(br->buffer + br->crc16_offset, br->consumed_words - br->crc16_offset, br->read_crc16); -#else - unsigned i; - - for (i = br->crc16_offset; i < br->consumed_words; i++) - crc16_update_word_(br, br->buffer[i]); -#endif - } - - br->crc16_offset = 0; -} - -static FLAC__bool bitreader_read_from_client_(FLAC__BitReader *br) -{ - uint32_t start, end; - size_t bytes; - FLAC__byte *target; -#if WORDS_BIGENDIAN -#else - brword preswap_backup; -#endif - - /* first shift the unconsumed buffer data toward the front as much as possible */ - if(br->consumed_words > 0) { - /* invalidate last seen framesync */ - br->last_seen_framesync = -1; - - crc16_update_block_(br); /* CRC consumed words */ - - start = br->consumed_words; - end = br->words + (br->bytes? 1:0); - memmove(br->buffer, br->buffer+start, FLAC__BYTES_PER_WORD * (end - start)); - - br->words -= start; - br->consumed_words = 0; - } - - /* - * set the target for reading, taking into account word alignment and endianness - */ - bytes = (br->capacity - br->words) * FLAC__BYTES_PER_WORD - br->bytes; - if(bytes == 0) - return false; /* no space left, buffer is too small; see note for FLAC__BITREADER_DEFAULT_CAPACITY */ - target = ((FLAC__byte*)(br->buffer+br->words)) + br->bytes; - - /* before reading, if the existing reader looks like this (say brword is 32 bits wide) - * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 (partial tail word is left-justified) - * buffer[BE]: 11 22 33 44 55 ?? ?? ?? (shown laid out as bytes sequentially in memory) - * buffer[LE]: 44 33 22 11 ?? ?? ?? 55 (?? being don't-care) - * ^^-------target, bytes=3 - * on LE machines, have to byteswap the odd tail word so nothing is - * overwritten: - */ -#if WORDS_BIGENDIAN -#else - preswap_backup = br->buffer[br->words]; - if(br->bytes) - br->buffer[br->words] = SWAP_BE_WORD_TO_HOST(br->buffer[br->words]); -#endif - - /* now it looks like: - * bitstream : 11 22 33 44 55 br->words=1 br->bytes=1 - * buffer[BE]: 11 22 33 44 55 ?? ?? ?? - * buffer[LE]: 44 33 22 11 55 ?? ?? ?? - * ^^-------target, bytes=3 - */ - - /* read in the data; note that the callback may return a smaller number of bytes */ - if(!br->read_callback(target, &bytes, br->client_data)){ - /* Despite the read callback failing, the data in the target - * might be used later, when the buffer is rewound. Therefore - * we revert the swap that was just done */ -#if WORDS_BIGENDIAN -#else - br->buffer[br->words] = preswap_backup; -#endif - return false; - } - - /* after reading bytes 66 77 88 99 AA BB CC DD EE FF from the client: - * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF - * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? - * buffer[LE]: 44 33 22 11 55 66 77 88 99 AA BB CC DD EE FF ?? - * now have to byteswap on LE machines: - */ -#if WORDS_BIGENDIAN -#else - end = (br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes + (FLAC__BYTES_PER_WORD-1)) / FLAC__BYTES_PER_WORD; - for(start = br->words; start < end; start++) - br->buffer[start] = SWAP_BE_WORD_TO_HOST(br->buffer[start]); -#endif - - /* now it looks like: - * bitstream : 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF - * buffer[BE]: 11 22 33 44 55 66 77 88 99 AA BB CC DD EE FF ?? - * buffer[LE]: 44 33 22 11 88 77 66 55 CC BB AA 99 ?? FF EE DD - * finally we'll update the reader values: - */ - end = br->words*FLAC__BYTES_PER_WORD + br->bytes + (uint32_t)bytes; - br->words = end / FLAC__BYTES_PER_WORD; - br->bytes = end % FLAC__BYTES_PER_WORD; - - return true; -} - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ - -FLAC__BitReader *FLAC__bitreader_new(void) -{ - FLAC__BitReader *br = calloc(1, sizeof(FLAC__BitReader)); - - /* calloc() implies: - memset(br, 0, sizeof(FLAC__BitReader)); - br->buffer = 0; - br->capacity = 0; - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->read_callback = 0; - br->client_data = 0; - */ - return br; -} - -void FLAC__bitreader_delete(FLAC__BitReader *br) -{ - FLAC__ASSERT(0 != br); - - FLAC__bitreader_free(br); - free(br); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -FLAC__bool FLAC__bitreader_init(FLAC__BitReader *br, FLAC__BitReaderReadCallback rcb, void *cd) -{ - FLAC__ASSERT(0 != br); - - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->capacity = FLAC__BITREADER_DEFAULT_CAPACITY; - br->buffer = malloc(sizeof(brword) * br->capacity); - if(br->buffer == 0) - return false; - br->read_callback = rcb; - br->client_data = cd; - br->read_limit_set = false; - br->read_limit = -1; - br->last_seen_framesync = -1; - - return true; -} - -void FLAC__bitreader_free(FLAC__BitReader *br) -{ - FLAC__ASSERT(0 != br); - - if(0 != br->buffer) - free(br->buffer); - br->buffer = 0; - br->capacity = 0; - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->read_callback = 0; - br->client_data = 0; - br->read_limit_set = false; - br->read_limit = -1; - br->last_seen_framesync = -1; -} - -FLAC__bool FLAC__bitreader_clear(FLAC__BitReader *br) -{ - br->words = br->bytes = 0; - br->consumed_words = br->consumed_bits = 0; - br->read_limit_set = false; - br->read_limit = -1; - br->last_seen_framesync = -1; - return true; -} - -void FLAC__bitreader_set_framesync_location(FLAC__BitReader *br) -{ - br->last_seen_framesync = br->consumed_words * FLAC__BYTES_PER_WORD + br->consumed_bits / 8; -} - -FLAC__bool FLAC__bitreader_rewind_to_after_last_seen_framesync(FLAC__BitReader *br) -{ - if(br->last_seen_framesync == (uint32_t)-1) { - br->consumed_words = br->consumed_bits = 0; - return false; - } - else { - br->consumed_words = (br->last_seen_framesync + 1) / FLAC__BYTES_PER_WORD; - br->consumed_bits = ((br->last_seen_framesync + 1) % FLAC__BYTES_PER_WORD) * 8; - return true; - } -} - -void FLAC__bitreader_reset_read_crc16(FLAC__BitReader *br, FLAC__uint16 seed) -{ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT((br->consumed_bits & 7) == 0); - - br->read_crc16 = (uint32_t)seed; - br->crc16_offset = br->consumed_words; - br->crc16_align = br->consumed_bits; -} - -FLAC__uint16 FLAC__bitreader_get_read_crc16(FLAC__BitReader *br) -{ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - /* CRC consumed words up to here */ - crc16_update_block_(br); - - FLAC__ASSERT((br->consumed_bits & 7) == 0); - FLAC__ASSERT(br->crc16_align <= br->consumed_bits); - - /* CRC any tail bytes in a partially-consumed word */ - if(br->consumed_bits) { - const brword tail = br->buffer[br->consumed_words]; - for( ; br->crc16_align < br->consumed_bits; br->crc16_align += 8) - br->read_crc16 = FLAC__CRC16_UPDATE((uint32_t)((tail >> (FLAC__BITS_PER_WORD-8-br->crc16_align)) & 0xff), br->read_crc16); - } - return br->read_crc16; -} - -inline FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br) -{ - return ((br->consumed_bits & 7) == 0); -} - -inline uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br) -{ - return 8 - (br->consumed_bits & 7); -} - -inline uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br) -{ - return (br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits; -} - -void FLAC__bitreader_set_limit(FLAC__BitReader *br, uint32_t limit) -{ - br->read_limit = limit; - br->read_limit_set = true; -} - -void FLAC__bitreader_remove_limit(FLAC__BitReader *br) -{ - br->read_limit_set = false; - br->read_limit = -1; -} - -uint32_t FLAC__bitreader_limit_remaining(FLAC__BitReader *br) -{ - FLAC__ASSERT(br->read_limit_set); - return br->read_limit; -} -void FLAC__bitreader_limit_invalidate(FLAC__BitReader *br) -{ - br->read_limit = -1; -} - -FLAC__bool FLAC__bitreader_read_raw_uint32(FLAC__BitReader *br, FLAC__uint32 *val, uint32_t bits) -{ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - FLAC__ASSERT(bits <= 32); - FLAC__ASSERT((br->capacity*FLAC__BITS_PER_WORD) * 2 >= bits); - FLAC__ASSERT(br->consumed_words <= br->words); - - /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ - FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); - - if(bits == 0) { /* OPT: investigate if this can ever happen, maybe change to assertion */ - *val = 0; - return true; - } - - if(br->read_limit_set && br->read_limit < (uint32_t)-1){ - if(br->read_limit < bits) { - br->read_limit = -1; - return false; - } - else - br->read_limit -= bits; - } - - while((br->words-br->consumed_words)*FLAC__BITS_PER_WORD + br->bytes*8 - br->consumed_bits < bits) { - if(!bitreader_read_from_client_(br)) - return false; - } - if(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ - /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ - if(br->consumed_bits) { - /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ - const uint32_t n = FLAC__BITS_PER_WORD - br->consumed_bits; - const brword word = br->buffer[br->consumed_words]; - const brword mask = br->consumed_bits < FLAC__BITS_PER_WORD ? FLAC__WORD_ALL_ONES >> br->consumed_bits : 0; - if(bits < n) { - uint32_t shift = n - bits; - *val = shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)((word & mask) >> shift) : 0; /* The result has <= 32 non-zero bits */ - br->consumed_bits += bits; - return true; - } - /* (FLAC__BITS_PER_WORD - br->consumed_bits <= bits) ==> (FLAC__WORD_ALL_ONES >> br->consumed_bits) has no more than 'bits' non-zero bits */ - *val = (FLAC__uint32)(word & mask); - bits -= n; - br->consumed_words++; - br->consumed_bits = 0; - if(bits) { /* if there are still bits left to read, there have to be less than 32 so they will all be in the next word */ - uint32_t shift = FLAC__BITS_PER_WORD - bits; - *val = bits < 32 ? *val << bits : 0; - *val |= shift < FLAC__BITS_PER_WORD ? (FLAC__uint32)(br->buffer[br->consumed_words] >> shift) : 0; - br->consumed_bits = bits; - } - return true; - } - else { /* br->consumed_bits == 0 */ - const brword word = br->buffer[br->consumed_words]; - if(bits < FLAC__BITS_PER_WORD) { - *val = (FLAC__uint32)(word >> (FLAC__BITS_PER_WORD-bits)); - br->consumed_bits = bits; - return true; - } - /* at this point bits == FLAC__BITS_PER_WORD == 32; because of previous assertions, it can't be larger */ - *val = (FLAC__uint32)word; - br->consumed_words++; - return true; - } - } - else { - /* in this case we're starting our read at a partial tail word; - * the reader has guaranteed that we have at least 'bits' bits - * available to read, which makes this case simpler. - */ - /* OPT: taking out the consumed_bits==0 "else" case below might make things faster if less code allows the compiler to inline this function */ - if(br->consumed_bits) { - /* this also works when consumed_bits==0, it's just a little slower than necessary for that case */ - FLAC__ASSERT(br->consumed_bits + bits <= br->bytes*8); - *val = (FLAC__uint32)((br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES >> br->consumed_bits)) >> (FLAC__BITS_PER_WORD-br->consumed_bits-bits)); - br->consumed_bits += bits; - return true; - } - else { - *val = (FLAC__uint32)(br->buffer[br->consumed_words] >> (FLAC__BITS_PER_WORD-bits)); - br->consumed_bits += bits; - return true; - } - } -} - -FLAC__bool FLAC__bitreader_read_raw_int32(FLAC__BitReader *br, FLAC__int32 *val, uint32_t bits) -{ - FLAC__uint32 uval, mask; - /* OPT: inline raw uint32 code here, or make into a macro if possible in the .h file */ - if (bits < 1 || ! FLAC__bitreader_read_raw_uint32(br, &uval, bits)) - return false; - /* sign-extend *val assuming it is currently bits wide. */ - /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */ - mask = bits >= 33 ? 0 : 1lu << (bits - 1); - *val = (uval ^ mask) - mask; - return true; -} - -FLAC__bool FLAC__bitreader_read_raw_uint64(FLAC__BitReader *br, FLAC__uint64 *val, uint32_t bits) -{ - FLAC__uint32 hi, lo; - - if(bits > 32) { - if(!FLAC__bitreader_read_raw_uint32(br, &hi, bits-32)) - return false; - if(!FLAC__bitreader_read_raw_uint32(br, &lo, 32)) - return false; - *val = hi; - *val <<= 32; - *val |= lo; - } - else { - if(!FLAC__bitreader_read_raw_uint32(br, &lo, bits)) - return false; - *val = lo; - } - return true; -} - -FLAC__bool FLAC__bitreader_read_raw_int64(FLAC__BitReader *br, FLAC__int64 *val, uint32_t bits) -{ - FLAC__uint64 uval, mask; - /* OPT: inline raw uint64 code here, or make into a macro if possible in the .h file */ - if (bits < 1 || ! FLAC__bitreader_read_raw_uint64(br, &uval, bits)) - return false; - /* sign-extend *val assuming it is currently bits wide. */ - /* From: https://graphics.stanford.edu/~seander/bithacks.html#FixedSignExtend */ - mask = bits >= 65 ? 0 : 1llu << (bits - 1); - *val = (uval ^ mask) - mask; - return true; -} - -inline FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val) -{ - FLAC__uint32 x8, x32 = 0; - - /* this doesn't need to be that fast as currently it is only used for vorbis comments */ - - if(!FLAC__bitreader_read_raw_uint32(br, &x32, 8)) - return false; - - if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) - return false; - x32 |= (x8 << 8); - - if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) - return false; - x32 |= (x8 << 16); - - if(!FLAC__bitreader_read_raw_uint32(br, &x8, 8)) - return false; - x32 |= (x8 << 24); - - *val = x32; - return true; -} - -FLAC__bool FLAC__bitreader_skip_bits_no_crc(FLAC__BitReader *br, uint32_t bits) -{ - /* - * OPT: a faster implementation is possible but probably not that useful - * since this is only called a couple of times in the metadata readers. - */ - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - if(bits > 0) { - const uint32_t n = br->consumed_bits & 7; - uint32_t m; - FLAC__uint32 x; - - if(n != 0) { - m = flac_min(8-n, bits); - if(!FLAC__bitreader_read_raw_uint32(br, &x, m)) - return false; - bits -= m; - } - m = bits / 8; - if(m > 0) { - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(br, m)) - return false; - bits %= 8; - } - if(bits > 0) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, bits)) - return false; - } - } - - return true; -} - -FLAC__bool FLAC__bitreader_skip_byte_block_aligned_no_crc(FLAC__BitReader *br, uint32_t nvals) -{ - FLAC__uint32 x; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); - - if(br->read_limit_set && br->read_limit < (uint32_t)-1){ - if(br->read_limit < nvals*8){ - br->read_limit = -1; - return false; - } - } - - /* step 1: skip over partial head word to get word aligned */ - while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - nvals--; - } - if(0 == nvals) - return true; - - /* step 2: skip whole words in chunks */ - while(nvals >= FLAC__BYTES_PER_WORD) { - if(br->consumed_words < br->words) { - br->consumed_words++; - nvals -= FLAC__BYTES_PER_WORD; - if(br->read_limit_set) - br->read_limit -= FLAC__BITS_PER_WORD; - } - else if(!bitreader_read_from_client_(br)) - return false; - } - /* step 3: skip any remainder from partial tail bytes */ - while(nvals) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - nvals--; - } - - return true; -} - -FLAC__bool FLAC__bitreader_read_byte_block_aligned_no_crc(FLAC__BitReader *br, FLAC__byte *val, uint32_t nvals) -{ - FLAC__uint32 x; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(br)); - - if(br->read_limit_set && br->read_limit < (uint32_t)-1){ - if(br->read_limit < nvals*8){ - br->read_limit = -1; - return false; - } - } - - /* step 1: read from partial head word to get word aligned */ - while(nvals && br->consumed_bits) { /* i.e. run until we read 'nvals' bytes or we hit the end of the head word */ - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - *val++ = (FLAC__byte)x; - nvals--; - } - if(0 == nvals) - return true; - /* step 2: read whole words in chunks */ - while(nvals >= FLAC__BYTES_PER_WORD) { - if(br->consumed_words < br->words) { - const brword word = br->buffer[br->consumed_words++]; -#if FLAC__BYTES_PER_WORD == 4 - val[0] = (FLAC__byte)(word >> 24); - val[1] = (FLAC__byte)(word >> 16); - val[2] = (FLAC__byte)(word >> 8); - val[3] = (FLAC__byte)word; -#elif FLAC__BYTES_PER_WORD == 8 - val[0] = (FLAC__byte)(word >> 56); - val[1] = (FLAC__byte)(word >> 48); - val[2] = (FLAC__byte)(word >> 40); - val[3] = (FLAC__byte)(word >> 32); - val[4] = (FLAC__byte)(word >> 24); - val[5] = (FLAC__byte)(word >> 16); - val[6] = (FLAC__byte)(word >> 8); - val[7] = (FLAC__byte)word; -#else - for(x = 0; x < FLAC__BYTES_PER_WORD; x++) - val[x] = (FLAC__byte)(word >> (8*(FLAC__BYTES_PER_WORD-x-1))); -#endif - val += FLAC__BYTES_PER_WORD; - nvals -= FLAC__BYTES_PER_WORD; - if(br->read_limit_set) - br->read_limit -= FLAC__BITS_PER_WORD; - } - else if(!bitreader_read_from_client_(br)) - return false; - } - /* step 3: read any remainder from partial tail bytes */ - while(nvals) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - *val++ = (FLAC__byte)x; - nvals--; - } - - return true; -} - -FLAC__bool FLAC__bitreader_read_unary_unsigned(FLAC__BitReader *br, uint32_t *val) -#if 0 /* slow but readable version */ -{ - uint32_t bit; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - *val = 0; - while(1) { - if(!FLAC__bitreader_read_bit(br, &bit)) - return false; - if(bit) - break; - else - *val++; - } - return true; -} -#else -{ - uint32_t i; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - *val = 0; - while(1) { - while(br->consumed_words < br->words) { /* if we've not consumed up to a partial tail word... */ - brword b = br->consumed_bits < FLAC__BITS_PER_WORD ? br->buffer[br->consumed_words] << br->consumed_bits : 0; - if(b) { - i = COUNT_ZERO_MSBS(b); - *val += i; - i++; - br->consumed_bits += i; - if(br->consumed_bits >= FLAC__BITS_PER_WORD) { /* faster way of testing if(br->consumed_bits == FLAC__BITS_PER_WORD) */ - br->consumed_words++; - br->consumed_bits = 0; - } - return true; - } - else { - *val += FLAC__BITS_PER_WORD - br->consumed_bits; - br->consumed_words++; - br->consumed_bits = 0; - /* didn't find stop bit yet, have to keep going... */ - } - } - /* at this point we've eaten up all the whole words; have to try - * reading through any tail bytes before calling the read callback. - * this is a repeat of the above logic adjusted for the fact we - * don't have a whole word. note though if the client is feeding - * us data a byte at a time (unlikely), br->consumed_bits may not - * be zero. - */ - if(br->bytes*8 > br->consumed_bits) { - const uint32_t end = br->bytes * 8; - brword b = (br->buffer[br->consumed_words] & (FLAC__WORD_ALL_ONES << (FLAC__BITS_PER_WORD-end))) << br->consumed_bits; - if(b) { - i = COUNT_ZERO_MSBS(b); - *val += i; - i++; - br->consumed_bits += i; - FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); - return true; - } - else { - *val += end - br->consumed_bits; - br->consumed_bits = end; - FLAC__ASSERT(br->consumed_bits < FLAC__BITS_PER_WORD); - /* didn't find stop bit yet, have to keep going... */ - } - } - if(!bitreader_read_from_client_(br)) - return false; - } -} -#endif - -#if 0 /* unused */ -FLAC__bool FLAC__bitreader_read_rice_signed(FLAC__BitReader *br, int *val, uint32_t parameter) -{ - FLAC__uint32 lsbs = 0, msbs = 0; - uint32_t uval; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - FLAC__ASSERT(parameter <= 31); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter)) - return false; - - /* compose the value */ - uval = (msbs << parameter) | lsbs; - if(uval & 1) - *val = -((int)(uval >> 1)) - 1; - else - *val = (int)(uval >> 1); - - return true; -} -#endif - -/* this is by far the most heavily used reader call. it ain't pretty but it's fast */ -FLAC__bool FLAC__bitreader_read_rice_signed_block(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter) -#include "deduplication/bitreader_read_rice_signed_block.c" - -#ifdef FLAC__BMI2_SUPPORTED -FLAC__SSE_TARGET("bmi2") -FLAC__bool FLAC__bitreader_read_rice_signed_block_bmi2(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter) -#include "deduplication/bitreader_read_rice_signed_block.c" -#endif - -#if 0 /* UNUSED */ -FLAC__bool FLAC__bitreader_read_golomb_signed(FLAC__BitReader *br, int *val, uint32_t parameter) -{ - FLAC__uint32 lsbs = 0, msbs = 0; - uint32_t bit, uval, k; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - k = FLAC__bitmath_ilog2(parameter); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) - return false; - - if(parameter == 1u<= d) { - if(!FLAC__bitreader_read_bit(br, &bit)) - return false; - lsbs <<= 1; - lsbs |= bit; - lsbs -= d; - } - /* compose the value */ - uval = msbs * parameter + lsbs; - } - - /* unfold uint32_t to signed */ - if(uval & 1) - *val = -((int)(uval >> 1)) - 1; - else - *val = (int)(uval >> 1); - - return true; -} - -FLAC__bool FLAC__bitreader_read_golomb_unsigned(FLAC__BitReader *br, uint32_t *val, uint32_t parameter) -{ - FLAC__uint32 lsbs, msbs = 0; - uint32_t bit, k; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - - k = FLAC__bitmath_ilog2(parameter); - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, k)) - return false; - - if(parameter == 1u<= d) { - if(!FLAC__bitreader_read_bit(br, &bit)) - return false; - lsbs <<= 1; - lsbs |= bit; - lsbs -= d; - } - /* compose the value */ - *val = msbs * parameter + lsbs; - } - - return true; -} -#endif /* UNUSED */ - -/* on return, if *val == 0xffffffff then the utf-8 sequence was invalid, but the return value will be true */ -FLAC__bool FLAC__bitreader_read_utf8_uint32(FLAC__BitReader *br, FLAC__uint32 *val, FLAC__byte *raw, uint32_t *rawlen) -{ - FLAC__uint32 v = 0; - FLAC__uint32 x; - uint32_t i; - - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80)) { /* 0xxxxxxx */ - v = x; - i = 0; - } - else if((x & 0xE0) == 0xC0) { /* 110xxxxx */ - v = x & 0x1F; - i = 1; - } - else if((x & 0xF0) == 0xE0) { /* 1110xxxx */ - v = x & 0x0F; - i = 2; - } - else if((x & 0xF8) == 0xF0) { /* 11110xxx */ - v = x & 0x07; - i = 3; - } - else if((x & 0xFC) == 0xF8) { /* 111110xx */ - v = x & 0x03; - i = 4; - } - else if((x & 0xFE) == 0xFC) { /* 1111110x */ - v = x & 0x01; - i = 5; - } - else { - *val = 0xffffffff; - return true; - } - for( ; i; i--) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ - *val = 0xffffffff; - return true; - } - v <<= 6; - v |= (x & 0x3F); - } - *val = v; - return true; -} - -/* on return, if *val == 0xffffffffffffffff then the utf-8 sequence was invalid, but the return value will be true */ -FLAC__bool FLAC__bitreader_read_utf8_uint64(FLAC__BitReader *br, FLAC__uint64 *val, FLAC__byte *raw, uint32_t *rawlen) -{ - FLAC__uint64 v = 0; - FLAC__uint32 x; - uint32_t i; - - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80)) { /* 0xxxxxxx */ - v = x; - i = 0; - } - else if((x & 0xE0) == 0xC0) { /* 110xxxxx */ - v = x & 0x1F; - i = 1; - } - else if((x & 0xF0) == 0xE0) { /* 1110xxxx */ - v = x & 0x0F; - i = 2; - } - else if((x & 0xF8) == 0xF0) { /* 11110xxx */ - v = x & 0x07; - i = 3; - } - else if((x & 0xFC) == 0xF8) { /* 111110xx */ - v = x & 0x03; - i = 4; - } - else if((x & 0xFE) == 0xFC) { /* 1111110x */ - v = x & 0x01; - i = 5; - } - else if(x == 0xFE) { /* 11111110 */ - v = 0; - i = 6; - } - else { - *val = FLAC__U64L(0xffffffffffffffff); - return true; - } - for( ; i; i--) { - if(!FLAC__bitreader_read_raw_uint32(br, &x, 8)) - return false; - if(raw) - raw[(*rawlen)++] = (FLAC__byte)x; - if(!(x & 0x80) || (x & 0x40)) { /* 10xxxxxx */ - *val = FLAC__U64L(0xffffffffffffffff); - return true; - } - v <<= 6; - v |= (x & 0x3F); - } - *val = v; - return true; -} - -/* These functions are declared inline in this file but are also callable as - * externs from elsewhere. - * According to the C99 spec, section 6.7.4, simply providing a function - * prototype in a header file without 'inline' and making the function inline - * in this file should be sufficient. - * Unfortunately, the Microsoft VS compiler doesn't pick them up externally. To - * fix that we add extern declarations here. - */ -extern FLAC__bool FLAC__bitreader_is_consumed_byte_aligned(const FLAC__BitReader *br); -extern uint32_t FLAC__bitreader_bits_left_for_byte_alignment(const FLAC__BitReader *br); -extern uint32_t FLAC__bitreader_get_input_bits_unconsumed(const FLAC__BitReader *br); -extern FLAC__bool FLAC__bitreader_read_uint32_little_endian(FLAC__BitReader *br, FLAC__uint32 *val); diff --git a/src/lib/flac/src/libFLAC/src/cpu.c b/src/lib/flac/src/libFLAC/src/cpu.c deleted file mode 100644 index 4c6aaaa6..00000000 --- a/src/lib/flac/src/libFLAC/src/cpu.c +++ /dev/null @@ -1,234 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#if 0 /* bstone */ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "private/cpu.h" -#include "share/compat.h" -#include -#include - -#if defined _MSC_VER -#include /* for __cpuid() and _xgetbv() */ -#elif defined __GNUC__ && defined HAVE_CPUID_H -#include /* for __get_cpuid() and __get_cpuid_max() */ -#endif - -#if defined(HAVE_SYS_AUXV_H) -#include -#endif - -#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM - -/* these are flags in EDX of CPUID AX=00000001 */ -static const uint32_t FLAC__CPUINFO_X86_CPUID_CMOV = 0x00008000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_MMX = 0x00800000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE = 0x02000000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE2 = 0x04000000; - -/* these are flags in ECX of CPUID AX=00000001 */ -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE3 = 0x00000001; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSSE3 = 0x00000200; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE41 = 0x00080000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_SSE42 = 0x00100000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_OSXSAVE = 0x08000000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX = 0x10000000; -static const uint32_t FLAC__CPUINFO_X86_CPUID_FMA = 0x00001000; - -/* these are flags in EBX of CPUID AX=00000007 */ -static const uint32_t FLAC__CPUINFO_X86_CPUID_AVX2 = 0x00000020; -static const uint32_t FLAC__CPUINFO_X86_CPUID_BMI2 = 0x00000100; - -static uint32_t -cpu_xgetbv_x86(void) -{ -#if (defined _MSC_VER || defined __INTEL_COMPILER) && FLAC__AVX_SUPPORTED - return (uint32_t)_xgetbv(0); -#elif defined __GNUC__ - uint32_t lo, hi; - __asm__ volatile (".byte 0x0f, 0x01, 0xd0" : "=a"(lo), "=d"(hi) : "c" (0)); - return lo; -#else - return 0; -#endif -} - -static uint32_t -cpu_have_cpuid(void) -{ -#if defined FLAC__CPU_X86_64 || defined __i686__ || defined __SSE__ || (defined _M_IX86_FP && _M_IX86_FP > 0) - /* target CPU does have CPUID instruction */ - return 1; -#elif defined __GNUC__ && defined HAVE_CPUID_H - if (__get_cpuid_max(0, 0) != 0) - return 1; - else - return 0; -#elif defined _MSC_VER - FLAC__uint32 flags1, flags2; - __asm { - pushfd - pushfd - pop eax - mov flags1, eax - xor eax, 0x200000 - push eax - popfd - pushfd - pop eax - mov flags2, eax - popfd - } - if (((flags1^flags2) & 0x200000) != 0) - return 1; - else - return 0; -#else - return 0; -#endif -} - -static void -cpuinfo_x86(FLAC__uint32 level, FLAC__uint32 *eax, FLAC__uint32 *ebx, FLAC__uint32 *ecx, FLAC__uint32 *edx) -{ -#if defined _MSC_VER - int cpuinfo[4]; - int ext = level & 0x80000000; - __cpuid(cpuinfo, ext); - if ((uint32_t)cpuinfo[0] >= level) { -#if FLAC__AVX_SUPPORTED - __cpuidex(cpuinfo, level, 0); /* for AVX2 detection */ -#else - __cpuid(cpuinfo, level); /* some old compilers don't support __cpuidex */ -#endif - *eax = cpuinfo[0]; *ebx = cpuinfo[1]; *ecx = cpuinfo[2]; *edx = cpuinfo[3]; - return; - } -#elif defined __GNUC__ && defined HAVE_CPUID_H - FLAC__uint32 ext = level & 0x80000000; - __cpuid(ext, *eax, *ebx, *ecx, *edx); - if (*eax >= level) { - __cpuid_count(level, 0, *eax, *ebx, *ecx, *edx); - return; - } -#endif - *eax = *ebx = *ecx = *edx = 0; -} - -#endif - -static void -x86_cpu_info (FLAC__CPUInfo *info) -{ -#if (defined FLAC__CPU_IA32 || defined FLAC__CPU_X86_64) && FLAC__HAS_X86INTRIN && !defined FLAC__NO_ASM - FLAC__bool x86_osxsave = false; - FLAC__bool os_avx = false; - FLAC__uint32 flags_eax, flags_ebx, flags_ecx, flags_edx; - - info->use_asm = true; /* we assume a minimum of 80386 */ - if (!cpu_have_cpuid()) - return; - - cpuinfo_x86(0, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); - info->x86.intel = (flags_ebx == 0x756E6547 && flags_edx == 0x49656E69 && flags_ecx == 0x6C65746E) ? true : false; /* GenuineIntel */ - cpuinfo_x86(1, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); - - info->x86.cmov = (flags_edx & FLAC__CPUINFO_X86_CPUID_CMOV ) ? true : false; - info->x86.mmx = (flags_edx & FLAC__CPUINFO_X86_CPUID_MMX ) ? true : false; - info->x86.sse = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE ) ? true : false; - info->x86.sse2 = (flags_edx & FLAC__CPUINFO_X86_CPUID_SSE2 ) ? true : false; - info->x86.sse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE3 ) ? true : false; - info->x86.ssse3 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSSE3) ? true : false; - info->x86.sse41 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE41) ? true : false; - info->x86.sse42 = (flags_ecx & FLAC__CPUINFO_X86_CPUID_SSE42) ? true : false; - - if (FLAC__AVX_SUPPORTED) { - x86_osxsave = (flags_ecx & FLAC__CPUINFO_X86_CPUID_OSXSAVE) ? true : false; - info->x86.avx = (flags_ecx & FLAC__CPUINFO_X86_CPUID_AVX ) ? true : false; - info->x86.fma = (flags_ecx & FLAC__CPUINFO_X86_CPUID_FMA ) ? true : false; - cpuinfo_x86(7, &flags_eax, &flags_ebx, &flags_ecx, &flags_edx); - info->x86.avx2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_AVX2 ) ? true : false; - info->x86.bmi2 = (flags_ebx & FLAC__CPUINFO_X86_CPUID_BMI2 ) ? true : false; - } - - /* - * now have to check for OS support of AVX instructions - */ - if (FLAC__AVX_SUPPORTED && info->x86.avx && x86_osxsave && (cpu_xgetbv_x86() & 0x6) == 0x6) { - os_avx = true; - } - if (!os_avx) { - /* no OS AVX support */ - info->x86.avx = false; - info->x86.avx2 = false; - info->x86.fma = false; - } -#else - info->use_asm = false; -#endif -} - -void FLAC__cpu_info (FLAC__CPUInfo *info) -{ - memset(info, 0, sizeof(*info)); - -#ifdef FLAC__CPU_IA32 - info->type = FLAC__CPUINFO_TYPE_IA32; -#elif defined FLAC__CPU_X86_64 - info->type = FLAC__CPUINFO_TYPE_X86_64; -#else - info->type = FLAC__CPUINFO_TYPE_UNKNOWN; -#endif - - switch (info->type) { - case FLAC__CPUINFO_TYPE_IA32: /* fallthrough */ - case FLAC__CPUINFO_TYPE_X86_64: - x86_cpu_info (info); - break; - default: - info->use_asm = false; - break; - } -} -#else /* bstone */ -#include "private/cpu.h" -#include - -void FLAC__cpu_info (FLAC__CPUInfo *info) -{ - memset(info, 0, sizeof(*info)); - info->type = FLAC__CPUINFO_TYPE_UNKNOWN; -} -#endif /* bstone */ diff --git a/src/lib/flac/src/libFLAC/src/crc.c b/src/lib/flac/src/libFLAC/src/crc.c deleted file mode 100644 index b245109b..00000000 --- a/src/lib/flac/src/libFLAC/src/crc.c +++ /dev/null @@ -1,436 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "private/crc.h" - -/* CRC-8, poly = x^8 + x^2 + x^1 + x^0, init = 0 */ - -FLAC__uint8 const FLAC__crc8_table[256] = { - 0x00, 0x07, 0x0E, 0x09, 0x1C, 0x1B, 0x12, 0x15, - 0x38, 0x3F, 0x36, 0x31, 0x24, 0x23, 0x2A, 0x2D, - 0x70, 0x77, 0x7E, 0x79, 0x6C, 0x6B, 0x62, 0x65, - 0x48, 0x4F, 0x46, 0x41, 0x54, 0x53, 0x5A, 0x5D, - 0xE0, 0xE7, 0xEE, 0xE9, 0xFC, 0xFB, 0xF2, 0xF5, - 0xD8, 0xDF, 0xD6, 0xD1, 0xC4, 0xC3, 0xCA, 0xCD, - 0x90, 0x97, 0x9E, 0x99, 0x8C, 0x8B, 0x82, 0x85, - 0xA8, 0xAF, 0xA6, 0xA1, 0xB4, 0xB3, 0xBA, 0xBD, - 0xC7, 0xC0, 0xC9, 0xCE, 0xDB, 0xDC, 0xD5, 0xD2, - 0xFF, 0xF8, 0xF1, 0xF6, 0xE3, 0xE4, 0xED, 0xEA, - 0xB7, 0xB0, 0xB9, 0xBE, 0xAB, 0xAC, 0xA5, 0xA2, - 0x8F, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9D, 0x9A, - 0x27, 0x20, 0x29, 0x2E, 0x3B, 0x3C, 0x35, 0x32, - 0x1F, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0D, 0x0A, - 0x57, 0x50, 0x59, 0x5E, 0x4B, 0x4C, 0x45, 0x42, - 0x6F, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7D, 0x7A, - 0x89, 0x8E, 0x87, 0x80, 0x95, 0x92, 0x9B, 0x9C, - 0xB1, 0xB6, 0xBF, 0xB8, 0xAD, 0xAA, 0xA3, 0xA4, - 0xF9, 0xFE, 0xF7, 0xF0, 0xE5, 0xE2, 0xEB, 0xEC, - 0xC1, 0xC6, 0xCF, 0xC8, 0xDD, 0xDA, 0xD3, 0xD4, - 0x69, 0x6E, 0x67, 0x60, 0x75, 0x72, 0x7B, 0x7C, - 0x51, 0x56, 0x5F, 0x58, 0x4D, 0x4A, 0x43, 0x44, - 0x19, 0x1E, 0x17, 0x10, 0x05, 0x02, 0x0B, 0x0C, - 0x21, 0x26, 0x2F, 0x28, 0x3D, 0x3A, 0x33, 0x34, - 0x4E, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5C, 0x5B, - 0x76, 0x71, 0x78, 0x7F, 0x6A, 0x6D, 0x64, 0x63, - 0x3E, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2C, 0x2B, - 0x06, 0x01, 0x08, 0x0F, 0x1A, 0x1D, 0x14, 0x13, - 0xAE, 0xA9, 0xA0, 0xA7, 0xB2, 0xB5, 0xBC, 0xBB, - 0x96, 0x91, 0x98, 0x9F, 0x8A, 0x8D, 0x84, 0x83, - 0xDE, 0xD9, 0xD0, 0xD7, 0xC2, 0xC5, 0xCC, 0xCB, - 0xE6, 0xE1, 0xE8, 0xEF, 0xFA, 0xFD, 0xF4, 0xF3 -}; - -/* CRC-16, poly = x^16 + x^15 + x^2 + x^0, init = 0 */ - -FLAC__uint16 const FLAC__crc16_table[8][256] = { - { 0x0000, 0x8005, 0x800f, 0x000a, 0x801b, 0x001e, 0x0014, 0x8011, - 0x8033, 0x0036, 0x003c, 0x8039, 0x0028, 0x802d, 0x8027, 0x0022, - 0x8063, 0x0066, 0x006c, 0x8069, 0x0078, 0x807d, 0x8077, 0x0072, - 0x0050, 0x8055, 0x805f, 0x005a, 0x804b, 0x004e, 0x0044, 0x8041, - 0x80c3, 0x00c6, 0x00cc, 0x80c9, 0x00d8, 0x80dd, 0x80d7, 0x00d2, - 0x00f0, 0x80f5, 0x80ff, 0x00fa, 0x80eb, 0x00ee, 0x00e4, 0x80e1, - 0x00a0, 0x80a5, 0x80af, 0x00aa, 0x80bb, 0x00be, 0x00b4, 0x80b1, - 0x8093, 0x0096, 0x009c, 0x8099, 0x0088, 0x808d, 0x8087, 0x0082, - 0x8183, 0x0186, 0x018c, 0x8189, 0x0198, 0x819d, 0x8197, 0x0192, - 0x01b0, 0x81b5, 0x81bf, 0x01ba, 0x81ab, 0x01ae, 0x01a4, 0x81a1, - 0x01e0, 0x81e5, 0x81ef, 0x01ea, 0x81fb, 0x01fe, 0x01f4, 0x81f1, - 0x81d3, 0x01d6, 0x01dc, 0x81d9, 0x01c8, 0x81cd, 0x81c7, 0x01c2, - 0x0140, 0x8145, 0x814f, 0x014a, 0x815b, 0x015e, 0x0154, 0x8151, - 0x8173, 0x0176, 0x017c, 0x8179, 0x0168, 0x816d, 0x8167, 0x0162, - 0x8123, 0x0126, 0x012c, 0x8129, 0x0138, 0x813d, 0x8137, 0x0132, - 0x0110, 0x8115, 0x811f, 0x011a, 0x810b, 0x010e, 0x0104, 0x8101, - 0x8303, 0x0306, 0x030c, 0x8309, 0x0318, 0x831d, 0x8317, 0x0312, - 0x0330, 0x8335, 0x833f, 0x033a, 0x832b, 0x032e, 0x0324, 0x8321, - 0x0360, 0x8365, 0x836f, 0x036a, 0x837b, 0x037e, 0x0374, 0x8371, - 0x8353, 0x0356, 0x035c, 0x8359, 0x0348, 0x834d, 0x8347, 0x0342, - 0x03c0, 0x83c5, 0x83cf, 0x03ca, 0x83db, 0x03de, 0x03d4, 0x83d1, - 0x83f3, 0x03f6, 0x03fc, 0x83f9, 0x03e8, 0x83ed, 0x83e7, 0x03e2, - 0x83a3, 0x03a6, 0x03ac, 0x83a9, 0x03b8, 0x83bd, 0x83b7, 0x03b2, - 0x0390, 0x8395, 0x839f, 0x039a, 0x838b, 0x038e, 0x0384, 0x8381, - 0x0280, 0x8285, 0x828f, 0x028a, 0x829b, 0x029e, 0x0294, 0x8291, - 0x82b3, 0x02b6, 0x02bc, 0x82b9, 0x02a8, 0x82ad, 0x82a7, 0x02a2, - 0x82e3, 0x02e6, 0x02ec, 0x82e9, 0x02f8, 0x82fd, 0x82f7, 0x02f2, - 0x02d0, 0x82d5, 0x82df, 0x02da, 0x82cb, 0x02ce, 0x02c4, 0x82c1, - 0x8243, 0x0246, 0x024c, 0x8249, 0x0258, 0x825d, 0x8257, 0x0252, - 0x0270, 0x8275, 0x827f, 0x027a, 0x826b, 0x026e, 0x0264, 0x8261, - 0x0220, 0x8225, 0x822f, 0x022a, 0x823b, 0x023e, 0x0234, 0x8231, - 0x8213, 0x0216, 0x021c, 0x8219, 0x0208, 0x820d, 0x8207, 0x0202 }, - - { 0x0000, 0x8603, 0x8c03, 0x0a00, 0x9803, 0x1e00, 0x1400, 0x9203, - 0xb003, 0x3600, 0x3c00, 0xba03, 0x2800, 0xae03, 0xa403, 0x2200, - 0xe003, 0x6600, 0x6c00, 0xea03, 0x7800, 0xfe03, 0xf403, 0x7200, - 0x5000, 0xd603, 0xdc03, 0x5a00, 0xc803, 0x4e00, 0x4400, 0xc203, - 0x4003, 0xc600, 0xcc00, 0x4a03, 0xd800, 0x5e03, 0x5403, 0xd200, - 0xf000, 0x7603, 0x7c03, 0xfa00, 0x6803, 0xee00, 0xe400, 0x6203, - 0xa000, 0x2603, 0x2c03, 0xaa00, 0x3803, 0xbe00, 0xb400, 0x3203, - 0x1003, 0x9600, 0x9c00, 0x1a03, 0x8800, 0x0e03, 0x0403, 0x8200, - 0x8006, 0x0605, 0x0c05, 0x8a06, 0x1805, 0x9e06, 0x9406, 0x1205, - 0x3005, 0xb606, 0xbc06, 0x3a05, 0xa806, 0x2e05, 0x2405, 0xa206, - 0x6005, 0xe606, 0xec06, 0x6a05, 0xf806, 0x7e05, 0x7405, 0xf206, - 0xd006, 0x5605, 0x5c05, 0xda06, 0x4805, 0xce06, 0xc406, 0x4205, - 0xc005, 0x4606, 0x4c06, 0xca05, 0x5806, 0xde05, 0xd405, 0x5206, - 0x7006, 0xf605, 0xfc05, 0x7a06, 0xe805, 0x6e06, 0x6406, 0xe205, - 0x2006, 0xa605, 0xac05, 0x2a06, 0xb805, 0x3e06, 0x3406, 0xb205, - 0x9005, 0x1606, 0x1c06, 0x9a05, 0x0806, 0x8e05, 0x8405, 0x0206, - 0x8009, 0x060a, 0x0c0a, 0x8a09, 0x180a, 0x9e09, 0x9409, 0x120a, - 0x300a, 0xb609, 0xbc09, 0x3a0a, 0xa809, 0x2e0a, 0x240a, 0xa209, - 0x600a, 0xe609, 0xec09, 0x6a0a, 0xf809, 0x7e0a, 0x740a, 0xf209, - 0xd009, 0x560a, 0x5c0a, 0xda09, 0x480a, 0xce09, 0xc409, 0x420a, - 0xc00a, 0x4609, 0x4c09, 0xca0a, 0x5809, 0xde0a, 0xd40a, 0x5209, - 0x7009, 0xf60a, 0xfc0a, 0x7a09, 0xe80a, 0x6e09, 0x6409, 0xe20a, - 0x2009, 0xa60a, 0xac0a, 0x2a09, 0xb80a, 0x3e09, 0x3409, 0xb20a, - 0x900a, 0x1609, 0x1c09, 0x9a0a, 0x0809, 0x8e0a, 0x840a, 0x0209, - 0x000f, 0x860c, 0x8c0c, 0x0a0f, 0x980c, 0x1e0f, 0x140f, 0x920c, - 0xb00c, 0x360f, 0x3c0f, 0xba0c, 0x280f, 0xae0c, 0xa40c, 0x220f, - 0xe00c, 0x660f, 0x6c0f, 0xea0c, 0x780f, 0xfe0c, 0xf40c, 0x720f, - 0x500f, 0xd60c, 0xdc0c, 0x5a0f, 0xc80c, 0x4e0f, 0x440f, 0xc20c, - 0x400c, 0xc60f, 0xcc0f, 0x4a0c, 0xd80f, 0x5e0c, 0x540c, 0xd20f, - 0xf00f, 0x760c, 0x7c0c, 0xfa0f, 0x680c, 0xee0f, 0xe40f, 0x620c, - 0xa00f, 0x260c, 0x2c0c, 0xaa0f, 0x380c, 0xbe0f, 0xb40f, 0x320c, - 0x100c, 0x960f, 0x9c0f, 0x1a0c, 0x880f, 0x0e0c, 0x040c, 0x820f }, - - { 0x0000, 0x8017, 0x802b, 0x003c, 0x8053, 0x0044, 0x0078, 0x806f, - 0x80a3, 0x00b4, 0x0088, 0x809f, 0x00f0, 0x80e7, 0x80db, 0x00cc, - 0x8143, 0x0154, 0x0168, 0x817f, 0x0110, 0x8107, 0x813b, 0x012c, - 0x01e0, 0x81f7, 0x81cb, 0x01dc, 0x81b3, 0x01a4, 0x0198, 0x818f, - 0x8283, 0x0294, 0x02a8, 0x82bf, 0x02d0, 0x82c7, 0x82fb, 0x02ec, - 0x0220, 0x8237, 0x820b, 0x021c, 0x8273, 0x0264, 0x0258, 0x824f, - 0x03c0, 0x83d7, 0x83eb, 0x03fc, 0x8393, 0x0384, 0x03b8, 0x83af, - 0x8363, 0x0374, 0x0348, 0x835f, 0x0330, 0x8327, 0x831b, 0x030c, - 0x8503, 0x0514, 0x0528, 0x853f, 0x0550, 0x8547, 0x857b, 0x056c, - 0x05a0, 0x85b7, 0x858b, 0x059c, 0x85f3, 0x05e4, 0x05d8, 0x85cf, - 0x0440, 0x8457, 0x846b, 0x047c, 0x8413, 0x0404, 0x0438, 0x842f, - 0x84e3, 0x04f4, 0x04c8, 0x84df, 0x04b0, 0x84a7, 0x849b, 0x048c, - 0x0780, 0x8797, 0x87ab, 0x07bc, 0x87d3, 0x07c4, 0x07f8, 0x87ef, - 0x8723, 0x0734, 0x0708, 0x871f, 0x0770, 0x8767, 0x875b, 0x074c, - 0x86c3, 0x06d4, 0x06e8, 0x86ff, 0x0690, 0x8687, 0x86bb, 0x06ac, - 0x0660, 0x8677, 0x864b, 0x065c, 0x8633, 0x0624, 0x0618, 0x860f, - 0x8a03, 0x0a14, 0x0a28, 0x8a3f, 0x0a50, 0x8a47, 0x8a7b, 0x0a6c, - 0x0aa0, 0x8ab7, 0x8a8b, 0x0a9c, 0x8af3, 0x0ae4, 0x0ad8, 0x8acf, - 0x0b40, 0x8b57, 0x8b6b, 0x0b7c, 0x8b13, 0x0b04, 0x0b38, 0x8b2f, - 0x8be3, 0x0bf4, 0x0bc8, 0x8bdf, 0x0bb0, 0x8ba7, 0x8b9b, 0x0b8c, - 0x0880, 0x8897, 0x88ab, 0x08bc, 0x88d3, 0x08c4, 0x08f8, 0x88ef, - 0x8823, 0x0834, 0x0808, 0x881f, 0x0870, 0x8867, 0x885b, 0x084c, - 0x89c3, 0x09d4, 0x09e8, 0x89ff, 0x0990, 0x8987, 0x89bb, 0x09ac, - 0x0960, 0x8977, 0x894b, 0x095c, 0x8933, 0x0924, 0x0918, 0x890f, - 0x0f00, 0x8f17, 0x8f2b, 0x0f3c, 0x8f53, 0x0f44, 0x0f78, 0x8f6f, - 0x8fa3, 0x0fb4, 0x0f88, 0x8f9f, 0x0ff0, 0x8fe7, 0x8fdb, 0x0fcc, - 0x8e43, 0x0e54, 0x0e68, 0x8e7f, 0x0e10, 0x8e07, 0x8e3b, 0x0e2c, - 0x0ee0, 0x8ef7, 0x8ecb, 0x0edc, 0x8eb3, 0x0ea4, 0x0e98, 0x8e8f, - 0x8d83, 0x0d94, 0x0da8, 0x8dbf, 0x0dd0, 0x8dc7, 0x8dfb, 0x0dec, - 0x0d20, 0x8d37, 0x8d0b, 0x0d1c, 0x8d73, 0x0d64, 0x0d58, 0x8d4f, - 0x0cc0, 0x8cd7, 0x8ceb, 0x0cfc, 0x8c93, 0x0c84, 0x0cb8, 0x8caf, - 0x8c63, 0x0c74, 0x0c48, 0x8c5f, 0x0c30, 0x8c27, 0x8c1b, 0x0c0c }, - - { 0x0000, 0x9403, 0xa803, 0x3c00, 0xd003, 0x4400, 0x7800, 0xec03, - 0x2003, 0xb400, 0x8800, 0x1c03, 0xf000, 0x6403, 0x5803, 0xcc00, - 0x4006, 0xd405, 0xe805, 0x7c06, 0x9005, 0x0406, 0x3806, 0xac05, - 0x6005, 0xf406, 0xc806, 0x5c05, 0xb006, 0x2405, 0x1805, 0x8c06, - 0x800c, 0x140f, 0x280f, 0xbc0c, 0x500f, 0xc40c, 0xf80c, 0x6c0f, - 0xa00f, 0x340c, 0x080c, 0x9c0f, 0x700c, 0xe40f, 0xd80f, 0x4c0c, - 0xc00a, 0x5409, 0x6809, 0xfc0a, 0x1009, 0x840a, 0xb80a, 0x2c09, - 0xe009, 0x740a, 0x480a, 0xdc09, 0x300a, 0xa409, 0x9809, 0x0c0a, - 0x801d, 0x141e, 0x281e, 0xbc1d, 0x501e, 0xc41d, 0xf81d, 0x6c1e, - 0xa01e, 0x341d, 0x081d, 0x9c1e, 0x701d, 0xe41e, 0xd81e, 0x4c1d, - 0xc01b, 0x5418, 0x6818, 0xfc1b, 0x1018, 0x841b, 0xb81b, 0x2c18, - 0xe018, 0x741b, 0x481b, 0xdc18, 0x301b, 0xa418, 0x9818, 0x0c1b, - 0x0011, 0x9412, 0xa812, 0x3c11, 0xd012, 0x4411, 0x7811, 0xec12, - 0x2012, 0xb411, 0x8811, 0x1c12, 0xf011, 0x6412, 0x5812, 0xcc11, - 0x4017, 0xd414, 0xe814, 0x7c17, 0x9014, 0x0417, 0x3817, 0xac14, - 0x6014, 0xf417, 0xc817, 0x5c14, 0xb017, 0x2414, 0x1814, 0x8c17, - 0x803f, 0x143c, 0x283c, 0xbc3f, 0x503c, 0xc43f, 0xf83f, 0x6c3c, - 0xa03c, 0x343f, 0x083f, 0x9c3c, 0x703f, 0xe43c, 0xd83c, 0x4c3f, - 0xc039, 0x543a, 0x683a, 0xfc39, 0x103a, 0x8439, 0xb839, 0x2c3a, - 0xe03a, 0x7439, 0x4839, 0xdc3a, 0x3039, 0xa43a, 0x983a, 0x0c39, - 0x0033, 0x9430, 0xa830, 0x3c33, 0xd030, 0x4433, 0x7833, 0xec30, - 0x2030, 0xb433, 0x8833, 0x1c30, 0xf033, 0x6430, 0x5830, 0xcc33, - 0x4035, 0xd436, 0xe836, 0x7c35, 0x9036, 0x0435, 0x3835, 0xac36, - 0x6036, 0xf435, 0xc835, 0x5c36, 0xb035, 0x2436, 0x1836, 0x8c35, - 0x0022, 0x9421, 0xa821, 0x3c22, 0xd021, 0x4422, 0x7822, 0xec21, - 0x2021, 0xb422, 0x8822, 0x1c21, 0xf022, 0x6421, 0x5821, 0xcc22, - 0x4024, 0xd427, 0xe827, 0x7c24, 0x9027, 0x0424, 0x3824, 0xac27, - 0x6027, 0xf424, 0xc824, 0x5c27, 0xb024, 0x2427, 0x1827, 0x8c24, - 0x802e, 0x142d, 0x282d, 0xbc2e, 0x502d, 0xc42e, 0xf82e, 0x6c2d, - 0xa02d, 0x342e, 0x082e, 0x9c2d, 0x702e, 0xe42d, 0xd82d, 0x4c2e, - 0xc028, 0x542b, 0x682b, 0xfc28, 0x102b, 0x8428, 0xb828, 0x2c2b, - 0xe02b, 0x7428, 0x4828, 0xdc2b, 0x3028, 0xa42b, 0x982b, 0x0c28 }, - - { 0x0000, 0x807b, 0x80f3, 0x0088, 0x81e3, 0x0198, 0x0110, 0x816b, - 0x83c3, 0x03b8, 0x0330, 0x834b, 0x0220, 0x825b, 0x82d3, 0x02a8, - 0x8783, 0x07f8, 0x0770, 0x870b, 0x0660, 0x861b, 0x8693, 0x06e8, - 0x0440, 0x843b, 0x84b3, 0x04c8, 0x85a3, 0x05d8, 0x0550, 0x852b, - 0x8f03, 0x0f78, 0x0ff0, 0x8f8b, 0x0ee0, 0x8e9b, 0x8e13, 0x0e68, - 0x0cc0, 0x8cbb, 0x8c33, 0x0c48, 0x8d23, 0x0d58, 0x0dd0, 0x8dab, - 0x0880, 0x88fb, 0x8873, 0x0808, 0x8963, 0x0918, 0x0990, 0x89eb, - 0x8b43, 0x0b38, 0x0bb0, 0x8bcb, 0x0aa0, 0x8adb, 0x8a53, 0x0a28, - 0x9e03, 0x1e78, 0x1ef0, 0x9e8b, 0x1fe0, 0x9f9b, 0x9f13, 0x1f68, - 0x1dc0, 0x9dbb, 0x9d33, 0x1d48, 0x9c23, 0x1c58, 0x1cd0, 0x9cab, - 0x1980, 0x99fb, 0x9973, 0x1908, 0x9863, 0x1818, 0x1890, 0x98eb, - 0x9a43, 0x1a38, 0x1ab0, 0x9acb, 0x1ba0, 0x9bdb, 0x9b53, 0x1b28, - 0x1100, 0x917b, 0x91f3, 0x1188, 0x90e3, 0x1098, 0x1010, 0x906b, - 0x92c3, 0x12b8, 0x1230, 0x924b, 0x1320, 0x935b, 0x93d3, 0x13a8, - 0x9683, 0x16f8, 0x1670, 0x960b, 0x1760, 0x971b, 0x9793, 0x17e8, - 0x1540, 0x953b, 0x95b3, 0x15c8, 0x94a3, 0x14d8, 0x1450, 0x942b, - 0xbc03, 0x3c78, 0x3cf0, 0xbc8b, 0x3de0, 0xbd9b, 0xbd13, 0x3d68, - 0x3fc0, 0xbfbb, 0xbf33, 0x3f48, 0xbe23, 0x3e58, 0x3ed0, 0xbeab, - 0x3b80, 0xbbfb, 0xbb73, 0x3b08, 0xba63, 0x3a18, 0x3a90, 0xbaeb, - 0xb843, 0x3838, 0x38b0, 0xb8cb, 0x39a0, 0xb9db, 0xb953, 0x3928, - 0x3300, 0xb37b, 0xb3f3, 0x3388, 0xb2e3, 0x3298, 0x3210, 0xb26b, - 0xb0c3, 0x30b8, 0x3030, 0xb04b, 0x3120, 0xb15b, 0xb1d3, 0x31a8, - 0xb483, 0x34f8, 0x3470, 0xb40b, 0x3560, 0xb51b, 0xb593, 0x35e8, - 0x3740, 0xb73b, 0xb7b3, 0x37c8, 0xb6a3, 0x36d8, 0x3650, 0xb62b, - 0x2200, 0xa27b, 0xa2f3, 0x2288, 0xa3e3, 0x2398, 0x2310, 0xa36b, - 0xa1c3, 0x21b8, 0x2130, 0xa14b, 0x2020, 0xa05b, 0xa0d3, 0x20a8, - 0xa583, 0x25f8, 0x2570, 0xa50b, 0x2460, 0xa41b, 0xa493, 0x24e8, - 0x2640, 0xa63b, 0xa6b3, 0x26c8, 0xa7a3, 0x27d8, 0x2750, 0xa72b, - 0xad03, 0x2d78, 0x2df0, 0xad8b, 0x2ce0, 0xac9b, 0xac13, 0x2c68, - 0x2ec0, 0xaebb, 0xae33, 0x2e48, 0xaf23, 0x2f58, 0x2fd0, 0xafab, - 0x2a80, 0xaafb, 0xaa73, 0x2a08, 0xab63, 0x2b18, 0x2b90, 0xabeb, - 0xa943, 0x2938, 0x29b0, 0xa9cb, 0x28a0, 0xa8db, 0xa853, 0x2828 }, - - { 0x0000, 0xf803, 0x7003, 0x8800, 0xe006, 0x1805, 0x9005, 0x6806, - 0x4009, 0xb80a, 0x300a, 0xc809, 0xa00f, 0x580c, 0xd00c, 0x280f, - 0x8012, 0x7811, 0xf011, 0x0812, 0x6014, 0x9817, 0x1017, 0xe814, - 0xc01b, 0x3818, 0xb018, 0x481b, 0x201d, 0xd81e, 0x501e, 0xa81d, - 0x8021, 0x7822, 0xf022, 0x0821, 0x6027, 0x9824, 0x1024, 0xe827, - 0xc028, 0x382b, 0xb02b, 0x4828, 0x202e, 0xd82d, 0x502d, 0xa82e, - 0x0033, 0xf830, 0x7030, 0x8833, 0xe035, 0x1836, 0x9036, 0x6835, - 0x403a, 0xb839, 0x3039, 0xc83a, 0xa03c, 0x583f, 0xd03f, 0x283c, - 0x8047, 0x7844, 0xf044, 0x0847, 0x6041, 0x9842, 0x1042, 0xe841, - 0xc04e, 0x384d, 0xb04d, 0x484e, 0x2048, 0xd84b, 0x504b, 0xa848, - 0x0055, 0xf856, 0x7056, 0x8855, 0xe053, 0x1850, 0x9050, 0x6853, - 0x405c, 0xb85f, 0x305f, 0xc85c, 0xa05a, 0x5859, 0xd059, 0x285a, - 0x0066, 0xf865, 0x7065, 0x8866, 0xe060, 0x1863, 0x9063, 0x6860, - 0x406f, 0xb86c, 0x306c, 0xc86f, 0xa069, 0x586a, 0xd06a, 0x2869, - 0x8074, 0x7877, 0xf077, 0x0874, 0x6072, 0x9871, 0x1071, 0xe872, - 0xc07d, 0x387e, 0xb07e, 0x487d, 0x207b, 0xd878, 0x5078, 0xa87b, - 0x808b, 0x7888, 0xf088, 0x088b, 0x608d, 0x988e, 0x108e, 0xe88d, - 0xc082, 0x3881, 0xb081, 0x4882, 0x2084, 0xd887, 0x5087, 0xa884, - 0x0099, 0xf89a, 0x709a, 0x8899, 0xe09f, 0x189c, 0x909c, 0x689f, - 0x4090, 0xb893, 0x3093, 0xc890, 0xa096, 0x5895, 0xd095, 0x2896, - 0x00aa, 0xf8a9, 0x70a9, 0x88aa, 0xe0ac, 0x18af, 0x90af, 0x68ac, - 0x40a3, 0xb8a0, 0x30a0, 0xc8a3, 0xa0a5, 0x58a6, 0xd0a6, 0x28a5, - 0x80b8, 0x78bb, 0xf0bb, 0x08b8, 0x60be, 0x98bd, 0x10bd, 0xe8be, - 0xc0b1, 0x38b2, 0xb0b2, 0x48b1, 0x20b7, 0xd8b4, 0x50b4, 0xa8b7, - 0x00cc, 0xf8cf, 0x70cf, 0x88cc, 0xe0ca, 0x18c9, 0x90c9, 0x68ca, - 0x40c5, 0xb8c6, 0x30c6, 0xc8c5, 0xa0c3, 0x58c0, 0xd0c0, 0x28c3, - 0x80de, 0x78dd, 0xf0dd, 0x08de, 0x60d8, 0x98db, 0x10db, 0xe8d8, - 0xc0d7, 0x38d4, 0xb0d4, 0x48d7, 0x20d1, 0xd8d2, 0x50d2, 0xa8d1, - 0x80ed, 0x78ee, 0xf0ee, 0x08ed, 0x60eb, 0x98e8, 0x10e8, 0xe8eb, - 0xc0e4, 0x38e7, 0xb0e7, 0x48e4, 0x20e2, 0xd8e1, 0x50e1, 0xa8e2, - 0x00ff, 0xf8fc, 0x70fc, 0x88ff, 0xe0f9, 0x18fa, 0x90fa, 0x68f9, - 0x40f6, 0xb8f5, 0x30f5, 0xc8f6, 0xa0f0, 0x58f3, 0xd0f3, 0x28f0 }, - - { 0x0000, 0x8113, 0x8223, 0x0330, 0x8443, 0x0550, 0x0660, 0x8773, - 0x8883, 0x0990, 0x0aa0, 0x8bb3, 0x0cc0, 0x8dd3, 0x8ee3, 0x0ff0, - 0x9103, 0x1010, 0x1320, 0x9233, 0x1540, 0x9453, 0x9763, 0x1670, - 0x1980, 0x9893, 0x9ba3, 0x1ab0, 0x9dc3, 0x1cd0, 0x1fe0, 0x9ef3, - 0xa203, 0x2310, 0x2020, 0xa133, 0x2640, 0xa753, 0xa463, 0x2570, - 0x2a80, 0xab93, 0xa8a3, 0x29b0, 0xaec3, 0x2fd0, 0x2ce0, 0xadf3, - 0x3300, 0xb213, 0xb123, 0x3030, 0xb743, 0x3650, 0x3560, 0xb473, - 0xbb83, 0x3a90, 0x39a0, 0xb8b3, 0x3fc0, 0xbed3, 0xbde3, 0x3cf0, - 0xc403, 0x4510, 0x4620, 0xc733, 0x4040, 0xc153, 0xc263, 0x4370, - 0x4c80, 0xcd93, 0xcea3, 0x4fb0, 0xc8c3, 0x49d0, 0x4ae0, 0xcbf3, - 0x5500, 0xd413, 0xd723, 0x5630, 0xd143, 0x5050, 0x5360, 0xd273, - 0xdd83, 0x5c90, 0x5fa0, 0xdeb3, 0x59c0, 0xd8d3, 0xdbe3, 0x5af0, - 0x6600, 0xe713, 0xe423, 0x6530, 0xe243, 0x6350, 0x6060, 0xe173, - 0xee83, 0x6f90, 0x6ca0, 0xedb3, 0x6ac0, 0xebd3, 0xe8e3, 0x69f0, - 0xf703, 0x7610, 0x7520, 0xf433, 0x7340, 0xf253, 0xf163, 0x7070, - 0x7f80, 0xfe93, 0xfda3, 0x7cb0, 0xfbc3, 0x7ad0, 0x79e0, 0xf8f3, - 0x0803, 0x8910, 0x8a20, 0x0b33, 0x8c40, 0x0d53, 0x0e63, 0x8f70, - 0x8080, 0x0193, 0x02a3, 0x83b0, 0x04c3, 0x85d0, 0x86e0, 0x07f3, - 0x9900, 0x1813, 0x1b23, 0x9a30, 0x1d43, 0x9c50, 0x9f60, 0x1e73, - 0x1183, 0x9090, 0x93a0, 0x12b3, 0x95c0, 0x14d3, 0x17e3, 0x96f0, - 0xaa00, 0x2b13, 0x2823, 0xa930, 0x2e43, 0xaf50, 0xac60, 0x2d73, - 0x2283, 0xa390, 0xa0a0, 0x21b3, 0xa6c0, 0x27d3, 0x24e3, 0xa5f0, - 0x3b03, 0xba10, 0xb920, 0x3833, 0xbf40, 0x3e53, 0x3d63, 0xbc70, - 0xb380, 0x3293, 0x31a3, 0xb0b0, 0x37c3, 0xb6d0, 0xb5e0, 0x34f3, - 0xcc00, 0x4d13, 0x4e23, 0xcf30, 0x4843, 0xc950, 0xca60, 0x4b73, - 0x4483, 0xc590, 0xc6a0, 0x47b3, 0xc0c0, 0x41d3, 0x42e3, 0xc3f0, - 0x5d03, 0xdc10, 0xdf20, 0x5e33, 0xd940, 0x5853, 0x5b63, 0xda70, - 0xd580, 0x5493, 0x57a3, 0xd6b0, 0x51c3, 0xd0d0, 0xd3e0, 0x52f3, - 0x6e03, 0xef10, 0xec20, 0x6d33, 0xea40, 0x6b53, 0x6863, 0xe970, - 0xe680, 0x6793, 0x64a3, 0xe5b0, 0x62c3, 0xe3d0, 0xe0e0, 0x61f3, - 0xff00, 0x7e13, 0x7d23, 0xfc30, 0x7b43, 0xfa50, 0xf960, 0x7873, - 0x7783, 0xf690, 0xf5a0, 0x74b3, 0xf3c0, 0x72d3, 0x71e3, 0xf0f0 }, - - { 0x0000, 0x1006, 0x200c, 0x300a, 0x4018, 0x501e, 0x6014, 0x7012, - 0x8030, 0x9036, 0xa03c, 0xb03a, 0xc028, 0xd02e, 0xe024, 0xf022, - 0x8065, 0x9063, 0xa069, 0xb06f, 0xc07d, 0xd07b, 0xe071, 0xf077, - 0x0055, 0x1053, 0x2059, 0x305f, 0x404d, 0x504b, 0x6041, 0x7047, - 0x80cf, 0x90c9, 0xa0c3, 0xb0c5, 0xc0d7, 0xd0d1, 0xe0db, 0xf0dd, - 0x00ff, 0x10f9, 0x20f3, 0x30f5, 0x40e7, 0x50e1, 0x60eb, 0x70ed, - 0x00aa, 0x10ac, 0x20a6, 0x30a0, 0x40b2, 0x50b4, 0x60be, 0x70b8, - 0x809a, 0x909c, 0xa096, 0xb090, 0xc082, 0xd084, 0xe08e, 0xf088, - 0x819b, 0x919d, 0xa197, 0xb191, 0xc183, 0xd185, 0xe18f, 0xf189, - 0x01ab, 0x11ad, 0x21a7, 0x31a1, 0x41b3, 0x51b5, 0x61bf, 0x71b9, - 0x01fe, 0x11f8, 0x21f2, 0x31f4, 0x41e6, 0x51e0, 0x61ea, 0x71ec, - 0x81ce, 0x91c8, 0xa1c2, 0xb1c4, 0xc1d6, 0xd1d0, 0xe1da, 0xf1dc, - 0x0154, 0x1152, 0x2158, 0x315e, 0x414c, 0x514a, 0x6140, 0x7146, - 0x8164, 0x9162, 0xa168, 0xb16e, 0xc17c, 0xd17a, 0xe170, 0xf176, - 0x8131, 0x9137, 0xa13d, 0xb13b, 0xc129, 0xd12f, 0xe125, 0xf123, - 0x0101, 0x1107, 0x210d, 0x310b, 0x4119, 0x511f, 0x6115, 0x7113, - 0x8333, 0x9335, 0xa33f, 0xb339, 0xc32b, 0xd32d, 0xe327, 0xf321, - 0x0303, 0x1305, 0x230f, 0x3309, 0x431b, 0x531d, 0x6317, 0x7311, - 0x0356, 0x1350, 0x235a, 0x335c, 0x434e, 0x5348, 0x6342, 0x7344, - 0x8366, 0x9360, 0xa36a, 0xb36c, 0xc37e, 0xd378, 0xe372, 0xf374, - 0x03fc, 0x13fa, 0x23f0, 0x33f6, 0x43e4, 0x53e2, 0x63e8, 0x73ee, - 0x83cc, 0x93ca, 0xa3c0, 0xb3c6, 0xc3d4, 0xd3d2, 0xe3d8, 0xf3de, - 0x8399, 0x939f, 0xa395, 0xb393, 0xc381, 0xd387, 0xe38d, 0xf38b, - 0x03a9, 0x13af, 0x23a5, 0x33a3, 0x43b1, 0x53b7, 0x63bd, 0x73bb, - 0x02a8, 0x12ae, 0x22a4, 0x32a2, 0x42b0, 0x52b6, 0x62bc, 0x72ba, - 0x8298, 0x929e, 0xa294, 0xb292, 0xc280, 0xd286, 0xe28c, 0xf28a, - 0x82cd, 0x92cb, 0xa2c1, 0xb2c7, 0xc2d5, 0xd2d3, 0xe2d9, 0xf2df, - 0x02fd, 0x12fb, 0x22f1, 0x32f7, 0x42e5, 0x52e3, 0x62e9, 0x72ef, - 0x8267, 0x9261, 0xa26b, 0xb26d, 0xc27f, 0xd279, 0xe273, 0xf275, - 0x0257, 0x1251, 0x225b, 0x325d, 0x424f, 0x5249, 0x6243, 0x7245, - 0x0202, 0x1204, 0x220e, 0x3208, 0x421a, 0x521c, 0x6216, 0x7210, - 0x8232, 0x9234, 0xa23e, 0xb238, 0xc22a, 0xd22c, 0xe226, 0xf220 } -}; - -#if 0 -void FLAC__crc16_init_table(void) -{ - int i, j; - FLAC__uint16 polynomial, crc; - polynomial = 0x8005; - - for(i = 0; i <= 0xFF; i++){ - crc = i << 8; - - for(j = 0; j < 8; j++) - crc = (crc << 1) ^ (crc & (1 << 15) ? polynomial : 0); - - FLAC__crc16_table[0][i] = crc; - } - - for(i = 0; i <= 0xFF; i++) - for(j = 1; j < 8; j++) - FLAC__crc16_table[j][i] = FLAC__crc16_table[0][FLAC__crc16_table[j - 1][i] >> 8] ^ (FLAC__crc16_table[j - 1][i] << 8); -} -#endif - -FLAC__uint8 FLAC__crc8(const FLAC__byte *data, uint32_t len) -{ - FLAC__uint8 crc = 0; - - while(len--) - crc = FLAC__crc8_table[crc ^ *data++]; - - return crc; -} - -FLAC__uint16 FLAC__crc16(const FLAC__byte *data, uint32_t len) -{ - FLAC__uint16 crc = 0; - - while(len >= 8){ - crc ^= data[0] << 8 | data[1]; - - crc = FLAC__crc16_table[7][crc >> 8] ^ FLAC__crc16_table[6][crc & 0xFF] ^ - FLAC__crc16_table[5][data[2] ] ^ FLAC__crc16_table[4][data[3] ] ^ - FLAC__crc16_table[3][data[4] ] ^ FLAC__crc16_table[2][data[5] ] ^ - FLAC__crc16_table[1][data[6] ] ^ FLAC__crc16_table[0][data[7] ]; - - data += 8; - len -= 8; - } - - while(len--) - crc = (crc<<8) ^ FLAC__crc16_table[0][(crc>>8) ^ *data++]; - - return crc; -} - -FLAC__uint16 FLAC__crc16_update_words32(const FLAC__uint32 *words, uint32_t len, FLAC__uint16 crc) -{ - while (len >= 2) { - crc ^= words[0] >> 16; - - crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^ - FLAC__crc16_table[5][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[4][ words[0] & 0xFF] ^ - FLAC__crc16_table[3][ words[1] >> 24 ] ^ FLAC__crc16_table[2][(words[1] >> 16) & 0xFF] ^ - FLAC__crc16_table[1][(words[1] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[1] & 0xFF]; - - words += 2; - len -= 2; - } - - if (len) { - crc ^= words[0] >> 16; - - crc = FLAC__crc16_table[3][crc >> 8 ] ^ FLAC__crc16_table[2][crc & 0xFF ] ^ - FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][words[0] & 0xFF]; - } - - return crc; -} - -FLAC__uint16 FLAC__crc16_update_words64(const FLAC__uint64 *words, uint32_t len, FLAC__uint16 crc) -{ - while (len--) { - crc ^= words[0] >> 48; - - crc = FLAC__crc16_table[7][crc >> 8 ] ^ FLAC__crc16_table[6][crc & 0xFF ] ^ - FLAC__crc16_table[5][(words[0] >> 40) & 0xFF] ^ FLAC__crc16_table[4][(words[0] >> 32) & 0xFF] ^ - FLAC__crc16_table[3][(words[0] >> 24) & 0xFF] ^ FLAC__crc16_table[2][(words[0] >> 16) & 0xFF] ^ - FLAC__crc16_table[1][(words[0] >> 8) & 0xFF] ^ FLAC__crc16_table[0][ words[0] & 0xFF]; - - words++; - } - - return crc; -} diff --git a/src/lib/flac/src/libFLAC/src/deduplication/bitreader_read_rice_signed_block.c b/src/lib/flac/src/libFLAC/src/deduplication/bitreader_read_rice_signed_block.c deleted file mode 100644 index 75ed47f7..00000000 --- a/src/lib/flac/src/libFLAC/src/deduplication/bitreader_read_rice_signed_block.c +++ /dev/null @@ -1,143 +0,0 @@ -{ - /* try and get br->consumed_words and br->consumed_bits into register; - * must remember to flush them back to *br before calling other - * bitreader functions that use them, and before returning */ - uint32_t cwords, words, lsbs, msbs, x, y, limit; - uint32_t ucbits; /* keep track of the number of unconsumed bits in word */ - brword b; - int *val, *end; - - FLAC__ASSERT(0 != br); - FLAC__ASSERT(0 != br->buffer); - /* WATCHOUT: code does not work with <32bit words; we can make things much faster with this assertion */ - FLAC__ASSERT(FLAC__BITS_PER_WORD >= 32); - FLAC__ASSERT(parameter < 32); - /* the above two asserts also guarantee that the binary part never straddles more than 2 words, so we don't have to loop to read it */ - - limit = UINT32_MAX >> parameter; /* Maximal msbs that can occur with residual bounded to int32_t */ - - val = vals; - end = vals + nvals; - - if(parameter == 0) { - while(val < end) { - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - /* Checking limit here would be overzealous: coding UINT32_MAX - * with parameter == 0 would take 4GiB */ - *val++ = (int)(msbs >> 1) ^ -(int)(msbs & 1); - } - - return true; - } - - FLAC__ASSERT(parameter > 0); - - cwords = br->consumed_words; - words = br->words; - - /* if we've not consumed up to a partial tail word... */ - if(cwords >= words) { - x = 0; - goto process_tail; - } - - ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; - b = br->buffer[cwords] << br->consumed_bits; /* keep unconsumed bits aligned to left */ - - while(val < end) { - /* read the unary MSBs and end bit */ - x = y = COUNT_ZERO_MSBS2(b); - if(x == FLAC__BITS_PER_WORD) { - x = ucbits; - do { - /* didn't find stop bit yet, have to keep going... */ - cwords++; - if (cwords >= words) - goto incomplete_msbs; - b = br->buffer[cwords]; - y = COUNT_ZERO_MSBS2(b); - x += y; - } while(y == FLAC__BITS_PER_WORD); - } - b <<= y; - b <<= 1; /* account for stop bit */ - ucbits = (ucbits - x - 1) % FLAC__BITS_PER_WORD; - msbs = x; - - if(x > limit) - return false; - - /* read the binary LSBs */ - x = (FLAC__uint32)(b >> (FLAC__BITS_PER_WORD - parameter)); /* parameter < 32, so we can cast to 32-bit uint32_t */ - if(parameter <= ucbits) { - ucbits -= parameter; - b <<= parameter; - } else { - /* there are still bits left to read, they will all be in the next word */ - cwords++; - if (cwords >= words) - goto incomplete_lsbs; - b = br->buffer[cwords]; - ucbits += FLAC__BITS_PER_WORD - parameter; - x |= (FLAC__uint32)(b >> ucbits); - b <<= FLAC__BITS_PER_WORD - ucbits; - } - lsbs = x; - - /* compose the value */ - x = (msbs << parameter) | lsbs; - *val++ = (int)(x >> 1) ^ -(int)(x & 1); - - continue; - - /* at this point we've eaten up all the whole words */ -process_tail: - do { - if(0) { -incomplete_msbs: - br->consumed_bits = 0; - br->consumed_words = cwords; - } - - /* read the unary MSBs and end bit */ - if(!FLAC__bitreader_read_unary_unsigned(br, &msbs)) - return false; - msbs += x; - x = ucbits = 0; - - if(0) { -incomplete_lsbs: - br->consumed_bits = 0; - br->consumed_words = cwords; - } - - /* read the binary LSBs */ - if(!FLAC__bitreader_read_raw_uint32(br, &lsbs, parameter - ucbits)) - return false; - lsbs = x | lsbs; - - /* compose the value */ - x = (msbs << parameter) | lsbs; - *val++ = (int)(x >> 1) ^ -(int)(x & 1); - x = 0; - - cwords = br->consumed_words; - words = br->words; - ucbits = FLAC__BITS_PER_WORD - br->consumed_bits; - b = cwords < br->capacity ? br->buffer[cwords] << br->consumed_bits : 0; - } while(cwords >= words && val < end); - } - - if(ucbits == 0 && cwords < words) { - /* don't leave the head word with no unconsumed bits */ - cwords++; - ucbits = FLAC__BITS_PER_WORD; - } - - br->consumed_bits = FLAC__BITS_PER_WORD - ucbits; - br->consumed_words = cwords; - - return true; -} diff --git a/src/lib/flac/src/libFLAC/src/deduplication/lpc_compute_autocorrelation_intrin.c b/src/lib/flac/src/libFLAC/src/deduplication/lpc_compute_autocorrelation_intrin.c deleted file mode 100644 index 76419db0..00000000 --- a/src/lib/flac/src/libFLAC/src/deduplication/lpc_compute_autocorrelation_intrin.c +++ /dev/null @@ -1,14 +0,0 @@ - int i, j; - (void) lag; - FLAC__ASSERT(lag <= MAX_LAG); - - for(i = 0; i < MAX_LAG; i++) - autoc[i] = 0.0; - - for(i = 0; i < MAX_LAG; i++) - for(j = 0; j <= i; j++) - autoc[j] += (double)data[i] * (double)data[i-j]; - - for(i = MAX_LAG; i < (int)data_len; i++) - for(j = 0; j < MAX_LAG; j++) - autoc[j] += (double)data[i] * (double)data[i-j]; diff --git a/src/lib/flac/src/libFLAC/src/fixed.c b/src/lib/flac/src/libFLAC/src/fixed.c deleted file mode 100644 index d7e7760c..00000000 --- a/src/lib/flac/src/libFLAC/src/fixed.c +++ /dev/null @@ -1,667 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include -#include "share/compat.h" -#include "private/bitmath.h" -#include "private/fixed.h" -#include "private/macros.h" -#include "FLAC/assert.h" - -#ifdef local_abs -#undef local_abs -#endif -#define local_abs(x) ((uint32_t)((x)<0? -(x) : (x))) - -#ifdef local_abs64 -#undef local_abs64 -#endif -#define local_abs64(x) ((uint64_t)((x)<0? -(x) : (x))) - -#ifdef FLAC__INTEGER_ONLY_LIBRARY -/* rbps stands for residual bits per sample - * - * (ln(2) * err) - * rbps = log (-----------) - * 2 ( n ) - */ -static FLAC__fixedpoint local__compute_rbps_integerized(FLAC__uint32 err, FLAC__uint32 n) -{ - FLAC__uint32 rbps; - uint32_t bits; /* the number of bits required to represent a number */ - int fracbits; /* the number of bits of rbps that comprise the fractional part */ - - FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); - FLAC__ASSERT(err > 0); - FLAC__ASSERT(n > 0); - - FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); - if(err <= n) - return 0; - /* - * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. - * These allow us later to know we won't lose too much precision in the - * fixed-point division (err< 0); - bits = FLAC__bitmath_ilog2(err)+1; - if(bits > 16) { - err >>= (bits-16); - fracbits -= (bits-16); - } - rbps = (FLAC__uint32)err; - - /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ - rbps *= FLAC__FP_LN2; - fracbits += 16; - FLAC__ASSERT(fracbits >= 0); - - /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ - { - const int f = fracbits & 3; - if(f) { - rbps >>= f; - fracbits -= f; - } - } - - rbps = FLAC__fixedpoint_log2(rbps, fracbits, (uint32_t)(-1)); - - if(rbps == 0) - return 0; - - /* - * The return value must have 16 fractional bits. Since the whole part - * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits - * must be >= -3, these assertion allows us to be able to shift rbps - * left if necessary to get 16 fracbits without losing any bits of the - * whole part of rbps. - * - * There is a slight chance due to accumulated error that the whole part - * will require 6 bits, so we use 6 in the assertion. Really though as - * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. - */ - FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); - FLAC__ASSERT(fracbits >= -3); - - /* now shift the decimal point into place */ - if(fracbits < 16) - return rbps << (16-fracbits); - else if(fracbits > 16) - return rbps >> (fracbits-16); - else - return rbps; -} - -static FLAC__fixedpoint local__compute_rbps_wide_integerized(FLAC__uint64 err, FLAC__uint32 n) -{ - FLAC__uint32 rbps; - uint32_t bits; /* the number of bits required to represent a number */ - int fracbits; /* the number of bits of rbps that comprise the fractional part */ - - FLAC__ASSERT(sizeof(rbps) == sizeof(FLAC__fixedpoint)); - FLAC__ASSERT(err > 0); - FLAC__ASSERT(n > 0); - - FLAC__ASSERT(n <= FLAC__MAX_BLOCK_SIZE); - if(err <= n) - return 0; - /* - * The above two things tell us 1) n fits in 16 bits; 2) err/n > 1. - * These allow us later to know we won't lose too much precision in the - * fixed-point division (err< 0); - bits = FLAC__bitmath_ilog2_wide(err)+1; - if(bits > 16) { - err >>= (bits-16); - fracbits -= (bits-16); - } - rbps = (FLAC__uint32)err; - - /* Multiply by fixed-point version of ln(2), with 16 fractional bits */ - rbps *= FLAC__FP_LN2; - fracbits += 16; - FLAC__ASSERT(fracbits >= 0); - - /* FLAC__fixedpoint_log2 requires fracbits%4 to be 0 */ - { - const int f = fracbits & 3; - if(f) { - rbps >>= f; - fracbits -= f; - } - } - - rbps = FLAC__fixedpoint_log2(rbps, fracbits, (uint32_t)(-1)); - - if(rbps == 0) - return 0; - - /* - * The return value must have 16 fractional bits. Since the whole part - * of the base-2 log of a 32 bit number must fit in 5 bits, and fracbits - * must be >= -3, these assertion allows us to be able to shift rbps - * left if necessary to get 16 fracbits without losing any bits of the - * whole part of rbps. - * - * There is a slight chance due to accumulated error that the whole part - * will require 6 bits, so we use 6 in the assertion. Really though as - * long as it fits in 13 bits (32 - (16 - (-3))) we are fine. - */ - FLAC__ASSERT((int)FLAC__bitmath_ilog2(rbps)+1 <= fracbits + 6); - FLAC__ASSERT(fracbits >= -3); - - /* now shift the decimal point into place */ - if(fracbits < 16) - return rbps << (16-fracbits); - else if(fracbits > 16) - return rbps >> (fracbits-16); - else - return rbps; -} -#endif - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#else -uint32_t FLAC__fixed_compute_best_predictor(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#endif -{ - FLAC__uint32 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; - uint32_t order; -#if 0 - /* This code has been around a long time, and was written when compilers weren't able - * to vectorize code. These days, compilers are better in optimizing the next block - * which is also much more readable - */ - FLAC__int32 last_error_0 = data[-1]; - FLAC__int32 last_error_1 = data[-1] - data[-2]; - FLAC__int32 last_error_2 = last_error_1 - (data[-2] - data[-3]); - FLAC__int32 last_error_3 = last_error_2 - (data[-2] - 2*data[-3] + data[-4]); - FLAC__int32 error, save; - uint32_t i; - /* total_error_* are 64-bits to avoid overflow when encoding - * erratic signals when the bits-per-sample and blocksize are - * large. - */ - for(i = 0; i < data_len; i++) { - error = data[i] ; total_error_0 += local_abs(error); save = error; - error -= last_error_0; total_error_1 += local_abs(error); last_error_0 = save; save = error; - error -= last_error_1; total_error_2 += local_abs(error); last_error_1 = save; save = error; - error -= last_error_2; total_error_3 += local_abs(error); last_error_2 = save; save = error; - error -= last_error_3; total_error_4 += local_abs(error); last_error_3 = save; - } -#else - int i; - for(i = 0; i < (int)data_len; i++) { - total_error_0 += local_abs(data[i]); - total_error_1 += local_abs(data[i] - data[i-1]); - total_error_2 += local_abs(data[i] - 2 * data[i-1] + data[i-2]); - total_error_3 += local_abs(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]); - total_error_4 += local_abs(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]); - } -#endif - - - /* prefer lower order */ - if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) - order = 0; - else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) - order = 1; - else if(total_error_2 <= flac_min(total_error_3, total_error_4)) - order = 2; - else if(total_error_3 <= total_error_4) - order = 3; - else - order = 4; - - /* Estimate the expected number of bits per residual signal sample. */ - /* 'total_error*' is linearly related to the variance of the residual */ - /* signal, so we use it directly to compute E(|x|) */ - FLAC__ASSERT(data_len > 0 || total_error_0 == 0); - FLAC__ASSERT(data_len > 0 || total_error_1 == 0); - FLAC__ASSERT(data_len > 0 || total_error_2 == 0); - FLAC__ASSERT(data_len > 0 || total_error_3 == 0); - FLAC__ASSERT(data_len > 0 || total_error_4 == 0); -#ifndef FLAC__INTEGER_ONLY_LIBRARY - residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); -#else - residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_integerized(total_error_0, data_len) : 0; - residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_integerized(total_error_1, data_len) : 0; - residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_integerized(total_error_2, data_len) : 0; - residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_integerized(total_error_3, data_len) : 0; - residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_integerized(total_error_4, data_len) : 0; -#endif - - return order; -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#else -uint32_t FLAC__fixed_compute_best_predictor_wide(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#endif -{ - FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0; - uint32_t order; - int i; - - for(i = 0; i < (int)data_len; i++) { - total_error_0 += local_abs(data[i]); - total_error_1 += local_abs(data[i] - data[i-1]); - total_error_2 += local_abs(data[i] - 2 * data[i-1] + data[i-2]); - total_error_3 += local_abs(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]); - total_error_4 += local_abs(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]); - } - - /* prefer lower order */ - if(total_error_0 <= flac_min(flac_min(flac_min(total_error_1, total_error_2), total_error_3), total_error_4)) - order = 0; - else if(total_error_1 <= flac_min(flac_min(total_error_2, total_error_3), total_error_4)) - order = 1; - else if(total_error_2 <= flac_min(total_error_3, total_error_4)) - order = 2; - else if(total_error_3 <= total_error_4) - order = 3; - else - order = 4; - - /* Estimate the expected number of bits per residual signal sample. */ - /* 'total_error*' is linearly related to the variance of the residual */ - /* signal, so we use it directly to compute E(|x|) */ - FLAC__ASSERT(data_len > 0 || total_error_0 == 0); - FLAC__ASSERT(data_len > 0 || total_error_1 == 0); - FLAC__ASSERT(data_len > 0 || total_error_2 == 0); - FLAC__ASSERT(data_len > 0 || total_error_3 == 0); - FLAC__ASSERT(data_len > 0 || total_error_4 == 0); -#ifndef FLAC__INTEGER_ONLY_LIBRARY - residual_bits_per_sample[0] = (float)((total_error_0 > 0) ? log(M_LN2 * (double)total_error_0 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[1] = (float)((total_error_1 > 0) ? log(M_LN2 * (double)total_error_1 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[2] = (float)((total_error_2 > 0) ? log(M_LN2 * (double)total_error_2 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[3] = (float)((total_error_3 > 0) ? log(M_LN2 * (double)total_error_3 / (double)data_len) / M_LN2 : 0.0); - residual_bits_per_sample[4] = (float)((total_error_4 > 0) ? log(M_LN2 * (double)total_error_4 / (double)data_len) / M_LN2 : 0.0); -#else - residual_bits_per_sample[0] = (total_error_0 > 0) ? local__compute_rbps_wide_integerized(total_error_0, data_len) : 0; - residual_bits_per_sample[1] = (total_error_1 > 0) ? local__compute_rbps_wide_integerized(total_error_1, data_len) : 0; - residual_bits_per_sample[2] = (total_error_2 > 0) ? local__compute_rbps_wide_integerized(total_error_2, data_len) : 0; - residual_bits_per_sample[3] = (total_error_3 > 0) ? local__compute_rbps_wide_integerized(total_error_3, data_len) : 0; - residual_bits_per_sample[4] = (total_error_4 > 0) ? local__compute_rbps_wide_integerized(total_error_4, data_len) : 0; -#endif - - return order; -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -#define CHECK_ORDER_IS_VALID(macro_order) \ -if(order_##macro_order##_is_valid && total_error_##macro_order < smallest_error) { \ - order = macro_order; \ - smallest_error = total_error_##macro_order ; \ - residual_bits_per_sample[ macro_order ] = (float)((total_error_##macro_order > 0) ? log(M_LN2 * (double)total_error_##macro_order / (double)data_len) / M_LN2 : 0.0); \ -} \ -else \ - residual_bits_per_sample[ macro_order ] = 34.0f; -#else -#define CHECK_ORDER_IS_VALID(macro_order) \ -if(order_##macro_order##_is_valid && total_error_##macro_order < smallest_error) { \ - order = macro_order; \ - smallest_error = total_error_##macro_order ; \ - residual_bits_per_sample[ macro_order ] = (total_error_##macro_order > 0) ? local__compute_rbps_wide_integerized(total_error_##macro_order, data_len) : 0; \ -} \ -else \ - residual_bits_per_sample[ macro_order ] = 34 * FLAC__FP_ONE; -#endif - - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#else -uint32_t FLAC__fixed_compute_best_predictor_limit_residual(const FLAC__int32 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#endif -{ - FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX; - FLAC__uint64 error_0, error_1, error_2, error_3, error_4; - FLAC__bool order_0_is_valid = true, order_1_is_valid = true, order_2_is_valid = true, order_3_is_valid = true, order_4_is_valid = true; - uint32_t order = 0; - int i; - - for(i = -4; i < (int)data_len; i++) { - error_0 = local_abs64((FLAC__int64)data[i]); - error_1 = (i > -4) ? local_abs64((FLAC__int64)data[i] - data[i-1]) : 0 ; - error_2 = (i > -3) ? local_abs64((FLAC__int64)data[i] - 2 * (FLAC__int64)data[i-1] + data[i-2]) : 0; - error_3 = (i > -2) ? local_abs64((FLAC__int64)data[i] - 3 * (FLAC__int64)data[i-1] + 3 * (FLAC__int64)data[i-2] - data[i-3]) : 0; - error_4 = (i > -1) ? local_abs64((FLAC__int64)data[i] - 4 * (FLAC__int64)data[i-1] + 6 * (FLAC__int64)data[i-2] - 4 * (FLAC__int64)data[i-3] + data[i-4]) : 0; - - total_error_0 += error_0; - total_error_1 += error_1; - total_error_2 += error_2; - total_error_3 += error_3; - total_error_4 += error_4; - - /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ - if(error_0 > INT32_MAX) - order_0_is_valid = false; - if(error_1 > INT32_MAX) - order_1_is_valid = false; - if(error_2 > INT32_MAX) - order_2_is_valid = false; - if(error_3 > INT32_MAX) - order_3_is_valid = false; - if(error_4 > INT32_MAX) - order_4_is_valid = false; - } - - CHECK_ORDER_IS_VALID(0); - CHECK_ORDER_IS_VALID(1); - CHECK_ORDER_IS_VALID(2); - CHECK_ORDER_IS_VALID(3); - CHECK_ORDER_IS_VALID(4); - - return order; -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY -uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, float residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#else -uint32_t FLAC__fixed_compute_best_predictor_limit_residual_33bit(const FLAC__int64 data[], uint32_t data_len, FLAC__fixedpoint residual_bits_per_sample[FLAC__MAX_FIXED_ORDER+1]) -#endif -{ - FLAC__uint64 total_error_0 = 0, total_error_1 = 0, total_error_2 = 0, total_error_3 = 0, total_error_4 = 0, smallest_error = UINT64_MAX; - FLAC__uint64 error_0, error_1, error_2, error_3, error_4; - FLAC__bool order_0_is_valid = true, order_1_is_valid = true, order_2_is_valid = true, order_3_is_valid = true, order_4_is_valid = true; - uint32_t order = 0; - int i; - - for(i = -4; i < (int)data_len; i++) { - error_0 = local_abs64(data[i]); - error_1 = (i > -4) ? local_abs64(data[i] - data[i-1]) : 0 ; - error_2 = (i > -3) ? local_abs64(data[i] - 2 * data[i-1] + data[i-2]) : 0; - error_3 = (i > -2) ? local_abs64(data[i] - 3 * data[i-1] + 3 * data[i-2] - data[i-3]) : 0; - error_4 = (i > -1) ? local_abs64(data[i] - 4 * data[i-1] + 6 * data[i-2] - 4 * data[i-3] + data[i-4]) : 0; - - total_error_0 += error_0; - total_error_1 += error_1; - total_error_2 += error_2; - total_error_3 += error_3; - total_error_4 += error_4; - - /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ - if(error_0 > INT32_MAX) - order_0_is_valid = false; - if(error_1 > INT32_MAX) - order_1_is_valid = false; - if(error_2 > INT32_MAX) - order_2_is_valid = false; - if(error_3 > INT32_MAX) - order_3_is_valid = false; - if(error_4 > INT32_MAX) - order_4_is_valid = false; - } - - CHECK_ORDER_IS_VALID(0); - CHECK_ORDER_IS_VALID(1); - CHECK_ORDER_IS_VALID(2); - CHECK_ORDER_IS_VALID(3); - CHECK_ORDER_IS_VALID(4); - - return order; -} - -void FLAC__fixed_compute_residual(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) -{ - const int idata_len = (int)data_len; - int i; - - switch(order) { - case 0: - FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); - memcpy(residual, data, sizeof(residual[0])*data_len); - break; - case 1: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 2*data[i-1] + data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} - -void FLAC__fixed_compute_residual_wide(const FLAC__int32 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) -{ - const int idata_len = (int)data_len; - int i; - - switch(order) { - case 0: - FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); - memcpy(residual, data, sizeof(residual[0])*data_len); - break; - case 1: - for(i = 0; i < idata_len; i++) - residual[i] = (FLAC__int64)data[i] - data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - residual[i] = (FLAC__int64)data[i] - 2*(FLAC__int64)data[i-1] + data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - residual[i] = (FLAC__int64)data[i] - 3*(FLAC__int64)data[i-1] + 3*(FLAC__int64)data[i-2] - data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - residual[i] = (FLAC__int64)data[i] - 4*(FLAC__int64)data[i-1] + 6*(FLAC__int64)data[i-2] - 4*(FLAC__int64)data[i-3] + data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} - -void FLAC__fixed_compute_residual_wide_33bit(const FLAC__int64 data[], uint32_t data_len, uint32_t order, FLAC__int32 residual[]) -{ - const int idata_len = (int)data_len; - int i; - - switch(order) { - case 0: - for(i = 0; i < idata_len; i++) - residual[i] = data[i]; - break; - case 1: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 2*data[i-1] + data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} - -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) -/* The attribute below is to silence the undefined sanitizer of oss-fuzz. - * Because fuzzing feeds bogus predictors and residual samples to the - * decoder, having overflows in this section is unavoidable. Also, - * because the calculated values are audio path only, there is no - * potential for security problems */ -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -void FLAC__fixed_restore_signal(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]) -{ - int i, idata_len = (int)data_len; - - switch(order) { - case 0: - FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); - memcpy(data, residual, sizeof(residual[0])*data_len); - break; - case 1: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + 2*data[i-1] - data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - data[i] = residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} - -void FLAC__fixed_restore_signal_wide(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int32 data[]) -{ - int i, idata_len = (int)data_len; - - switch(order) { - case 0: - FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); - memcpy(data, residual, sizeof(residual[0])*data_len); - break; - case 1: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + (FLAC__int64)data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + 2*(FLAC__int64)data[i-1] - (FLAC__int64)data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + 3*(FLAC__int64)data[i-1] - 3*(FLAC__int64)data[i-2] + (FLAC__int64)data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + 4*(FLAC__int64)data[i-1] - 6*(FLAC__int64)data[i-2] + 4*(FLAC__int64)data[i-3] - (FLAC__int64)data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} - -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) -/* The attribute below is to silence the undefined sanitizer of oss-fuzz. - * Because fuzzing feeds bogus predictors and residual samples to the - * decoder, having overflows in this section is unavoidable. Also, - * because the calculated values are audio path only, there is no - * potential for security problems */ -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -void FLAC__fixed_restore_signal_wide_33bit(const FLAC__int32 residual[], uint32_t data_len, uint32_t order, FLAC__int64 data[]) -{ - int i, idata_len = (int)data_len; - - switch(order) { - case 0: - for(i = 0; i < idata_len; i++) - data[i] = residual[i]; - break; - case 1: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + data[i-1]; - break; - case 2: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + 2*data[i-1] - data[i-2]; - break; - case 3: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + 3*data[i-1] - 3*data[i-2] + data[i-3]; - break; - case 4: - for(i = 0; i < idata_len; i++) - data[i] = (FLAC__int64)residual[i] + 4*data[i-1] - 6*data[i-2] + 4*data[i-3] - data[i-4]; - break; - default: - FLAC__ASSERT(0); - } -} diff --git a/src/lib/flac/src/libFLAC/src/format.c b/src/lib/flac/src/libFLAC/src/format.c deleted file mode 100644 index ae36cf24..00000000 --- a/src/lib/flac/src/libFLAC/src/format.c +++ /dev/null @@ -1,610 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if 0 /* bstone */ -#include -#endif /* bstone */ -#include /* for qsort() */ -#include /* for memset() */ -#include "FLAC/assert.h" -#include "FLAC/format.h" -#include "share/alloc.h" -#include "share/compat.h" -#include "private/format.h" -#include "private/macros.h" - -#if (defined GIT_COMMIT_HASH && defined GIT_COMMIT_DATE) -# ifdef GIT_COMMIT_TAG -FLAC_API const char *FLAC__VERSION_STRING = GIT_COMMIT_TAG; -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " GIT_COMMIT_TAG " " GIT_COMMIT_DATE; -# else -FLAC_API const char *FLAC__VERSION_STRING = "git-" GIT_COMMIT_HASH " " GIT_COMMIT_DATE; -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC git-" GIT_COMMIT_HASH " " GIT_COMMIT_DATE; -# endif -#else -/* PACKAGE_VERSION should come from configure */ -FLAC_API const char *FLAC__VERSION_STRING = PACKAGE_VERSION; -FLAC_API const char *FLAC__VENDOR_STRING = "reference libFLAC " PACKAGE_VERSION " 20250211"; -#endif - -FLAC_API const FLAC__byte FLAC__STREAM_SYNC_STRING[4] = { 'f','L','a','C' }; -FLAC_API const uint32_t FLAC__STREAM_SYNC = 0x664C6143; -FLAC_API const uint32_t FLAC__STREAM_SYNC_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN = 16; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN = 16; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN = 24; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN = 24; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN = 20; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN = 3; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN = 5; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN = 36; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_STREAMINFO_MD5SUM_LEN = 128; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_APPLICATION_ID_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN = 16; /* bits */ - -FLAC_API const FLAC__uint64 FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER = FLAC__U64L(0xffffffffffffffff); - -FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN = 8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN = 3*8; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN = 8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN = 12*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN = 1; /* bit */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN = 1; /* bit */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN = 6+13*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN = 8; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN = 128*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN = 64; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN = 1; /* bit */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN = 7+258*8; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN = 8; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_TYPE_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_COLORS_LEN = 32; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN = 32; /* bits */ - -FLAC_API const uint32_t FLAC__STREAM_METADATA_IS_LAST_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_TYPE_LEN = 7; /* bits */ -FLAC_API const uint32_t FLAC__STREAM_METADATA_LENGTH_LEN = 24; /* bits */ - -FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC = 0x3ffe; -FLAC_API const uint32_t FLAC__FRAME_HEADER_SYNC_LEN = 14; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_RESERVED_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCKING_STRATEGY_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_BLOCK_SIZE_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_SAMPLE_RATE_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_CHANNEL_ASSIGNMENT_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_BITS_PER_SAMPLE_LEN = 3; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_ZERO_PAD_LEN = 1; /* bits */ -FLAC_API const uint32_t FLAC__FRAME_HEADER_CRC_LEN = 8; /* bits */ - -FLAC_API const uint32_t FLAC__FRAME_FOOTER_CRC_LEN = 16; /* bits */ - -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_TYPE_LEN = 2; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN = 4; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN = 5; /* bits */ -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN = 5; /* bits */ - -FLAC_API const uint32_t FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER = 15; /* == (1< FLAC__MAX_SAMPLE_RATE) { - return false; - } - else - return true; -} - -FLAC_API FLAC__bool FLAC__format_blocksize_is_subset(uint32_t blocksize, uint32_t sample_rate) -{ - if(blocksize > 16384) - return false; - else if(sample_rate <= 48000 && blocksize > 4608) - return false; - else - return true; -} - -FLAC_API FLAC__bool FLAC__format_sample_rate_is_subset(uint32_t sample_rate) -{ - if( // sample rate is not subset if - !FLAC__format_sample_rate_is_valid(sample_rate) || // sample rate is invalid or - sample_rate >= ((1u << 16) * 10) || // sample rate is larger then or equal to 655360 or - (sample_rate >= (1u << 16) && sample_rate % 10 != 0) //sample rate is >= 65536 and not divisible by 10 - ) { - return false; - } - else - return true; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API FLAC__bool FLAC__format_seektable_is_legal(const FLAC__StreamMetadata_SeekTable *seek_table) -{ - uint32_t i; - FLAC__uint64 prev_sample_number = 0; - FLAC__bool got_prev = false; - - FLAC__ASSERT(0 != seek_table); - - if((FLAC__uint64)(seek_table->num_points) * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH >= (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) - return false; - - for(i = 0; i < seek_table->num_points; i++) { - if(got_prev) { - if( - seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && - seek_table->points[i].sample_number <= prev_sample_number - ) - return false; - } - prev_sample_number = seek_table->points[i].sample_number; - got_prev = true; - } - - return true; -} - -/* used as the sort predicate for qsort() */ -static int seekpoint_compare_(const FLAC__StreamMetadata_SeekPoint *l, const FLAC__StreamMetadata_SeekPoint *r) -{ - /* we don't just 'return l->sample_number - r->sample_number' since the result (FLAC__int64) might overflow an 'int' */ - if(l->sample_number == r->sample_number) - return 0; - else if(l->sample_number < r->sample_number) - return -1; - else - return 1; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API uint32_t FLAC__format_seektable_sort(FLAC__StreamMetadata_SeekTable *seek_table) -{ - uint32_t i, j; - FLAC__bool first; - - FLAC__ASSERT(0 != seek_table); - - if (seek_table->num_points == 0) - return 0; - - /* sort the seekpoints */ - qsort(seek_table->points, seek_table->num_points, sizeof(FLAC__StreamMetadata_SeekPoint), (int (*)(const void *, const void *))seekpoint_compare_); - - /* uniquify the seekpoints */ - first = true; - for(i = j = 0; i < seek_table->num_points; i++) { - if(seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER) { - if(!first) { - if(seek_table->points[i].sample_number == seek_table->points[j-1].sample_number) - continue; - } - } - first = false; - seek_table->points[j++] = seek_table->points[i]; - } - - for(i = j; i < seek_table->num_points; i++) { - seek_table->points[i].sample_number = FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER; - seek_table->points[i].stream_offset = 0; - seek_table->points[i].frame_samples = 0; - } - - return j; -} - -/* - * also disallows non-shortest-form encodings, c.f. - * http://www.unicode.org/versions/corrigendum1.html - * and a more clear explanation at the end of this section: - * http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8 - */ -static uint32_t utf8len_(const FLAC__byte *utf8) -{ - FLAC__ASSERT(0 != utf8); - if ((utf8[0] & 0x80) == 0) { - return 1; - } - else if ((utf8[0] & 0xE0) == 0xC0 && (utf8[1] & 0xC0) == 0x80) { - if ((utf8[0] & 0xFE) == 0xC0) /* overlong sequence check */ - return 0; - return 2; - } - else if ((utf8[0] & 0xF0) == 0xE0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80) { - if (utf8[0] == 0xE0 && (utf8[1] & 0xE0) == 0x80) /* overlong sequence check */ - return 0; - /* illegal surrogates check (U+D800...U+DFFF and U+FFFE...U+FFFF) */ - if (utf8[0] == 0xED && (utf8[1] & 0xE0) == 0xA0) /* D800-DFFF */ - return 0; - if (utf8[0] == 0xEF && utf8[1] == 0xBF && (utf8[2] & 0xFE) == 0xBE) /* FFFE-FFFF */ - return 0; - return 3; - } - else if ((utf8[0] & 0xF8) == 0xF0 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80) { - if (utf8[0] == 0xF0 && (utf8[1] & 0xF0) == 0x80) /* overlong sequence check */ - return 0; - return 4; - } - else if ((utf8[0] & 0xFC) == 0xF8 && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80) { - if (utf8[0] == 0xF8 && (utf8[1] & 0xF8) == 0x80) /* overlong sequence check */ - return 0; - return 5; - } - else if ((utf8[0] & 0xFE) == 0xFC && (utf8[1] & 0xC0) == 0x80 && (utf8[2] & 0xC0) == 0x80 && (utf8[3] & 0xC0) == 0x80 && (utf8[4] & 0xC0) == 0x80 && (utf8[5] & 0xC0) == 0x80) { - if (utf8[0] == 0xFC && (utf8[1] & 0xFC) == 0x80) /* overlong sequence check */ - return 0; - return 6; - } - else { - return 0; - } -} - -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_name_is_legal(const char *name) -{ - char c; - for(c = *name; c; c = *(++name)) - if(c < 0x20 || c == 0x3d || c > 0x7d) - return false; - return true; -} - -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_value_is_legal(const FLAC__byte *value, uint32_t length) -{ - if(length == (uint32_t)(-1)) { - while(*value) { - uint32_t n = utf8len_(value); - if(n == 0) - return false; - value += n; - } - } - else { - const FLAC__byte *end = value + length; - while(value < end) { - uint32_t n = utf8len_(value); - if(n == 0) - return false; - value += n; - } - if(value != end) - return false; - } - return true; -} - -FLAC_API FLAC__bool FLAC__format_vorbiscomment_entry_is_legal(const FLAC__byte *entry, uint32_t length) -{ - const FLAC__byte *s, *end; - - for(s = entry, end = s + length; s < end && *s != '='; s++) { - if(*s < 0x20 || *s > 0x7D) - return false; - } - if(s == end) - return false; - - s++; /* skip '=' */ - - while(s < end) { - uint32_t n = utf8len_(s); - if(n == 0) - return false; - s += n; - } - if(s != end) - return false; - - return true; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API FLAC__bool FLAC__format_cuesheet_is_legal(const FLAC__StreamMetadata_CueSheet *cue_sheet, FLAC__bool check_cd_da_subset, const char **violation) -{ - uint32_t i, j; - - if(check_cd_da_subset) { - if(cue_sheet->lead_in < 2 * 44100) { - if(violation) *violation = "CD-DA cue sheet must have a lead-in length of at least 2 seconds"; - return false; - } - if(cue_sheet->lead_in % 588 != 0) { - if(violation) *violation = "CD-DA cue sheet lead-in length must be evenly divisible by 588 samples"; - return false; - } - } - - if(cue_sheet->num_tracks == 0) { - if(violation) *violation = "cue sheet must have at least one track (the lead-out)"; - return false; - } - - if(check_cd_da_subset && cue_sheet->tracks[cue_sheet->num_tracks-1].number != 170) { - if(violation) *violation = "CD-DA cue sheet must have a lead-out track number 170 (0xAA)"; - return false; - } - - for(i = 0; i < cue_sheet->num_tracks; i++) { - if(cue_sheet->tracks[i].number == 0) { - if(violation) *violation = "cue sheet may not have a track number 0"; - return false; - } - - if(check_cd_da_subset) { - if(!((cue_sheet->tracks[i].number >= 1 && cue_sheet->tracks[i].number <= 99) || cue_sheet->tracks[i].number == 170)) { - if(violation) *violation = "CD-DA cue sheet track number must be 1-99 or 170"; - return false; - } - } - - if(check_cd_da_subset && cue_sheet->tracks[i].offset % 588 != 0) { - if(violation) { - if(i == cue_sheet->num_tracks-1) /* the lead-out track... */ - *violation = "CD-DA cue sheet lead-out offset must be evenly divisible by 588 samples"; - else - *violation = "CD-DA cue sheet track offset must be evenly divisible by 588 samples"; - } - return false; - } - - if(i < cue_sheet->num_tracks - 1) { - if(cue_sheet->tracks[i].num_indices == 0) { - if(violation) *violation = "cue sheet track must have at least one index point"; - return false; - } - - if(cue_sheet->tracks[i].indices[0].number > 1) { - if(violation) *violation = "cue sheet track's first index number must be 0 or 1"; - return false; - } - } - - for(j = 0; j < cue_sheet->tracks[i].num_indices; j++) { - if(check_cd_da_subset && cue_sheet->tracks[i].indices[j].offset % 588 != 0) { - if(violation) *violation = "CD-DA cue sheet track index offset must be evenly divisible by 588 samples"; - return false; - } - - if(j > 0) { - if(cue_sheet->tracks[i].indices[j].number != cue_sheet->tracks[i].indices[j-1].number + 1) { - if(violation) *violation = "cue sheet track index numbers must increase by 1"; - return false; - } - } - } - } - - return true; -} - -/* @@@@ add to unit tests; it is already indirectly tested by the metadata_object tests */ -FLAC_API FLAC__bool FLAC__format_picture_is_legal(const FLAC__StreamMetadata_Picture *picture, const char **violation) -{ - char *p; - FLAC__byte *b; - - for(p = picture->mime_type; *p; p++) { - if(*p < 0x20 || *p > 0x7e) { - if(violation) *violation = "MIME type string must contain only printable ASCII characters (0x20-0x7e)"; - return false; - } - } - - for(b = picture->description; *b; ) { - uint32_t n = utf8len_(b); - if(n == 0) { - if(violation) *violation = "description string must be valid UTF-8"; - return false; - } - b += n; - } - - return true; -} - -/* - * These routines are private to libFLAC - */ -#if 0 /* UNUSED */ -uint32_t FLAC__format_get_max_rice_partition_order(uint32_t blocksize, uint32_t predictor_order) -{ - return - FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order( - FLAC__format_get_max_rice_partition_order_from_blocksize(blocksize), - blocksize, - predictor_order - ); -} -#endif - -uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize(uint32_t blocksize) -{ - uint32_t max_rice_partition_order = 0; - while(!(blocksize & 1)) { - max_rice_partition_order++; - blocksize >>= 1; - } - return flac_min(FLAC__MAX_RICE_PARTITION_ORDER, max_rice_partition_order); -} - -uint32_t FLAC__format_get_max_rice_partition_order_from_blocksize_limited_max_and_predictor_order(uint32_t limit, uint32_t blocksize, uint32_t predictor_order) -{ - uint32_t max_rice_partition_order = limit; - - while(max_rice_partition_order > 0 && (blocksize >> max_rice_partition_order) <= predictor_order) - max_rice_partition_order--; - - FLAC__ASSERT( - (max_rice_partition_order == 0 && blocksize >= predictor_order) || - (max_rice_partition_order > 0 && blocksize >> max_rice_partition_order > predictor_order) - ); - - return max_rice_partition_order; -} - -void FLAC__format_entropy_coding_method_partitioned_rice_contents_init(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) -{ - FLAC__ASSERT(0 != object); - - object->parameters = 0; - object->raw_bits = 0; - object->capacity_by_order = 0; -} - -void FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(FLAC__EntropyCodingMethod_PartitionedRiceContents *object) -{ - FLAC__ASSERT(0 != object); - - if(0 != object->parameters) - free(object->parameters); - if(0 != object->raw_bits) - free(object->raw_bits); - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(object); -} - -#if defined(_MSC_VER) -// silence three MSVC warnings 'result of 32-bit shift implicitly converted to 64 bits (was 64-bit shift intended?)' -#pragma warning ( disable : 4334 ) -#endif - -FLAC__bool FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(FLAC__EntropyCodingMethod_PartitionedRiceContents *object, uint32_t max_partition_order) -{ - FLAC__ASSERT(0 != object); - - if(object->capacity_by_order < max_partition_order || object->parameters == NULL || object->raw_bits == NULL) { - if(0 == (object->parameters = safe_realloc_(object->parameters, sizeof(uint32_t)*(1 << max_partition_order)))) - return false; - if(0 == (object->raw_bits = safe_realloc_(object->raw_bits, sizeof(uint32_t)*(1 << max_partition_order)))) - return false; - memset(object->raw_bits, 0, sizeof(uint32_t)*(1 << max_partition_order)); - object->capacity_by_order = max_partition_order; - } - - return true; -} - -#if defined(_MSC_VER) -#pragma warning ( default : 4334 ) -#endif diff --git a/src/lib/flac/src/libFLAC/src/lpc.c b/src/lib/flac/src/libFLAC/src/lpc.c deleted file mode 100644 index 7b1fbc43..00000000 --- a/src/lib/flac/src/libFLAC/src/lpc.c +++ /dev/null @@ -1,1634 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#include -#include - -#include "FLAC/assert.h" -#include "FLAC/format.h" -#include "share/compat.h" -#include "private/bitmath.h" -#include "private/lpc.h" -#include "private/macros.h" - -#if 0 /* bstone */ -#if !defined(NDEBUG) || defined FLAC__OVERFLOW_DETECT || defined FLAC__OVERFLOW_DETECT_VERBOSE -#include -#endif -#endif /* bstone */ - -/* OPT: #undef'ing this may improve the speed on some architectures */ -#define FLAC__LPC_UNROLLED_FILTER_LOOPS - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -#if defined(_MSC_VER) && (_MSC_VER < 1800) -#include -static inline long int lround(double x) { - return (long)(x + _copysign(0.5, x)); -} -#elif !defined(HAVE_LROUND) && defined(__GNUC__) -static inline long int lround(double x) { - return (long)(x + __builtin_copysign(0.5, x)); -} -/* If this fails, we are in the presence of a mid 90's compiler, move along... */ -#endif - -void FLAC__lpc_window_data(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len) -{ - uint32_t i; - for(i = 0; i < data_len; i++) - out[i] = in[i] * window[i]; -} - -void FLAC__lpc_window_data_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len) -{ - uint32_t i; - for(i = 0; i < data_len; i++) - out[i] = in[i] * window[i]; -} - -void FLAC__lpc_window_data_partial(const FLAC__int32 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift) -{ - uint32_t i, j; - if((part_size + data_shift) < data_len){ - for(i = 0; i < part_size; i++) - out[i] = in[data_shift+i] * window[i]; - i = flac_min(i,data_len - part_size - data_shift); - for(j = data_len - part_size; j < data_len; i++, j++) - out[i] = in[data_shift+i] * window[j]; - if(i < data_len) - out[i] = 0.0f; - } -} - -void FLAC__lpc_window_data_partial_wide(const FLAC__int64 in[], const FLAC__real window[], FLAC__real out[], uint32_t data_len, uint32_t part_size, uint32_t data_shift) -{ - uint32_t i, j; - if((part_size + data_shift) < data_len){ - for(i = 0; i < part_size; i++) - out[i] = in[data_shift+i] * window[i]; - i = flac_min(i,data_len - part_size - data_shift); - for(j = data_len - part_size; j < data_len; i++, j++) - out[i] = in[data_shift+i] * window[j]; - if(i < data_len) - out[i] = 0.0f; - } -} - -void FLAC__lpc_compute_autocorrelation(const FLAC__real data[], uint32_t data_len, uint32_t lag, double autoc[]) -{ - /* a readable, but slower, version */ -#if 0 - double d; - uint32_t i; - - FLAC__ASSERT(lag > 0); - FLAC__ASSERT(lag <= data_len); - - /* - * Technically we should subtract the mean first like so: - * for(i = 0; i < data_len; i++) - * data[i] -= mean; - * but it appears not to make enough of a difference to matter, and - * most signals are already closely centered around zero - */ - while(lag--) { - for(i = lag, d = 0.0; i < data_len; i++) - d += data[i] * (double)data[i - lag]; - autoc[lag] = d; - } -#endif - if (data_len < FLAC__MAX_LPC_ORDER || lag > 16) { - /* - * this version tends to run faster because of better data locality - * ('data_len' is usually much larger than 'lag') - */ - double d; - uint32_t sample, coeff; - const uint32_t limit = data_len - lag; - - FLAC__ASSERT(lag > 0); - FLAC__ASSERT(lag <= data_len); - - for(coeff = 0; coeff < lag; coeff++) - autoc[coeff] = 0.0; - for(sample = 0; sample <= limit; sample++) { - d = data[sample]; - for(coeff = 0; coeff < lag; coeff++) - autoc[coeff] += d * data[sample+coeff]; - } - for(; sample < data_len; sample++) { - d = data[sample]; - for(coeff = 0; coeff < data_len - sample; coeff++) - autoc[coeff] += d * data[sample+coeff]; - } - } - else if(lag <= 8) { - #undef MAX_LAG - #define MAX_LAG 8 - #include "deduplication/lpc_compute_autocorrelation_intrin.c" - } - else if(lag <= 12) { - #undef MAX_LAG - #define MAX_LAG 12 - #include "deduplication/lpc_compute_autocorrelation_intrin.c" - } - else if(lag <= 16) { - #undef MAX_LAG - #define MAX_LAG 16 - #include "deduplication/lpc_compute_autocorrelation_intrin.c" - } - -} - -void FLAC__lpc_compute_lp_coefficients(const double autoc[], uint32_t *max_order, FLAC__real lp_coeff[][FLAC__MAX_LPC_ORDER], double error[]) -{ - uint32_t i, j; - double r, err, lpc[FLAC__MAX_LPC_ORDER]; - - FLAC__ASSERT(0 != max_order); - FLAC__ASSERT(0 < *max_order); - FLAC__ASSERT(*max_order <= FLAC__MAX_LPC_ORDER); - FLAC__ASSERT(autoc[0] != 0.0); - - err = autoc[0]; - - for(i = 0; i < *max_order; i++) { - /* Sum up this iteration's reflection coefficient. */ - r = -autoc[i+1]; - for(j = 0; j < i; j++) - r -= lpc[j] * autoc[i-j]; - r /= err; - - /* Update LPC coefficients and total error. */ - lpc[i]=r; - for(j = 0; j < (i>>1); j++) { - double tmp = lpc[j]; - lpc[j] += r * lpc[i-1-j]; - lpc[i-1-j] += r * tmp; - } - if(i & 1) - lpc[j] += lpc[j] * r; - - err *= (1.0 - r * r); - - /* save this order */ - for(j = 0; j <= i; j++) - lp_coeff[i][j] = (FLAC__real)(-lpc[j]); /* negate FIR filter coeff to get predictor coeff */ - error[i] = err; - - /* see SF bug https://sourceforge.net/p/flac/bugs/234/ */ - if(err == 0.0) { - *max_order = i+1; - return; - } - } -} - -int FLAC__lpc_quantize_coefficients(const FLAC__real lp_coeff[], uint32_t order, uint32_t precision, FLAC__int32 qlp_coeff[], int *shift) -{ - uint32_t i; - double cmax; - FLAC__int32 qmax, qmin; - - FLAC__ASSERT(precision > 0); - FLAC__ASSERT(precision >= FLAC__MIN_QLP_COEFF_PRECISION); - - /* drop one bit for the sign; from here on out we consider only |lp_coeff[i]| */ - precision--; - qmax = 1 << precision; - qmin = -qmax; - qmax--; - - /* calc cmax = max( |lp_coeff[i]| ) */ - cmax = 0.0; - for(i = 0; i < order; i++) { - const double d = fabs(lp_coeff[i]); - if(d > cmax) - cmax = d; - } - - if(cmax <= 0.0) { - /* => coefficients are all 0, which means our constant-detect didn't work */ - return 2; - } - else { - const int max_shiftlimit = (1 << (FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN-1)) - 1; - const int min_shiftlimit = -max_shiftlimit - 1; - int log2cmax; - - (void)frexp(cmax, &log2cmax); - log2cmax--; - *shift = (int)precision - log2cmax - 1; - - if(*shift > max_shiftlimit) - *shift = max_shiftlimit; - else if(*shift < min_shiftlimit) - return 1; - } - - if(*shift >= 0) { - double error = 0.0; - FLAC__int32 q; - for(i = 0; i < order; i++) { - error += lp_coeff[i] * (1 << *shift); - q = lround(error); - -#ifdef FLAC__OVERFLOW_DETECT - if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ - flac_fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); - else if(q < qmin) - flac_fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q qmax) - q = qmax; - else if(q < qmin) - q = qmin; - error -= q; - qlp_coeff[i] = q; - } - } - /* negative shift is very rare but due to design flaw, negative shift is - * not allowed in the decoder, so it must be handled specially by scaling - * down coeffs - */ - else { - const int nshift = -(*shift); - double error = 0.0; - FLAC__int32 q; -#ifndef NDEBUG - flac_fprintf(stderr,"FLAC__lpc_quantize_coefficients: negative shift=%d order=%u cmax=%f\n", *shift, order, cmax); -#endif - for(i = 0; i < order; i++) { - error += lp_coeff[i] / (1 << nshift); - q = lround(error); -#ifdef FLAC__OVERFLOW_DETECT - if(q > qmax+1) /* we expect q==qmax+1 occasionally due to rounding */ - flac_fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q>qmax %d>%d shift=%d cmax=%f precision=%u lpc[%u]=%f\n",q,qmax,*shift,cmax,precision+1,i,lp_coeff[i]); - else if(q < qmin) - flac_fprintf(stderr,"FLAC__lpc_quantize_coefficients: quantizer overflow: q qmax) - q = qmax; - else if(q < qmin) - q = qmin; - error -= q; - qlp_coeff[i] = q; - } - *shift = 0; - } - - return 0; -} - -#if defined(_MSC_VER) -// silence MSVC warnings about __restrict modifier -#pragma warning ( disable : 4028 ) -#endif - -void FLAC__lpc_compute_residual_from_qlp_coefficients(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - FLAC__int64 sumo; - uint32_t i, j; - FLAC__int32 sum; - const FLAC__int32 *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - flac_fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sumo = 0; - sum = 0; - history = data; - for(j = 0; j < order; j++) { - sum += qlp_coeff[j] * (*(--history)); - sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); - if(sumo > 2147483647ll || sumo < -2147483648ll) - flac_fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); - } - *(residual++) = *(data++) - (sum >> lp_quantization); - } - - /* Here's a slower but clearer version: - for(i = 0; i < data_len; i++) { - sum = 0; - for(j = 0; j < order; j++) - sum += qlp_coeff[j] * data[i-j-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - */ -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int32 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - residual[i] = data[i] - ((qlp_coeff[0] * data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * data[i-13]; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[ 9] * data[i-10]; - sum += qlp_coeff[ 8] * data[i- 9]; - sum += qlp_coeff[ 7] * data[i- 8]; - sum += qlp_coeff[ 6] * data[i- 7]; - sum += qlp_coeff[ 5] * data[i- 6]; - sum += qlp_coeff[ 4] * data[i- 5]; - sum += qlp_coeff[ 3] * data[i- 4]; - sum += qlp_coeff[ 2] * data[i- 3]; - sum += qlp_coeff[ 1] * data[i- 2]; - sum += qlp_coeff[ 0] * data[i- 1]; - } - residual[i] = data[i] - (sum >> lp_quantization); - } - } -} -#endif - -void FLAC__lpc_compute_residual_from_qlp_coefficients_wide(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - uint32_t i, j; - FLAC__int64 sum; - const FLAC__int32 *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - flac_fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sum = 0; - history = data; - for(j = 0; j < order; j++) - sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); - if(FLAC__bitmath_silog2((FLAC__int64)(*data) - (sum >> lp_quantization)) > 32) { - flac_fprintf(stderr,"FLAC__lpc_compute_residual_from_qlp_coefficients_wide: OVERFLOW, i=%u, data=%d, sum=%" PRId64 ", residual=%" PRId64 "\n", i, *data, (int64_t)(sum >> lp_quantization), ((FLAC__int64)(*data) - (sum >> lp_quantization))); - break; - } - *(residual++) = *(data++) - (FLAC__int32)(sum >> lp_quantization); - } -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int64 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - residual[i] = data[i] - (sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - residual[i] = data[i] - ((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; - sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; - sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; - sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; - sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; - sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; - sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; - sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; - sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; - } - residual[i] = data[i] - (sum >> lp_quantization); - } - } -} -#endif - -FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual(const FLAC__int32 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) -{ - int i; - FLAC__int64 sum, residual_to_check; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; /* Falls through. */ - case 12: sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; /* Falls through. */ - case 11: sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; /* Falls through. */ - case 10: sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; /* Falls through. */ - case 9: sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; /* Falls through. */ - case 8: sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; /* Falls through. */ - case 7: sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; /* Falls through. */ - case 6: sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; /* Falls through. */ - case 5: sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; /* Falls through. */ - case 4: sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; /* Falls through. */ - case 3: sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; /* Falls through. */ - case 2: sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; /* Falls through. */ - case 1: sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; - } - residual_to_check = data[i] - (sum >> lp_quantization); - /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ - if(residual_to_check <= INT32_MIN || residual_to_check > INT32_MAX) - return false; - else - residual[i] = residual_to_check; - } - return true; -} - -FLAC__bool FLAC__lpc_compute_residual_from_qlp_coefficients_limit_residual_33bit(const FLAC__int64 * flac_restrict data, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict residual) -{ - int i; - FLAC__int64 sum, residual_to_check; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * data[i-13]; /* Falls through. */ - case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ - case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ - case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ - case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ - case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ - case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ - case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ - case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ - case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ - case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ - case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ - case 1: sum += qlp_coeff[ 0] * data[i- 1]; - } - residual_to_check = data[i] - (sum >> lp_quantization); - /* residual must not be INT32_MIN because abs(INT32_MIN) is undefined */ - if(residual_to_check <= INT32_MIN || residual_to_check > INT32_MAX) - return false; - else - residual[i] = residual_to_check; - } - return true; -} - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ - -FLAC__uint64 FLAC__lpc_max_prediction_value_before_shift(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order) -{ - FLAC__uint64 max_abs_sample_value = (FLAC__uint64)(1) << (subframe_bps - 1); - FLAC__uint32 abs_sum_of_qlp_coeff = 0; - uint32_t i; - for(i = 0; i < order; i++) - abs_sum_of_qlp_coeff += abs(qlp_coeff[i]); - return max_abs_sample_value * abs_sum_of_qlp_coeff; -} - -uint32_t FLAC__lpc_max_prediction_before_shift_bps(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order) -{ - /* This used to be subframe_bps + qlp_coeff_precision + FLAC__bitmath_ilog2(order) - * but that treats both the samples as well as the predictor as unknown. The - * predictor is known however, so taking the log2 of the sum of the absolute values - * of all coefficients is a more accurate representation of the predictor */ - return FLAC__bitmath_silog2(FLAC__lpc_max_prediction_value_before_shift(subframe_bps, qlp_coeff, order)); -} - - -uint32_t FLAC__lpc_max_residual_bps(uint32_t subframe_bps, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization) -{ - FLAC__uint64 max_abs_sample_value = (FLAC__uint64)(1) << (subframe_bps - 1); - FLAC__uint64 max_prediction_value_after_shift = -1 * ((-1 * (FLAC__int64)FLAC__lpc_max_prediction_value_before_shift(subframe_bps, qlp_coeff, order)) >> lp_quantization); - FLAC__uint64 max_residual_value = max_abs_sample_value + max_prediction_value_after_shift; - return FLAC__bitmath_silog2(max_residual_value); -} - -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) -/* The attribute below is to silence the undefined sanitizer of oss-fuzz. - * Because fuzzing feeds bogus predictors and residual samples to the - * decoder, having overflows in this section is unavoidable. Also, - * because the calculated values are audio path only, there is no - * potential for security problems */ -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -void FLAC__lpc_restore_signal(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - FLAC__int64 sumo; - uint32_t i, j; - FLAC__int32 sum; - const FLAC__int32 *r = residual, *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - flac_fprintf(stderr,"FLAC__lpc_restore_signal: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sumo = 0; - sum = 0; - history = data; - for(j = 0; j < order; j++) { - sum += qlp_coeff[j] * (*(--history)); - sumo += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*history); -#ifdef FLAC__OVERFLOW_DETECT - if(sumo > 2147483647ll || sumo < -2147483648ll) - flac_fprintf(stderr,"FLAC__lpc_restore_signal: OVERFLOW, i=%u, j=%u, c=%d, d=%d, sumo=%" PRId64 "\n",i,j,qlp_coeff[j],*history,sumo); -#endif - } - *(data++) = *(r++) + (sum >> lp_quantization); - } - - /* Here's a slower but clearer version: - for(i = 0; i < data_len; i++) { - sum = 0; - for(j = 0; j < order; j++) - sum += qlp_coeff[j] * data[i-j-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - */ -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int32 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * data[i-10]; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * data[i-9]; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * data[i-8]; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * data[i-7]; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * data[i-6]; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * data[i-5]; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * data[i-4]; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * data[i-3]; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * data[i-2]; - sum += qlp_coeff[0] * data[i-1]; - data[i] = residual[i] + (sum >> lp_quantization); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - data[i] = residual[i] + ((qlp_coeff[0] * data[i-1]) >> lp_quantization); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * data[i-13]; - sum += qlp_coeff[11] * data[i-12]; - sum += qlp_coeff[10] * data[i-11]; - sum += qlp_coeff[ 9] * data[i-10]; - sum += qlp_coeff[ 8] * data[i- 9]; - sum += qlp_coeff[ 7] * data[i- 8]; - sum += qlp_coeff[ 6] * data[i- 7]; - sum += qlp_coeff[ 5] * data[i- 6]; - sum += qlp_coeff[ 4] * data[i- 5]; - sum += qlp_coeff[ 3] * data[i- 4]; - sum += qlp_coeff[ 2] * data[i- 3]; - sum += qlp_coeff[ 1] * data[i- 2]; - sum += qlp_coeff[ 0] * data[i- 1]; - } - data[i] = residual[i] + (sum >> lp_quantization); - } - } -} -#endif - -void FLAC__lpc_restore_signal_wide(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int32 * flac_restrict data) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - uint32_t i, j; - FLAC__int64 sum; - const FLAC__int32 *r = residual, *history; - -#ifdef FLAC__OVERFLOW_DETECT_VERBOSE - flac_fprintf(stderr,"FLAC__lpc_restore_signal_wide: data_len=%d, order=%u, lpq=%d",data_len,order,lp_quantization); - for(i=0;i 0); - - for(i = 0; i < data_len; i++) { - sum = 0; - history = data; - for(j = 0; j < order; j++) - sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); -#ifdef FLAC__OVERFLOW_DETECT - if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 32) { - flac_fprintf(stderr,"FLAC__lpc_restore_signal_wide: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization))); - break; - } -#endif - *(data++) = (FLAC__int32)(*(r++) + (sum >> lp_quantization)); - } -} -#else /* fully unrolled version for normal use */ -{ - int i; - FLAC__int64 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - /* - * We do unique versions up to 12th order since that's the subset limit. - * Also they are roughly ordered to match frequency of occurrence to - * minimize branching. - */ - if(order <= 12) { - if(order > 8) { - if(order > 10) { - if(order == 12) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - else { /* order == 11 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - } - else { - if(order == 10) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - else { /* order == 9 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[8] * (FLAC__int64)data[i-9]; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - } - } - else if(order > 4) { - if(order > 6) { - if(order == 8) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[7] * (FLAC__int64)data[i-8]; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - else { /* order == 7 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[6] * (FLAC__int64)data[i-7]; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - } - else { - if(order == 6) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[5] * (FLAC__int64)data[i-6]; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - else { /* order == 5 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[4] * (FLAC__int64)data[i-5]; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - } - } - else { - if(order > 2) { - if(order == 4) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[3] * (FLAC__int64)data[i-4]; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - else { /* order == 3 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[2] * (FLAC__int64)data[i-3]; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - } - else { - if(order == 2) { - for(i = 0; i < (int)data_len; i++) { - sum = 0; - sum += qlp_coeff[1] * (FLAC__int64)data[i-2]; - sum += qlp_coeff[0] * (FLAC__int64)data[i-1]; - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } - else { /* order == 1 */ - for(i = 0; i < (int)data_len; i++) - data[i] = (FLAC__int32)(residual[i] + ((qlp_coeff[0] * (FLAC__int64)data[i-1]) >> lp_quantization)); - } - } - } - } - else { /* order > 12 */ - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * (FLAC__int64)data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * (FLAC__int64)data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * (FLAC__int64)data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * (FLAC__int64)data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * (FLAC__int64)data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * (FLAC__int64)data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * (FLAC__int64)data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * (FLAC__int64)data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * (FLAC__int64)data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * (FLAC__int64)data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * (FLAC__int64)data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * (FLAC__int64)data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * (FLAC__int64)data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * (FLAC__int64)data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * (FLAC__int64)data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * (FLAC__int64)data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * (FLAC__int64)data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * (FLAC__int64)data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * (FLAC__int64)data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * (FLAC__int64)data[i-13]; - sum += qlp_coeff[11] * (FLAC__int64)data[i-12]; - sum += qlp_coeff[10] * (FLAC__int64)data[i-11]; - sum += qlp_coeff[ 9] * (FLAC__int64)data[i-10]; - sum += qlp_coeff[ 8] * (FLAC__int64)data[i- 9]; - sum += qlp_coeff[ 7] * (FLAC__int64)data[i- 8]; - sum += qlp_coeff[ 6] * (FLAC__int64)data[i- 7]; - sum += qlp_coeff[ 5] * (FLAC__int64)data[i- 6]; - sum += qlp_coeff[ 4] * (FLAC__int64)data[i- 5]; - sum += qlp_coeff[ 3] * (FLAC__int64)data[i- 4]; - sum += qlp_coeff[ 2] * (FLAC__int64)data[i- 3]; - sum += qlp_coeff[ 1] * (FLAC__int64)data[i- 2]; - sum += qlp_coeff[ 0] * (FLAC__int64)data[i- 1]; - } - data[i] = (FLAC__int32) (residual[i] + (sum >> lp_quantization)); - } - } -} -#endif - -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) -/* The attribute below is to silence the undefined sanitizer of oss-fuzz. - * Because fuzzing feeds bogus predictors and residual samples to the - * decoder, having overflows in this section is unavoidable. Also, - * because the calculated values are audio path only, there is no - * potential for security problems */ -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -void FLAC__lpc_restore_signal_wide_33bit(const FLAC__int32 * flac_restrict residual, uint32_t data_len, const FLAC__int32 * flac_restrict qlp_coeff, uint32_t order, int lp_quantization, FLAC__int64 * flac_restrict data) -#if defined(FLAC__OVERFLOW_DETECT) || !defined(FLAC__LPC_UNROLLED_FILTER_LOOPS) -{ - uint32_t i, j; - FLAC__int64 sum; - const FLAC__int32 *r = residual; - const FLAC__int64 *history; - - FLAC__ASSERT(order > 0); - - for(i = 0; i < data_len; i++) { - sum = 0; - history = data; - for(j = 0; j < order; j++) - sum += (FLAC__int64)qlp_coeff[j] * (FLAC__int64)(*(--history)); -#ifdef FLAC__OVERFLOW_DETECT - if(FLAC__bitmath_silog2((FLAC__int64)(*r) + (sum >> lp_quantization)) > 33) { - flac_fprintf(stderr,"FLAC__lpc_restore_signal_33bit: OVERFLOW, i=%u, residual=%d, sum=%" PRId64 ", data=%" PRId64 "\n", i, *r, (sum >> lp_quantization), ((FLAC__int64)(*r) + (sum >> lp_quantization))); - break; - } -#endif - *(data++) = (FLAC__int64)(*(r++)) + (sum >> lp_quantization); - } -} -#else /* unrolled version for normal use */ -{ - int i; - FLAC__int64 sum; - - FLAC__ASSERT(order > 0); - FLAC__ASSERT(order <= 32); - - for(i = 0; i < (int)data_len; i++) { - sum = 0; - switch(order) { - case 32: sum += qlp_coeff[31] * data[i-32]; /* Falls through. */ - case 31: sum += qlp_coeff[30] * data[i-31]; /* Falls through. */ - case 30: sum += qlp_coeff[29] * data[i-30]; /* Falls through. */ - case 29: sum += qlp_coeff[28] * data[i-29]; /* Falls through. */ - case 28: sum += qlp_coeff[27] * data[i-28]; /* Falls through. */ - case 27: sum += qlp_coeff[26] * data[i-27]; /* Falls through. */ - case 26: sum += qlp_coeff[25] * data[i-26]; /* Falls through. */ - case 25: sum += qlp_coeff[24] * data[i-25]; /* Falls through. */ - case 24: sum += qlp_coeff[23] * data[i-24]; /* Falls through. */ - case 23: sum += qlp_coeff[22] * data[i-23]; /* Falls through. */ - case 22: sum += qlp_coeff[21] * data[i-22]; /* Falls through. */ - case 21: sum += qlp_coeff[20] * data[i-21]; /* Falls through. */ - case 20: sum += qlp_coeff[19] * data[i-20]; /* Falls through. */ - case 19: sum += qlp_coeff[18] * data[i-19]; /* Falls through. */ - case 18: sum += qlp_coeff[17] * data[i-18]; /* Falls through. */ - case 17: sum += qlp_coeff[16] * data[i-17]; /* Falls through. */ - case 16: sum += qlp_coeff[15] * data[i-16]; /* Falls through. */ - case 15: sum += qlp_coeff[14] * data[i-15]; /* Falls through. */ - case 14: sum += qlp_coeff[13] * data[i-14]; /* Falls through. */ - case 13: sum += qlp_coeff[12] * data[i-13]; /* Falls through. */ - case 12: sum += qlp_coeff[11] * data[i-12]; /* Falls through. */ - case 11: sum += qlp_coeff[10] * data[i-11]; /* Falls through. */ - case 10: sum += qlp_coeff[ 9] * data[i-10]; /* Falls through. */ - case 9: sum += qlp_coeff[ 8] * data[i- 9]; /* Falls through. */ - case 8: sum += qlp_coeff[ 7] * data[i- 8]; /* Falls through. */ - case 7: sum += qlp_coeff[ 6] * data[i- 7]; /* Falls through. */ - case 6: sum += qlp_coeff[ 5] * data[i- 6]; /* Falls through. */ - case 5: sum += qlp_coeff[ 4] * data[i- 5]; /* Falls through. */ - case 4: sum += qlp_coeff[ 3] * data[i- 4]; /* Falls through. */ - case 3: sum += qlp_coeff[ 2] * data[i- 3]; /* Falls through. */ - case 2: sum += qlp_coeff[ 1] * data[i- 2]; /* Falls through. */ - case 1: sum += qlp_coeff[ 0] * data[i- 1]; - } - data[i] = residual[i] + (sum >> lp_quantization); - } -} -#endif - -#if defined(_MSC_VER) -#pragma warning ( default : 4028 ) -#endif - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -double FLAC__lpc_compute_expected_bits_per_residual_sample(double lpc_error, uint32_t total_samples) -{ - double error_scale; - - FLAC__ASSERT(total_samples > 0); - - error_scale = 0.5 / (double)total_samples; - - return FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error, error_scale); -} - -double FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(double lpc_error, double error_scale) -{ - if(lpc_error > 0.0) { - double bps = (double)0.5 * log(error_scale * lpc_error) / M_LN2; - if(bps >= 0.0) - return bps; - else - return 0.0; - } - else if(lpc_error < 0.0) { /* error should not be negative but can happen due to inadequate floating-point resolution */ - return 1e32; - } - else { - return 0.0; - } -} - -uint32_t FLAC__lpc_compute_best_order(const double lpc_error[], uint32_t max_order, uint32_t total_samples, uint32_t overhead_bits_per_order) -{ - uint32_t order, indx, best_index; /* 'index' the index into lpc_error; index==order-1 since lpc_error[0] is for order==1, lpc_error[1] is for order==2, etc */ - double bits, best_bits, error_scale; - - FLAC__ASSERT(max_order > 0); - FLAC__ASSERT(total_samples > 0); - - error_scale = 0.5 / (double)total_samples; - - best_index = 0; - best_bits = (uint32_t)(-1); - - for(indx = 0, order = 1; indx < max_order; indx++, order++) { - bits = FLAC__lpc_compute_expected_bits_per_residual_sample_with_error_scale(lpc_error[indx], error_scale) * (double)(total_samples - order) + (double)(order * overhead_bits_per_order); - if(bits < best_bits) { - best_index = indx; - best_bits = bits; - } - } - - return best_index+1; /* +1 since indx of lpc_error[] is order-1 */ -} - -#endif /* !defined FLAC__INTEGER_ONLY_LIBRARY */ diff --git a/src/lib/flac/src/libFLAC/src/md5.c b/src/lib/flac/src/libFLAC/src/md5.c deleted file mode 100644 index a2dbaf11..00000000 --- a/src/lib/flac/src/libFLAC/src/md5.c +++ /dev/null @@ -1,522 +0,0 @@ -#ifdef HAVE_CONFIG_H -# include -#endif - -#include /* for malloc() */ -#include /* for memcpy() */ - -#include "private/md5.h" -#include "share/alloc.h" -#include "share/compat.h" -#include "share/endswap.h" - -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - * - * Changed so as no longer to depend on Colin Plumb's `usual.h' header - * definitions; now uses stuff from dpkg's config.h. - * - Ian Jackson . - * Still in the public domain. - * - * Josh Coalson: made some changes to integrate with libFLAC. - * Still in the public domain. - */ - -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f,w,x,y,z,in,s) \ - (w += f(x,y,z) + in, w = (w<>(32-s)) + x) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ - -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -/* This tremendously speeds up undefined behaviour fuzzing */ -__attribute__((no_sanitize("unsigned-integer-overflow"))) -#endif -static void FLAC__MD5Transform(FLAC__uint32 buf[4], FLAC__uint32 const in[16]) -{ - register FLAC__uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -#if WORDS_BIGENDIAN -//@@@@@@ OPT: use bswap/intrinsics -static void byteSwap(FLAC__uint32 *buf, uint32_t words) -{ - register FLAC__uint32 x; - do { - x = *buf; - x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); - *buf++ = (x >> 16) | (x << 16); - } while (--words); -} -static void byteSwapX16(FLAC__uint32 *buf) -{ - register FLAC__uint32 x; - - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf++ = (x >> 16) | (x << 16); - x = *buf; x = ((x << 8) & 0xff00ff00) | ((x >> 8) & 0x00ff00ff); *buf = (x >> 16) | (x << 16); -} -#else -#define byteSwap(buf, words) -#define byteSwapX16(buf) -#endif - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static void FLAC__MD5Update(FLAC__MD5Context *ctx, FLAC__byte const *buf, uint32_t len) -{ - FLAC__uint32 t; - - /* Update byte count */ - - t = ctx->bytes[0]; - if ((ctx->bytes[0] = t + len) < t) - ctx->bytes[1]++; /* Carry from low to high */ - - t = 64 - (t & 0x3f); /* Space available in ctx->in (at least 1) */ - if (t > len) { - memcpy((FLAC__byte *)ctx->in + 64 - t, buf, len); - return; - } - /* First chunk is an odd size */ - memcpy((FLAC__byte *)ctx->in + 64 - t, buf, t); - byteSwapX16(ctx->in); - FLAC__MD5Transform(ctx->buf, ctx->in); - buf += t; - len -= t; - - /* Process data in 64-byte chunks */ - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteSwapX16(ctx->in); - FLAC__MD5Transform(ctx->buf, ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - memcpy(ctx->in, buf, len); -} - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -void FLAC__MD5Init(FLAC__MD5Context *ctx) -{ - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - - ctx->bytes[0] = 0; - ctx->bytes[1] = 0; - - ctx->internal_buf.p8 = 0; - ctx->capacity = 0; -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -void FLAC__MD5Final(FLAC__byte digest[16], FLAC__MD5Context *ctx) -{ - int count = ctx->bytes[0] & 0x3f; /* Number of bytes in ctx->in */ - FLAC__byte *p = (FLAC__byte *)ctx->in + count; - - /* Set the first char of padding to 0x80. There is always room. */ - *p++ = 0x80; - - /* Bytes of padding needed to make 56 bytes (-8..55) */ - count = 56 - 1 - count; - - if (count < 0) { /* Padding forces an extra block */ - memset(p, 0, count + 8); - byteSwapX16(ctx->in); - FLAC__MD5Transform(ctx->buf, ctx->in); - p = (FLAC__byte *)ctx->in; - count = 56; - } - memset(p, 0, count); - byteSwap(ctx->in, 14); - - /* Append length in bits and transform */ - ctx->in[14] = ctx->bytes[0] << 3; - ctx->in[15] = ctx->bytes[1] << 3 | ctx->bytes[0] >> 29; - FLAC__MD5Transform(ctx->buf, ctx->in); - - byteSwap(ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - if (0 != ctx->internal_buf.p8) { - free(ctx->internal_buf.p8); - ctx->internal_buf.p8 = 0; - ctx->capacity = 0; - } - memset(ctx, 0, sizeof(*ctx)); /* In case it's sensitive */ -} - -/* - * Convert the incoming audio signal to a byte stream - */ -static void format_input_(FLAC__multibyte *mbuf, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample) -{ - FLAC__byte *buf_ = mbuf->p8; - FLAC__int16 *buf16 = mbuf->p16; - FLAC__int32 *buf32 = mbuf->p32; - FLAC__int32 a_word; - uint32_t channel, sample; - - /* Storage in the output buffer, buf, is little endian. */ - -#define BYTES_CHANNEL_SELECTOR(bytes, channels) (bytes * 100 + channels) - - /* First do the most commonly used combinations. */ - switch (BYTES_CHANNEL_SELECTOR (bytes_per_sample, channels)) { - /* One byte per sample. */ - case (BYTES_CHANNEL_SELECTOR (1, 1)): - for (sample = 0; sample < samples; sample++) - *buf_++ = signal[0][sample]; - return; - - case (BYTES_CHANNEL_SELECTOR (1, 2)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - } - return; - - case (BYTES_CHANNEL_SELECTOR (1, 4)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - *buf_++ = signal[2][sample]; - *buf_++ = signal[3][sample]; - } - return; - - case (BYTES_CHANNEL_SELECTOR (1, 6)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - *buf_++ = signal[2][sample]; - *buf_++ = signal[3][sample]; - *buf_++ = signal[4][sample]; - *buf_++ = signal[5][sample]; - } - return; - - case (BYTES_CHANNEL_SELECTOR (1, 8)): - for (sample = 0; sample < samples; sample++) { - *buf_++ = signal[0][sample]; - *buf_++ = signal[1][sample]; - *buf_++ = signal[2][sample]; - *buf_++ = signal[3][sample]; - *buf_++ = signal[4][sample]; - *buf_++ = signal[5][sample]; - *buf_++ = signal[6][sample]; - *buf_++ = signal[7][sample]; - } - return; - - /* Two bytes per sample. */ - case (BYTES_CHANNEL_SELECTOR (2, 1)): - for (sample = 0; sample < samples; sample++) - *buf16++ = H2LE_16(signal[0][sample]); - return; - - case (BYTES_CHANNEL_SELECTOR (2, 2)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (2, 4)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - *buf16++ = H2LE_16(signal[2][sample]); - *buf16++ = H2LE_16(signal[3][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (2, 6)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - *buf16++ = H2LE_16(signal[2][sample]); - *buf16++ = H2LE_16(signal[3][sample]); - *buf16++ = H2LE_16(signal[4][sample]); - *buf16++ = H2LE_16(signal[5][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (2, 8)): - for (sample = 0; sample < samples; sample++) { - *buf16++ = H2LE_16(signal[0][sample]); - *buf16++ = H2LE_16(signal[1][sample]); - *buf16++ = H2LE_16(signal[2][sample]); - *buf16++ = H2LE_16(signal[3][sample]); - *buf16++ = H2LE_16(signal[4][sample]); - *buf16++ = H2LE_16(signal[5][sample]); - *buf16++ = H2LE_16(signal[6][sample]); - *buf16++ = H2LE_16(signal[7][sample]); - } - return; - - /* Three bytes per sample. */ - case (BYTES_CHANNEL_SELECTOR (3, 1)): - for (sample = 0; sample < samples; sample++) { - a_word = signal[0][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - } - return; - - case (BYTES_CHANNEL_SELECTOR (3, 2)): - for (sample = 0; sample < samples; sample++) { - a_word = signal[0][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - a_word = signal[1][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - } - return; - - /* Four bytes per sample. */ - case (BYTES_CHANNEL_SELECTOR (4, 1)): - for (sample = 0; sample < samples; sample++) - *buf32++ = H2LE_32(signal[0][sample]); - return; - - case (BYTES_CHANNEL_SELECTOR (4, 2)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (4, 4)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - *buf32++ = H2LE_32(signal[2][sample]); - *buf32++ = H2LE_32(signal[3][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (4, 6)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - *buf32++ = H2LE_32(signal[2][sample]); - *buf32++ = H2LE_32(signal[3][sample]); - *buf32++ = H2LE_32(signal[4][sample]); - *buf32++ = H2LE_32(signal[5][sample]); - } - return; - - case (BYTES_CHANNEL_SELECTOR (4, 8)): - for (sample = 0; sample < samples; sample++) { - *buf32++ = H2LE_32(signal[0][sample]); - *buf32++ = H2LE_32(signal[1][sample]); - *buf32++ = H2LE_32(signal[2][sample]); - *buf32++ = H2LE_32(signal[3][sample]); - *buf32++ = H2LE_32(signal[4][sample]); - *buf32++ = H2LE_32(signal[5][sample]); - *buf32++ = H2LE_32(signal[6][sample]); - *buf32++ = H2LE_32(signal[7][sample]); - } - return; - - default: - break; - } - - /* General version. */ - switch (bytes_per_sample) { - case 1: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) - *buf_++ = signal[channel][sample]; - return; - - case 2: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) - *buf16++ = H2LE_16(signal[channel][sample]); - return; - - case 3: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) { - a_word = signal[channel][sample]; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; a_word >>= 8; - *buf_++ = (FLAC__byte)a_word; - } - return; - - case 4: - for (sample = 0; sample < samples; sample++) - for (channel = 0; channel < channels; channel++) - *buf32++ = H2LE_32(signal[channel][sample]); - return; - - default: - break; - } -} - -/* - * Convert the incoming audio signal to a byte stream and FLAC__MD5Update it. - */ -FLAC__bool FLAC__MD5Accumulate(FLAC__MD5Context *ctx, const FLAC__int32 * const signal[], uint32_t channels, uint32_t samples, uint32_t bytes_per_sample) -{ - const size_t bytes_needed = (size_t)channels * (size_t)samples * (size_t)bytes_per_sample; - - /* overflow check */ - if ((size_t)channels > SIZE_MAX / (size_t)bytes_per_sample) - return false; - if ((size_t)channels * (size_t)bytes_per_sample > SIZE_MAX / (size_t)samples) - return false; - - if (ctx->capacity < bytes_needed) { - if (0 == (ctx->internal_buf.p8 = safe_realloc_(ctx->internal_buf.p8, bytes_needed))) { - if (0 == (ctx->internal_buf.p8 = safe_malloc_(bytes_needed))) { - ctx->capacity = 0; - return false; - } - } - ctx->capacity = bytes_needed; - } - - format_input_(&ctx->internal_buf, signal, channels, samples, bytes_per_sample); - - FLAC__MD5Update(ctx, ctx->internal_buf.p8, bytes_needed); - - return true; -} diff --git a/src/lib/flac/src/libFLAC/src/memory.c b/src/lib/flac/src/libFLAC/src/memory.c deleted file mode 100644 index 9ef0181c..00000000 --- a/src/lib/flac/src/libFLAC/src/memory.c +++ /dev/null @@ -1,219 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2001-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#ifdef HAVE_STDINT_H -#include -#endif - -#include "private/memory.h" -#include "FLAC/assert.h" -#include "share/compat.h" -#include "share/alloc.h" - -void *FLAC__memory_alloc_aligned(size_t bytes, void **aligned_address) -{ - void *x; - - FLAC__ASSERT(0 != aligned_address); - -#ifdef FLAC__ALIGN_MALLOC_DATA - /* align on 32-byte (256-bit) boundary */ - x = safe_malloc_add_2op_(bytes, /*+*/31L); - *aligned_address = (void*)(((uintptr_t)x + 31L) & -32L); -#else - x = safe_malloc_(bytes); - *aligned_address = x; -#endif - return x; -} - -FLAC__bool FLAC__memory_alloc_aligned_int32_array(size_t elements, FLAC__int32 **unaligned_pointer, FLAC__int32 **aligned_pointer) -{ - FLAC__int32 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__int32 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -FLAC__bool FLAC__memory_alloc_aligned_uint32_array(size_t elements, FLAC__uint32 **unaligned_pointer, FLAC__uint32 **aligned_pointer) -{ - FLAC__uint32 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__uint32 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -FLAC__bool FLAC__memory_alloc_aligned_int64_array(size_t elements, FLAC__int64 **unaligned_pointer, FLAC__int64 **aligned_pointer) -{ - FLAC__int64 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__int64 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -FLAC__bool FLAC__memory_alloc_aligned_uint64_array(size_t elements, FLAC__uint64 **unaligned_pointer, FLAC__uint64 **aligned_pointer) -{ - FLAC__uint64 *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__uint64 *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -#ifndef FLAC__INTEGER_ONLY_LIBRARY - -FLAC__bool FLAC__memory_alloc_aligned_real_array(size_t elements, FLAC__real **unaligned_pointer, FLAC__real **aligned_pointer) -{ - FLAC__real *pu; /* unaligned pointer */ - union { /* union needed to comply with C99 pointer aliasing rules */ - FLAC__real *pa; /* aligned pointer */ - void *pv; /* aligned pointer alias */ - } u; - - FLAC__ASSERT(elements > 0); - FLAC__ASSERT(0 != unaligned_pointer); - FLAC__ASSERT(0 != aligned_pointer); - FLAC__ASSERT(unaligned_pointer != aligned_pointer); - - if(elements > SIZE_MAX / sizeof(*pu)) /* overflow check */ - return false; - - pu = FLAC__memory_alloc_aligned(sizeof(*pu) * elements, &u.pv); - if(0 == pu) { - return false; - } - else { - if(*unaligned_pointer != 0) - free(*unaligned_pointer); - *unaligned_pointer = pu; - *aligned_pointer = u.pa; - return true; - } -} - -#endif - -void *safe_malloc_mul_2op_p(size_t size1, size_t size2) -{ - if(!size1 || !size2) - return malloc(1); /* malloc(0) is undefined; FLAC src convention is to always allocate */ - if(size1 > SIZE_MAX / size2) - return 0; - return malloc(size1*size2); -} diff --git a/src/lib/flac/src/libFLAC/src/stream_decoder.c b/src/lib/flac/src/libFLAC/src/stream_decoder.c deleted file mode 100644 index 7c70e116..00000000 --- a/src/lib/flac/src/libFLAC/src/stream_decoder.c +++ /dev/null @@ -1,4191 +0,0 @@ -/* libFLAC - Free Lossless Audio Codec library - * Copyright (C) 2000-2009 Josh Coalson - * Copyright (C) 2011-2025 Xiph.Org Foundation - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * - Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * - Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * - Neither the name of the Xiph.org Foundation nor the names of its - * contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR - * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef HAVE_CONFIG_H -# include -#endif - -#if 0 /* bstone */ -#include -#endif /* bstone */ -#include /* for malloc() */ -#include /* for memset/memcpy() */ -#include /* for off_t */ -#include /* for stat() */ -#include "share/compat.h" -#include "FLAC/assert.h" -#include "share/alloc.h" -#include "protected/stream_decoder.h" -#include "private/bitreader.h" -#include "private/bitmath.h" -#include "private/cpu.h" -#include "private/crc.h" -#include "private/fixed.h" -#include "private/format.h" -#include "private/lpc.h" -#include "private/md5.h" -#include "private/memory.h" -#include "private/macros.h" - - -/* technically this should be in an "export.c" but this is convenient enough */ -FLAC_API int FLAC_API_SUPPORTS_OGG_FLAC = FLAC__HAS_OGG; - - -/*********************************************************************** - * - * Private static data - * - ***********************************************************************/ - -static const FLAC__byte ID3V2_TAG_[3] = { 'I', 'D', '3' }; - -/*********************************************************************** - * - * Private class method prototypes - * - ***********************************************************************/ - -static void set_defaults_(FLAC__StreamDecoder *decoder); -#if 0 /* bstone */ -static FILE *get_binary_stdin_(void); -#endif /* bstone */ -static FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels, uint32_t bps); -static FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id); -static FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length); -static FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length); -static FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length); -static FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj); -static FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj); -static FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder); -static FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode); -static FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder); -static FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode); -static FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode); -static FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended); -static FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder); -static void undo_channel_coding(FLAC__StreamDecoder *decoder); -static FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data); -#if FLAC__HAS_OGG -static FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes); -static FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -#endif -static FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]); -static void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status); -static FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); -#if FLAC__HAS_OGG -static FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample); -#endif -#if 0 /* bstone */ -static FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data); -static FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data); -static FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data); -static FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data); -static FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data); -#endif /* bstone */ -static void reset_decoder_internal_(FLAC__StreamDecoder* decoder); - -/*********************************************************************** - * - * Private class data - * - ***********************************************************************/ - -typedef struct FLAC__StreamDecoderPrivate { - FLAC__bool is_ogg; - FLAC__StreamDecoderReadCallback read_callback; - FLAC__StreamDecoderSeekCallback seek_callback; - FLAC__StreamDecoderTellCallback tell_callback; - FLAC__StreamDecoderLengthCallback length_callback; - FLAC__StreamDecoderEofCallback eof_callback; - FLAC__StreamDecoderWriteCallback write_callback; - FLAC__StreamDecoderMetadataCallback metadata_callback; - FLAC__StreamDecoderErrorCallback error_callback; - void *client_data; -#if 0 /* bstone */ - FILE *file; /* only used if FLAC__stream_decoder_init_file()/FLAC__stream_decoder_init_file() called, else NULL */ -#endif /* bstone */ - FLAC__BitReader *input; - FLAC__int32 *output[FLAC__MAX_CHANNELS]; - FLAC__int32 *residual[FLAC__MAX_CHANNELS]; /* WATCHOUT: these are the aligned pointers; the real pointers that should be free()'d are residual_unaligned[] below */ - FLAC__int64 *side_subframe; - FLAC__bool side_subframe_in_use; - FLAC__EntropyCodingMethod_PartitionedRiceContents partitioned_rice_contents[FLAC__MAX_CHANNELS]; - uint32_t output_capacity, output_channels; - FLAC__uint32 fixed_block_size, next_fixed_block_size; - FLAC__uint64 samples_decoded; - FLAC__bool has_stream_info, has_seek_table; - FLAC__StreamMetadata stream_info; - FLAC__StreamMetadata seek_table; - FLAC__bool metadata_filter[128]; /* MAGIC number 128 == total number of metadata block types == 1 << 7 */ - FLAC__byte *metadata_filter_ids; - size_t metadata_filter_ids_count, metadata_filter_ids_capacity; /* units for both are IDs, not bytes */ - FLAC__Frame frame; - FLAC__bool cached; /* true if there is a byte in lookahead */ - FLAC__CPUInfo cpuinfo; - FLAC__byte header_warmup[2]; /* contains the sync code and reserved bits */ - FLAC__byte lookahead; /* temp storage when we need to look ahead one byte in the stream */ - /* unaligned (original) pointers to allocated data */ - FLAC__int32 *residual_unaligned[FLAC__MAX_CHANNELS]; - FLAC__bool do_md5_checking; /* initially gets protected_->md5_checking but is turned off after a seek or if the metadata has a zero MD5 */ - FLAC__bool internal_reset_hack; /* used only during init() so we can call reset to set up the decoder without rewinding the input */ - FLAC__bool is_seeking; - FLAC__bool is_indexing; /* to be able to seek in chained streams */ - FLAC__MD5Context md5context; - FLAC__byte computed_md5sum[16]; /* this is the sum we computed from the decoded data */ - /* (the rest of these are only used for seeking) */ - FLAC__Frame last_frame; /* holds the info of the last frame we decoded or seeked to */ - FLAC__bool last_frame_is_set; - FLAC__uint64 first_frame_offset; /* hint to the seek routine of where in the stream the first audio frame starts */ - FLAC__uint64 last_seen_framesync; /* if tell callback works, the location of the last seen frame sync code, to rewind to if needed */ - FLAC__uint64 target_sample; - uint32_t unparseable_frame_count; /* used to tell whether we're decoding a future version of FLAC or just got a bad sync */ - FLAC__bool got_a_frame; /* hack needed in Ogg FLAC seek routine and find_total_samples to check when process_single() actually writes a frame */ - FLAC__bool (*local_bitreader_read_rice_signed_block)(FLAC__BitReader *br, int vals[], uint32_t nvals, uint32_t parameter); - FLAC__bool error_has_been_sent; /* To check whether a missing frame has been signalled yet */ -#if FLAC__HAS_OGG - FLAC__bool ogg_decoder_aspect_allocation_failure; -#endif -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - uint32_t fuzzing_rewind_count; /* To stop excessive rewinding, as it causes timeouts */ -#endif -} FLAC__StreamDecoderPrivate; - -/*********************************************************************** - * - * Public static class data - * - ***********************************************************************/ - -FLAC_API const char * const FLAC__StreamDecoderStateString[] = { - "FLAC__STREAM_DECODER_SEARCH_FOR_METADATA", - "FLAC__STREAM_DECODER_READ_METADATA", - "FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC", - "FLAC__STREAM_DECODER_READ_FRAME", - "FLAC__STREAM_DECODER_END_OF_STREAM", - "FLAC__STREAM_DECODER_OGG_ERROR", - "FLAC__STREAM_DECODER_SEEK_ERROR", - "FLAC__STREAM_DECODER_ABORTED", - "FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR", - "FLAC__STREAM_DECODER_UNINITIALIZED", - "FLAC__STREAM_DECODER_END_OF_LINK" -}; - -FLAC_API const char * const FLAC__StreamDecoderInitStatusString[] = { - "FLAC__STREAM_DECODER_INIT_STATUS_OK", - "FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER", - "FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS", - "FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR", - "FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE", - "FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED" -}; - -FLAC_API const char * const FLAC__StreamDecoderReadStatusString[] = { - "FLAC__STREAM_DECODER_READ_STATUS_CONTINUE", - "FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM", - "FLAC__STREAM_DECODER_READ_STATUS_ABORT", - "FLAC__STREAM_DECODER_READ_STATUS_END_OF_LINK" -}; - -FLAC_API const char * const FLAC__StreamDecoderSeekStatusString[] = { - "FLAC__STREAM_DECODER_SEEK_STATUS_OK", - "FLAC__STREAM_DECODER_SEEK_STATUS_ERROR", - "FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamDecoderTellStatusString[] = { - "FLAC__STREAM_DECODER_TELL_STATUS_OK", - "FLAC__STREAM_DECODER_TELL_STATUS_ERROR", - "FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamDecoderLengthStatusString[] = { - "FLAC__STREAM_DECODER_LENGTH_STATUS_OK", - "FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR", - "FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED" -}; - -FLAC_API const char * const FLAC__StreamDecoderWriteStatusString[] = { - "FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE", - "FLAC__STREAM_DECODER_WRITE_STATUS_ABORT" -}; - -FLAC_API const char * const FLAC__StreamDecoderErrorStatusString[] = { - "FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC", - "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER", - "FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH", - "FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM", - "FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA", - "FLAC__STREAM_DECODER_ERROR_STATUS_OUT_OF_BOUNDS", - "FLAC__STREAM_DECODER_ERROR_STATUS_MISSING_FRAME" -}; - -/*********************************************************************** - * - * Class constructor/destructor - * - ***********************************************************************/ -FLAC_API FLAC__StreamDecoder *FLAC__stream_decoder_new(void) -{ - FLAC__StreamDecoder *decoder; - uint32_t i; - - FLAC__ASSERT(sizeof(int) >= 4); /* we want to die right away if this is not true */ - - decoder = safe_calloc_(1, sizeof(FLAC__StreamDecoder)); - if(decoder == 0) { - return 0; - } - - decoder->protected_ = safe_calloc_(1, sizeof(FLAC__StreamDecoderProtected)); - if(decoder->protected_ == 0) { - free(decoder); - return 0; - } - - decoder->private_ = safe_calloc_(1, sizeof(FLAC__StreamDecoderPrivate)); - if(decoder->private_ == 0) { - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->input = FLAC__bitreader_new(); - if(decoder->private_->input == 0) { - free(decoder->private_); - free(decoder->protected_); - free(decoder); - return 0; - } - - decoder->private_->metadata_filter_ids_capacity = 16; - if(0 == (decoder->private_->metadata_filter_ids = malloc((FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) * decoder->private_->metadata_filter_ids_capacity))) { - FLAC__bitreader_delete(decoder->private_->input); - free(decoder->private_); - free(decoder->protected_); - free(decoder); - return 0; - } - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - decoder->private_->output[i] = 0; - decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; - } - - decoder->private_->side_subframe = 0; - - decoder->private_->output_capacity = 0; - decoder->private_->output_channels = 0; - decoder->private_->has_seek_table = false; - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) - FLAC__format_entropy_coding_method_partitioned_rice_contents_init(&decoder->private_->partitioned_rice_contents[i]); - -#if 0 /* bstone */ - decoder->private_->file = 0; -#endif /* bstone */ - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; - - return decoder; -} - -FLAC_API void FLAC__stream_decoder_delete(FLAC__StreamDecoder *decoder) -{ - uint32_t i; - - if (decoder == NULL) - return ; - - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->private_->input); - - (void)FLAC__stream_decoder_finish(decoder); - - if(0 != decoder->private_->metadata_filter_ids) - free(decoder->private_->metadata_filter_ids); - - FLAC__bitreader_delete(decoder->private_->input); - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) - FLAC__format_entropy_coding_method_partitioned_rice_contents_clear(&decoder->private_->partitioned_rice_contents[i]); - - free(decoder->private_); - free(decoder->protected_); - free(decoder); -} - -/*********************************************************************** - * - * Public class methods - * - ***********************************************************************/ - -static FLAC__StreamDecoderInitStatus init_stream_internal_( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FLAC__ASSERT(0 != decoder); - - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(FLAC__HAS_OGG == 0 && is_ogg) - return FLAC__STREAM_DECODER_INIT_STATUS_UNSUPPORTED_CONTAINER; - - if( - 0 == read_callback || - 0 == write_callback || - 0 == error_callback || - (seek_callback && (0 == tell_callback || 0 == length_callback || 0 == eof_callback)) - ) - return FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; - -#if FLAC__HAS_OGG - decoder->private_->is_ogg = is_ogg; - if(is_ogg && !FLAC__ogg_decoder_aspect_init(&decoder->protected_->ogg_decoder_aspect)) { - FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect); - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; - } -#endif - - FLAC__cpu_info(&decoder->private_->cpuinfo); - decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block; - -#ifdef FLAC__BMI2_SUPPORTED - if (decoder->private_->cpuinfo.x86.bmi2) { - decoder->private_->local_bitreader_read_rice_signed_block = FLAC__bitreader_read_rice_signed_block_bmi2; - } -#endif - - /* from here on, errors are fatal */ - - if(!FLAC__bitreader_init(decoder->private_->input, read_callback_, decoder)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; - } - - decoder->private_->read_callback = read_callback; - decoder->private_->seek_callback = seek_callback; - decoder->private_->tell_callback = tell_callback; - decoder->private_->length_callback = length_callback; - decoder->private_->eof_callback = eof_callback; - decoder->private_->write_callback = write_callback; - decoder->private_->metadata_callback = metadata_callback; - decoder->private_->error_callback = error_callback; - decoder->private_->client_data = client_data; - decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; - decoder->private_->samples_decoded = 0; - decoder->private_->has_stream_info = false; - decoder->private_->cached = false; - - decoder->private_->do_md5_checking = decoder->protected_->md5_checking; - decoder->private_->is_seeking = false; - decoder->private_->is_indexing = false; - - decoder->private_->internal_reset_hack = true; /* so the following reset does not try to rewind the input */ - if(!FLAC__stream_decoder_reset(decoder)) { - /* above call sets the state for us */ - return FLAC__STREAM_DECODER_INIT_STATUS_MEMORY_ALLOCATION_ERROR; - } - - return FLAC__STREAM_DECODER_INIT_STATUS_OK; -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_stream_internal_( - decoder, - read_callback, - seek_callback, - tell_callback, - length_callback, - eof_callback, - write_callback, - metadata_callback, - error_callback, - client_data, - /*is_ogg=*/false - ); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_stream( - FLAC__StreamDecoder *decoder, - FLAC__StreamDecoderReadCallback read_callback, - FLAC__StreamDecoderSeekCallback seek_callback, - FLAC__StreamDecoderTellCallback tell_callback, - FLAC__StreamDecoderLengthCallback length_callback, - FLAC__StreamDecoderEofCallback eof_callback, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_stream_internal_( - decoder, - read_callback, - seek_callback, - tell_callback, - length_callback, - eof_callback, - write_callback, - metadata_callback, - error_callback, - client_data, - /*is_ogg=*/true - ); -} - -#if 0 /* bstone */ -static FLAC__StreamDecoderInitStatus init_FILE_internal_( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != file); - - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(0 == write_callback || 0 == error_callback) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; - - /* - * To make sure that our file does not go unclosed after an error, we - * must assign the FILE pointer before any further error can occur in - * this routine. - */ - if(file == stdin) - file = get_binary_stdin_(); /* just to be safe */ - - decoder->private_->file = file; - - return init_stream_internal_( - decoder, - file_read_callback_, - decoder->private_->file == stdin? 0: file_seek_callback_, - decoder->private_->file == stdin? 0: file_tell_callback_, - decoder->private_->file == stdin? 0: file_length_callback_, - file_eof_callback_, - write_callback, - metadata_callback, - error_callback, - client_data, - is_ogg - ); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_FILE( - FLAC__StreamDecoder *decoder, - FILE *file, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); -} - -static FLAC__StreamDecoderInitStatus init_file_internal_( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data, - FLAC__bool is_ogg -) -{ - FILE *file; - - FLAC__ASSERT(0 != decoder); - - /* - * To make sure that our file does not go unclosed after an error, we - * have to do the same entrance checks here that are later performed - * in FLAC__stream_decoder_init_FILE() before the FILE* is assigned. - */ - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_ALREADY_INITIALIZED; - - if(0 == write_callback || 0 == error_callback) - return decoder->protected_->initstate = FLAC__STREAM_DECODER_INIT_STATUS_INVALID_CALLBACKS; - - file = filename? flac_fopen(filename, "rb") : stdin; - - if(0 == file) - return FLAC__STREAM_DECODER_INIT_STATUS_ERROR_OPENING_FILE; - - return init_FILE_internal_(decoder, file, write_callback, metadata_callback, error_callback, client_data, is_ogg); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/false); -} - -FLAC_API FLAC__StreamDecoderInitStatus FLAC__stream_decoder_init_ogg_file( - FLAC__StreamDecoder *decoder, - const char *filename, - FLAC__StreamDecoderWriteCallback write_callback, - FLAC__StreamDecoderMetadataCallback metadata_callback, - FLAC__StreamDecoderErrorCallback error_callback, - void *client_data -) -{ - return init_file_internal_(decoder, filename, write_callback, metadata_callback, error_callback, client_data, /*is_ogg=*/true); -} -#endif /* bstone */ - -FLAC_API FLAC__bool FLAC__stream_decoder_finish(FLAC__StreamDecoder *decoder) -{ - FLAC__bool md5_failed = false; - uint32_t i; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return true; - - /* see the comment in FLAC__stream_decoder_reset() as to why we - * always call FLAC__MD5Final() - */ - FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); - - free(decoder->private_->seek_table.data.seek_table.points); - decoder->private_->seek_table.data.seek_table.points = 0; - decoder->private_->has_seek_table = false; - - FLAC__bitreader_free(decoder->private_->input); - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - /* WATCHOUT: - * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN() - * require that the output arrays have a buffer of up to 3 zeroes - * in front (at negative indices) for alignment purposes; - * we use 4 to keep the data well-aligned. - */ - if(0 != decoder->private_->output[i]) { - free(decoder->private_->output[i]-4); - decoder->private_->output[i] = 0; - } - if(0 != decoder->private_->residual_unaligned[i]) { - free(decoder->private_->residual_unaligned[i]); - decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; - } - } - if(0 != decoder->private_->side_subframe) { - free(decoder->private_->side_subframe); - decoder->private_->side_subframe = 0; - } - decoder->private_->output_capacity = 0; - decoder->private_->output_channels = 0; - -#if FLAC__HAS_OGG - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_finish(&decoder->protected_->ogg_decoder_aspect); -#endif - -#if 0 /* bstone */ - if(0 != decoder->private_->file) { - if(decoder->private_->file != stdin) - fclose(decoder->private_->file); - decoder->private_->file = 0; - } -#endif /* bstone */ - - if(decoder->private_->do_md5_checking) { - if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16)) - md5_failed = true; - } - decoder->private_->is_seeking = false; - decoder->private_->is_indexing = false; - - set_defaults_(decoder); - - decoder->protected_->state = FLAC__STREAM_DECODER_UNINITIALIZED; - - return !md5_failed; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_ogg_serial_number(FLAC__StreamDecoder *decoder, long value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; -#if FLAC__HAS_OGG - /* can't check decoder->private_->is_ogg since that's not set until init time */ - FLAC__ogg_decoder_aspect_set_serial_number(&decoder->protected_->ogg_decoder_aspect, value); - return true; -#else - (void)value; - return false; -#endif -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_decode_chained_stream(FLAC__StreamDecoder* decoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - if (decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; -#if FLAC__HAS_OGG - FLAC__ogg_decoder_aspect_set_decode_chained_stream(&decoder->protected_->ogg_decoder_aspect, value); - return true; -#else - (void)value; - return false; -#endif -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_md5_checking(FLAC__StreamDecoder *decoder, FLAC__bool value) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - if(decoder->protected_->state != FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - decoder->protected_->md5_checking = value; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE); - /* double protection */ - if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE) - return false; - decoder->private_->metadata_filter[type] = true; - if(type == FLAC__METADATA_TYPE_APPLICATION) - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != id); - - if(decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) - return true; - - FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); - - if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { - if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - decoder->private_->metadata_filter_ids_capacity *= 2; - } - - memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); - decoder->private_->metadata_filter_ids_count++; - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_respond_all(FLAC__StreamDecoder *decoder) -{ - uint32_t i; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - for(i = 0; i < sizeof(decoder->private_->metadata_filter) / sizeof(decoder->private_->metadata_filter[0]); i++) - decoder->private_->metadata_filter[i] = true; - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore(FLAC__StreamDecoder *decoder, FLAC__MetadataType type) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT((uint32_t)type <= FLAC__MAX_METADATA_TYPE_CODE); - /* double protection */ - if((uint32_t)type > FLAC__MAX_METADATA_TYPE_CODE) - return false; - decoder->private_->metadata_filter[type] = false; - if(type == FLAC__METADATA_TYPE_APPLICATION) - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_application(FLAC__StreamDecoder *decoder, const FLAC__byte id[4]) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - FLAC__ASSERT(0 != id); - - if(!decoder->private_->metadata_filter[FLAC__METADATA_TYPE_APPLICATION]) - return true; - - FLAC__ASSERT(0 != decoder->private_->metadata_filter_ids); - - if(decoder->private_->metadata_filter_ids_count == decoder->private_->metadata_filter_ids_capacity) { - if(0 == (decoder->private_->metadata_filter_ids = safe_realloc_mul_2op_(decoder->private_->metadata_filter_ids, decoder->private_->metadata_filter_ids_capacity, /*times*/2))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - decoder->private_->metadata_filter_ids_capacity *= 2; - } - - memcpy(decoder->private_->metadata_filter_ids + decoder->private_->metadata_filter_ids_count * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)); - decoder->private_->metadata_filter_ids_count++; - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_set_metadata_ignore_all(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); - decoder->private_->metadata_filter_ids_count = 0; - return true; -} - -FLAC_API FLAC__StreamDecoderState FLAC__stream_decoder_get_state(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->state; -} - -FLAC_API const char *FLAC__stream_decoder_get_resolved_state_string(const FLAC__StreamDecoder *decoder) -{ - return FLAC__StreamDecoderStateString[decoder->protected_->state]; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_chained_stream(const FLAC__StreamDecoder* decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); -#if FLAC__HAS_OGG - return FLAC__ogg_decoder_aspect_get_decode_chained_stream(&decoder->protected_->ogg_decoder_aspect); -#else - (void)decoder; - return false; -#endif -} - -FLAC_API FLAC__bool FLAC__stream_decoder_get_md5_checking(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->md5_checking; -} - -FLAC_API FLAC__uint64 FLAC__stream_decoder_get_total_samples(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->private_->has_stream_info? decoder->private_->stream_info.data.stream_info.total_samples : 0; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_channels(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->channels; -} - -FLAC_API FLAC__ChannelAssignment FLAC__stream_decoder_get_channel_assignment(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->channel_assignment; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_bits_per_sample(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->bits_per_sample; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_sample_rate(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->sample_rate; -} - -FLAC_API uint32_t FLAC__stream_decoder_get_blocksize(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - return decoder->protected_->blocksize; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_get_decode_position(const FLAC__StreamDecoder *decoder, FLAC__uint64 *position) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != position); - - if(FLAC__HAS_OGG && decoder->private_->is_ogg) - return false; - - if(0 == decoder->private_->tell_callback) - return false; - if(decoder->private_->tell_callback(decoder, position, decoder->private_->client_data) != FLAC__STREAM_DECODER_TELL_STATUS_OK) - return false; - /* should never happen since all FLAC frames and metadata blocks are byte aligned, but check just in case */ - if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) - return false; - FLAC__ASSERT(*position >= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder)); - *position -= FLAC__stream_decoder_get_input_bytes_unconsumed(decoder); - return true; -} - -FLAC_API const void *FLAC__stream_decoder_get_client_data(FLAC__StreamDecoder *decoder) -{ - return decoder->private_->client_data; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_flush(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(!decoder->private_->internal_reset_hack && decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) - return false; - - decoder->private_->samples_decoded = 0; - decoder->private_->do_md5_checking = false; - decoder->private_->last_seen_framesync = 0; - decoder->private_->last_frame_is_set = false; - -#if FLAC__HAS_OGG - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_flush(&decoder->protected_->ogg_decoder_aspect); -#endif - - if(!FLAC__bitreader_clear(decoder->private_->input)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - - return true; -} - -void reset_decoder_internal_(FLAC__StreamDecoder* decoder) { - /* This code resets only the FLAC parser and decoder, not the Ogg part, - * nor the input buffering etc. This is used to prepare the FLAC - * decoder to receive another Ogg chain link */ - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; - - decoder->private_->has_stream_info = false; - - free(decoder->private_->seek_table.data.seek_table.points); - decoder->private_->seek_table.data.seek_table.points = 0; - decoder->private_->has_seek_table = false; - - decoder->private_->do_md5_checking = decoder->protected_->md5_checking; - /* - * This goes in reset() and not flush() because according to the spec, a - * fixed-blocksize stream must stay that way through the whole stream. - */ - decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size = 0; - - /* We initialize the FLAC__MD5Context even though we may never use it. This - * is because md5 checking may be turned on to start and then turned off if - * a seek occurs. So we init the context here and finalize it in - * FLAC__stream_decoder_finish() to make sure things are always cleaned up - * properly. - */ - if(!decoder->private_->internal_reset_hack) { - /* Only finish MD5 context when it has been initialized - * (i.e. when internal_reset_hack is not set) */ - FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); - } - else - decoder->private_->internal_reset_hack = false; - FLAC__MD5Init(&decoder->private_->md5context); - - decoder->private_->first_frame_offset = 0; - decoder->private_->unparseable_frame_count = 0; - decoder->private_->last_seen_framesync = 0; - decoder->private_->last_frame_is_set = false; - decoder->private_->error_has_been_sent = false; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_reset(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - -#if FLAC__HAS_OGG - /*@@@ could go in !internal_reset_hack block below */ - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_reset(&decoder->protected_->ogg_decoder_aspect); -#endif - - /* Rewind if necessary. If FLAC__stream_decoder_init() is calling us, - * (internal_reset_hack) don't try to rewind since we are already at - * the beginning of the stream and don't want to fail if the input is - * not seekable. - */ - if(!decoder->private_->internal_reset_hack) { -#if 0 /* bstone */ - if(decoder->private_->file == stdin) - return false; /* can't rewind stdin, reset fails */ -#endif /* bstone */ - if(decoder->private_->seek_callback && decoder->private_->seek_callback(decoder, 0, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) - return false; /* seekable and seek fails, reset fails */ - } - - reset_decoder_internal_(decoder); - - return true; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_single(FLAC__StreamDecoder *decoder) -{ - FLAC__bool got_a_frame; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - else - return true; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder)) { - return true; /* above function sets the status for us */ - } - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/true)) - return false; /* above function sets the status for us */ - if(got_a_frame) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_END_OF_LINK: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_metadata(FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - case FLAC__STREAM_DECODER_READ_FRAME: - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_END_OF_LINK: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_link(FLAC__StreamDecoder *decoder) -{ - FLAC__bool dummy; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder)) { - return true; /* above function sets the status for us */ - } - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_END_OF_LINK: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_finish_link(FLAC__StreamDecoder *decoder) -{ - FLAC__bool md5_failed = false; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - FLAC__ASSERT(0 != decoder->protected_); - - if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_LINK) { - FLAC__ASSERT(0); /* This function should not be called in any other state */ - return true; - } - - FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); - - if(decoder->private_->do_md5_checking) { - if(memcmp(decoder->private_->stream_info.data.stream_info.md5sum, decoder->private_->computed_md5sum, 16)) - md5_failed = true; - } - - reset_decoder_internal_(decoder); - -#if FLAC__HAS_OGG - if(decoder->private_->is_ogg) - FLAC__ogg_decoder_aspect_next_link(&decoder->protected_->ogg_decoder_aspect); -#endif - - return !md5_failed; -} - -FLAC_API FLAC__bool FLAC__stream_decoder_process_until_end_of_stream(FLAC__StreamDecoder *decoder) -{ - FLAC__bool dummy; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - if(!find_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_READ_METADATA: - if(!read_metadata_(decoder)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder) && decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_LINK && decoder->protected_->state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) { - return true; /* above function sets the status for us */ - } - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &dummy, /*do_full_decode=*/true)) - return false; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_LINK: - FLAC__stream_decoder_finish_link(decoder); - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_frame(FLAC__StreamDecoder *decoder) -{ - FLAC__bool got_a_frame; - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - while(1) { - switch(decoder->protected_->state) { - case FLAC__STREAM_DECODER_SEARCH_FOR_METADATA: - case FLAC__STREAM_DECODER_READ_METADATA: - return false; - case FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC: - if(!frame_sync_(decoder)) { - return true; /* above function sets the status for us */ - } - break; - case FLAC__STREAM_DECODER_READ_FRAME: - if(!read_frame_(decoder, &got_a_frame, /*do_full_decode=*/false)) - return false; /* above function sets the status for us */ - if(got_a_frame) - return true; /* above function sets the status for us */ - break; - case FLAC__STREAM_DECODER_END_OF_STREAM: - case FLAC__STREAM_DECODER_END_OF_LINK: - case FLAC__STREAM_DECODER_ABORTED: - return true; - default: - return false; - } - } -} - -FLAC_API FLAC__bool FLAC__stream_decoder_skip_single_link(FLAC__StreamDecoder *decoder) -{ -#if FLAC__HAS_OGG - FLAC__OggDecoderAspectReadStatus status; - FLAC__ASSERT_DECLARATION(FLAC__uint32 linknumber_start); - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->protected_); - - if(!decoder->private_->is_ogg || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED || - decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return false; - - FLAC__ASSERT_DECLARATION(linknumber_start = decoder->protected_->ogg_decoder_aspect.current_linknumber); - - if(!FLAC__bitreader_clear(decoder->private_->input)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - status = FLAC__ogg_decoder_aspect_skip_link(&decoder->protected_->ogg_decoder_aspect, read_callback_proxy_, decoder->private_->seek_callback, decoder->private_->tell_callback, decoder->private_->length_callback, decoder, decoder->private_->client_data); - if(status == FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM) { - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - return true; - } - else if(status == FLAC__OGG_DECODER_ASPECT_READ_STATUS_CALLBACKS_NONFUNCTIONAL) { - decoder->private_->is_seeking = true; - FLAC__stream_decoder_process_until_end_of_link(decoder); - if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_LINK) - FLAC__stream_decoder_finish_link(decoder); - decoder->private_->is_seeking = false; - } - else if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_OGG_ERROR; - return false; - } - else { - FLAC__MD5Final(decoder->private_->computed_md5sum, &decoder->private_->md5context); - reset_decoder_internal_(decoder); - } - - FLAC__ASSERT(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM || decoder->protected_->ogg_decoder_aspect.current_linknumber > linknumber_start); - return true; -#else - (void)decoder; - return false; -#endif -} - -FLAC_API FLAC__bool FLAC__stream_decoder_seek_absolute(FLAC__StreamDecoder *decoder, FLAC__uint64 sample) -{ - FLAC__uint64 length; - - FLAC__ASSERT(0 != decoder); - - if( - decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && - decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA && - decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && - decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME && - decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM - ) - return false; - - if(0 == decoder->private_->seek_callback) - return false; - - FLAC__ASSERT(decoder->private_->seek_callback); - FLAC__ASSERT(decoder->private_->tell_callback); - FLAC__ASSERT(decoder->private_->length_callback); - FLAC__ASSERT(decoder->private_->eof_callback); - - if(!FLAC__stream_decoder_get_decode_chained_stream(decoder) && FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) - return false; - - decoder->private_->is_seeking = true; - - /* turn off md5 checking if a seek is attempted */ - decoder->private_->do_md5_checking = false; - - /* get the file length (currently our algorithm needs to know the length so it's also an error to get FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED) */ - if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) { - decoder->private_->is_seeking = false; - return false; - } - - /* if we haven't finished processing the metadata yet, do that so we have the STREAMINFO, SEEK_TABLE, and first_frame_offset */ - if( - decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_METADATA || - decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA - ) { - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) { - /* above call sets the state for us */ - decoder->private_->is_seeking = false; - return false; - } - /* check this again in case we didn't know total_samples the first time */ - if(FLAC__stream_decoder_get_total_samples(decoder) > 0 && sample >= FLAC__stream_decoder_get_total_samples(decoder)) { - decoder->private_->is_seeking = false; - return false; - } - } - - { - const FLAC__bool ok = -#if FLAC__HAS_OGG - decoder->private_->is_ogg? - seek_to_absolute_sample_ogg_(decoder, length, sample) : -#endif - seek_to_absolute_sample_(decoder, length, sample) - ; - decoder->private_->is_seeking = false; - return ok; - } -} - -FLAC_API FLAC__uint64 FLAC__stream_decoder_find_total_samples(FLAC__StreamDecoder *decoder) -{ - if( - decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_METADATA && - decoder->protected_->state != FLAC__STREAM_DECODER_READ_METADATA && - decoder->protected_->state != FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && - decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME && - decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM - ) - return 0; - - if( - decoder->private_->length_callback == NULL || - decoder->private_->seek_callback == NULL || - decoder->private_->tell_callback == NULL - ) - return 0; - -#if FLAC__HAS_OGG - if(decoder->private_->is_ogg && FLAC__ogg_decoder_aspect_get_decode_chained_stream(&decoder->protected_->ogg_decoder_aspect)) { - /* Keep moving forward until reaching end-of-stream */ - uint32_t i; - FLAC__uint64 total_samples = 0; - decoder->private_->is_indexing = true; - while(1) { - FLAC__OggDecoderAspectReadStatus status; - if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM || - decoder->protected_->state == FLAC__STREAM_DECODER_OGG_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - decoder->private_->is_indexing = false; - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return 0; - } - status = FLAC__ogg_decoder_aspect_skip_link(&decoder->protected_->ogg_decoder_aspect, read_callback_proxy_, decoder->private_->seek_callback, decoder->private_->tell_callback, decoder->private_->length_callback, decoder, decoder->private_->client_data); - if(status == FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM) - break; - else if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return 0; - } - } - decoder->private_->is_indexing = false; - for(i = 0; i < decoder->protected_->ogg_decoder_aspect.number_of_links_indexed; i++) { - total_samples += decoder->protected_->ogg_decoder_aspect.linkdetails[i].samples; - } - return total_samples; - } - else -#endif /* FLAC__HAS_OGG */ - { /* not decoding chained ogg */ - FLAC__uint64 length; - FLAC__uint64 pos; - uint32_t eof_distance = 1024; /* Some number, needs tuning */ - decoder->private_->is_seeking = true; - decoder->private_->target_sample = UINT64_MAX; - /* get the file length */ - if(decoder->private_->length_callback(decoder, &length, decoder->private_->client_data) != FLAC__STREAM_DECODER_LENGTH_STATUS_OK) { - decoder->private_->is_indexing = false; - return 0; - } - pos = length; - for( ; ; eof_distance *= 2) { - if(eof_distance > (1u << FLAC__STREAM_METADATA_LENGTH_LEN)) { - /* Could not find a frame within a reasonable distance of EOF */ - return 0; - } - else if(pos == 0) { - /* Did not find a frame while reading from the start of the file */ - return 0; - } - else if(eof_distance > length) { - pos = 0; - } - else { - pos = length - eof_distance; - } - - if(decoder->private_->seek_callback(decoder, pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return 0; - } - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return 0; - } - - decoder->private_->got_a_frame = false; - if(!FLAC__stream_decoder_process_single(decoder) || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->protected_->state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return 0; - } - if(decoder->private_->got_a_frame) { - /* Found a frame, but we need the last frame and the frame before that, unless the last frame is - * also the first frame */ - if(decoder->private_->frame.header.number.sample_number > 0) { - /* For now, assume this is not the last frame, set blocksize, and continue. - * If it turns out this is not the last frame, we'll start over anyway */ - decoder->private_->fixed_block_size = decoder->private_->last_frame.header.blocksize; - if(!FLAC__stream_decoder_process_single(decoder) || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->protected_->state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return 0; - } - if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) { - /* Found last frame, but need to find frame before that too */ - continue; - } - } - if(!FLAC__stream_decoder_process_until_end_of_stream(decoder)) - return 0; - FLAC__ASSERT(decoder->private_->is_seeking); - FLAC__ASSERT(decoder->private_->last_frame_is_set); - decoder->private_->is_seeking = false; - return (FLAC__uint64)decoder->private_->last_frame.header.number.sample_number + (FLAC__uint64)decoder->private_->last_frame.header.blocksize; - - } - } - } - return 0; -} - -FLAC_API int32_t FLAC__stream_decoder_get_link_lengths(FLAC__StreamDecoder *decoder, FLAC__uint64 **link_lengths) -{ - /* If we don't have Ogg, this is (for now) useless, fail */ -#if FLAC__HAS_OGG - uint32_t i; - - /* Check whether we're decoding chaines ogg, and decoder is somewhat valid */ - if(!decoder->private_->is_ogg || - !FLAC__stream_decoder_get_decode_chained_stream(decoder) || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED || - decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_UNINITIALIZED) - return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID; - - /* Check whether link details are known. If not, fail */ - if(decoder->protected_->ogg_decoder_aspect.number_of_links_indexed == 0 || - !decoder->protected_->ogg_decoder_aspect.linkdetails[decoder->protected_->ogg_decoder_aspect.number_of_links_indexed - 1].is_last) - return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_NOT_INDEXED; - - if(link_lengths != NULL) { - *link_lengths = safe_malloc_mul_2op_p(sizeof(FLAC__uint64), decoder->protected_->ogg_decoder_aspect.number_of_links_indexed); - if(*link_lengths == NULL) - return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_MEMORY_ALLOCATION_ERROR; - - for(i = 0; i < decoder->protected_->ogg_decoder_aspect.number_of_links_indexed; i++) - (*link_lengths)[i] = decoder->protected_->ogg_decoder_aspect.linkdetails[i].samples; - } - - return decoder->protected_->ogg_decoder_aspect.number_of_links_indexed; -#else - (void)decoder; - (void)link_lengths; - return FLAC__STREAM_DECODER_GET_LINK_LENGTHS_INVALID; -#endif -} - - -/*********************************************************************** - * - * Protected class methods - * - ***********************************************************************/ - -uint32_t FLAC__stream_decoder_get_input_bytes_unconsumed(const FLAC__StreamDecoder *decoder) -{ - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - FLAC__ASSERT(!(FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) & 7)); - return FLAC__bitreader_get_input_bits_unconsumed(decoder->private_->input) / 8; -} - -/*********************************************************************** - * - * Private class methods - * - ***********************************************************************/ - -void set_defaults_(FLAC__StreamDecoder *decoder) -{ - decoder->private_->is_ogg = false; - decoder->private_->read_callback = 0; - decoder->private_->seek_callback = 0; - decoder->private_->tell_callback = 0; - decoder->private_->length_callback = 0; - decoder->private_->eof_callback = 0; - decoder->private_->write_callback = 0; - decoder->private_->metadata_callback = 0; - decoder->private_->error_callback = 0; - decoder->private_->client_data = 0; - - memset(decoder->private_->metadata_filter, 0, sizeof(decoder->private_->metadata_filter)); - decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] = true; - decoder->private_->metadata_filter_ids_count = 0; - - decoder->protected_->md5_checking = false; - -#if FLAC__HAS_OGG - FLAC__ogg_decoder_aspect_set_defaults(&decoder->protected_->ogg_decoder_aspect); -#endif -} - -#if 0 /* bstone */ -/* - * This will forcibly set stdin to binary mode (for OSes that require it) - */ -FILE *get_binary_stdin_(void) -{ - /* if something breaks here it is probably due to the presence or - * absence of an underscore before the identifiers 'setmode', - * 'fileno', and/or 'O_BINARY'; check your system header files. - */ -#if defined _MSC_VER || defined __MINGW32__ - _setmode(_fileno(stdin), _O_BINARY); -#elif defined __EMX__ - setmode(fileno(stdin), O_BINARY); -#endif - - return stdin; -} -#endif /* bstone */ - -FLAC__bool allocate_output_(FLAC__StreamDecoder *decoder, uint32_t size, uint32_t channels, uint32_t bps) -{ - uint32_t i; - FLAC__int32 *tmp; - - if(size <= decoder->private_->output_capacity && channels <= decoder->private_->output_channels && - (bps < 32 || decoder->private_->side_subframe != 0)) - return true; - - /* simply using realloc() is not practical because the number of channels may change mid-stream */ - - for(i = 0; i < FLAC__MAX_CHANNELS; i++) { - if(0 != decoder->private_->output[i]) { - free(decoder->private_->output[i]-4); - decoder->private_->output[i] = 0; - } - if(0 != decoder->private_->residual_unaligned[i]) { - free(decoder->private_->residual_unaligned[i]); - decoder->private_->residual_unaligned[i] = decoder->private_->residual[i] = 0; - } - } - - if(0 != decoder->private_->side_subframe) { - free(decoder->private_->side_subframe); - decoder->private_->side_subframe = 0; - } - - /* Only grow per-channel buffers, even if number of channels increases */ - if(decoder->private_->output_capacity > size) { - size = decoder->private_->output_capacity; - } - - for(i = 0; i < channels; i++) { - /* WATCHOUT: - * FLAC__lpc_restore_signal_asm_ia32_mmx() and ..._intrin_sseN() - * require that the output arrays have a buffer of up to 3 zeroes - * in front (at negative indices) for alignment purposes; - * we use 4 to keep the data well-aligned. - */ - tmp = safe_malloc_muladd2_(sizeof(FLAC__int32), /*times (*/size, /*+*/4/*)*/); - if(tmp == 0) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - memset(tmp, 0, sizeof(FLAC__int32)*4); - decoder->private_->output[i] = tmp + 4; - - if(!FLAC__memory_alloc_aligned_int32_array(size, &decoder->private_->residual_unaligned[i], &decoder->private_->residual[i])) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - } - - if(bps == 32) { - decoder->private_->side_subframe = safe_malloc_mul_2op_p(sizeof(FLAC__int64), /*times (*/size); - if(decoder->private_->side_subframe == NULL) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - } - - decoder->private_->output_capacity = size; - decoder->private_->output_channels = channels; - - return true; -} - -FLAC__bool has_id_filtered_(FLAC__StreamDecoder *decoder, FLAC__byte *id) -{ - size_t i; - - FLAC__ASSERT(0 != decoder); - FLAC__ASSERT(0 != decoder->private_); - - for(i = 0; i < decoder->private_->metadata_filter_ids_count; i++) - if(0 == memcmp(decoder->private_->metadata_filter_ids + i * (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8), id, (FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8))) - return true; - - return false; -} - -FLAC__bool find_metadata_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - uint32_t i, id; - FLAC__bool first = true; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - for(i = id = 0; i < 4; ) { - if(decoder->private_->cached) { - x = (FLAC__uint32)decoder->private_->lookahead; - decoder->private_->cached = false; - } - else { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - } - if(x == FLAC__STREAM_SYNC_STRING[i]) { - first = true; - i++; - id = 0; - continue; - } - - if(id >= 3) - return false; - - if(x == ID3V2_TAG_[id]) { - id++; - i = 0; - if(id == 3) { - if(!skip_id3v2_tag_(decoder)) - return false; /* skip_id3v2_tag_ sets the state for us */ - } - continue; - } - id = 0; - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->header_warmup[0] = (FLAC__byte)x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - - /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ - /* else we have to check if the second byte is the end of a sync code */ - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->lookahead = (FLAC__byte)x; - decoder->private_->cached = true; - } - else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ - decoder->private_->header_warmup[1] = (FLAC__byte)x; - decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; - return true; - } - } - i = 0; - if(first) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - first = false; - } - } - - decoder->protected_->state = FLAC__STREAM_DECODER_READ_METADATA; - return true; -} - -FLAC__bool read_metadata_(FLAC__StreamDecoder *decoder) -{ - FLAC__bool is_last; - FLAC__uint32 i, x, type, length; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_IS_LAST_LEN)) - return false; /* read_callback_ sets the state for us */ - is_last = x? true : false; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &type, FLAC__STREAM_METADATA_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &length, FLAC__STREAM_METADATA_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(type == FLAC__METADATA_TYPE_STREAMINFO) { - if(!read_metadata_streaminfo_(decoder, is_last, length)) - return false; - - decoder->private_->has_stream_info = true; - if(0 == memcmp(decoder->private_->stream_info.data.stream_info.md5sum, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 16)) - decoder->private_->do_md5_checking = false; - if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_STREAMINFO] && decoder->private_->metadata_callback) - decoder->private_->metadata_callback(decoder, &decoder->private_->stream_info, decoder->private_->client_data); - } - else if(type == FLAC__METADATA_TYPE_SEEKTABLE) { - /* just in case we already have a seek table, and reading the next one fails: */ - decoder->private_->has_seek_table = false; - - if(length > 0) { - if(!read_metadata_seektable_(decoder, is_last, length)) - return false; - - decoder->private_->has_seek_table = true; - if(!decoder->private_->is_seeking && decoder->private_->metadata_filter[FLAC__METADATA_TYPE_SEEKTABLE] && decoder->private_->metadata_callback) - decoder->private_->metadata_callback(decoder, &decoder->private_->seek_table, decoder->private_->client_data); - } - } - else { - FLAC__bool skip_it = !decoder->private_->metadata_filter[type]; - uint32_t real_length = length; - FLAC__StreamMetadata block; - - memset(&block, 0, sizeof(block)); - block.is_last = is_last; - block.type = (FLAC__MetadataType)type; - block.length = length; - - if(type == FLAC__METADATA_TYPE_APPLICATION) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.id, FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8)) - return false; /* read_callback_ sets the state for us */ - - if(real_length < FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8) { /* underflow check */ - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR;/*@@@@@@ maybe wrong error? need to resync?*/ - return false; - } - - real_length -= FLAC__STREAM_METADATA_APPLICATION_ID_LEN/8; - - if(decoder->private_->metadata_filter_ids_count > 0 && has_id_filtered_(decoder, block.data.application.id)) - skip_it = !skip_it; - } - - if(skip_it) { - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) - return false; /* read_callback_ sets the state for us */ - } - else { - FLAC__bool ok = true; - FLAC__bitreader_set_limit(decoder->private_->input, real_length*8); - switch(type) { - case FLAC__METADATA_TYPE_PADDING: - /* skip the padding bytes */ - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, real_length)) - ok = false; /* read_callback_ sets the state for us */ - break; - case FLAC__METADATA_TYPE_APPLICATION: - /* remember, we read the ID already */ - if(real_length > 0) { - if(0 == (block.data.application.data = malloc(real_length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - ok = false; - } - else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.application.data, real_length)) - ok = false; /* read_callback_ sets the state for us */ - } - else - block.data.application.data = 0; - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(!read_metadata_vorbiscomment_(decoder, &block.data.vorbis_comment, real_length)) - ok = false; - break; - case FLAC__METADATA_TYPE_CUESHEET: - if(!read_metadata_cuesheet_(decoder, &block.data.cue_sheet)) - ok = false; - break; - case FLAC__METADATA_TYPE_PICTURE: - if(!read_metadata_picture_(decoder, &block.data.picture)) - ok = false; - break; - case FLAC__METADATA_TYPE_STREAMINFO: - case FLAC__METADATA_TYPE_SEEKTABLE: - FLAC__ASSERT(0); - break; - default: - if(real_length > 0) { - if(0 == (block.data.unknown.data = malloc(real_length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - ok = false; - } - else if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, block.data.unknown.data, real_length)) - ok = false; /* read_callback_ sets the state for us */ - } - else - block.data.unknown.data = 0; - break; - } - if(FLAC__bitreader_limit_remaining(decoder->private_->input) > 0) { - /* Content in metadata block didn't fit in block length - * We cannot know whether the length or the content was - * corrupt, so stop parsing metadata */ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_METADATA); - if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_METADATA) - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - ok = false; - } - FLAC__bitreader_remove_limit(decoder->private_->input); - if(ok && !decoder->private_->is_seeking && decoder->private_->metadata_callback) - decoder->private_->metadata_callback(decoder, &block, decoder->private_->client_data); - - /* now we have to free any malloc()ed data in the block */ - switch(type) { - case FLAC__METADATA_TYPE_PADDING: - break; - case FLAC__METADATA_TYPE_APPLICATION: - if(0 != block.data.application.data) - free(block.data.application.data); - break; - case FLAC__METADATA_TYPE_VORBIS_COMMENT: - if(0 != block.data.vorbis_comment.vendor_string.entry) - free(block.data.vorbis_comment.vendor_string.entry); - if(block.data.vorbis_comment.num_comments > 0) - for(i = 0; i < block.data.vorbis_comment.num_comments; i++) - if(0 != block.data.vorbis_comment.comments[i].entry) - free(block.data.vorbis_comment.comments[i].entry); - if(0 != block.data.vorbis_comment.comments) - free(block.data.vorbis_comment.comments); - break; - case FLAC__METADATA_TYPE_CUESHEET: - if(block.data.cue_sheet.num_tracks > 0 && 0 != block.data.cue_sheet.tracks) - for(i = 0; i < block.data.cue_sheet.num_tracks; i++) - if(0 != block.data.cue_sheet.tracks[i].indices) - free(block.data.cue_sheet.tracks[i].indices); - if(0 != block.data.cue_sheet.tracks) - free(block.data.cue_sheet.tracks); - break; - case FLAC__METADATA_TYPE_PICTURE: - if(0 != block.data.picture.mime_type) - free(block.data.picture.mime_type); - if(0 != block.data.picture.description) - free(block.data.picture.description); - if(0 != block.data.picture.data) - free(block.data.picture.data); - break; - case FLAC__METADATA_TYPE_STREAMINFO: - case FLAC__METADATA_TYPE_SEEKTABLE: - FLAC__ASSERT(0); - default: - if(0 != block.data.unknown.data) - free(block.data.unknown.data); - break; - } - - if(!ok) /* anything that unsets "ok" should also make sure decoder->protected_->state is updated */ - return false; - } - } - - if(is_last) { - /* if this fails, it's OK, it's just a hint for the seek routine */ - if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->first_frame_offset)) - decoder->private_->first_frame_offset = 0; - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - } - - return true; -} - -FLAC__bool read_metadata_streaminfo_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length) -{ - FLAC__uint32 x; - uint32_t bits, used_bits = 0; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - decoder->private_->stream_info.type = FLAC__METADATA_TYPE_STREAMINFO; - decoder->private_->stream_info.is_last = is_last; - decoder->private_->stream_info.length = length; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_BLOCK_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, bits)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.min_blocksize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_BLOCK_SIZE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.max_blocksize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MIN_FRAME_SIZE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.min_framesize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_MAX_FRAME_SIZE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.max_framesize = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_SAMPLE_RATE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.sample_rate = x; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_CHANNELS_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.channels = x+1; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_STREAMINFO_BITS_PER_SAMPLE_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->stream_info.data.stream_info.bits_per_sample = x+1; - used_bits += bits; - - bits = FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN; - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &decoder->private_->stream_info.data.stream_info.total_samples, FLAC__STREAM_METADATA_STREAMINFO_TOTAL_SAMPLES_LEN)) - return false; /* read_callback_ sets the state for us */ - used_bits += bits; - - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, decoder->private_->stream_info.data.stream_info.md5sum, 16)) - return false; /* read_callback_ sets the state for us */ - used_bits += 16*8; - - /* skip the rest of the block */ - FLAC__ASSERT(used_bits % 8 == 0); - if (length < (used_bits / 8)) - return false; /* read_callback_ sets the state for us */ - length -= (used_bits / 8); - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, length)) - return false; /* read_callback_ sets the state for us */ - - return true; -} - -FLAC__bool read_metadata_seektable_(FLAC__StreamDecoder *decoder, FLAC__bool is_last, uint32_t length) -{ - FLAC__uint32 i, x; - FLAC__uint64 xx; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - decoder->private_->seek_table.type = FLAC__METADATA_TYPE_SEEKTABLE; - decoder->private_->seek_table.is_last = is_last; - decoder->private_->seek_table.length = length; - - if(length % FLAC__STREAM_METADATA_SEEKPOINT_LENGTH) { - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - - decoder->private_->seek_table.data.seek_table.num_points = length / FLAC__STREAM_METADATA_SEEKPOINT_LENGTH; - - /* use realloc since we may pass through here several times (e.g. after seeking) */ - if(0 == (decoder->private_->seek_table.data.seek_table.points = safe_realloc_mul_2op_(decoder->private_->seek_table.data.seek_table.points, decoder->private_->seek_table.data.seek_table.num_points, /*times*/sizeof(FLAC__StreamMetadata_SeekPoint)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(i = 0; i < decoder->private_->seek_table.data.seek_table.num_points; i++) { - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_SAMPLE_NUMBER_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->seek_table.data.seek_table.points[i].sample_number = xx; - - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &xx, FLAC__STREAM_METADATA_SEEKPOINT_STREAM_OFFSET_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->seek_table.data.seek_table.points[i].stream_offset = xx; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_SEEKPOINT_FRAME_SAMPLES_LEN)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->seek_table.data.seek_table.points[i].frame_samples = x; - } - length -= (decoder->private_->seek_table.data.seek_table.num_points * FLAC__STREAM_METADATA_SEEKPOINT_LENGTH); - - FLAC__ASSERT(length == 0); - - return true; -} - -FLAC__bool read_metadata_vorbiscomment_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_VorbisComment *obj, uint32_t length) -{ - FLAC__uint32 i; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - /* read vendor string */ - if (length >= 8) { - length -= 8; /* vendor string length + num comments entries alone take 8 bytes */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); - if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->vendor_string.length)) - return false; /* read_callback_ sets the state for us */ - if (length < obj->vendor_string.length) { - obj->vendor_string.length = 0; - obj->vendor_string.entry = 0; - goto skip; - } - else - length -= obj->vendor_string.length; - if (0 == (obj->vendor_string.entry = safe_malloc_add_2op_(obj->vendor_string.length, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->vendor_string.entry, obj->vendor_string.length)) - return false; /* read_callback_ sets the state for us */ - obj->vendor_string.entry[obj->vendor_string.length] = '\0'; - - /* read num comments */ - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_NUM_COMMENTS_LEN == 32); - if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->num_comments)) - return false; /* read_callback_ sets the state for us */ - - /* read comments */ - if (obj->num_comments > 100000) { - /* Possibly malicious file. */ - obj->num_comments = 0; - return false; - } - if (obj->num_comments > 0) { - if (0 == (obj->comments = safe_malloc_mul_2op_p(obj->num_comments, /*times*/sizeof(FLAC__StreamMetadata_VorbisComment_Entry)))) { - obj->num_comments = 0; - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for (i = 0; i < obj->num_comments; i++) { - /* Initialize here just to make sure. */ - obj->comments[i].length = 0; - obj->comments[i].entry = 0; - - FLAC__ASSERT(FLAC__STREAM_METADATA_VORBIS_COMMENT_ENTRY_LENGTH_LEN == 32); - if (length < 4) { - obj->num_comments = i; - goto skip; - } - else - length -= 4; - if (!FLAC__bitreader_read_uint32_little_endian(decoder->private_->input, &obj->comments[i].length)) { - obj->num_comments = i; - return false; /* read_callback_ sets the state for us */ - } - if (length < obj->comments[i].length) { - obj->num_comments = i; - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - else - length -= obj->comments[i].length; - if (0 == (obj->comments[i].entry = safe_malloc_add_2op_(obj->comments[i].length, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - obj->num_comments = i; - return false; - } - memset (obj->comments[i].entry, 0, obj->comments[i].length) ; - if (!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->comments[i].entry, obj->comments[i].length)) { - /* Current i-th entry is bad, so we delete it. */ - free (obj->comments[i].entry) ; - obj->comments[i].entry = NULL ; - obj->num_comments = i; - goto skip; - } - obj->comments[i].entry[obj->comments[i].length] = '\0'; - } - } - } - else { - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - - skip: - if (length > 0) { - /* length > 0 can only happen on files with invalid data in comments */ - if(obj->num_comments < 1) { - free(obj->comments); - obj->comments = NULL; - } - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - - return true; -} - -FLAC__bool read_metadata_cuesheet_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_CueSheet *obj) -{ - FLAC__uint32 i, j, x; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - memset(obj, 0, sizeof(FLAC__StreamMetadata_CueSheet)); - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN % 8 == 0); - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->media_catalog_number, FLAC__STREAM_METADATA_CUESHEET_MEDIA_CATALOG_NUMBER_LEN/8)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &obj->lead_in, FLAC__STREAM_METADATA_CUESHEET_LEAD_IN_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_IS_CD_LEN)) - return false; /* read_callback_ sets the state for us */ - obj->is_cd = x? true : false; - - if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_RESERVED_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_NUM_TRACKS_LEN)) - return false; /* read_callback_ sets the state for us */ - obj->num_tracks = x; - - if(obj->num_tracks > 0) { - if(0 == (obj->tracks = safe_calloc_(obj->num_tracks, sizeof(FLAC__StreamMetadata_CueSheet_Track)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(i = 0; i < obj->num_tracks; i++) { - FLAC__StreamMetadata_CueSheet_Track *track = &obj->tracks[i]; - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &track->offset, FLAC__STREAM_METADATA_CUESHEET_TRACK_OFFSET_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUMBER_LEN)) - return false; /* read_callback_ sets the state for us */ - track->number = (FLAC__byte)x; - - FLAC__ASSERT(FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN % 8 == 0); - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)track->isrc, FLAC__STREAM_METADATA_CUESHEET_TRACK_ISRC_LEN/8)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - track->type = x; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_PRE_EMPHASIS_LEN)) - return false; /* read_callback_ sets the state for us */ - track->pre_emphasis = x; - - if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_TRACK_RESERVED_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_TRACK_NUM_INDICES_LEN)) - return false; /* read_callback_ sets the state for us */ - track->num_indices = (FLAC__byte)x; - - if(track->num_indices > 0) { - if(0 == (track->indices = safe_calloc_(track->num_indices, sizeof(FLAC__StreamMetadata_CueSheet_Index)))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - for(j = 0; j < track->num_indices; j++) { - FLAC__StreamMetadata_CueSheet_Index *indx = &track->indices[j]; - if(!FLAC__bitreader_read_raw_uint64(decoder->private_->input, &indx->offset, FLAC__STREAM_METADATA_CUESHEET_INDEX_OFFSET_LEN)) - return false; /* read_callback_ sets the state for us */ - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_CUESHEET_INDEX_NUMBER_LEN)) - return false; /* read_callback_ sets the state for us */ - indx->number = (FLAC__byte)x; - - if(!FLAC__bitreader_skip_bits_no_crc(decoder->private_->input, FLAC__STREAM_METADATA_CUESHEET_INDEX_RESERVED_LEN)) - return false; /* read_callback_ sets the state for us */ - } - } - } - } - else { /* obj->num_tracks == 0 */ - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - - return true; -} - -FLAC__bool read_metadata_picture_(FLAC__StreamDecoder *decoder, FLAC__StreamMetadata_Picture *obj) -{ - FLAC__uint32 x; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - /* read type */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - if(x < FLAC__STREAM_METADATA_PICTURE_TYPE_UNDEFINED) - obj->type = x; - else - obj->type = FLAC__STREAM_METADATA_PICTURE_TYPE_OTHER; - - /* read MIME type */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_MIME_TYPE_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - if(FLAC__bitreader_limit_remaining(decoder->private_->input) < x){ - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - if(0 == (obj->mime_type = safe_malloc_add_2op_(x, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if(x > 0) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, (FLAC__byte*)obj->mime_type, x)) - return false; /* read_callback_ sets the state for us */ - } - obj->mime_type[x] = '\0'; - - /* read description */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__STREAM_METADATA_PICTURE_DESCRIPTION_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - if(FLAC__bitreader_limit_remaining(decoder->private_->input) < x){ - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - if(0 == (obj->description = safe_malloc_add_2op_(x, /*+*/1))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if(x > 0) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->description, x)) - return false; /* read_callback_ sets the state for us */ - } - obj->description[x] = '\0'; - - /* read width */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->width, FLAC__STREAM_METADATA_PICTURE_WIDTH_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read height */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->height, FLAC__STREAM_METADATA_PICTURE_HEIGHT_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read depth */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->depth, FLAC__STREAM_METADATA_PICTURE_DEPTH_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read colors */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &obj->colors, FLAC__STREAM_METADATA_PICTURE_COLORS_LEN)) - return false; /* read_callback_ sets the state for us */ - - /* read data */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &(obj->data_length), FLAC__STREAM_METADATA_PICTURE_DATA_LENGTH_LEN)) - return false; /* read_callback_ sets the state for us */ - if(FLAC__bitreader_limit_remaining(decoder->private_->input) < obj->data_length){ - FLAC__bitreader_limit_invalidate(decoder->private_->input); - return false; - } - if(0 == (obj->data = safe_malloc_(obj->data_length))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - if(obj->data_length > 0) { - if(!FLAC__bitreader_read_byte_block_aligned_no_crc(decoder->private_->input, obj->data, obj->data_length)) - return false; /* read_callback_ sets the state for us */ - } - - return true; -} - -FLAC__bool skip_id3v2_tag_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - uint32_t i, skip; - - /* skip the version and flags bytes */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 24)) - return false; /* read_callback_ sets the state for us */ - /* get the size (in bytes) to skip */ - skip = 0; - for(i = 0; i < 4; i++) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - skip <<= 7; - skip |= (x & 0x7f); - } - /* skip the rest of the tag */ - if(!FLAC__bitreader_skip_byte_block_aligned_no_crc(decoder->private_->input, skip)) - return false; /* read_callback_ sets the state for us */ - return true; -} - -FLAC__bool frame_sync_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - FLAC__bool first = true; - - /* make sure we're byte aligned */ - if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) - return false; /* read_callback_ sets the state for us */ - } - - while(1) { - if(decoder->private_->cached) { - x = (FLAC__uint32)decoder->private_->lookahead; - decoder->private_->cached = false; - } - else { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - } - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->header_warmup[0] = (FLAC__byte)x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - - /* we have to check if we just read two 0xff's in a row; the second may actually be the beginning of the sync code */ - /* else we have to check if the second byte is the end of a sync code */ - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - decoder->private_->lookahead = (FLAC__byte)x; - decoder->private_->cached = true; - } - else if(x >> 1 == 0x7c) { /* MAGIC NUMBER for the last 6 sync bits and reserved 7th bit */ - decoder->private_->header_warmup[1] = (FLAC__byte)x; - decoder->protected_->state = FLAC__STREAM_DECODER_READ_FRAME; - - /* Save location so we can rewind in case the frame turns - * out to be invalid after the header */ - FLAC__bitreader_set_framesync_location(decoder->private_->input); - if(!FLAC__stream_decoder_get_decode_position(decoder, &decoder->private_->last_seen_framesync)) - decoder->private_->last_seen_framesync = 0; - return true; - } - } - if(first) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - first = false; - } - } - - return true; -} - -FLAC__bool read_frame_(FLAC__StreamDecoder *decoder, FLAC__bool *got_a_frame, FLAC__bool do_full_decode) -{ - uint32_t channel; - uint32_t i; - uint32_t frame_crc; /* the one we calculate from the input stream */ - FLAC__uint32 x; - - *got_a_frame = false; - decoder->private_->side_subframe_in_use = false; - - /* init the CRC */ - frame_crc = 0; - frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[0], frame_crc); - frame_crc = FLAC__CRC16_UPDATE(decoder->private_->header_warmup[1], frame_crc); - FLAC__bitreader_reset_read_crc16(decoder->private_->input, (FLAC__uint16)frame_crc); - - if(!read_frame_header_(decoder)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means we didn't sync on a valid header */ - return true; - if(!allocate_output_(decoder, decoder->private_->frame.header.blocksize, decoder->private_->frame.header.channels, decoder->private_->frame.header.bits_per_sample)) - return false; - for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { - /* - * first figure the correct bits-per-sample of the subframe - */ - uint32_t bps = decoder->private_->frame.header.bits_per_sample; - switch(decoder->private_->frame.header.channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - /* no adjustment needed */ - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - if(channel == 1) - bps++; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - if(channel == 0) - bps++; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - if(channel == 1) - bps++; - break; - default: - FLAC__ASSERT(0); - } - /* - * now read it - */ - if(!read_subframe_(decoder, channel, bps, do_full_decode)){ - /* read_callback_ sets the state for us */ - if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) - break; - else - return false; - } - if(decoder->protected_->state != FLAC__STREAM_DECODER_READ_FRAME) - break; - } - - if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM) - if(!read_zero_padding_(decoder)) - return false; - - /* - * Read the frame CRC-16 from the footer and check - */ - if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) { - frame_crc = FLAC__bitreader_get_read_crc16(decoder->private_->input); - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, FLAC__FRAME_FOOTER_CRC_LEN)) { - /* read_callback_ sets the state for us */ - if(decoder->protected_->state != FLAC__STREAM_DECODER_END_OF_STREAM) - return false; - } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - } - if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME && frame_crc == x) { -#endif - if(do_full_decode) { - /* Undo any special channel coding */ - undo_channel_coding(decoder); - /* Check whether decoded data actually fits bps */ - for(channel = 0; channel < decoder->private_->frame.header.channels; channel++) { - int shift_bits = 32 - decoder->private_->frame.header.bits_per_sample; - int lower_limit = INT32_MIN >> shift_bits; - int upper_limit = INT32_MAX >> shift_bits; - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - /* Check whether shift_bits MSBs are 'empty' by shifting up and down */ - if((decoder->private_->output[channel][i] < lower_limit) || - (decoder->private_->output[channel][i] > upper_limit)) { - /* Bad frame, emit error */ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_OUT_OF_BOUNDS); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - break; - } - } - } - } - } -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - else if (decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) { - /* Bad frame, emit error */ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - } -#endif - - /* Check whether frames are missing, if so, add silence to compensate */ - if(decoder->private_->last_frame_is_set && decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME && !decoder->private_->is_seeking && do_full_decode) { - FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - if(decoder->private_->last_frame.header.number.sample_number + decoder->private_->last_frame.header.blocksize < decoder->private_->frame.header.number.sample_number) { - uint32_t padding_samples_needed = decoder->private_->frame.header.number.sample_number - (decoder->private_->last_frame.header.number.sample_number + decoder->private_->last_frame.header.blocksize); - /* Send an error that we lost sync, but only in case no error - * has been sent yet. This is the case if exactly one or more - * frames are missing, and the frames before and after it - * are complete */ - if(!decoder->private_->error_has_been_sent) - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_MISSING_FRAME); - /* Do some extra validation to assure last frame an current frame - * header are both valid before adding silence inbetween - * Technically both frames could be valid with differing sample_rates, - * channels and bits_per_sample, but it is quite rare */ - if(decoder->private_->last_frame.header.sample_rate == decoder->private_->frame.header.sample_rate && - decoder->private_->last_frame.header.channels == decoder->private_->frame.header.channels && - decoder->private_->last_frame.header.bits_per_sample == decoder->private_->frame.header.bits_per_sample && - decoder->private_->last_frame.header.blocksize >= 16) { - FLAC__Frame empty_frame; - FLAC__int32 * empty_buffer[FLAC__MAX_CHANNELS] = {NULL}; - empty_frame.header = decoder->private_->last_frame.header; - empty_frame.footer.crc = 0; - for(i = 0; i < empty_frame.header.channels; i++) { - empty_buffer[i] = safe_calloc_(empty_frame.header.blocksize, sizeof(FLAC__int32)); - if(empty_buffer[i] == NULL) { - for(i = 0; i < empty_frame.header.channels; i++) - if(empty_buffer[i] != NULL) - free(empty_buffer[i]); - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - } - /* No repairs larger than 5 seconds or 50 frames are made, to not - * unexpectedly create enormous files when one of the headers was - * corrupt after all */ - if(padding_samples_needed > (5*empty_frame.header.sample_rate)) - padding_samples_needed = 5*empty_frame.header.sample_rate; - if(padding_samples_needed > (50*empty_frame.header.blocksize)) - padding_samples_needed = 50*empty_frame.header.blocksize; - while(padding_samples_needed){ - empty_frame.header.number.sample_number += empty_frame.header.blocksize; - if(padding_samples_needed < empty_frame.header.blocksize) - empty_frame.header.blocksize = padding_samples_needed; - padding_samples_needed -= empty_frame.header.blocksize; - decoder->protected_->blocksize = empty_frame.header.blocksize; - - FLAC__ASSERT(empty_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - decoder->private_->samples_decoded = empty_frame.header.number.sample_number + empty_frame.header.blocksize; - - for(channel = 0; channel < empty_frame.header.channels; channel++) { - empty_frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT; - empty_frame.subframes[channel].data.constant.value = 0; - empty_frame.subframes[channel].wasted_bits = 0; - } - - if(write_audio_frame_to_client_(decoder, &empty_frame, (const FLAC__int32 * const *)empty_buffer) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) { - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - for(i = 0; i < empty_frame.header.channels; i++) - if(empty_buffer[i] != NULL) - free(empty_buffer[i]); - return false; - } - } - for(i = 0; i < empty_frame.header.channels; i++) - if(empty_buffer[i] != NULL) - free(empty_buffer[i]); - - } - } - } - - decoder->private_->error_has_been_sent = false; - - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC || decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM) { -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - decoder->private_->fuzzing_rewind_count++; /* To stop excessive rewinding, as it causes timeouts */ -#endif - /* Got corruption, rewind if possible. Return value of seek - * isn't checked, if the seek fails the decoder will continue anyway */ - if(!FLAC__bitreader_rewind_to_after_last_seen_framesync(decoder->private_->input)){ -#ifndef NDEBUG - flac_fprintf(stderr, "Rewinding, seeking necessary\n"); -#endif - if(decoder->private_->seek_callback && decoder->private_->last_seen_framesync){ - /* Last framesync isn't in bitreader anymore, rewind with seek if possible */ -#ifndef NDEBUG - FLAC__uint64 current_decode_position; - if(FLAC__stream_decoder_get_decode_position(decoder, ¤t_decode_position)) - flac_fprintf(stderr, "Bitreader was %" PRIu64 " bytes short\n", current_decode_position-decoder->private_->last_seen_framesync); -#endif - if(decoder->private_->seek_callback(decoder, decoder->private_->last_seen_framesync, decoder->private_->client_data) == FLAC__STREAM_DECODER_SEEK_STATUS_ERROR) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__bitreader_clear(decoder->private_->input)) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - } - } -#ifndef NDEBUG - else{ - flac_fprintf(stderr, "Rewinding, seeking not necessary\n"); - } -#endif - } - else { - *got_a_frame = true; -#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - decoder->private_->fuzzing_rewind_count = 0; -#endif - - /* we wait to update fixed_block_size until here, when we're sure we've got a proper frame and hence a correct blocksize */ - if(decoder->private_->next_fixed_block_size) - decoder->private_->fixed_block_size = decoder->private_->next_fixed_block_size; - - /* put the latest values into the public section of the decoder instance */ - decoder->protected_->channels = decoder->private_->frame.header.channels; - decoder->protected_->channel_assignment = decoder->private_->frame.header.channel_assignment; - decoder->protected_->bits_per_sample = decoder->private_->frame.header.bits_per_sample; - decoder->protected_->sample_rate = decoder->private_->frame.header.sample_rate; - decoder->protected_->blocksize = decoder->private_->frame.header.blocksize; - - FLAC__ASSERT(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - decoder->private_->samples_decoded = decoder->private_->frame.header.number.sample_number + decoder->private_->frame.header.blocksize; - - /* write it */ - if(do_full_decode) { - if(write_audio_frame_to_client_(decoder, &decoder->private_->frame, (const FLAC__int32 * const *)decoder->private_->output) != FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE) { - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - } - } - - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; -} - -FLAC__bool read_frame_header_(FLAC__StreamDecoder *decoder) -{ - FLAC__uint32 x; - FLAC__uint64 xx; - uint32_t i, blocksize_hint = 0, sample_rate_hint = 0; - FLAC__byte crc8, raw_header[16]; /* MAGIC NUMBER based on the maximum frame header size, including CRC */ - uint32_t raw_header_len; - FLAC__bool is_unparseable = false; - - FLAC__ASSERT(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)); - - /* init the raw header with the saved bits from synchronization */ - raw_header[0] = decoder->private_->header_warmup[0]; - raw_header[1] = decoder->private_->header_warmup[1]; - raw_header_len = 2; - - /* check to make sure that reserved bit is 0 */ - if(raw_header[1] & 0x02) /* MAGIC NUMBER */ - is_unparseable = true; - - /* - * Note that along the way as we read the header, we look for a sync - * code inside. If we find one it would indicate that our original - * sync was bad since there cannot be a sync code in a valid header. - * - * Three kinds of things can go wrong when reading the frame header: - * 1) We may have sync'ed incorrectly and not landed on a frame header. - * If we don't find a sync code, it can end up looking like we read - * a valid but unparseable header, until getting to the frame header - * CRC. Even then we could get a false positive on the CRC. - * 2) We may have sync'ed correctly but on an unparseable frame (from a - * future encoder). - * 3) We may be on a damaged frame which appears valid but unparseable. - * - * For all these reasons, we try and read a complete frame header as - * long as it seems valid, even if unparseable, up until the frame - * header CRC. - */ - - /* - * read in the raw header as bytes so we can CRC it, and parse it on the way - */ - for(i = 0; i < 2; i++) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - if(x == 0xff) { /* MAGIC NUMBER for the first 8 frame sync bits */ - /* if we get here it means our original sync was erroneous since the sync code cannot appear in the header */ - decoder->private_->lookahead = (FLAC__byte)x; - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - raw_header[raw_header_len++] = (FLAC__byte)x; - } - - switch(x = raw_header[2] >> 4) { - case 0: - is_unparseable = true; - break; - case 1: - decoder->private_->frame.header.blocksize = 192; - break; - case 2: - case 3: - case 4: - case 5: - decoder->private_->frame.header.blocksize = 576 << (x-2); - break; - case 6: - case 7: - blocksize_hint = x; - break; - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: - decoder->private_->frame.header.blocksize = 256 << (x-8); - break; - default: - FLAC__ASSERT(0); - break; - } - - switch(x = raw_header[2] & 0x0f) { - case 0: - if(decoder->private_->has_stream_info) - decoder->private_->frame.header.sample_rate = decoder->private_->stream_info.data.stream_info.sample_rate; - else - is_unparseable = true; - break; - case 1: - decoder->private_->frame.header.sample_rate = 88200; - break; - case 2: - decoder->private_->frame.header.sample_rate = 176400; - break; - case 3: - decoder->private_->frame.header.sample_rate = 192000; - break; - case 4: - decoder->private_->frame.header.sample_rate = 8000; - break; - case 5: - decoder->private_->frame.header.sample_rate = 16000; - break; - case 6: - decoder->private_->frame.header.sample_rate = 22050; - break; - case 7: - decoder->private_->frame.header.sample_rate = 24000; - break; - case 8: - decoder->private_->frame.header.sample_rate = 32000; - break; - case 9: - decoder->private_->frame.header.sample_rate = 44100; - break; - case 10: - decoder->private_->frame.header.sample_rate = 48000; - break; - case 11: - decoder->private_->frame.header.sample_rate = 96000; - break; - case 12: - case 13: - case 14: - sample_rate_hint = x; - break; - case 15: - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - default: - FLAC__ASSERT(0); - } - - x = (uint32_t)(raw_header[3] >> 4); - if(x & 8) { - decoder->private_->frame.header.channels = 2; - switch(x & 7) { - case 0: - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE; - break; - case 1: - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE; - break; - case 2: - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_MID_SIDE; - break; - default: - is_unparseable = true; - break; - } - } - else { - decoder->private_->frame.header.channels = (uint32_t)x + 1; - decoder->private_->frame.header.channel_assignment = FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT; - } - - switch(x = (uint32_t)(raw_header[3] & 0x0e) >> 1) { - case 0: - if(decoder->private_->has_stream_info) - decoder->private_->frame.header.bits_per_sample = decoder->private_->stream_info.data.stream_info.bits_per_sample; - else - is_unparseable = true; - break; - case 1: - decoder->private_->frame.header.bits_per_sample = 8; - break; - case 2: - decoder->private_->frame.header.bits_per_sample = 12; - break; - case 3: - is_unparseable = true; - break; - case 4: - decoder->private_->frame.header.bits_per_sample = 16; - break; - case 5: - decoder->private_->frame.header.bits_per_sample = 20; - break; - case 6: - decoder->private_->frame.header.bits_per_sample = 24; - break; - case 7: - decoder->private_->frame.header.bits_per_sample = 32; - break; - default: - FLAC__ASSERT(0); - break; - } - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - /* check to make sure that reserved bit is 0 */ - if(raw_header[3] & 0x01) /* MAGIC NUMBER */ - is_unparseable = true; -#endif - - /* read the frame's starting sample number (or frame number as the case may be) */ - if( - raw_header[1] & 0x01 || - /*@@@ this clause is a concession to the old way of doing variable blocksize; the only known implementation is flake and can probably be removed without inconveniencing anyone */ - (decoder->private_->has_stream_info && decoder->private_->stream_info.data.stream_info.min_blocksize != decoder->private_->stream_info.data.stream_info.max_blocksize) - ) { /* variable blocksize */ - if(!FLAC__bitreader_read_utf8_uint64(decoder->private_->input, &xx, raw_header, &raw_header_len)) - return false; /* read_callback_ sets the state for us */ - if(xx == FLAC__U64L(0xffffffffffffffff)) { /* i.e. non-UTF8 code... */ - decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; - decoder->private_->frame.header.number.sample_number = xx; - } - else { /* fixed blocksize */ - if(!FLAC__bitreader_read_utf8_uint32(decoder->private_->input, &x, raw_header, &raw_header_len)) - return false; /* read_callback_ sets the state for us */ - if(x == 0xffffffff) { /* i.e. non-UTF8 code... */ - decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER; - decoder->private_->frame.header.number.frame_number = x; - } - - if(blocksize_hint) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)x; - if(blocksize_hint == 7) { - FLAC__uint32 _x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)_x; - x = (x << 8) | _x; - } - decoder->private_->frame.header.blocksize = x+1; - if(decoder->private_->frame.header.blocksize > 65535) { /* invalid blocksize (65536) specified */ - decoder->private_->lookahead = raw_header[raw_header_len-1]; /* back up as much as we can */ - decoder->private_->cached = true; - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - } - - if(sample_rate_hint) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)x; - if(sample_rate_hint != 12) { - FLAC__uint32 _x; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &_x, 8)) - return false; /* read_callback_ sets the state for us */ - raw_header[raw_header_len++] = (FLAC__byte)_x; - x = (x << 8) | _x; - } - if(sample_rate_hint == 12) - decoder->private_->frame.header.sample_rate = x*1000; - else if(sample_rate_hint == 13) - decoder->private_->frame.header.sample_rate = x; - else - decoder->private_->frame.header.sample_rate = x*10; - } - - /* read the CRC-8 byte */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) - return false; /* read_callback_ sets the state for us */ - crc8 = (FLAC__byte)x; - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if(FLAC__crc8(raw_header, raw_header_len) != crc8) { -#else - if(decoder->private_->fuzzing_rewind_count > 32 && (FLAC__crc8(raw_header, raw_header_len) << 4) != (crc8 << 4)) { -#endif - - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - /* calculate the sample number from the frame number if needed */ - decoder->private_->next_fixed_block_size = 0; - if(decoder->private_->frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_FRAME_NUMBER) { - x = decoder->private_->frame.header.number.frame_number; - decoder->private_->frame.header.number_type = FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER; - if(decoder->private_->fixed_block_size) - decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->fixed_block_size * (FLAC__uint64)x; - else if(decoder->private_->has_stream_info) { - if(decoder->private_->stream_info.data.stream_info.min_blocksize == decoder->private_->stream_info.data.stream_info.max_blocksize) { - decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->stream_info.data.stream_info.min_blocksize * (FLAC__uint64)x; - decoder->private_->next_fixed_block_size = decoder->private_->stream_info.data.stream_info.max_blocksize; - } - else - is_unparseable = true; - } - else if(x == 0) { - decoder->private_->frame.header.number.sample_number = 0; - decoder->private_->next_fixed_block_size = decoder->private_->frame.header.blocksize; - } - else { - /* can only get here if the stream has invalid frame numbering and no STREAMINFO, so assume it's not the last (possibly short) frame */ - decoder->private_->frame.header.number.sample_number = (FLAC__uint64)decoder->private_->frame.header.blocksize * (FLAC__uint64)x; - } - } - - if(is_unparseable) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - return true; -} - -FLAC__bool read_subframe_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) -{ - FLAC__uint32 x; - FLAC__bool wasted_bits; - uint32_t i; - - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &x, 8)) /* MAGIC NUMBER */ - return false; /* read_callback_ sets the state for us */ - - wasted_bits = (x & 1); - x &= 0xfe; - - if(wasted_bits) { - uint32_t u; - if(!FLAC__bitreader_read_unary_unsigned(decoder->private_->input, &u)) - return false; /* read_callback_ sets the state for us */ - decoder->private_->frame.subframes[channel].wasted_bits = u+1; - if (decoder->private_->frame.subframes[channel].wasted_bits >= bps) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - bps -= decoder->private_->frame.subframes[channel].wasted_bits; - } - else - decoder->private_->frame.subframes[channel].wasted_bits = 0; - - /* - * Lots of magic numbers here - */ - if(x & 0x80) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else if(x == 0) { - if(!read_subframe_constant_(decoder, channel, bps, do_full_decode)) - return false; - } - else if(x == 2) { - if(!read_subframe_verbatim_(decoder, channel, bps, do_full_decode)) - return false; - } - else if(x < 16) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else if(x <= 24) { - uint32_t predictor_order = (x>>1)&7; - if(decoder->private_->frame.header.blocksize <= predictor_order){ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - if(!read_subframe_fixed_(decoder, channel, bps, predictor_order, do_full_decode)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ - return true; - } - else if(x < 64) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else { - uint32_t predictor_order = ((x>>1)&31)+1; - if(decoder->private_->frame.header.blocksize <= predictor_order){ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - if(!read_subframe_lpc_(decoder, channel, bps, predictor_order, do_full_decode)) - return false; - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC) /* means bad sync or got corruption */ - return true; - } - - if(wasted_bits && do_full_decode) { - x = decoder->private_->frame.subframes[channel].wasted_bits; - if((bps + x) < 33) { - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - uint32_t val = decoder->private_->output[channel][i]; - decoder->private_->output[channel][i] = (val << x); - } - } - else { - /* When there are wasted bits, bps is never 33 and so - * side_subframe is never already in use */ - FLAC__ASSERT(!decoder->private_->side_subframe_in_use); - decoder->private_->side_subframe_in_use = true; - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - uint64_t val = decoder->private_->output[channel][i]; - decoder->private_->side_subframe[i] = (val << x); - } - } - } - - return true; -} - -FLAC__bool read_subframe_constant_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) -{ - FLAC__Subframe_Constant *subframe = &decoder->private_->frame.subframes[channel].data.constant; - FLAC__int64 x; - uint32_t i; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_CONSTANT; - - if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &x, bps)) - return false; /* read_callback_ sets the state for us */ - - subframe->value = x; - - /* decode the subframe */ - if(do_full_decode) { - if(bps <= 32) { - FLAC__int32 *output = decoder->private_->output[channel]; - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - output[i] = x; - } else { - FLAC__int64 *output = decoder->private_->side_subframe; - decoder->private_->side_subframe_in_use = true; - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - output[i] = x; - } - } - - return true; -} - -FLAC__bool read_subframe_fixed_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode) -{ - FLAC__Subframe_Fixed *subframe = &decoder->private_->frame.subframes[channel].data.fixed; - FLAC__int64 i64; - FLAC__uint32 u32; - uint32_t u; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_FIXED; - - subframe->residual = decoder->private_->residual[channel]; - subframe->order = order; - - /* read warm-up samples */ - for(u = 0; u < order; u++) { - if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &i64, bps)) - return false; /* read_callback_ sets the state for us */ - subframe->warmup[u] = i64; - } - - /* read entropy coding method info */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) - return false; /* read_callback_ sets the state for us */ - if((decoder->private_->frame.header.blocksize >> u32 < order) || - (decoder->private_->frame.header.blocksize % (1 << u32) > 0)) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->entropy_coding_method.data.partitioned_rice.order = u32; - subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; - break; - default: - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - /* read residual */ - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) - return false; - break; - default: - FLAC__ASSERT(0); - } - - /* decode the subframe */ - if(do_full_decode) { - if(bps < 33){ - uint32_t i; - for(i = 0; i < order; i++) - decoder->private_->output[channel][i] = subframe->warmup[i]; - if(bps+order <= 32) - FLAC__fixed_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order); - else - FLAC__fixed_restore_signal_wide(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->output[channel]+order); - } - else { - decoder->private_->side_subframe_in_use = true; - memcpy(decoder->private_->side_subframe, subframe->warmup, sizeof(FLAC__int64) * order); - FLAC__fixed_restore_signal_wide_33bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, order, decoder->private_->side_subframe+order); - } - } - - return true; -} - -FLAC__bool read_subframe_lpc_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, const uint32_t order, FLAC__bool do_full_decode) -{ - FLAC__Subframe_LPC *subframe = &decoder->private_->frame.subframes[channel].data.lpc; - FLAC__int32 i32; - FLAC__int64 i64; - FLAC__uint32 u32; - uint32_t u; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_LPC; - - subframe->residual = decoder->private_->residual[channel]; - subframe->order = order; - - /* read warm-up samples */ - for(u = 0; u < order; u++) { - if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &i64, bps)) - return false; /* read_callback_ sets the state for us */ - subframe->warmup[u] = i64; - } - - /* read qlp coeff precision */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN)) - return false; /* read_callback_ sets the state for us */ - if(u32 == (1u << FLAC__SUBFRAME_LPC_QLP_COEFF_PRECISION_LEN) - 1) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->qlp_coeff_precision = u32+1; - - /* read qlp shift */ - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, FLAC__SUBFRAME_LPC_QLP_SHIFT_LEN)) - return false; /* read_callback_ sets the state for us */ - if(i32 < 0) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->quantization_level = i32; - - /* read quantized lp coefficiencts */ - for(u = 0; u < order; u++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i32, subframe->qlp_coeff_precision)) - return false; /* read_callback_ sets the state for us */ - subframe->qlp_coeff[u] = i32; - } - - /* read entropy coding method info */ - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_TYPE_LEN)) - return false; /* read_callback_ sets the state for us */ - subframe->entropy_coding_method.type = (FLAC__EntropyCodingMethodType)u32; - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &u32, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ORDER_LEN)) - return false; /* read_callback_ sets the state for us */ - if((decoder->private_->frame.header.blocksize >> u32 < order) || - (decoder->private_->frame.header.blocksize % (1 << u32) > 0)) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - subframe->entropy_coding_method.data.partitioned_rice.order = u32; - subframe->entropy_coding_method.data.partitioned_rice.contents = &decoder->private_->partitioned_rice_contents[channel]; - break; - default: - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - - /* read residual */ - switch(subframe->entropy_coding_method.type) { - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE: - case FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2: - if(!read_residual_partitioned_rice_(decoder, order, subframe->entropy_coding_method.data.partitioned_rice.order, &decoder->private_->partitioned_rice_contents[channel], decoder->private_->residual[channel], /*is_extended=*/subframe->entropy_coding_method.type == FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2)) - return false; - break; - default: - FLAC__ASSERT(0); - } - - /* decode the subframe */ - if(do_full_decode) { - if(bps <= 32) { - uint32_t i; - for(i = 0; i < order; i++) - decoder->private_->output[channel][i] = subframe->warmup[i]; - if(FLAC__lpc_max_residual_bps(bps, subframe->qlp_coeff, order, subframe->quantization_level) <= 32 && - FLAC__lpc_max_prediction_before_shift_bps(bps, subframe->qlp_coeff, order) <= 32) - FLAC__lpc_restore_signal(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - else - FLAC__lpc_restore_signal_wide(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->output[channel]+order); - } - else { - decoder->private_->side_subframe_in_use = true; - memcpy(decoder->private_->side_subframe, subframe->warmup, sizeof(FLAC__int64) * order); - FLAC__lpc_restore_signal_wide_33bit(decoder->private_->residual[channel], decoder->private_->frame.header.blocksize-order, subframe->qlp_coeff, order, subframe->quantization_level, decoder->private_->side_subframe+order); - } - } - - return true; -} - -FLAC__bool read_subframe_verbatim_(FLAC__StreamDecoder *decoder, uint32_t channel, uint32_t bps, FLAC__bool do_full_decode) -{ - FLAC__Subframe_Verbatim *subframe = &decoder->private_->frame.subframes[channel].data.verbatim; - uint32_t i; - - decoder->private_->frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM; - - if(bps < 33) { - FLAC__int32 x, *residual = decoder->private_->residual[channel]; - - subframe->data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32; - subframe->data.int32 = residual; - - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &x, bps)) - return false; /* read_callback_ sets the state for us */ - residual[i] = x; - } - - /* decode the subframe */ - if(do_full_decode) - memcpy(decoder->private_->output[channel], subframe->data.int32, sizeof(FLAC__int32) * decoder->private_->frame.header.blocksize); - } - else { - FLAC__int64 x, *side = decoder->private_->side_subframe; - - subframe->data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT64; - subframe->data.int64 = side; - decoder->private_->side_subframe_in_use = true; - - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - if(!FLAC__bitreader_read_raw_int64(decoder->private_->input, &x, bps)) - return false; /* read_callback_ sets the state for us */ - side[i] = x; - } - } - - return true; -} - -FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_t predictor_order, uint32_t partition_order, FLAC__EntropyCodingMethod_PartitionedRiceContents *partitioned_rice_contents, FLAC__int32 *residual, FLAC__bool is_extended) -{ - FLAC__uint32 rice_parameter; - int i; - uint32_t partition, sample, u; - const uint32_t partitions = 1u << partition_order; - const uint32_t partition_samples = decoder->private_->frame.header.blocksize >> partition_order; - const uint32_t plen = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_PARAMETER_LEN : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_PARAMETER_LEN; - const uint32_t pesc = is_extended? FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE2_ESCAPE_PARAMETER : FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_ESCAPE_PARAMETER; - - /* invalid predictor and partition orders mush be handled in the callers */ - FLAC__ASSERT(partition_order > 0? partition_samples >= predictor_order : decoder->private_->frame.header.blocksize >= predictor_order); - - if(!FLAC__format_entropy_coding_method_partitioned_rice_contents_ensure_size(partitioned_rice_contents, flac_max(6u, partition_order))) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } - - sample = 0; - for(partition = 0; partition < partitions; partition++) { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, plen)) - return false; /* read_callback_ sets the state for us */ - partitioned_rice_contents->parameters[partition] = rice_parameter; - if(rice_parameter < pesc) { - partitioned_rice_contents->raw_bits[partition] = 0; - u = (partition == 0) ? partition_samples - predictor_order : partition_samples; - if(!decoder->private_->local_bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter)){ - if(decoder->protected_->state == FLAC__STREAM_DECODER_READ_FRAME) { - /* no error was set, read_callback_ didn't set it, so - * invalid rice symbol was found */ - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - return true; - } - else - return false; /* read_callback_ sets the state for us */ - } - sample += u; - } - else { - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &rice_parameter, FLAC__ENTROPY_CODING_METHOD_PARTITIONED_RICE_RAW_LEN)) - return false; /* read_callback_ sets the state for us */ - partitioned_rice_contents->raw_bits[partition] = rice_parameter; - if(rice_parameter == 0) { - for(u = (partition == 0)? predictor_order : 0; u < partition_samples; u++, sample++) - residual[sample] = 0; - } - else{ - for(u = (partition == 0)? predictor_order : 0; u < partition_samples; u++, sample++) { - if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter)) - return false; /* read_callback_ sets the state for us */ - residual[sample] = i; - } - } - } - } - - return true; -} - -FLAC__bool read_zero_padding_(FLAC__StreamDecoder *decoder) -{ - if(!FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) { - FLAC__uint32 zero = 0; - if(!FLAC__bitreader_read_raw_uint32(decoder->private_->input, &zero, FLAC__bitreader_bits_left_for_byte_alignment(decoder->private_->input))) - return false; /* read_callback_ sets the state for us */ -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - if(zero != 0) { - send_error_to_client_(decoder, FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC); - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC; - } -#endif - } - return true; -} - -FLAC__bool read_callback_(FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder *)client_data; - - if( -#if FLAC__HAS_OGG - /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ - !decoder->private_->is_ogg && -#endif - decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) - ) { - *bytes = 0; - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - return false; - } - else if(*bytes > 0) { - /* While seeking, it is possible for our seek to land in the - * middle of audio data that looks exactly like a frame header - * from a future version of an encoder. When that happens, our - * error callback will get an - * FLAC__STREAM_DECODER_UNPARSEABLE_STREAM and increment its - * unparseable_frame_count. But there is a remote possibility - * that it is properly synced at such a "future-codec frame", - * so to make sure, we wait to see many "unparseable" errors in - * a row before bailing out. - */ - if(decoder->private_->is_seeking && decoder->private_->unparseable_frame_count > 20) { - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - else { - const FLAC__StreamDecoderReadStatus status = -#if FLAC__HAS_OGG - decoder->private_->is_ogg? - read_callback_ogg_aspect_(decoder, buffer, bytes) : -#endif - decoder->private_->read_callback(decoder, buffer, bytes, decoder->private_->client_data) - ; - if(status == FLAC__STREAM_DECODER_READ_STATUS_ABORT) { -#if FLAC__HAS_OGG - if(decoder->private_->ogg_decoder_aspect_allocation_failure) { - decoder->protected_->state = FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR; - return false; - } -#endif - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - else if(*bytes == 0) { - if(status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_LINK) { - if(FLAC__bitreader_is_consumed_byte_aligned(decoder->private_->input)) - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_LINK; - else - decoder->protected_->state = FLAC__STREAM_DECODER_OGG_ERROR; - return false; - } - else if( - status == FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM || - ( -#if FLAC__HAS_OGG - /* see [1] HACK NOTE below for why we don't call the eof_callback when decoding Ogg FLAC */ - !decoder->private_->is_ogg && -#endif - decoder->private_->eof_callback && decoder->private_->eof_callback(decoder, decoder->private_->client_data) - ) - ) { - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - return false; - } - else - return true; - } - else - return true; - } - } - else { - /* abort to avoid a deadlock */ - decoder->protected_->state = FLAC__STREAM_DECODER_ABORTED; - return false; - } - /* [1] @@@ HACK NOTE: The end-of-stream checking has to be hacked around - * for Ogg FLAC. This is because the ogg decoder aspect can lose sync - * and at the same time hit the end of the stream (for example, seeking - * to a point that is after the beginning of the last Ogg page). There - * is no way to report an Ogg sync loss through the callbacks (see note - * in read_callback_ogg_aspect_()) so it returns CONTINUE with *bytes==0. - * So to keep the decoder from stopping at this point we gate the call - * to the eof_callback and let the Ogg decoder aspect set the - * end-of-stream state when it is needed. - */ -} - -#if defined(FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION) && !defined(FUZZING_BUILD_MODE_FLAC_SANITIZE_SIGNED_INTEGER_OVERFLOW) -/* The attribute below is to silence the undefined sanitizer of oss-fuzz. - * Because fuzzing feeds bogus predictors and residual samples to the - * decoder, having overflows in this section is unavoidable. Also, - * because the calculated values are audio path only, there is no - * potential for security problems */ -__attribute__((no_sanitize("signed-integer-overflow"))) -#endif -void undo_channel_coding(FLAC__StreamDecoder *decoder) { - uint32_t i; - switch(decoder->private_->frame.header.channel_assignment) { - case FLAC__CHANNEL_ASSIGNMENT_INDEPENDENT: - /* do nothing */ - break; - case FLAC__CHANNEL_ASSIGNMENT_LEFT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32)); - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - if(decoder->private_->side_subframe_in_use) - decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->side_subframe[i]; - else - decoder->private_->output[1][i] = decoder->private_->output[0][i] - decoder->private_->output[1][i]; - break; - case FLAC__CHANNEL_ASSIGNMENT_RIGHT_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32)); - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) - if(decoder->private_->side_subframe_in_use) - decoder->private_->output[0][i] = decoder->private_->output[1][i] + decoder->private_->side_subframe[i]; - else - decoder->private_->output[0][i] += decoder->private_->output[1][i]; - break; - case FLAC__CHANNEL_ASSIGNMENT_MID_SIDE: - FLAC__ASSERT(decoder->private_->frame.header.channels == 2); - FLAC__ASSERT(decoder->private_->side_subframe_in_use != /* logical XOR */ (decoder->private_->frame.header.bits_per_sample < 32)); - for(i = 0; i < decoder->private_->frame.header.blocksize; i++) { - if(!decoder->private_->side_subframe_in_use){ - FLAC__int32 mid, side; - mid = decoder->private_->output[0][i]; - side = decoder->private_->output[1][i]; - mid = ((uint32_t) mid) << 1; - mid |= (side & 1); /* i.e. if 'side' is odd... */ - decoder->private_->output[0][i] = (mid + side) >> 1; - decoder->private_->output[1][i] = (mid - side) >> 1; - } - else { /* bps == 32 */ - FLAC__int64 mid; - mid = ((uint64_t)decoder->private_->output[0][i]) << 1; - mid |= (decoder->private_->side_subframe[i] & 1); /* i.e. if 'side' is odd... */ - decoder->private_->output[0][i] = (mid + decoder->private_->side_subframe[i]) >> 1; - decoder->private_->output[1][i] = (mid - decoder->private_->side_subframe[i]) >> 1; - } - } - break; - default: - FLAC__ASSERT(0); - break; - } -} - -#if FLAC__HAS_OGG -FLAC__StreamDecoderReadStatus read_callback_ogg_aspect_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes) -{ - switch(FLAC__ogg_decoder_aspect_read_callback_wrapper(&decoder->protected_->ogg_decoder_aspect, buffer, bytes, read_callback_proxy_, decoder->private_->tell_callback, decoder, decoder->private_->client_data)) { - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK: - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - /* we don't really have a way to handle lost sync via read - * callback so we'll let it pass and let the underlying - * FLAC decoder catch the error - */ - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_LOST_SYNC: - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM: - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_LINK: - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_LINK; - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_NOT_FLAC: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_UNSUPPORTED_MAPPING_VERSION: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT: - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_ERROR: - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - case FLAC__OGG_DECODER_ASPECT_READ_STATUS_MEMORY_ALLOCATION_ERROR: - decoder->private_->ogg_decoder_aspect_allocation_failure = true; - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - default: - FLAC__ASSERT(0); - /* double protection */ - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - } -} - -FLAC__OggDecoderAspectReadStatus read_callback_proxy_(const void *void_decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - FLAC__StreamDecoder *decoder = (FLAC__StreamDecoder*)void_decoder; - - switch(decoder->private_->read_callback(decoder, buffer, bytes, client_data)) { - case FLAC__STREAM_DECODER_READ_STATUS_CONTINUE: - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK; - case FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM: - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM; - case FLAC__STREAM_DECODER_READ_STATUS_ABORT: - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; - default: - /* double protection: */ - FLAC__ASSERT(0); - return FLAC__OGG_DECODER_ASPECT_READ_STATUS_ABORT; - } -} -#endif - -FLAC__StreamDecoderWriteStatus write_audio_frame_to_client_(FLAC__StreamDecoder *decoder, const FLAC__Frame *frame, const FLAC__int32 * const buffer[]) -{ - decoder->private_->last_frame = *frame; /* save the frame */ - decoder->private_->last_frame_is_set = true; - if(decoder->private_->is_seeking && !decoder->private_->is_indexing) { - FLAC__uint64 this_frame_sample = frame->header.number.sample_number; - FLAC__uint64 next_frame_sample = this_frame_sample + (FLAC__uint64)frame->header.blocksize; - FLAC__uint64 target_sample = decoder->private_->target_sample; - - FLAC__ASSERT(frame->header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - - decoder->private_->got_a_frame = true; - - if(this_frame_sample <= target_sample && target_sample < next_frame_sample) { /* we hit our target frame */ - uint32_t delta = (uint32_t)(target_sample - this_frame_sample); - /* kick out of seek mode */ - decoder->private_->is_seeking = false; - /* shift out the samples before target_sample */ - if(delta > 0) { - uint32_t channel; - const FLAC__int32 *newbuffer[FLAC__MAX_CHANNELS]; - for(channel = 0; channel < frame->header.channels; channel++) { - newbuffer[channel] = buffer[channel] + delta; - decoder->private_->last_frame.subframes[channel].type = FLAC__SUBFRAME_TYPE_VERBATIM; - decoder->private_->last_frame.subframes[channel].data.verbatim.data_type = FLAC__VERBATIM_SUBFRAME_DATA_TYPE_INT32; - decoder->private_->last_frame.subframes[channel].data.verbatim.data.int32 = newbuffer[channel]; - } - decoder->private_->last_frame.header.blocksize -= delta; - decoder->private_->last_frame.header.number.sample_number += (FLAC__uint64)delta; - /* write the relevant samples */ - return decoder->private_->write_callback(decoder, &decoder->private_->last_frame, newbuffer, decoder->private_->client_data); - } - else { - /* write the relevant samples */ - return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); - } - } - else { - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - } - } - else if(!decoder->private_->is_indexing) { - /* - * If we never got STREAMINFO, turn off MD5 checking to save - * cycles since we don't have a sum to compare to anyway - */ - if(!decoder->private_->has_stream_info) - decoder->private_->do_md5_checking = false; - if(decoder->private_->do_md5_checking) { - if(!FLAC__MD5Accumulate(&decoder->private_->md5context, buffer, frame->header.channels, frame->header.blocksize, (frame->header.bits_per_sample+7) / 8)) - return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT; - } - return decoder->private_->write_callback(decoder, frame, buffer, decoder->private_->client_data); - } - else { /* decoder->private_->is_indexing == true */ - return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE; - } -} - -void send_error_to_client_(const FLAC__StreamDecoder *decoder, FLAC__StreamDecoderErrorStatus status) -{ - if(!decoder->private_->is_seeking) { - decoder->private_->error_has_been_sent = true; - decoder->private_->error_callback(decoder, status, decoder->private_->client_data); - } - else if(status == FLAC__STREAM_DECODER_ERROR_STATUS_UNPARSEABLE_STREAM) - decoder->private_->unparseable_frame_count++; -} - -FLAC__bool seek_to_absolute_sample_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) -{ - FLAC__uint64 first_frame_offset = decoder->private_->first_frame_offset, lower_bound, upper_bound, lower_bound_sample, upper_bound_sample, this_frame_sample; - FLAC__int64 pos = -1; - int i; - uint32_t approx_bytes_per_frame; - FLAC__bool first_seek = true, seek_from_lower_bound = false; - const FLAC__uint64 total_samples = FLAC__stream_decoder_get_total_samples(decoder); - const uint32_t min_blocksize = decoder->private_->stream_info.data.stream_info.min_blocksize; - const uint32_t max_blocksize = decoder->private_->stream_info.data.stream_info.max_blocksize; - const uint32_t max_framesize = decoder->private_->stream_info.data.stream_info.max_framesize; - const uint32_t min_framesize = decoder->private_->stream_info.data.stream_info.min_framesize; - /* take these from the current frame in case they've changed mid-stream */ - uint32_t channels = FLAC__stream_decoder_get_channels(decoder); - uint32_t bps = FLAC__stream_decoder_get_bits_per_sample(decoder); - const FLAC__StreamMetadata_SeekTable *seek_table = decoder->private_->has_seek_table? &decoder->private_->seek_table.data.seek_table : 0; - - /* use values from stream info if we didn't decode a frame */ - if(channels == 0) - channels = decoder->private_->stream_info.data.stream_info.channels; - if(bps == 0) - bps = decoder->private_->stream_info.data.stream_info.bits_per_sample; - - /* we are just guessing here */ - if(max_framesize > 0) - approx_bytes_per_frame = (max_framesize + min_framesize) / 2 + 1; - /* - * Check if it's a known fixed-blocksize stream. Note that though - * the spec doesn't allow zeroes in the STREAMINFO block, we may - * never get a STREAMINFO block when decoding so the value of - * min_blocksize might be zero. - */ - else if(min_blocksize == max_blocksize && min_blocksize > 0) { - /* note there are no () around 'bps/8' to keep precision up since it's an integer calculation */ - approx_bytes_per_frame = min_blocksize * channels * bps/8 + 64; - } - else - approx_bytes_per_frame = 4096 * channels * bps/8 + 64; - - /* - * First, we set an upper and lower bound on where in the - * stream we will search. For now we take the current position - * as one bound and, depending on where the target position lies, - * the beginning of the first frame or the end of the stream as - * the other bound. - */ - lower_bound = first_frame_offset; - lower_bound_sample = 0; - upper_bound = stream_length; - upper_bound_sample = total_samples > 0 ? total_samples : target_sample /*estimate it*/; - - if(decoder->protected_->state == FLAC__STREAM_DECODER_SEARCH_FOR_FRAME_SYNC && - decoder->private_->samples_decoded != 0) { - if(target_sample < decoder->private_->samples_decoded) { - if(FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) - upper_bound_sample = decoder->private_->samples_decoded; - } else { - if(FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) - lower_bound_sample = decoder->private_->samples_decoded; - } - } - - /* - * Now we refine the bounds if we have a seektable with - * suitable points. Note that according to the spec they - * must be ordered by ascending sample number. - * - * Note: to protect against invalid seek tables we will ignore points - * that have frame_samples==0 or sample_number>=total_samples. Also, - * because math is limited to 64-bit ints, seekpoints with an offset - * larger than 2^63 (8 exbibyte) are rejected. - */ - if(seek_table) { - FLAC__uint64 new_lower_bound = lower_bound; - FLAC__uint64 new_upper_bound = upper_bound; - FLAC__uint64 new_lower_bound_sample = lower_bound_sample; - FLAC__uint64 new_upper_bound_sample = upper_bound_sample; - - /* find the closest seek point <= target_sample, if it exists */ - for(i = (int)seek_table->num_points - 1; i >= 0; i--) { - if( - seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && - seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ - (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ - seek_table->points[i].sample_number <= target_sample - ) - break; - } - if(i >= 0) { /* i.e. we found a suitable seek point... */ - new_lower_bound = first_frame_offset + seek_table->points[i].stream_offset; - new_lower_bound_sample = seek_table->points[i].sample_number; - } - - /* find the closest seek point > target_sample, if it exists */ - for(i = 0; i < (int)seek_table->num_points; i++) { - if( - seek_table->points[i].sample_number != FLAC__STREAM_METADATA_SEEKPOINT_PLACEHOLDER && - seek_table->points[i].frame_samples > 0 && /* defense against bad seekpoints */ - (total_samples <= 0 || seek_table->points[i].sample_number < total_samples) && /* defense against bad seekpoints */ - seek_table->points[i].sample_number > target_sample - ) - break; - } - if(i < (int)seek_table->num_points) { /* i.e. we found a suitable seek point... */ - new_upper_bound = first_frame_offset + seek_table->points[i].stream_offset; - new_upper_bound_sample = seek_table->points[i].sample_number; - } - /* final protection against unsorted seek tables; keep original values if bogus */ - if(new_upper_bound >= new_lower_bound) { - lower_bound = new_lower_bound; - upper_bound = new_upper_bound; - lower_bound_sample = new_lower_bound_sample; - upper_bound_sample = new_upper_bound_sample; - } - } - -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - FLAC__ASSERT(upper_bound_sample >= lower_bound_sample); -#endif - /* there are 3 insidious ways that the following equality occurs, which - * we need to fix: - * 1) total_samples is 0 (unknown) and target_sample is 0 - * 2) total_samples is 0 (unknown) and target_sample happens to be - * exactly equal to the last seek point in the seek table; this - * means there is no seek point above it, and upper_bound_samples - * remains equal to the estimate (of target_samples) we made above - * in either case it does not hurt to move upper_bound_sample up by 1 - * 3) the file is corrupt - */ - if(upper_bound_sample == lower_bound_sample) { - if(total_samples == 0) - upper_bound_sample++; - else { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - } - - decoder->private_->target_sample = target_sample; - while(1) { - /* check whether decoder is still valid so bad state isn't overwritten - * with seek error */ - if(decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) - return false; - /* check if the bounds are still ok */ - if (lower_bound_sample >= upper_bound_sample || - lower_bound > upper_bound || - upper_bound >= INT64_MAX || - target_sample > upper_bound_sample) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(seek_from_lower_bound) { - pos = lower_bound; - } - else { -#ifndef FLAC__INTEGER_ONLY_LIBRARY - pos = (FLAC__int64)lower_bound + (FLAC__int64)((double)(target_sample - lower_bound_sample) / (double)(upper_bound_sample - lower_bound_sample) * (double)(upper_bound - lower_bound)) - approx_bytes_per_frame; -#else - /* a little less accurate: */ - if(upper_bound - lower_bound < 0xffffffff) - pos = (FLAC__int64)lower_bound + (FLAC__int64)(((target_sample - lower_bound_sample) * (upper_bound - lower_bound)) / (upper_bound_sample - lower_bound_sample)) - approx_bytes_per_frame; - else { /* @@@ WATCHOUT, ~2TB limit */ - FLAC__uint64 ratio = (1<<16) / (upper_bound_sample - lower_bound_sample); - pos = (FLAC__int64)lower_bound + (FLAC__int64)((((target_sample - lower_bound_sample)>>8) * ((upper_bound - lower_bound)>>8) * ratio)) - approx_bytes_per_frame; - } -#endif - } - if(pos >= (FLAC__int64)upper_bound) - pos = (FLAC__int64)upper_bound - 1; - if(pos < (FLAC__int64)lower_bound) - pos = (FLAC__int64)lower_bound; - if(decoder->private_->seek_callback(decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - /* Now we need to get a frame. First we need to reset our - * unparseable_frame_count; if we get too many unparseable - * frames in a row, the read callback will return - * FLAC__STREAM_DECODER_READ_STATUS_ABORT, causing - * FLAC__stream_decoder_process_single() to return false. - */ - decoder->private_->unparseable_frame_count = 0; - if(!FLAC__stream_decoder_process_single(decoder) || decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED || 0 == decoder->private_->samples_decoded) { - /* No frame could be decoded */ - if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->private_->eof_callback(decoder, decoder->private_->client_data) && !seek_from_lower_bound){ - /* decoder has hit end of stream while processing corrupt - * frame. To remedy this, try decoding a frame at the lower - * bound so the seek after that hopefully ends up somewhere - * else */ - seek_from_lower_bound = true; - continue; - } - else { - if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->protected_->state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - } - seek_from_lower_bound = false; - - /* our write callback will change the state when it gets to the target frame */ - /* actually, we could have got_a_frame if our decoder is at FLAC__STREAM_DECODER_END_OF_STREAM so we need to check for that also */ - if(!decoder->private_->is_seeking) - break; - - FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - this_frame_sample = decoder->private_->last_frame.header.number.sample_number; - - if(this_frame_sample + decoder->private_->last_frame.header.blocksize >= upper_bound_sample && !first_seek) { - if (pos == (FLAC__int64)lower_bound) { - /* can't move back any more than the first frame, something is fatally wrong */ - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - /* our last move backwards wasn't big enough, try again */ - approx_bytes_per_frame = approx_bytes_per_frame? approx_bytes_per_frame * 2 : 16; - continue; - } - /* allow one seek over upper bound, so we can get a correct upper_bound_sample for streams with unknown total_samples */ - first_seek = false; - - /* make sure we are not seeking in corrupted stream */ - if (this_frame_sample < lower_bound_sample) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - - /* we need to narrow the search */ - if(target_sample < this_frame_sample) { - upper_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; -/*@@@@@@ what will decode position be if at end of stream? */ - if(!FLAC__stream_decoder_get_decode_position(decoder, &upper_bound)) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - approx_bytes_per_frame = (uint32_t)(2 * (upper_bound - pos) / 3 + 16); - } - else { /* target_sample >= this_frame_sample + this frame's blocksize */ - lower_bound_sample = this_frame_sample + decoder->private_->last_frame.header.blocksize; - if(!FLAC__stream_decoder_get_decode_position(decoder, &lower_bound)) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - approx_bytes_per_frame = (uint32_t)(2 * (lower_bound - pos) / 3 + 16); - } - } - - return true; -} - -#if FLAC__HAS_OGG -FLAC__bool seek_to_absolute_sample_ogg_(FLAC__StreamDecoder *decoder, FLAC__uint64 stream_length, FLAC__uint64 target_sample) -{ - FLAC__uint64 left_pos = 0, right_pos = stream_length; - FLAC__uint64 left_sample = 0, right_sample = 0; - FLAC__uint64 this_frame_sample = (FLAC__uint64)0 - 1; - FLAC__uint64 pos = 0; /* only initialized to avoid compiler warning */ - FLAC__bool did_a_seek; - FLAC__OggDecoderAspect_TargetLink *target_link; - uint32_t current_linknumber = decoder->protected_->ogg_decoder_aspect.current_linknumber; - uint32_t iteration = 0; - - /* In the first iterations, we will calculate the target byte position - * by the distance from the target sample to left_sample and - * right_sample (let's call it "proportional search"). After that, we - * will switch to binary search. - */ - uint32_t BINARY_SEARCH_AFTER_ITERATION = 2; - - /* We will switch to a linear search once our current sample is less - * than this number of samples ahead of the target sample - */ - static const FLAC__uint64 LINEAR_SEARCH_WITHIN_SAMPLES = FLAC__MAX_BLOCK_SIZE * 2; - - if(FLAC__ogg_decoder_aspect_get_decode_chained_stream(&decoder->protected_->ogg_decoder_aspect)) { - /* Check whether target sample is contained by indexed links. - * If it is not keep moving forward until found */ - decoder->private_->is_indexing = true; - while(NULL == (target_link = FLAC__ogg_decoder_aspect_get_target_link(&decoder->protected_->ogg_decoder_aspect, target_sample))) { - FLAC__OggDecoderAspectReadStatus status; - if(decoder->protected_->state == FLAC__STREAM_DECODER_END_OF_STREAM || - decoder->protected_->state == FLAC__STREAM_DECODER_OGG_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - /* Target sample is not contained in stream or other error */ - decoder->private_->is_indexing = false; - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - status = FLAC__ogg_decoder_aspect_skip_link(&decoder->protected_->ogg_decoder_aspect, read_callback_proxy_, decoder->private_->seek_callback, decoder->private_->tell_callback, decoder->private_->length_callback, decoder, decoder->private_->client_data); - if(status == FLAC__OGG_DECODER_ASPECT_READ_STATUS_END_OF_STREAM) - decoder->protected_->state = FLAC__STREAM_DECODER_END_OF_STREAM; - else if(status != FLAC__OGG_DECODER_ASPECT_READ_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - } - decoder->private_->is_indexing = false; - /* Target link found, send metadata if necessary */ - FLAC__ogg_decoder_aspect_set_seek_parameters(&decoder->protected_->ogg_decoder_aspect, target_link); - if(target_link->linknumber != current_linknumber) { - if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)target_link->start_byte, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - decoder->protected_->state = FLAC__STREAM_DECODER_SEARCH_FOR_METADATA; - decoder->private_->is_seeking = false; - if(!FLAC__stream_decoder_process_until_end_of_metadata(decoder)) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - decoder->private_->is_seeking = true; - } - /* set boundaries */ - left_pos = target_link->start_byte; - left_sample = 0; - right_pos = target_link->end_byte; - right_sample = target_link->samples_this_link; - target_sample -= target_link->samples_in_preceding_links; - } - else { - right_sample = FLAC__stream_decoder_get_total_samples(decoder); - - /* If the total number of samples is unknown, use a large value, and - * force binary search immediately. - */ - if(right_sample == 0) { - right_sample = (FLAC__uint64)(-1); - BINARY_SEARCH_AFTER_ITERATION = 0; - } - } - - decoder->private_->target_sample = target_sample; - for( ; ; iteration++) { - /* Do sanity checks on bounds */ - if(right_pos <= left_pos || right_pos - left_pos < 9) { - /* FLAC frame is at least 9 byte in size */ - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if (iteration == 0 || this_frame_sample > target_sample || target_sample - this_frame_sample > LINEAR_SEARCH_WITHIN_SAMPLES) { - if (iteration >= BINARY_SEARCH_AFTER_ITERATION) { - pos = (right_pos + left_pos) / 2; - } - else { -#ifndef FLAC__INTEGER_ONLY_LIBRARY - pos = (FLAC__uint64)((double)(target_sample - left_sample) / (double)(right_sample - left_sample) * (double)(right_pos - left_pos)) + left_pos; -#else - /* a little less accurate: */ - if ((target_sample-left_sample <= 0xffffffff) && (right_pos-left_pos <= 0xffffffff)) - pos = (FLAC__int64)(((target_sample-left_sample) * (right_pos-left_pos)) / (right_sample-left_sample)) + left_pos; - else /* @@@ WATCHOUT, ~2TB limit */ - pos = (FLAC__int64)((((target_sample-left_sample)>>8) * ((right_pos-left_pos)>>8)) / ((right_sample-left_sample)>>16)) + left_pos; -#endif - /* @@@ TODO: might want to limit pos to some distance - * before EOF, to make sure we land before the last frame, - * thereby getting a this_frame_sample and so having a better - * estimate. - */ - } - - /* physical seek */ - if(decoder->private_->seek_callback((FLAC__StreamDecoder*)decoder, (FLAC__uint64)pos, decoder->private_->client_data) != FLAC__STREAM_DECODER_SEEK_STATUS_OK) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!FLAC__stream_decoder_flush(decoder)) { - /* above call sets the state for us */ - return false; - } - did_a_seek = true; - } - else - did_a_seek = false; - - decoder->private_->got_a_frame = false; - if(!FLAC__stream_decoder_process_single(decoder) || - decoder->protected_->state == FLAC__STREAM_DECODER_ABORTED) { - if(decoder->protected_->state != FLAC__STREAM_DECODER_ABORTED && decoder->protected_->state != FLAC__STREAM_DECODER_MEMORY_ALLOCATION_ERROR) - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - if(!decoder->private_->got_a_frame) { - if(did_a_seek) { - /* this can happen if we seek to a point after the last frame; we drop - * to binary search right away in this case to avoid any wasted - * iterations of proportional search. - */ - right_pos = pos; - BINARY_SEARCH_AFTER_ITERATION = 0; - } - else { - /* this can probably only happen if total_samples is unknown and the - * target_sample is past the end of the stream - */ - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - } - /* our write callback will change the state when it gets to the target frame */ - else if(!decoder->private_->is_seeking) { - break; - } - else { - this_frame_sample = decoder->private_->last_frame.header.number.sample_number; - FLAC__ASSERT(decoder->private_->last_frame.header.number_type == FLAC__FRAME_NUMBER_TYPE_SAMPLE_NUMBER); - - if (did_a_seek) { - if (this_frame_sample <= target_sample) { - /* The 'equal' case should not happen, since - * FLAC__stream_decoder_process_single() - * should recognize that it has hit the - * target sample and we would exit through - * the 'break' above. - */ - FLAC__ASSERT(this_frame_sample != target_sample); - - left_sample = this_frame_sample; - /* sanity check to avoid infinite loop */ - if (left_pos == pos) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - left_pos = pos; - } - else { - right_sample = this_frame_sample; - /* sanity check to avoid infinite loop */ - if (right_pos == pos) { - decoder->protected_->state = FLAC__STREAM_DECODER_SEEK_ERROR; - return false; - } - right_pos = pos; - } - } - } - } - /* Tell ogg decoder aspect that seeking is done */ - FLAC__ogg_decoder_aspect_set_seek_parameters(&decoder->protected_->ogg_decoder_aspect, 0); - return true; -} -#endif - -#if 0 /* bstone */ -FLAC__StreamDecoderReadStatus file_read_callback_(const FLAC__StreamDecoder *decoder, FLAC__byte buffer[], size_t *bytes, void *client_data) -{ - (void)client_data; - - if(*bytes > 0) { - *bytes = fread(buffer, sizeof(FLAC__byte), *bytes, decoder->private_->file); - if(ferror(decoder->private_->file)) - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; - else if(*bytes == 0) - return FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM; - else - return FLAC__STREAM_DECODER_READ_STATUS_CONTINUE; - } - else - return FLAC__STREAM_DECODER_READ_STATUS_ABORT; /* abort to avoid a deadlock */ -} - -FLAC__StreamDecoderSeekStatus file_seek_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 absolute_byte_offset, void *client_data) -{ - (void)client_data; - - if(decoder->private_->file == stdin) - return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED; - else if(fseeko(decoder->private_->file, (FLAC__off_t)absolute_byte_offset, SEEK_SET) < 0) - return FLAC__STREAM_DECODER_SEEK_STATUS_ERROR; - else - return FLAC__STREAM_DECODER_SEEK_STATUS_OK; -} - -FLAC__StreamDecoderTellStatus file_tell_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *absolute_byte_offset, void *client_data) -{ - FLAC__off_t pos; - (void)client_data; - - if(decoder->private_->file == stdin) - return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED; - else if((pos = ftello(decoder->private_->file)) < 0) - return FLAC__STREAM_DECODER_TELL_STATUS_ERROR; - else { - *absolute_byte_offset = (FLAC__uint64)pos; - return FLAC__STREAM_DECODER_TELL_STATUS_OK; - } -} - -FLAC__StreamDecoderLengthStatus file_length_callback_(const FLAC__StreamDecoder *decoder, FLAC__uint64 *stream_length, void *client_data) -{ - struct flac_stat_s filestats; - (void)client_data; - - if(decoder->private_->file == stdin) - return FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED; - -#ifndef FLAC__USE_FILELENGTHI64 - if(flac_fstat(fileno(decoder->private_->file), &filestats) != 0) -#else - filestats.st_size = _filelengthi64(fileno(decoder->private_->file)); - if(filestats.st_size < 0) -#endif - return FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR; - else { - *stream_length = (FLAC__uint64)filestats.st_size; - return FLAC__STREAM_DECODER_LENGTH_STATUS_OK; - } -} - -FLAC__bool file_eof_callback_(const FLAC__StreamDecoder *decoder, void *client_data) -{ - (void)client_data; - - return feof(decoder->private_->file)? true : false; -} -#endif /* bstone */ diff --git a/src/lib/ogg/CMakeLists.txt b/src/lib/ogg/CMakeLists.txt deleted file mode 100644 index a9489c81..00000000 --- a/src/lib/ogg/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -# bstone -cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -project(bstone_lib_ogg VERSION 1.0.0 LANGUAGES C) -message(STATUS "[${PROJECT_NAME}] v${PROJECT_VERSION}") -add_library(${PROJECT_NAME} STATIC) -add_library(bstone::lib::ogg ALIAS ${PROJECT_NAME}) -set_target_properties(${PROJECT_NAME} PROPERTIES - C_STANDARD 99 - C_STANDARD_REQUIRED ON - C_EXTENSIONS OFF -) -target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W1>) -target_include_directories(${PROJECT_NAME} PUBLIC include) -target_sources(${PROJECT_NAME} PRIVATE - include/ogg/config_types.h - include/ogg/ogg.h - include/ogg/os_types.h - src/bitwise.c - src/crctable.h - src/framing.c -) diff --git a/src/lib/ogg/COPYING b/src/lib/ogg/COPYING deleted file mode 100644 index 6111c6c5..00000000 --- a/src/lib/ogg/COPYING +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2002, Xiph.org Foundation - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -- Neither the name of the Xiph.org Foundation nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/lib/ogg/bstone_ogg_changelog.txt b/src/lib/ogg/bstone_ogg_changelog.txt deleted file mode 100644 index fbfdefc9..00000000 --- a/src/lib/ogg/bstone_ogg_changelog.txt +++ /dev/null @@ -1,5 +0,0 @@ -Based on https://downloads.xiph.org/releases/ogg/libogg-1.3.6.zip - -- Essential files only. -- Custom CMake scripts. -- Custom header `include/ogg/config_types.h`. diff --git a/src/lib/ogg/include/ogg/config_types.h b/src/lib/ogg/include/ogg/config_types.h deleted file mode 100644 index 9a6118bd..00000000 --- a/src/lib/ogg/include/ogg/config_types.h +++ /dev/null @@ -1 +0,0 @@ -#include diff --git a/src/lib/ogg/include/ogg/ogg.h b/src/lib/ogg/include/ogg/ogg.h deleted file mode 100644 index c4325aa7..00000000 --- a/src/lib/ogg/include/ogg/ogg.h +++ /dev/null @@ -1,209 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: toplevel libogg include - - ********************************************************************/ -#ifndef _OGG_H -#define _OGG_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -typedef struct { - void *iov_base; - size_t iov_len; -} ogg_iovec_t; - -typedef struct { - long endbyte; - int endbit; - - unsigned char *buffer; - unsigned char *ptr; - long storage; -} oggpack_buffer; - -/* ogg_page is used to encapsulate the data in one Ogg bitstream page *****/ - -typedef struct { - unsigned char *header; - long header_len; - unsigned char *body; - long body_len; -} ogg_page; - -/* ogg_stream_state contains the current encode/decode state of a logical - Ogg bitstream **********************************************************/ - -typedef struct { - unsigned char *body_data; /* bytes from packet bodies */ - long body_storage; /* storage elements allocated */ - long body_fill; /* elements stored; fill mark */ - long body_returned; /* elements of fill returned */ - - - int *lacing_vals; /* The values that will go to the segment table */ - ogg_int64_t *granule_vals; /* granulepos values for headers. Not compact - this way, but it is simple coupled to the - lacing fifo */ - long lacing_storage; - long lacing_fill; - long lacing_packet; - long lacing_returned; - - unsigned char header[282]; /* working space for header encode */ - int header_fill; - - int e_o_s; /* set when we have buffered the last packet in the - logical bitstream */ - int b_o_s; /* set after we've written the initial page - of a logical bitstream */ - long serialno; - long pageno; - ogg_int64_t packetno; /* sequence number for decode; the framing - knows where there's a hole in the data, - but we need coupling so that the codec - (which is in a separate abstraction - layer) also knows about the gap */ - ogg_int64_t granulepos; - -} ogg_stream_state; - -/* ogg_packet is used to encapsulate the data and metadata belonging - to a single raw Ogg/Vorbis packet *************************************/ - -typedef struct { - unsigned char *packet; - long bytes; - long b_o_s; - long e_o_s; - - ogg_int64_t granulepos; - - ogg_int64_t packetno; /* sequence number for decode; the framing - knows where there's a hole in the data, - but we need coupling so that the codec - (which is in a separate abstraction - layer) also knows about the gap */ -} ogg_packet; - -typedef struct { - unsigned char *data; - int storage; - int fill; - int returned; - - int unsynced; - int headerbytes; - int bodybytes; -} ogg_sync_state; - -/* Ogg BITSTREAM PRIMITIVES: bitstream ************************/ - -extern void oggpack_writeinit(oggpack_buffer *b); -extern int oggpack_writecheck(oggpack_buffer *b); -extern void oggpack_writetrunc(oggpack_buffer *b,long bits); -extern void oggpack_writealign(oggpack_buffer *b); -extern void oggpack_writecopy(oggpack_buffer *b,void *source,long bits); -extern void oggpack_reset(oggpack_buffer *b); -extern void oggpack_writeclear(oggpack_buffer *b); -extern void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); -extern void oggpack_write(oggpack_buffer *b,unsigned long value,int bits); -extern long oggpack_look(oggpack_buffer *b,int bits); -extern long oggpack_look1(oggpack_buffer *b); -extern void oggpack_adv(oggpack_buffer *b,int bits); -extern void oggpack_adv1(oggpack_buffer *b); -extern long oggpack_read(oggpack_buffer *b,int bits); -extern long oggpack_read1(oggpack_buffer *b); -extern long oggpack_bytes(oggpack_buffer *b); -extern long oggpack_bits(oggpack_buffer *b); -extern unsigned char *oggpack_get_buffer(oggpack_buffer *b); - -extern void oggpackB_writeinit(oggpack_buffer *b); -extern int oggpackB_writecheck(oggpack_buffer *b); -extern void oggpackB_writetrunc(oggpack_buffer *b,long bits); -extern void oggpackB_writealign(oggpack_buffer *b); -extern void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits); -extern void oggpackB_reset(oggpack_buffer *b); -extern void oggpackB_writeclear(oggpack_buffer *b); -extern void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes); -extern void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits); -extern long oggpackB_look(oggpack_buffer *b,int bits); -extern long oggpackB_look1(oggpack_buffer *b); -extern void oggpackB_adv(oggpack_buffer *b,int bits); -extern void oggpackB_adv1(oggpack_buffer *b); -extern long oggpackB_read(oggpack_buffer *b,int bits); -extern long oggpackB_read1(oggpack_buffer *b); -extern long oggpackB_bytes(oggpack_buffer *b); -extern long oggpackB_bits(oggpack_buffer *b); -extern unsigned char *oggpackB_get_buffer(oggpack_buffer *b); - -/* Ogg BITSTREAM PRIMITIVES: encoding **************************/ - -extern int ogg_stream_packetin(ogg_stream_state *os, ogg_packet *op); -extern int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, - int count, long e_o_s, ogg_int64_t granulepos); -extern int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og); -extern int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill); -extern int ogg_stream_flush(ogg_stream_state *os, ogg_page *og); -extern int ogg_stream_flush_fill(ogg_stream_state *os, ogg_page *og, int nfill); - -/* Ogg BITSTREAM PRIMITIVES: decoding **************************/ - -extern int ogg_sync_init(ogg_sync_state *oy); -extern int ogg_sync_clear(ogg_sync_state *oy); -extern int ogg_sync_reset(ogg_sync_state *oy); -extern int ogg_sync_destroy(ogg_sync_state *oy); -extern int ogg_sync_check(ogg_sync_state *oy); - -extern char *ogg_sync_buffer(ogg_sync_state *oy, long size); -extern int ogg_sync_wrote(ogg_sync_state *oy, long bytes); -extern long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og); -extern int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og); -extern int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og); -extern int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op); -extern int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op); - -/* Ogg BITSTREAM PRIMITIVES: general ***************************/ - -extern int ogg_stream_init(ogg_stream_state *os,int serialno); -extern int ogg_stream_clear(ogg_stream_state *os); -extern int ogg_stream_reset(ogg_stream_state *os); -extern int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno); -extern int ogg_stream_destroy(ogg_stream_state *os); -extern int ogg_stream_check(ogg_stream_state *os); -extern int ogg_stream_eos(ogg_stream_state *os); - -extern void ogg_page_checksum_set(ogg_page *og); - -extern int ogg_page_version(const ogg_page *og); -extern int ogg_page_continued(const ogg_page *og); -extern int ogg_page_bos(const ogg_page *og); -extern int ogg_page_eos(const ogg_page *og); -extern ogg_int64_t ogg_page_granulepos(const ogg_page *og); -extern int ogg_page_serialno(const ogg_page *og); -extern long ogg_page_pageno(const ogg_page *og); -extern int ogg_page_packets(const ogg_page *og); - -extern void ogg_packet_clear(ogg_packet *op); - - -#ifdef __cplusplus -} -#endif - -#endif /* _OGG_H */ diff --git a/src/lib/ogg/include/ogg/os_types.h b/src/lib/ogg/include/ogg/os_types.h deleted file mode 100644 index e655a1d6..00000000 --- a/src/lib/ogg/include/ogg/os_types.h +++ /dev/null @@ -1,158 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2002 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: Define a consistent set of types on each platform. - - ********************************************************************/ -#ifndef _OS_TYPES_H -#define _OS_TYPES_H - -/* make it easy on the folks that want to compile the libs with a - different malloc than stdlib */ -#define _ogg_malloc malloc -#define _ogg_calloc calloc -#define _ogg_realloc realloc -#define _ogg_free free - -#if defined(_WIN32) - -# if defined(__CYGWIN__) -# include - typedef int16_t ogg_int16_t; - typedef uint16_t ogg_uint16_t; - typedef int32_t ogg_int32_t; - typedef uint32_t ogg_uint32_t; - typedef int64_t ogg_int64_t; - typedef uint64_t ogg_uint64_t; -# elif defined(__MINGW32__) -# include - typedef short ogg_int16_t; - typedef unsigned short ogg_uint16_t; - typedef int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef long long ogg_int64_t; - typedef unsigned long long ogg_uint64_t; -# elif defined(__MWERKS__) - typedef long long ogg_int64_t; - typedef unsigned long long ogg_uint64_t; - typedef int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef short ogg_int16_t; - typedef unsigned short ogg_uint16_t; -# else -# if defined(_MSC_VER) && (_MSC_VER >= 1800) /* MSVC 2013 and newer */ -# include - typedef int16_t ogg_int16_t; - typedef uint16_t ogg_uint16_t; - typedef int32_t ogg_int32_t; - typedef uint32_t ogg_uint32_t; - typedef int64_t ogg_int64_t; - typedef uint64_t ogg_uint64_t; -# else - /* MSVC/Borland */ - typedef __int64 ogg_int64_t; - typedef __int32 ogg_int32_t; - typedef unsigned __int32 ogg_uint32_t; - typedef unsigned __int64 ogg_uint64_t; - typedef __int16 ogg_int16_t; - typedef unsigned __int16 ogg_uint16_t; -# endif -# endif - -#elif (defined(__APPLE__) && defined(__MACH__)) /* MacOS X Framework build */ - -# include - typedef int16_t ogg_int16_t; - typedef u_int16_t ogg_uint16_t; - typedef int32_t ogg_int32_t; - typedef u_int32_t ogg_uint32_t; - typedef int64_t ogg_int64_t; - typedef u_int64_t ogg_uint64_t; - -#elif defined(__HAIKU__) - - /* Haiku */ -# include - typedef short ogg_int16_t; - typedef unsigned short ogg_uint16_t; - typedef int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef long long ogg_int64_t; - typedef unsigned long long ogg_uint64_t; - -#elif defined(__BEOS__) - - /* Be */ -# include - typedef int16_t ogg_int16_t; - typedef uint16_t ogg_uint16_t; - typedef int32_t ogg_int32_t; - typedef uint32_t ogg_uint32_t; - typedef int64_t ogg_int64_t; - typedef uint64_t ogg_uint64_t; - -#elif defined (__EMX__) - - /* OS/2 GCC */ - typedef short ogg_int16_t; - typedef unsigned short ogg_uint16_t; - typedef int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef long long ogg_int64_t; - typedef unsigned long long ogg_uint64_t; - - -#elif defined (DJGPP) - - /* DJGPP */ - typedef short ogg_int16_t; - typedef int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef long long ogg_int64_t; - typedef unsigned long long ogg_uint64_t; - -#elif defined(R5900) - - /* PS2 EE */ - typedef long ogg_int64_t; - typedef unsigned long ogg_uint64_t; - typedef int ogg_int32_t; - typedef unsigned ogg_uint32_t; - typedef short ogg_int16_t; - -#elif defined(__SYMBIAN32__) - - /* Symbian GCC */ - typedef signed short ogg_int16_t; - typedef unsigned short ogg_uint16_t; - typedef signed int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef long long int ogg_int64_t; - typedef unsigned long long int ogg_uint64_t; - -#elif defined(__TMS320C6X__) - - /* TI C64x compiler */ - typedef signed short ogg_int16_t; - typedef unsigned short ogg_uint16_t; - typedef signed int ogg_int32_t; - typedef unsigned int ogg_uint32_t; - typedef long long int ogg_int64_t; - typedef unsigned long long int ogg_uint64_t; - -#else - -# include - -#endif - -#endif /* _OS_TYPES_H */ diff --git a/src/lib/ogg/src/bitwise.c b/src/lib/ogg/src/bitwise.c deleted file mode 100644 index 75b1f0ed..00000000 --- a/src/lib/ogg/src/bitwise.c +++ /dev/null @@ -1,1089 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2014 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: packing variable sized words into an octet stream - - ********************************************************************/ - -/* We're 'LSb' endian; if we write a word but read individual bits, - then we'll read the lsb first */ - -#include -#include -#include -#include - -#define BUFFER_INCREMENT 256 - -static const unsigned long mask[]= -{0x00000000,0x00000001,0x00000003,0x00000007,0x0000000f, - 0x0000001f,0x0000003f,0x0000007f,0x000000ff,0x000001ff, - 0x000003ff,0x000007ff,0x00000fff,0x00001fff,0x00003fff, - 0x00007fff,0x0000ffff,0x0001ffff,0x0003ffff,0x0007ffff, - 0x000fffff,0x001fffff,0x003fffff,0x007fffff,0x00ffffff, - 0x01ffffff,0x03ffffff,0x07ffffff,0x0fffffff,0x1fffffff, - 0x3fffffff,0x7fffffff,0xffffffff }; - -static const unsigned int mask8B[]= -{0x00,0x80,0xc0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff}; - -void oggpack_writeinit(oggpack_buffer *b){ - memset(b,0,sizeof(*b)); - b->ptr=b->buffer=_ogg_malloc(BUFFER_INCREMENT); - if (!b->buffer) - return; - b->buffer[0]='\0'; - b->storage=BUFFER_INCREMENT; -} - -void oggpackB_writeinit(oggpack_buffer *b){ - oggpack_writeinit(b); -} - -int oggpack_writecheck(oggpack_buffer *b){ - if(!b->ptr || !b->storage)return -1; - return 0; -} - -int oggpackB_writecheck(oggpack_buffer *b){ - return oggpack_writecheck(b); -} - -void oggpack_writetrunc(oggpack_buffer *b,long bits){ - long bytes=bits>>3; - if(b->ptr){ - bits-=bytes*8; - b->ptr=b->buffer+bytes; - b->endbit=bits; - b->endbyte=bytes; - *b->ptr&=mask[bits]; - } -} - -void oggpackB_writetrunc(oggpack_buffer *b,long bits){ - long bytes=bits>>3; - if(b->ptr){ - bits-=bytes*8; - b->ptr=b->buffer+bytes; - b->endbit=bits; - b->endbyte=bytes; - *b->ptr&=mask8B[bits]; - } -} - -/* Takes only up to 32 bits. */ -void oggpack_write(oggpack_buffer *b,unsigned long value,int bits){ - if(bits<0 || bits>32) goto err; - if(b->endbyte>=b->storage-4){ - void *ret; - if(!b->ptr)return; - if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; - ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); - if(!ret) goto err; - b->buffer=ret; - b->storage+=BUFFER_INCREMENT; - b->ptr=b->buffer+b->endbyte; - } - - value&=mask[bits]; - bits+=b->endbit; - - b->ptr[0]|=value<endbit; - - if(bits>=8){ - b->ptr[1]=(unsigned char)(value>>(8-b->endbit)); - if(bits>=16){ - b->ptr[2]=(unsigned char)(value>>(16-b->endbit)); - if(bits>=24){ - b->ptr[3]=(unsigned char)(value>>(24-b->endbit)); - if(bits>=32){ - if(b->endbit) - b->ptr[4]=(unsigned char)(value>>(32-b->endbit)); - else - b->ptr[4]=0; - } - } - } - } - - b->endbyte+=bits/8; - b->ptr+=bits/8; - b->endbit=bits&7; - return; - err: - oggpack_writeclear(b); -} - -/* Takes only up to 32 bits. */ -void oggpackB_write(oggpack_buffer *b,unsigned long value,int bits){ - if(bits<0 || bits>32) goto err; - if(b->endbyte>=b->storage-4){ - void *ret; - if(!b->ptr)return; - if(b->storage>LONG_MAX-BUFFER_INCREMENT) goto err; - ret=_ogg_realloc(b->buffer,b->storage+BUFFER_INCREMENT); - if(!ret) goto err; - b->buffer=ret; - b->storage+=BUFFER_INCREMENT; - b->ptr=b->buffer+b->endbyte; - } - - value=(value&mask[bits])<<(32-bits); - bits+=b->endbit; - - b->ptr[0]|=value>>(24+b->endbit); - - if(bits>=8){ - b->ptr[1]=(unsigned char)(value>>(16+b->endbit)); - if(bits>=16){ - b->ptr[2]=(unsigned char)(value>>(8+b->endbit)); - if(bits>=24){ - b->ptr[3]=(unsigned char)(value>>(b->endbit)); - if(bits>=32){ - if(b->endbit) - b->ptr[4]=(unsigned char)(value<<(8-b->endbit)); - else - b->ptr[4]=0; - } - } - } - } - - b->endbyte+=bits/8; - b->ptr+=bits/8; - b->endbit=bits&7; - return; - err: - oggpack_writeclear(b); -} - -void oggpack_writealign(oggpack_buffer *b){ - int bits=8-b->endbit; - if(bits<8) - oggpack_write(b,0,bits); -} - -void oggpackB_writealign(oggpack_buffer *b){ - int bits=8-b->endbit; - if(bits<8) - oggpackB_write(b,0,bits); -} - -static void oggpack_writecopy_helper(oggpack_buffer *b, - void *source, - long bits, - void (*w)(oggpack_buffer *, - unsigned long, - int), - int msb){ - unsigned char *ptr=(unsigned char *)source; - - long bytes=bits/8; - long pbytes=(b->endbit+bits)/8; - bits-=bytes*8; - - /* expand storage up-front */ - if(b->endbyte+pbytes>=b->storage){ - void *ret; - if(!b->ptr) goto err; - if(b->storage>b->endbyte+pbytes+BUFFER_INCREMENT) goto err; - b->storage=b->endbyte+pbytes+BUFFER_INCREMENT; - ret=_ogg_realloc(b->buffer,b->storage); - if(!ret) goto err; - b->buffer=ret; - b->ptr=b->buffer+b->endbyte; - } - - /* copy whole octets */ - if(b->endbit){ - int i; - /* unaligned copy. Do it the hard way. */ - for(i=0;iptr,source,bytes); - b->ptr+=bytes; - b->endbyte+=bytes; - *b->ptr=0; - } - - /* copy trailing bits */ - if(bits){ - if(msb) - w(b,(unsigned long)(ptr[bytes]>>(8-bits)),bits); - else - w(b,(unsigned long)(ptr[bytes]),bits); - } - return; - err: - oggpack_writeclear(b); -} - -void oggpack_writecopy(oggpack_buffer *b,void *source,long bits){ - oggpack_writecopy_helper(b,source,bits,oggpack_write,0); -} - -void oggpackB_writecopy(oggpack_buffer *b,void *source,long bits){ - oggpack_writecopy_helper(b,source,bits,oggpackB_write,1); -} - -void oggpack_reset(oggpack_buffer *b){ - if(!b->ptr)return; - b->ptr=b->buffer; - b->buffer[0]=0; - b->endbit=b->endbyte=0; -} - -void oggpackB_reset(oggpack_buffer *b){ - oggpack_reset(b); -} - -void oggpack_writeclear(oggpack_buffer *b){ - if(b->buffer)_ogg_free(b->buffer); - memset(b,0,sizeof(*b)); -} - -void oggpackB_writeclear(oggpack_buffer *b){ - oggpack_writeclear(b); -} - -void oggpack_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ - memset(b,0,sizeof(*b)); - b->buffer=b->ptr=buf; - b->storage=bytes; -} - -void oggpackB_readinit(oggpack_buffer *b,unsigned char *buf,int bytes){ - oggpack_readinit(b,buf,bytes); -} - -/* Read in bits without advancing the bitptr; bits <= 32 */ -long oggpack_look(oggpack_buffer *b,int bits){ - unsigned long ret; - unsigned long m; - - if(bits<0 || bits>32) return -1; - m=mask[bits]; - bits+=b->endbit; - - if(b->endbyte >= b->storage-4){ - /* not the main path */ - if(b->endbyte > b->storage-((bits+7)>>3)) return -1; - /* special case to avoid reading b->ptr[0], which might be past the end of - the buffer; also skips some useless accounting */ - else if(!bits)return(0L); - } - - ret=b->ptr[0]>>b->endbit; - if(bits>8){ - ret|=(unsigned long)b->ptr[1]<<(8-b->endbit); - if(bits>16){ - ret|=(unsigned long)b->ptr[2]<<(16-b->endbit); - if(bits>24){ - ret|=(unsigned long)b->ptr[3]<<(24-b->endbit); - if(bits>32 && b->endbit) - ret|=(unsigned long)b->ptr[4]<<(32-b->endbit); - } - } - } - return(m&ret); -} - -/* Read in bits without advancing the bitptr; bits <= 32 */ -long oggpackB_look(oggpack_buffer *b,int bits){ - unsigned long ret; - int m=32-bits; - - if(m<0 || m>32) return -1; - bits+=b->endbit; - - if(b->endbyte >= b->storage-4){ - /* not the main path */ - if(b->endbyte > b->storage-((bits+7)>>3)) return -1; - /* special case to avoid reading b->ptr[0], which might be past the end of - the buffer; also skips some useless accounting */ - else if(!bits)return(0L); - } - - ret=(unsigned long)b->ptr[0]<<(24+b->endbit); - if(bits>8){ - ret|=(unsigned long)b->ptr[1]<<(16+b->endbit); - if(bits>16){ - ret|=(unsigned long)b->ptr[2]<<(8+b->endbit); - if(bits>24){ - ret|=(unsigned long)b->ptr[3]<<(b->endbit); - if(bits>32 && b->endbit) - ret|=b->ptr[4]>>(8-b->endbit); - } - } - } - return ((ret&0xffffffff)>>(m>>1))>>((m+1)>>1); -} - -long oggpack_look1(oggpack_buffer *b){ - if(b->endbyte>=b->storage)return(-1); - return((b->ptr[0]>>b->endbit)&1); -} - -long oggpackB_look1(oggpack_buffer *b){ - if(b->endbyte>=b->storage)return(-1); - return((b->ptr[0]>>(7-b->endbit))&1); -} - -void oggpack_adv(oggpack_buffer *b,int bits){ - bits+=b->endbit; - - if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; - - b->ptr+=bits/8; - b->endbyte+=bits/8; - b->endbit=bits&7; - return; - - overflow: - b->ptr=NULL; - b->endbyte=b->storage; - b->endbit=1; -} - -void oggpackB_adv(oggpack_buffer *b,int bits){ - oggpack_adv(b,bits); -} - -void oggpack_adv1(oggpack_buffer *b){ - if(++(b->endbit)>7){ - b->endbit=0; - b->ptr++; - b->endbyte++; - } -} - -void oggpackB_adv1(oggpack_buffer *b){ - oggpack_adv1(b); -} - -/* bits <= 32 */ -long oggpack_read(oggpack_buffer *b,int bits){ - long ret; - unsigned long m; - - if(bits<0 || bits>32) goto err; - m=mask[bits]; - bits+=b->endbit; - - if(b->endbyte >= b->storage-4){ - /* not the main path */ - if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; - /* special case to avoid reading b->ptr[0], which might be past the end of - the buffer; also skips some useless accounting */ - else if(!bits)return(0L); - } - - ret=b->ptr[0]>>b->endbit; - if(bits>8){ - ret|=(unsigned long)b->ptr[1]<<(8-b->endbit); - if(bits>16){ - ret|=(unsigned long)b->ptr[2]<<(16-b->endbit); - if(bits>24){ - ret|=(unsigned long)b->ptr[3]<<(24-b->endbit); - if(bits>32 && b->endbit){ - ret|=(unsigned long)b->ptr[4]<<(32-b->endbit); - } - } - } - } - ret&=m; - b->ptr+=bits/8; - b->endbyte+=bits/8; - b->endbit=bits&7; - return ret; - - overflow: - err: - b->ptr=NULL; - b->endbyte=b->storage; - b->endbit=1; - return -1L; -} - -/* bits <= 32 */ -long oggpackB_read(oggpack_buffer *b,int bits){ - long ret; - long m=32-bits; - - if(m<0 || m>32) goto err; - bits+=b->endbit; - - if(b->endbyte+4>=b->storage){ - /* not the main path */ - if(b->endbyte > b->storage-((bits+7)>>3)) goto overflow; - /* special case to avoid reading b->ptr[0], which might be past the end of - the buffer; also skips some useless accounting */ - else if(!bits)return(0L); - } - - ret=(unsigned long)b->ptr[0]<<(24+b->endbit); - if(bits>8){ - ret|=(unsigned long)b->ptr[1]<<(16+b->endbit); - if(bits>16){ - ret|=(unsigned long)b->ptr[2]<<(8+b->endbit); - if(bits>24){ - ret|=(unsigned long)b->ptr[3]<<(b->endbit); - if(bits>32 && b->endbit) - ret|=b->ptr[4]>>(8-b->endbit); - } - } - } - ret=((ret&0xffffffffUL)>>(m>>1))>>((m+1)>>1); - - b->ptr+=bits/8; - b->endbyte+=bits/8; - b->endbit=bits&7; - return ret; - - overflow: - err: - b->ptr=NULL; - b->endbyte=b->storage; - b->endbit=1; - return -1L; -} - -long oggpack_read1(oggpack_buffer *b){ - long ret; - - if(b->endbyte >= b->storage) goto overflow; - ret=(b->ptr[0]>>b->endbit)&1; - - b->endbit++; - if(b->endbit>7){ - b->endbit=0; - b->ptr++; - b->endbyte++; - } - return ret; - - overflow: - b->ptr=NULL; - b->endbyte=b->storage; - b->endbit=1; - return -1L; -} - -long oggpackB_read1(oggpack_buffer *b){ - long ret; - - if(b->endbyte >= b->storage) goto overflow; - ret=(b->ptr[0]>>(7-b->endbit))&1; - - b->endbit++; - if(b->endbit>7){ - b->endbit=0; - b->ptr++; - b->endbyte++; - } - return ret; - - overflow: - b->ptr=NULL; - b->endbyte=b->storage; - b->endbit=1; - return -1L; -} - -long oggpack_bytes(oggpack_buffer *b){ - return(b->endbyte+(b->endbit+7)/8); -} - -long oggpack_bits(oggpack_buffer *b){ - return(b->endbyte*8+b->endbit); -} - -long oggpackB_bytes(oggpack_buffer *b){ - return oggpack_bytes(b); -} - -long oggpackB_bits(oggpack_buffer *b){ - return oggpack_bits(b); -} - -unsigned char *oggpack_get_buffer(oggpack_buffer *b){ - return(b->buffer); -} - -unsigned char *oggpackB_get_buffer(oggpack_buffer *b){ - return oggpack_get_buffer(b); -} - -/* Self test of the bitwise routines; everything else is based on - them, so they damned well better be solid. */ - -#ifdef _V_SELFTEST -#include - -static int ilog(unsigned int v){ - int ret=0; - while(v){ - ret++; - v>>=1; - } - return(ret); -} - -oggpack_buffer o; -oggpack_buffer r; - -void report(char *in){ - fprintf(stderr,"%s",in); - exit(1); -} - -void cliptest(unsigned long *b,int vals,int bits,int *comp,int compsize){ - long bytes,i; - unsigned char *buffer; - - oggpack_reset(&o); - for(i=0;i - -static const ogg_uint32_t crc_lookup[8][256]={ -{0x00000000,0x04c11db7,0x09823b6e,0x0d4326d9,0x130476dc,0x17c56b6b,0x1a864db2,0x1e475005, - 0x2608edb8,0x22c9f00f,0x2f8ad6d6,0x2b4bcb61,0x350c9b64,0x31cd86d3,0x3c8ea00a,0x384fbdbd, - 0x4c11db70,0x48d0c6c7,0x4593e01e,0x4152fda9,0x5f15adac,0x5bd4b01b,0x569796c2,0x52568b75, - 0x6a1936c8,0x6ed82b7f,0x639b0da6,0x675a1011,0x791d4014,0x7ddc5da3,0x709f7b7a,0x745e66cd, - 0x9823b6e0,0x9ce2ab57,0x91a18d8e,0x95609039,0x8b27c03c,0x8fe6dd8b,0x82a5fb52,0x8664e6e5, - 0xbe2b5b58,0xbaea46ef,0xb7a96036,0xb3687d81,0xad2f2d84,0xa9ee3033,0xa4ad16ea,0xa06c0b5d, - 0xd4326d90,0xd0f37027,0xddb056fe,0xd9714b49,0xc7361b4c,0xc3f706fb,0xceb42022,0xca753d95, - 0xf23a8028,0xf6fb9d9f,0xfbb8bb46,0xff79a6f1,0xe13ef6f4,0xe5ffeb43,0xe8bccd9a,0xec7dd02d, - 0x34867077,0x30476dc0,0x3d044b19,0x39c556ae,0x278206ab,0x23431b1c,0x2e003dc5,0x2ac12072, - 0x128e9dcf,0x164f8078,0x1b0ca6a1,0x1fcdbb16,0x018aeb13,0x054bf6a4,0x0808d07d,0x0cc9cdca, - 0x7897ab07,0x7c56b6b0,0x71159069,0x75d48dde,0x6b93dddb,0x6f52c06c,0x6211e6b5,0x66d0fb02, - 0x5e9f46bf,0x5a5e5b08,0x571d7dd1,0x53dc6066,0x4d9b3063,0x495a2dd4,0x44190b0d,0x40d816ba, - 0xaca5c697,0xa864db20,0xa527fdf9,0xa1e6e04e,0xbfa1b04b,0xbb60adfc,0xb6238b25,0xb2e29692, - 0x8aad2b2f,0x8e6c3698,0x832f1041,0x87ee0df6,0x99a95df3,0x9d684044,0x902b669d,0x94ea7b2a, - 0xe0b41de7,0xe4750050,0xe9362689,0xedf73b3e,0xf3b06b3b,0xf771768c,0xfa325055,0xfef34de2, - 0xc6bcf05f,0xc27dede8,0xcf3ecb31,0xcbffd686,0xd5b88683,0xd1799b34,0xdc3abded,0xd8fba05a, - 0x690ce0ee,0x6dcdfd59,0x608edb80,0x644fc637,0x7a089632,0x7ec98b85,0x738aad5c,0x774bb0eb, - 0x4f040d56,0x4bc510e1,0x46863638,0x42472b8f,0x5c007b8a,0x58c1663d,0x558240e4,0x51435d53, - 0x251d3b9e,0x21dc2629,0x2c9f00f0,0x285e1d47,0x36194d42,0x32d850f5,0x3f9b762c,0x3b5a6b9b, - 0x0315d626,0x07d4cb91,0x0a97ed48,0x0e56f0ff,0x1011a0fa,0x14d0bd4d,0x19939b94,0x1d528623, - 0xf12f560e,0xf5ee4bb9,0xf8ad6d60,0xfc6c70d7,0xe22b20d2,0xe6ea3d65,0xeba91bbc,0xef68060b, - 0xd727bbb6,0xd3e6a601,0xdea580d8,0xda649d6f,0xc423cd6a,0xc0e2d0dd,0xcda1f604,0xc960ebb3, - 0xbd3e8d7e,0xb9ff90c9,0xb4bcb610,0xb07daba7,0xae3afba2,0xaafbe615,0xa7b8c0cc,0xa379dd7b, - 0x9b3660c6,0x9ff77d71,0x92b45ba8,0x9675461f,0x8832161a,0x8cf30bad,0x81b02d74,0x857130c3, - 0x5d8a9099,0x594b8d2e,0x5408abf7,0x50c9b640,0x4e8ee645,0x4a4ffbf2,0x470cdd2b,0x43cdc09c, - 0x7b827d21,0x7f436096,0x7200464f,0x76c15bf8,0x68860bfd,0x6c47164a,0x61043093,0x65c52d24, - 0x119b4be9,0x155a565e,0x18197087,0x1cd86d30,0x029f3d35,0x065e2082,0x0b1d065b,0x0fdc1bec, - 0x3793a651,0x3352bbe6,0x3e119d3f,0x3ad08088,0x2497d08d,0x2056cd3a,0x2d15ebe3,0x29d4f654, - 0xc5a92679,0xc1683bce,0xcc2b1d17,0xc8ea00a0,0xd6ad50a5,0xd26c4d12,0xdf2f6bcb,0xdbee767c, - 0xe3a1cbc1,0xe760d676,0xea23f0af,0xeee2ed18,0xf0a5bd1d,0xf464a0aa,0xf9278673,0xfde69bc4, - 0x89b8fd09,0x8d79e0be,0x803ac667,0x84fbdbd0,0x9abc8bd5,0x9e7d9662,0x933eb0bb,0x97ffad0c, - 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4}, - -{0x00000000,0xd219c1dc,0xa0f29e0f,0x72eb5fd3,0x452421a9,0x973de075,0xe5d6bfa6,0x37cf7e7a, - 0x8a484352,0x5851828e,0x2abadd5d,0xf8a31c81,0xcf6c62fb,0x1d75a327,0x6f9efcf4,0xbd873d28, - 0x10519b13,0xc2485acf,0xb0a3051c,0x62bac4c0,0x5575baba,0x876c7b66,0xf58724b5,0x279ee569, - 0x9a19d841,0x4800199d,0x3aeb464e,0xe8f28792,0xdf3df9e8,0x0d243834,0x7fcf67e7,0xadd6a63b, - 0x20a33626,0xf2baf7fa,0x8051a829,0x524869f5,0x6587178f,0xb79ed653,0xc5758980,0x176c485c, - 0xaaeb7574,0x78f2b4a8,0x0a19eb7b,0xd8002aa7,0xefcf54dd,0x3dd69501,0x4f3dcad2,0x9d240b0e, - 0x30f2ad35,0xe2eb6ce9,0x9000333a,0x4219f2e6,0x75d68c9c,0xa7cf4d40,0xd5241293,0x073dd34f, - 0xbabaee67,0x68a32fbb,0x1a487068,0xc851b1b4,0xff9ecfce,0x2d870e12,0x5f6c51c1,0x8d75901d, - 0x41466c4c,0x935fad90,0xe1b4f243,0x33ad339f,0x04624de5,0xd67b8c39,0xa490d3ea,0x76891236, - 0xcb0e2f1e,0x1917eec2,0x6bfcb111,0xb9e570cd,0x8e2a0eb7,0x5c33cf6b,0x2ed890b8,0xfcc15164, - 0x5117f75f,0x830e3683,0xf1e56950,0x23fca88c,0x1433d6f6,0xc62a172a,0xb4c148f9,0x66d88925, - 0xdb5fb40d,0x094675d1,0x7bad2a02,0xa9b4ebde,0x9e7b95a4,0x4c625478,0x3e890bab,0xec90ca77, - 0x61e55a6a,0xb3fc9bb6,0xc117c465,0x130e05b9,0x24c17bc3,0xf6d8ba1f,0x8433e5cc,0x562a2410, - 0xebad1938,0x39b4d8e4,0x4b5f8737,0x994646eb,0xae893891,0x7c90f94d,0x0e7ba69e,0xdc626742, - 0x71b4c179,0xa3ad00a5,0xd1465f76,0x035f9eaa,0x3490e0d0,0xe689210c,0x94627edf,0x467bbf03, - 0xfbfc822b,0x29e543f7,0x5b0e1c24,0x8917ddf8,0xbed8a382,0x6cc1625e,0x1e2a3d8d,0xcc33fc51, - 0x828cd898,0x50951944,0x227e4697,0xf067874b,0xc7a8f931,0x15b138ed,0x675a673e,0xb543a6e2, - 0x08c49bca,0xdadd5a16,0xa83605c5,0x7a2fc419,0x4de0ba63,0x9ff97bbf,0xed12246c,0x3f0be5b0, - 0x92dd438b,0x40c48257,0x322fdd84,0xe0361c58,0xd7f96222,0x05e0a3fe,0x770bfc2d,0xa5123df1, - 0x189500d9,0xca8cc105,0xb8679ed6,0x6a7e5f0a,0x5db12170,0x8fa8e0ac,0xfd43bf7f,0x2f5a7ea3, - 0xa22feebe,0x70362f62,0x02dd70b1,0xd0c4b16d,0xe70bcf17,0x35120ecb,0x47f95118,0x95e090c4, - 0x2867adec,0xfa7e6c30,0x889533e3,0x5a8cf23f,0x6d438c45,0xbf5a4d99,0xcdb1124a,0x1fa8d396, - 0xb27e75ad,0x6067b471,0x128ceba2,0xc0952a7e,0xf75a5404,0x254395d8,0x57a8ca0b,0x85b10bd7, - 0x383636ff,0xea2ff723,0x98c4a8f0,0x4add692c,0x7d121756,0xaf0bd68a,0xdde08959,0x0ff94885, - 0xc3cab4d4,0x11d37508,0x63382adb,0xb121eb07,0x86ee957d,0x54f754a1,0x261c0b72,0xf405caae, - 0x4982f786,0x9b9b365a,0xe9706989,0x3b69a855,0x0ca6d62f,0xdebf17f3,0xac544820,0x7e4d89fc, - 0xd39b2fc7,0x0182ee1b,0x7369b1c8,0xa1707014,0x96bf0e6e,0x44a6cfb2,0x364d9061,0xe45451bd, - 0x59d36c95,0x8bcaad49,0xf921f29a,0x2b383346,0x1cf74d3c,0xceee8ce0,0xbc05d333,0x6e1c12ef, - 0xe36982f2,0x3170432e,0x439b1cfd,0x9182dd21,0xa64da35b,0x74546287,0x06bf3d54,0xd4a6fc88, - 0x6921c1a0,0xbb38007c,0xc9d35faf,0x1bca9e73,0x2c05e009,0xfe1c21d5,0x8cf77e06,0x5eeebfda, - 0xf33819e1,0x2121d83d,0x53ca87ee,0x81d34632,0xb61c3848,0x6405f994,0x16eea647,0xc4f7679b, - 0x79705ab3,0xab699b6f,0xd982c4bc,0x0b9b0560,0x3c547b1a,0xee4dbac6,0x9ca6e515,0x4ebf24c9}, - -{0x00000000,0x01d8ac87,0x03b1590e,0x0269f589,0x0762b21c,0x06ba1e9b,0x04d3eb12,0x050b4795, - 0x0ec56438,0x0f1dc8bf,0x0d743d36,0x0cac91b1,0x09a7d624,0x087f7aa3,0x0a168f2a,0x0bce23ad, - 0x1d8ac870,0x1c5264f7,0x1e3b917e,0x1fe33df9,0x1ae87a6c,0x1b30d6eb,0x19592362,0x18818fe5, - 0x134fac48,0x129700cf,0x10fef546,0x112659c1,0x142d1e54,0x15f5b2d3,0x179c475a,0x1644ebdd, - 0x3b1590e0,0x3acd3c67,0x38a4c9ee,0x397c6569,0x3c7722fc,0x3daf8e7b,0x3fc67bf2,0x3e1ed775, - 0x35d0f4d8,0x3408585f,0x3661add6,0x37b90151,0x32b246c4,0x336aea43,0x31031fca,0x30dbb34d, - 0x269f5890,0x2747f417,0x252e019e,0x24f6ad19,0x21fdea8c,0x2025460b,0x224cb382,0x23941f05, - 0x285a3ca8,0x2982902f,0x2beb65a6,0x2a33c921,0x2f388eb4,0x2ee02233,0x2c89d7ba,0x2d517b3d, - 0x762b21c0,0x77f38d47,0x759a78ce,0x7442d449,0x714993dc,0x70913f5b,0x72f8cad2,0x73206655, - 0x78ee45f8,0x7936e97f,0x7b5f1cf6,0x7a87b071,0x7f8cf7e4,0x7e545b63,0x7c3daeea,0x7de5026d, - 0x6ba1e9b0,0x6a794537,0x6810b0be,0x69c81c39,0x6cc35bac,0x6d1bf72b,0x6f7202a2,0x6eaaae25, - 0x65648d88,0x64bc210f,0x66d5d486,0x670d7801,0x62063f94,0x63de9313,0x61b7669a,0x606fca1d, - 0x4d3eb120,0x4ce61da7,0x4e8fe82e,0x4f5744a9,0x4a5c033c,0x4b84afbb,0x49ed5a32,0x4835f6b5, - 0x43fbd518,0x4223799f,0x404a8c16,0x41922091,0x44996704,0x4541cb83,0x47283e0a,0x46f0928d, - 0x50b47950,0x516cd5d7,0x5305205e,0x52dd8cd9,0x57d6cb4c,0x560e67cb,0x54679242,0x55bf3ec5, - 0x5e711d68,0x5fa9b1ef,0x5dc04466,0x5c18e8e1,0x5913af74,0x58cb03f3,0x5aa2f67a,0x5b7a5afd, - 0xec564380,0xed8eef07,0xefe71a8e,0xee3fb609,0xeb34f19c,0xeaec5d1b,0xe885a892,0xe95d0415, - 0xe29327b8,0xe34b8b3f,0xe1227eb6,0xe0fad231,0xe5f195a4,0xe4293923,0xe640ccaa,0xe798602d, - 0xf1dc8bf0,0xf0042777,0xf26dd2fe,0xf3b57e79,0xf6be39ec,0xf766956b,0xf50f60e2,0xf4d7cc65, - 0xff19efc8,0xfec1434f,0xfca8b6c6,0xfd701a41,0xf87b5dd4,0xf9a3f153,0xfbca04da,0xfa12a85d, - 0xd743d360,0xd69b7fe7,0xd4f28a6e,0xd52a26e9,0xd021617c,0xd1f9cdfb,0xd3903872,0xd24894f5, - 0xd986b758,0xd85e1bdf,0xda37ee56,0xdbef42d1,0xdee40544,0xdf3ca9c3,0xdd555c4a,0xdc8df0cd, - 0xcac91b10,0xcb11b797,0xc978421e,0xc8a0ee99,0xcdaba90c,0xcc73058b,0xce1af002,0xcfc25c85, - 0xc40c7f28,0xc5d4d3af,0xc7bd2626,0xc6658aa1,0xc36ecd34,0xc2b661b3,0xc0df943a,0xc10738bd, - 0x9a7d6240,0x9ba5cec7,0x99cc3b4e,0x981497c9,0x9d1fd05c,0x9cc77cdb,0x9eae8952,0x9f7625d5, - 0x94b80678,0x9560aaff,0x97095f76,0x96d1f3f1,0x93dab464,0x920218e3,0x906bed6a,0x91b341ed, - 0x87f7aa30,0x862f06b7,0x8446f33e,0x859e5fb9,0x8095182c,0x814db4ab,0x83244122,0x82fceda5, - 0x8932ce08,0x88ea628f,0x8a839706,0x8b5b3b81,0x8e507c14,0x8f88d093,0x8de1251a,0x8c39899d, - 0xa168f2a0,0xa0b05e27,0xa2d9abae,0xa3010729,0xa60a40bc,0xa7d2ec3b,0xa5bb19b2,0xa463b535, - 0xafad9698,0xae753a1f,0xac1ccf96,0xadc46311,0xa8cf2484,0xa9178803,0xab7e7d8a,0xaaa6d10d, - 0xbce23ad0,0xbd3a9657,0xbf5363de,0xbe8bcf59,0xbb8088cc,0xba58244b,0xb831d1c2,0xb9e97d45, - 0xb2275ee8,0xb3fff26f,0xb19607e6,0xb04eab61,0xb545ecf4,0xb49d4073,0xb6f4b5fa,0xb72c197d}, - -{0x00000000,0xdc6d9ab7,0xbc1a28d9,0x6077b26e,0x7cf54c05,0xa098d6b2,0xc0ef64dc,0x1c82fe6b, - 0xf9ea980a,0x258702bd,0x45f0b0d3,0x999d2a64,0x851fd40f,0x59724eb8,0x3905fcd6,0xe5686661, - 0xf7142da3,0x2b79b714,0x4b0e057a,0x97639fcd,0x8be161a6,0x578cfb11,0x37fb497f,0xeb96d3c8, - 0x0efeb5a9,0xd2932f1e,0xb2e49d70,0x6e8907c7,0x720bf9ac,0xae66631b,0xce11d175,0x127c4bc2, - 0xeae946f1,0x3684dc46,0x56f36e28,0x8a9ef49f,0x961c0af4,0x4a719043,0x2a06222d,0xf66bb89a, - 0x1303defb,0xcf6e444c,0xaf19f622,0x73746c95,0x6ff692fe,0xb39b0849,0xd3ecba27,0x0f812090, - 0x1dfd6b52,0xc190f1e5,0xa1e7438b,0x7d8ad93c,0x61082757,0xbd65bde0,0xdd120f8e,0x017f9539, - 0xe417f358,0x387a69ef,0x580ddb81,0x84604136,0x98e2bf5d,0x448f25ea,0x24f89784,0xf8950d33, - 0xd1139055,0x0d7e0ae2,0x6d09b88c,0xb164223b,0xade6dc50,0x718b46e7,0x11fcf489,0xcd916e3e, - 0x28f9085f,0xf49492e8,0x94e32086,0x488eba31,0x540c445a,0x8861deed,0xe8166c83,0x347bf634, - 0x2607bdf6,0xfa6a2741,0x9a1d952f,0x46700f98,0x5af2f1f3,0x869f6b44,0xe6e8d92a,0x3a85439d, - 0xdfed25fc,0x0380bf4b,0x63f70d25,0xbf9a9792,0xa31869f9,0x7f75f34e,0x1f024120,0xc36fdb97, - 0x3bfad6a4,0xe7974c13,0x87e0fe7d,0x5b8d64ca,0x470f9aa1,0x9b620016,0xfb15b278,0x277828cf, - 0xc2104eae,0x1e7dd419,0x7e0a6677,0xa267fcc0,0xbee502ab,0x6288981c,0x02ff2a72,0xde92b0c5, - 0xcceefb07,0x108361b0,0x70f4d3de,0xac994969,0xb01bb702,0x6c762db5,0x0c019fdb,0xd06c056c, - 0x3504630d,0xe969f9ba,0x891e4bd4,0x5573d163,0x49f12f08,0x959cb5bf,0xf5eb07d1,0x29869d66, - 0xa6e63d1d,0x7a8ba7aa,0x1afc15c4,0xc6918f73,0xda137118,0x067eebaf,0x660959c1,0xba64c376, - 0x5f0ca517,0x83613fa0,0xe3168dce,0x3f7b1779,0x23f9e912,0xff9473a5,0x9fe3c1cb,0x438e5b7c, - 0x51f210be,0x8d9f8a09,0xede83867,0x3185a2d0,0x2d075cbb,0xf16ac60c,0x911d7462,0x4d70eed5, - 0xa81888b4,0x74751203,0x1402a06d,0xc86f3ada,0xd4edc4b1,0x08805e06,0x68f7ec68,0xb49a76df, - 0x4c0f7bec,0x9062e15b,0xf0155335,0x2c78c982,0x30fa37e9,0xec97ad5e,0x8ce01f30,0x508d8587, - 0xb5e5e3e6,0x69887951,0x09ffcb3f,0xd5925188,0xc910afe3,0x157d3554,0x750a873a,0xa9671d8d, - 0xbb1b564f,0x6776ccf8,0x07017e96,0xdb6ce421,0xc7ee1a4a,0x1b8380fd,0x7bf43293,0xa799a824, - 0x42f1ce45,0x9e9c54f2,0xfeebe69c,0x22867c2b,0x3e048240,0xe26918f7,0x821eaa99,0x5e73302e, - 0x77f5ad48,0xab9837ff,0xcbef8591,0x17821f26,0x0b00e14d,0xd76d7bfa,0xb71ac994,0x6b775323, - 0x8e1f3542,0x5272aff5,0x32051d9b,0xee68872c,0xf2ea7947,0x2e87e3f0,0x4ef0519e,0x929dcb29, - 0x80e180eb,0x5c8c1a5c,0x3cfba832,0xe0963285,0xfc14ccee,0x20795659,0x400ee437,0x9c637e80, - 0x790b18e1,0xa5668256,0xc5113038,0x197caa8f,0x05fe54e4,0xd993ce53,0xb9e47c3d,0x6589e68a, - 0x9d1cebb9,0x4171710e,0x2106c360,0xfd6b59d7,0xe1e9a7bc,0x3d843d0b,0x5df38f65,0x819e15d2, - 0x64f673b3,0xb89be904,0xd8ec5b6a,0x0481c1dd,0x18033fb6,0xc46ea501,0xa419176f,0x78748dd8, - 0x6a08c61a,0xb6655cad,0xd612eec3,0x0a7f7474,0x16fd8a1f,0xca9010a8,0xaae7a2c6,0x768a3871, - 0x93e25e10,0x4f8fc4a7,0x2ff876c9,0xf395ec7e,0xef171215,0x337a88a2,0x530d3acc,0x8f60a07b}, - -{0x00000000,0x490d678d,0x921acf1a,0xdb17a897,0x20f48383,0x69f9e40e,0xb2ee4c99,0xfbe32b14, - 0x41e90706,0x08e4608b,0xd3f3c81c,0x9afeaf91,0x611d8485,0x2810e308,0xf3074b9f,0xba0a2c12, - 0x83d20e0c,0xcadf6981,0x11c8c116,0x58c5a69b,0xa3268d8f,0xea2bea02,0x313c4295,0x78312518, - 0xc23b090a,0x8b366e87,0x5021c610,0x192ca19d,0xe2cf8a89,0xabc2ed04,0x70d54593,0x39d8221e, - 0x036501af,0x4a686622,0x917fceb5,0xd872a938,0x2391822c,0x6a9ce5a1,0xb18b4d36,0xf8862abb, - 0x428c06a9,0x0b816124,0xd096c9b3,0x999bae3e,0x6278852a,0x2b75e2a7,0xf0624a30,0xb96f2dbd, - 0x80b70fa3,0xc9ba682e,0x12adc0b9,0x5ba0a734,0xa0438c20,0xe94eebad,0x3259433a,0x7b5424b7, - 0xc15e08a5,0x88536f28,0x5344c7bf,0x1a49a032,0xe1aa8b26,0xa8a7ecab,0x73b0443c,0x3abd23b1, - 0x06ca035e,0x4fc764d3,0x94d0cc44,0xddddabc9,0x263e80dd,0x6f33e750,0xb4244fc7,0xfd29284a, - 0x47230458,0x0e2e63d5,0xd539cb42,0x9c34accf,0x67d787db,0x2edae056,0xf5cd48c1,0xbcc02f4c, - 0x85180d52,0xcc156adf,0x1702c248,0x5e0fa5c5,0xa5ec8ed1,0xece1e95c,0x37f641cb,0x7efb2646, - 0xc4f10a54,0x8dfc6dd9,0x56ebc54e,0x1fe6a2c3,0xe40589d7,0xad08ee5a,0x761f46cd,0x3f122140, - 0x05af02f1,0x4ca2657c,0x97b5cdeb,0xdeb8aa66,0x255b8172,0x6c56e6ff,0xb7414e68,0xfe4c29e5, - 0x444605f7,0x0d4b627a,0xd65ccaed,0x9f51ad60,0x64b28674,0x2dbfe1f9,0xf6a8496e,0xbfa52ee3, - 0x867d0cfd,0xcf706b70,0x1467c3e7,0x5d6aa46a,0xa6898f7e,0xef84e8f3,0x34934064,0x7d9e27e9, - 0xc7940bfb,0x8e996c76,0x558ec4e1,0x1c83a36c,0xe7608878,0xae6deff5,0x757a4762,0x3c7720ef, - 0x0d9406bc,0x44996131,0x9f8ec9a6,0xd683ae2b,0x2d60853f,0x646de2b2,0xbf7a4a25,0xf6772da8, - 0x4c7d01ba,0x05706637,0xde67cea0,0x976aa92d,0x6c898239,0x2584e5b4,0xfe934d23,0xb79e2aae, - 0x8e4608b0,0xc74b6f3d,0x1c5cc7aa,0x5551a027,0xaeb28b33,0xe7bfecbe,0x3ca84429,0x75a523a4, - 0xcfaf0fb6,0x86a2683b,0x5db5c0ac,0x14b8a721,0xef5b8c35,0xa656ebb8,0x7d41432f,0x344c24a2, - 0x0ef10713,0x47fc609e,0x9cebc809,0xd5e6af84,0x2e058490,0x6708e31d,0xbc1f4b8a,0xf5122c07, - 0x4f180015,0x06156798,0xdd02cf0f,0x940fa882,0x6fec8396,0x26e1e41b,0xfdf64c8c,0xb4fb2b01, - 0x8d23091f,0xc42e6e92,0x1f39c605,0x5634a188,0xadd78a9c,0xe4daed11,0x3fcd4586,0x76c0220b, - 0xccca0e19,0x85c76994,0x5ed0c103,0x17dda68e,0xec3e8d9a,0xa533ea17,0x7e244280,0x3729250d, - 0x0b5e05e2,0x4253626f,0x9944caf8,0xd049ad75,0x2baa8661,0x62a7e1ec,0xb9b0497b,0xf0bd2ef6, - 0x4ab702e4,0x03ba6569,0xd8adcdfe,0x91a0aa73,0x6a438167,0x234ee6ea,0xf8594e7d,0xb15429f0, - 0x888c0bee,0xc1816c63,0x1a96c4f4,0x539ba379,0xa878886d,0xe175efe0,0x3a624777,0x736f20fa, - 0xc9650ce8,0x80686b65,0x5b7fc3f2,0x1272a47f,0xe9918f6b,0xa09ce8e6,0x7b8b4071,0x328627fc, - 0x083b044d,0x413663c0,0x9a21cb57,0xd32cacda,0x28cf87ce,0x61c2e043,0xbad548d4,0xf3d82f59, - 0x49d2034b,0x00df64c6,0xdbc8cc51,0x92c5abdc,0x692680c8,0x202be745,0xfb3c4fd2,0xb231285f, - 0x8be90a41,0xc2e46dcc,0x19f3c55b,0x50fea2d6,0xab1d89c2,0xe210ee4f,0x390746d8,0x700a2155, - 0xca000d47,0x830d6aca,0x581ac25d,0x1117a5d0,0xeaf48ec4,0xa3f9e949,0x78ee41de,0x31e32653}, - -{0x00000000,0x1b280d78,0x36501af0,0x2d781788,0x6ca035e0,0x77883898,0x5af02f10,0x41d82268, - 0xd9406bc0,0xc26866b8,0xef107130,0xf4387c48,0xb5e05e20,0xaec85358,0x83b044d0,0x989849a8, - 0xb641ca37,0xad69c74f,0x8011d0c7,0x9b39ddbf,0xdae1ffd7,0xc1c9f2af,0xecb1e527,0xf799e85f, - 0x6f01a1f7,0x7429ac8f,0x5951bb07,0x4279b67f,0x03a19417,0x1889996f,0x35f18ee7,0x2ed9839f, - 0x684289d9,0x736a84a1,0x5e129329,0x453a9e51,0x04e2bc39,0x1fcab141,0x32b2a6c9,0x299aabb1, - 0xb102e219,0xaa2aef61,0x8752f8e9,0x9c7af591,0xdda2d7f9,0xc68ada81,0xebf2cd09,0xf0dac071, - 0xde0343ee,0xc52b4e96,0xe853591e,0xf37b5466,0xb2a3760e,0xa98b7b76,0x84f36cfe,0x9fdb6186, - 0x0743282e,0x1c6b2556,0x311332de,0x2a3b3fa6,0x6be31dce,0x70cb10b6,0x5db3073e,0x469b0a46, - 0xd08513b2,0xcbad1eca,0xe6d50942,0xfdfd043a,0xbc252652,0xa70d2b2a,0x8a753ca2,0x915d31da, - 0x09c57872,0x12ed750a,0x3f956282,0x24bd6ffa,0x65654d92,0x7e4d40ea,0x53355762,0x481d5a1a, - 0x66c4d985,0x7decd4fd,0x5094c375,0x4bbcce0d,0x0a64ec65,0x114ce11d,0x3c34f695,0x271cfbed, - 0xbf84b245,0xa4acbf3d,0x89d4a8b5,0x92fca5cd,0xd32487a5,0xc80c8add,0xe5749d55,0xfe5c902d, - 0xb8c79a6b,0xa3ef9713,0x8e97809b,0x95bf8de3,0xd467af8b,0xcf4fa2f3,0xe237b57b,0xf91fb803, - 0x6187f1ab,0x7aaffcd3,0x57d7eb5b,0x4cffe623,0x0d27c44b,0x160fc933,0x3b77debb,0x205fd3c3, - 0x0e86505c,0x15ae5d24,0x38d64aac,0x23fe47d4,0x622665bc,0x790e68c4,0x54767f4c,0x4f5e7234, - 0xd7c63b9c,0xccee36e4,0xe196216c,0xfabe2c14,0xbb660e7c,0xa04e0304,0x8d36148c,0x961e19f4, - 0xa5cb3ad3,0xbee337ab,0x939b2023,0x88b32d5b,0xc96b0f33,0xd243024b,0xff3b15c3,0xe41318bb, - 0x7c8b5113,0x67a35c6b,0x4adb4be3,0x51f3469b,0x102b64f3,0x0b03698b,0x267b7e03,0x3d53737b, - 0x138af0e4,0x08a2fd9c,0x25daea14,0x3ef2e76c,0x7f2ac504,0x6402c87c,0x497adff4,0x5252d28c, - 0xcaca9b24,0xd1e2965c,0xfc9a81d4,0xe7b28cac,0xa66aaec4,0xbd42a3bc,0x903ab434,0x8b12b94c, - 0xcd89b30a,0xd6a1be72,0xfbd9a9fa,0xe0f1a482,0xa12986ea,0xba018b92,0x97799c1a,0x8c519162, - 0x14c9d8ca,0x0fe1d5b2,0x2299c23a,0x39b1cf42,0x7869ed2a,0x6341e052,0x4e39f7da,0x5511faa2, - 0x7bc8793d,0x60e07445,0x4d9863cd,0x56b06eb5,0x17684cdd,0x0c4041a5,0x2138562d,0x3a105b55, - 0xa28812fd,0xb9a01f85,0x94d8080d,0x8ff00575,0xce28271d,0xd5002a65,0xf8783ded,0xe3503095, - 0x754e2961,0x6e662419,0x431e3391,0x58363ee9,0x19ee1c81,0x02c611f9,0x2fbe0671,0x34960b09, - 0xac0e42a1,0xb7264fd9,0x9a5e5851,0x81765529,0xc0ae7741,0xdb867a39,0xf6fe6db1,0xedd660c9, - 0xc30fe356,0xd827ee2e,0xf55ff9a6,0xee77f4de,0xafafd6b6,0xb487dbce,0x99ffcc46,0x82d7c13e, - 0x1a4f8896,0x016785ee,0x2c1f9266,0x37379f1e,0x76efbd76,0x6dc7b00e,0x40bfa786,0x5b97aafe, - 0x1d0ca0b8,0x0624adc0,0x2b5cba48,0x3074b730,0x71ac9558,0x6a849820,0x47fc8fa8,0x5cd482d0, - 0xc44ccb78,0xdf64c600,0xf21cd188,0xe934dcf0,0xa8ecfe98,0xb3c4f3e0,0x9ebce468,0x8594e910, - 0xab4d6a8f,0xb06567f7,0x9d1d707f,0x86357d07,0xc7ed5f6f,0xdcc55217,0xf1bd459f,0xea9548e7, - 0x720d014f,0x69250c37,0x445d1bbf,0x5f7516c7,0x1ead34af,0x058539d7,0x28fd2e5f,0x33d52327}, - -{0x00000000,0x4f576811,0x9eaed022,0xd1f9b833,0x399cbdf3,0x76cbd5e2,0xa7326dd1,0xe86505c0, - 0x73397be6,0x3c6e13f7,0xed97abc4,0xa2c0c3d5,0x4aa5c615,0x05f2ae04,0xd40b1637,0x9b5c7e26, - 0xe672f7cc,0xa9259fdd,0x78dc27ee,0x378b4fff,0xdfee4a3f,0x90b9222e,0x41409a1d,0x0e17f20c, - 0x954b8c2a,0xda1ce43b,0x0be55c08,0x44b23419,0xacd731d9,0xe38059c8,0x3279e1fb,0x7d2e89ea, - 0xc824f22f,0x87739a3e,0x568a220d,0x19dd4a1c,0xf1b84fdc,0xbeef27cd,0x6f169ffe,0x2041f7ef, - 0xbb1d89c9,0xf44ae1d8,0x25b359eb,0x6ae431fa,0x8281343a,0xcdd65c2b,0x1c2fe418,0x53788c09, - 0x2e5605e3,0x61016df2,0xb0f8d5c1,0xffafbdd0,0x17cab810,0x589dd001,0x89646832,0xc6330023, - 0x5d6f7e05,0x12381614,0xc3c1ae27,0x8c96c636,0x64f3c3f6,0x2ba4abe7,0xfa5d13d4,0xb50a7bc5, - 0x9488f9e9,0xdbdf91f8,0x0a2629cb,0x457141da,0xad14441a,0xe2432c0b,0x33ba9438,0x7cedfc29, - 0xe7b1820f,0xa8e6ea1e,0x791f522d,0x36483a3c,0xde2d3ffc,0x917a57ed,0x4083efde,0x0fd487cf, - 0x72fa0e25,0x3dad6634,0xec54de07,0xa303b616,0x4b66b3d6,0x0431dbc7,0xd5c863f4,0x9a9f0be5, - 0x01c375c3,0x4e941dd2,0x9f6da5e1,0xd03acdf0,0x385fc830,0x7708a021,0xa6f11812,0xe9a67003, - 0x5cac0bc6,0x13fb63d7,0xc202dbe4,0x8d55b3f5,0x6530b635,0x2a67de24,0xfb9e6617,0xb4c90e06, - 0x2f957020,0x60c21831,0xb13ba002,0xfe6cc813,0x1609cdd3,0x595ea5c2,0x88a71df1,0xc7f075e0, - 0xbadefc0a,0xf589941b,0x24702c28,0x6b274439,0x834241f9,0xcc1529e8,0x1dec91db,0x52bbf9ca, - 0xc9e787ec,0x86b0effd,0x574957ce,0x181e3fdf,0xf07b3a1f,0xbf2c520e,0x6ed5ea3d,0x2182822c, - 0x2dd0ee65,0x62878674,0xb37e3e47,0xfc295656,0x144c5396,0x5b1b3b87,0x8ae283b4,0xc5b5eba5, - 0x5ee99583,0x11befd92,0xc04745a1,0x8f102db0,0x67752870,0x28224061,0xf9dbf852,0xb68c9043, - 0xcba219a9,0x84f571b8,0x550cc98b,0x1a5ba19a,0xf23ea45a,0xbd69cc4b,0x6c907478,0x23c71c69, - 0xb89b624f,0xf7cc0a5e,0x2635b26d,0x6962da7c,0x8107dfbc,0xce50b7ad,0x1fa90f9e,0x50fe678f, - 0xe5f41c4a,0xaaa3745b,0x7b5acc68,0x340da479,0xdc68a1b9,0x933fc9a8,0x42c6719b,0x0d91198a, - 0x96cd67ac,0xd99a0fbd,0x0863b78e,0x4734df9f,0xaf51da5f,0xe006b24e,0x31ff0a7d,0x7ea8626c, - 0x0386eb86,0x4cd18397,0x9d283ba4,0xd27f53b5,0x3a1a5675,0x754d3e64,0xa4b48657,0xebe3ee46, - 0x70bf9060,0x3fe8f871,0xee114042,0xa1462853,0x49232d93,0x06744582,0xd78dfdb1,0x98da95a0, - 0xb958178c,0xf60f7f9d,0x27f6c7ae,0x68a1afbf,0x80c4aa7f,0xcf93c26e,0x1e6a7a5d,0x513d124c, - 0xca616c6a,0x8536047b,0x54cfbc48,0x1b98d459,0xf3fdd199,0xbcaab988,0x6d5301bb,0x220469aa, - 0x5f2ae040,0x107d8851,0xc1843062,0x8ed35873,0x66b65db3,0x29e135a2,0xf8188d91,0xb74fe580, - 0x2c139ba6,0x6344f3b7,0xb2bd4b84,0xfdea2395,0x158f2655,0x5ad84e44,0x8b21f677,0xc4769e66, - 0x717ce5a3,0x3e2b8db2,0xefd23581,0xa0855d90,0x48e05850,0x07b73041,0xd64e8872,0x9919e063, - 0x02459e45,0x4d12f654,0x9ceb4e67,0xd3bc2676,0x3bd923b6,0x748e4ba7,0xa577f394,0xea209b85, - 0x970e126f,0xd8597a7e,0x09a0c24d,0x46f7aa5c,0xae92af9c,0xe1c5c78d,0x303c7fbe,0x7f6b17af, - 0xe4376989,0xab600198,0x7a99b9ab,0x35ced1ba,0xddabd47a,0x92fcbc6b,0x43050458,0x0c526c49}, - -{0x00000000,0x5ba1dcca,0xb743b994,0xece2655e,0x6a466e9f,0x31e7b255,0xdd05d70b,0x86a40bc1, - 0xd48cdd3e,0x8f2d01f4,0x63cf64aa,0x386eb860,0xbecab3a1,0xe56b6f6b,0x09890a35,0x5228d6ff, - 0xadd8a7cb,0xf6797b01,0x1a9b1e5f,0x413ac295,0xc79ec954,0x9c3f159e,0x70dd70c0,0x2b7cac0a, - 0x79547af5,0x22f5a63f,0xce17c361,0x95b61fab,0x1312146a,0x48b3c8a0,0xa451adfe,0xfff07134, - 0x5f705221,0x04d18eeb,0xe833ebb5,0xb392377f,0x35363cbe,0x6e97e074,0x8275852a,0xd9d459e0, - 0x8bfc8f1f,0xd05d53d5,0x3cbf368b,0x671eea41,0xe1bae180,0xba1b3d4a,0x56f95814,0x0d5884de, - 0xf2a8f5ea,0xa9092920,0x45eb4c7e,0x1e4a90b4,0x98ee9b75,0xc34f47bf,0x2fad22e1,0x740cfe2b, - 0x262428d4,0x7d85f41e,0x91679140,0xcac64d8a,0x4c62464b,0x17c39a81,0xfb21ffdf,0xa0802315, - 0xbee0a442,0xe5417888,0x09a31dd6,0x5202c11c,0xd4a6cadd,0x8f071617,0x63e57349,0x3844af83, - 0x6a6c797c,0x31cda5b6,0xdd2fc0e8,0x868e1c22,0x002a17e3,0x5b8bcb29,0xb769ae77,0xecc872bd, - 0x13380389,0x4899df43,0xa47bba1d,0xffda66d7,0x797e6d16,0x22dfb1dc,0xce3dd482,0x959c0848, - 0xc7b4deb7,0x9c15027d,0x70f76723,0x2b56bbe9,0xadf2b028,0xf6536ce2,0x1ab109bc,0x4110d576, - 0xe190f663,0xba312aa9,0x56d34ff7,0x0d72933d,0x8bd698fc,0xd0774436,0x3c952168,0x6734fda2, - 0x351c2b5d,0x6ebdf797,0x825f92c9,0xd9fe4e03,0x5f5a45c2,0x04fb9908,0xe819fc56,0xb3b8209c, - 0x4c4851a8,0x17e98d62,0xfb0be83c,0xa0aa34f6,0x260e3f37,0x7dafe3fd,0x914d86a3,0xcaec5a69, - 0x98c48c96,0xc365505c,0x2f873502,0x7426e9c8,0xf282e209,0xa9233ec3,0x45c15b9d,0x1e608757, - 0x79005533,0x22a189f9,0xce43eca7,0x95e2306d,0x13463bac,0x48e7e766,0xa4058238,0xffa45ef2, - 0xad8c880d,0xf62d54c7,0x1acf3199,0x416eed53,0xc7cae692,0x9c6b3a58,0x70895f06,0x2b2883cc, - 0xd4d8f2f8,0x8f792e32,0x639b4b6c,0x383a97a6,0xbe9e9c67,0xe53f40ad,0x09dd25f3,0x527cf939, - 0x00542fc6,0x5bf5f30c,0xb7179652,0xecb64a98,0x6a124159,0x31b39d93,0xdd51f8cd,0x86f02407, - 0x26700712,0x7dd1dbd8,0x9133be86,0xca92624c,0x4c36698d,0x1797b547,0xfb75d019,0xa0d40cd3, - 0xf2fcda2c,0xa95d06e6,0x45bf63b8,0x1e1ebf72,0x98bab4b3,0xc31b6879,0x2ff90d27,0x7458d1ed, - 0x8ba8a0d9,0xd0097c13,0x3ceb194d,0x674ac587,0xe1eece46,0xba4f128c,0x56ad77d2,0x0d0cab18, - 0x5f247de7,0x0485a12d,0xe867c473,0xb3c618b9,0x35621378,0x6ec3cfb2,0x8221aaec,0xd9807626, - 0xc7e0f171,0x9c412dbb,0x70a348e5,0x2b02942f,0xada69fee,0xf6074324,0x1ae5267a,0x4144fab0, - 0x136c2c4f,0x48cdf085,0xa42f95db,0xff8e4911,0x792a42d0,0x228b9e1a,0xce69fb44,0x95c8278e, - 0x6a3856ba,0x31998a70,0xdd7bef2e,0x86da33e4,0x007e3825,0x5bdfe4ef,0xb73d81b1,0xec9c5d7b, - 0xbeb48b84,0xe515574e,0x09f73210,0x5256eeda,0xd4f2e51b,0x8f5339d1,0x63b15c8f,0x38108045, - 0x9890a350,0xc3317f9a,0x2fd31ac4,0x7472c60e,0xf2d6cdcf,0xa9771105,0x4595745b,0x1e34a891, - 0x4c1c7e6e,0x17bda2a4,0xfb5fc7fa,0xa0fe1b30,0x265a10f1,0x7dfbcc3b,0x9119a965,0xcab875af, - 0x3548049b,0x6ee9d851,0x820bbd0f,0xd9aa61c5,0x5f0e6a04,0x04afb6ce,0xe84dd390,0xb3ec0f5a, - 0xe1c4d9a5,0xba65056f,0x56876031,0x0d26bcfb,0x8b82b73a,0xd0236bf0,0x3cc10eae,0x6760d264}}; diff --git a/src/lib/ogg/src/framing.c b/src/lib/ogg/src/framing.c deleted file mode 100644 index 0ddf0fcf..00000000 --- a/src/lib/ogg/src/framing.c +++ /dev/null @@ -1,2138 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE Ogg CONTAINER SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2018 * - * by the Xiph.Org Foundation http://www.xiph.org/ * - * * - ******************************************************************** - - function: code raw packets into framed OggSquish stream and - decode Ogg streams back into raw packets - - note: The CRC code is directly derived from public domain code by - Ross Williams (ross@guest.adelaide.edu.au). See docs/framing.html - for details. - - ********************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include -#include -#include - -/* A complete description of Ogg framing exists in docs/framing.html */ - -int ogg_page_version(const ogg_page *og){ - return((int)(og->header[4])); -} - -int ogg_page_continued(const ogg_page *og){ - return((int)(og->header[5]&0x01)); -} - -int ogg_page_bos(const ogg_page *og){ - return((int)(og->header[5]&0x02)); -} - -int ogg_page_eos(const ogg_page *og){ - return((int)(og->header[5]&0x04)); -} - -ogg_int64_t ogg_page_granulepos(const ogg_page *og){ - unsigned char *page=og->header; - ogg_uint64_t granulepos=page[13]&(0xff); - granulepos= (granulepos<<8)|(page[12]&0xff); - granulepos= (granulepos<<8)|(page[11]&0xff); - granulepos= (granulepos<<8)|(page[10]&0xff); - granulepos= (granulepos<<8)|(page[9]&0xff); - granulepos= (granulepos<<8)|(page[8]&0xff); - granulepos= (granulepos<<8)|(page[7]&0xff); - granulepos= (granulepos<<8)|(page[6]&0xff); - return((ogg_int64_t)granulepos); -} - -int ogg_page_serialno(const ogg_page *og){ - return((int)((ogg_uint32_t)og->header[14]) | - ((ogg_uint32_t)og->header[15]<<8) | - ((ogg_uint32_t)og->header[16]<<16) | - ((ogg_uint32_t)og->header[17]<<24)); -} - -long ogg_page_pageno(const ogg_page *og){ - return((long)((ogg_uint32_t)og->header[18]) | - ((ogg_uint32_t)og->header[19]<<8) | - ((ogg_uint32_t)og->header[20]<<16) | - ((ogg_uint32_t)og->header[21]<<24)); -} - - - -/* returns the number of packets that are completed on this page (if - the leading packet is begun on a previous page, but ends on this - page, it's counted */ - -/* NOTE: - If a page consists of a packet begun on a previous page, and a new - packet begun (but not completed) on this page, the return will be: - ogg_page_packets(page) ==1, - ogg_page_continued(page) !=0 - - If a page happens to be a single packet that was begun on a - previous page, and spans to the next page (in the case of a three or - more page packet), the return will be: - ogg_page_packets(page) ==0, - ogg_page_continued(page) !=0 -*/ - -int ogg_page_packets(const ogg_page *og){ - int i,n=og->header[26],count=0; - for(i=0;iheader[27+i]<255)count++; - return(count); -} - - -#if 0 -/* helper to initialize lookup for direct-table CRC (illustrative; we - use the static init in crctable.h) */ - -static void _ogg_crc_init(){ - int i, j; - ogg_uint32_t polynomial, crc; - polynomial = 0x04c11db7; /* The same as the ethernet generator - polynomial, although we use an - unreflected alg and an init/final - of 0, not 0xffffffff */ - for (i = 0; i <= 0xFF; i++){ - crc = i << 24; - - for (j = 0; j < 8; j++) - crc = (crc << 1) ^ (crc & (1 << 31) ? polynomial : 0); - - crc_lookup[0][i] = crc; - } - - for (i = 0; i <= 0xFF; i++) - for (j = 1; j < 8; j++) - crc_lookup[j][i] = crc_lookup[0][(crc_lookup[j - 1][i] >> 24) & 0xFF] ^ (crc_lookup[j - 1][i] << 8); -} -#endif - -#include "crctable.h" - -/* init the encode/decode logical stream state */ - -int ogg_stream_init(ogg_stream_state *os,int serialno){ - if(os){ - memset(os,0,sizeof(*os)); - os->body_storage=16*1024; - os->lacing_storage=1024; - - os->body_data=_ogg_malloc(os->body_storage*sizeof(*os->body_data)); - os->lacing_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->lacing_vals)); - os->granule_vals=_ogg_malloc(os->lacing_storage*sizeof(*os->granule_vals)); - - if(!os->body_data || !os->lacing_vals || !os->granule_vals){ - ogg_stream_clear(os); - return -1; - } - - os->serialno=serialno; - - return(0); - } - return(-1); -} - -/* async/delayed error detection for the ogg_stream_state */ -int ogg_stream_check(ogg_stream_state *os){ - if(!os || !os->body_data) return -1; - return 0; -} - -/* _clear does not free os, only the non-flat storage within */ -int ogg_stream_clear(ogg_stream_state *os){ - if(os){ - if(os->body_data)_ogg_free(os->body_data); - if(os->lacing_vals)_ogg_free(os->lacing_vals); - if(os->granule_vals)_ogg_free(os->granule_vals); - - memset(os,0,sizeof(*os)); - } - return(0); -} - -int ogg_stream_destroy(ogg_stream_state *os){ - if(os){ - ogg_stream_clear(os); - _ogg_free(os); - } - return(0); -} - -/* Helpers for ogg_stream_encode; this keeps the structure and - what's happening fairly clear */ - -static int _os_body_expand(ogg_stream_state *os,long needed){ - if(os->body_storage-needed<=os->body_fill){ - long body_storage; - void *ret; - if(os->body_storage>LONG_MAX-needed){ - ogg_stream_clear(os); - return -1; - } - body_storage=os->body_storage+needed; - if(body_storagebody_data,body_storage*sizeof(*os->body_data)); - if(!ret){ - ogg_stream_clear(os); - return -1; - } - os->body_storage=body_storage; - os->body_data=ret; - } - return 0; -} - -static int _os_lacing_expand(ogg_stream_state *os,long needed){ - if(os->lacing_storage-needed<=os->lacing_fill){ - long lacing_storage; - void *ret; - if(os->lacing_storage>LONG_MAX-needed){ - ogg_stream_clear(os); - return -1; - } - lacing_storage=os->lacing_storage+needed; - if(lacing_storagelacing_vals,lacing_storage*sizeof(*os->lacing_vals)); - if(!ret){ - ogg_stream_clear(os); - return -1; - } - os->lacing_vals=ret; - ret=_ogg_realloc(os->granule_vals,lacing_storage* - sizeof(*os->granule_vals)); - if(!ret){ - ogg_stream_clear(os); - return -1; - } - os->granule_vals=ret; - os->lacing_storage=lacing_storage; - } - return 0; -} - -/* checksum the page */ -/* Direct table CRC; note that this will be faster in the future if we - perform the checksum simultaneously with other copies */ - -static ogg_uint32_t _os_update_crc(ogg_uint32_t crc, unsigned char *buffer, int size){ - while (size>=8){ - crc^=((ogg_uint32_t)buffer[0]<<24)|((ogg_uint32_t)buffer[1]<<16)|((ogg_uint32_t)buffer[2]<<8)|((ogg_uint32_t)buffer[3]); - - crc=crc_lookup[7][ crc>>24 ]^crc_lookup[6][(crc>>16)&0xFF]^ - crc_lookup[5][(crc>> 8)&0xFF]^crc_lookup[4][ crc &0xFF]^ - crc_lookup[3][buffer[4] ]^crc_lookup[2][buffer[5] ]^ - crc_lookup[1][buffer[6] ]^crc_lookup[0][buffer[7] ]; - - buffer+=8; - size-=8; - } - - while (size--) - crc=(crc<<8)^crc_lookup[0][((crc >> 24)&0xff)^*buffer++]; - return crc; -} - -void ogg_page_checksum_set(ogg_page *og){ - if(og){ - ogg_uint32_t crc_reg=0; - - /* safety; needed for API behavior, but not framing code */ - og->header[22]=0; - og->header[23]=0; - og->header[24]=0; - og->header[25]=0; - - crc_reg=_os_update_crc(crc_reg,og->header,og->header_len); - crc_reg=_os_update_crc(crc_reg,og->body,og->body_len); - - og->header[22]=(unsigned char)(crc_reg&0xff); - og->header[23]=(unsigned char)((crc_reg>>8)&0xff); - og->header[24]=(unsigned char)((crc_reg>>16)&0xff); - og->header[25]=(unsigned char)((crc_reg>>24)&0xff); - } -} - -/* submit data to the internal buffer of the framing engine */ -int ogg_stream_iovecin(ogg_stream_state *os, ogg_iovec_t *iov, int count, - long e_o_s, ogg_int64_t granulepos){ - - long bytes = 0, lacing_vals; - int i; - - if(ogg_stream_check(os)) return -1; - if(!iov) return 0; - - for (i = 0; i < count; ++i){ - if(iov[i].iov_len>LONG_MAX) return -1; - if(bytes>LONG_MAX-(long)iov[i].iov_len) return -1; - bytes += (long)iov[i].iov_len; - } - lacing_vals=bytes/255+1; - - if(os->body_returned){ - /* advance packet data according to the body_returned pointer. We - had to keep it around to return a pointer into the buffer last - call */ - - os->body_fill-=os->body_returned; - if(os->body_fill) - memmove(os->body_data,os->body_data+os->body_returned, - os->body_fill); - os->body_returned=0; - } - - /* make sure we have the buffer storage */ - if(_os_body_expand(os,bytes) || _os_lacing_expand(os,lacing_vals)) - return -1; - - /* Copy in the submitted packet. Yes, the copy is a waste; this is - the liability of overly clean abstraction for the time being. It - will actually be fairly easy to eliminate the extra copy in the - future */ - - for (i = 0; i < count; ++i) { - memcpy(os->body_data+os->body_fill, iov[i].iov_base, iov[i].iov_len); - os->body_fill += (int)iov[i].iov_len; - } - - /* Store lacing vals for this packet */ - for(i=0;ilacing_vals[os->lacing_fill+i]=255; - os->granule_vals[os->lacing_fill+i]=os->granulepos; - } - os->lacing_vals[os->lacing_fill+i]=bytes%255; - os->granulepos=os->granule_vals[os->lacing_fill+i]=granulepos; - - /* flag the first segment as the beginning of the packet */ - os->lacing_vals[os->lacing_fill]|= 0x100; - - os->lacing_fill+=lacing_vals; - - /* for the sake of completeness */ - os->packetno++; - - if(e_o_s)os->e_o_s=1; - - return(0); -} - -int ogg_stream_packetin(ogg_stream_state *os,ogg_packet *op){ - ogg_iovec_t iov; - iov.iov_base = op->packet; - iov.iov_len = op->bytes; - return ogg_stream_iovecin(os, &iov, 1, op->e_o_s, op->granulepos); -} - -/* Conditionally flush a page; force==0 will only flush nominal-size - pages, force==1 forces us to flush a page regardless of page size - so long as there's any data available at all. */ -static int ogg_stream_flush_i(ogg_stream_state *os,ogg_page *og, int force, int nfill){ - int i; - int vals=0; - int maxvals; - int bytes=0; - long acc=0; - ogg_int64_t granule_pos=-1; - - if(ogg_stream_check(os)) return(0); - maxvals=(os->lacing_fill>255?255:os->lacing_fill); - if(maxvals==0) return(0); - - /* construct a page */ - /* decide how many segments to include */ - - /* If this is the initial header case, the first page must only include - the initial header packet */ - if(os->b_o_s==0){ /* 'initial header page' case */ - granule_pos=0; - for(vals=0;valslacing_vals[vals]&0x0ff)<255){ - vals++; - break; - } - } - }else{ - - /* The extra packets_done, packet_just_done logic here attempts to do two things: - 1) Don't unnecessarily span pages. - 2) Unless necessary, don't flush pages if there are less than four packets on - them; this expands page size to reduce unnecessary overhead if incoming packets - are large. - These are not necessary behaviors, just 'always better than naive flushing' - without requiring an application to explicitly request a specific optimized - behavior. We'll want an explicit behavior setup pathway eventually as well. */ - - int packets_done=0; - int packet_just_done=0; - for(vals=0;valsnfill && packet_just_done>=4){ - force=1; - break; - } - acc+=os->lacing_vals[vals]&0x0ff; - if((os->lacing_vals[vals]&0xff)<255){ - granule_pos=os->granule_vals[vals]; - packet_just_done=++packets_done; - }else - packet_just_done=0; - } - if(vals==255)force=1; - } - - if(!force) return(0); - - /* construct the header in temp storage */ - memcpy(os->header,"OggS",4); - - /* stream structure version */ - os->header[4]=0x00; - - /* continued packet flag? */ - os->header[5]=0x00; - if((os->lacing_vals[0]&0x100)==0)os->header[5]|=0x01; - /* first page flag? */ - if(os->b_o_s==0)os->header[5]|=0x02; - /* last page flag? */ - if(os->e_o_s && os->lacing_fill==vals)os->header[5]|=0x04; - os->b_o_s=1; - - /* 64 bits of PCM position */ - for(i=6;i<14;i++){ - os->header[i]=(unsigned char)(granule_pos&0xff); - granule_pos>>=8; - } - - /* 32 bits of stream serial number */ - { - long serialno=os->serialno; - for(i=14;i<18;i++){ - os->header[i]=(unsigned char)(serialno&0xff); - serialno>>=8; - } - } - - /* 32 bits of page counter (we have both counter and page header - because this val can roll over) */ - if(os->pageno==-1)os->pageno=0; /* because someone called - stream_reset; this would be a - strange thing to do in an - encode stream, but it has - plausible uses */ - { - long pageno=os->pageno++; - for(i=18;i<22;i++){ - os->header[i]=(unsigned char)(pageno&0xff); - pageno>>=8; - } - } - - /* zero for computation; filled in later */ - os->header[22]=0; - os->header[23]=0; - os->header[24]=0; - os->header[25]=0; - - /* segment table */ - os->header[26]=(unsigned char)(vals&0xff); - for(i=0;iheader[i+27]=(unsigned char)(os->lacing_vals[i]&0xff); - - /* set pointers in the ogg_page struct */ - og->header=os->header; - og->header_len=os->header_fill=vals+27; - og->body=os->body_data+os->body_returned; - og->body_len=bytes; - - /* advance the lacing data and set the body_returned pointer */ - - os->lacing_fill-=vals; - memmove(os->lacing_vals,os->lacing_vals+vals,os->lacing_fill*sizeof(*os->lacing_vals)); - memmove(os->granule_vals,os->granule_vals+vals,os->lacing_fill*sizeof(*os->granule_vals)); - os->body_returned+=bytes; - - /* calculate the checksum */ - - ogg_page_checksum_set(og); - - /* done */ - return(1); -} - -/* This will flush remaining packets into a page (returning nonzero), - even if there is not enough data to trigger a flush normally - (undersized page). If there are no packets or partial packets to - flush, ogg_stream_flush returns 0. Note that ogg_stream_flush will - try to flush a normal sized page like ogg_stream_pageout; a call to - ogg_stream_flush does not guarantee that all packets have flushed. - Only a return value of 0 from ogg_stream_flush indicates all packet - data is flushed into pages. - - since ogg_stream_flush will flush the last page in a stream even if - it's undersized, you almost certainly want to use ogg_stream_pageout - (and *not* ogg_stream_flush) unless you specifically need to flush - a page regardless of size in the middle of a stream. */ - -int ogg_stream_flush(ogg_stream_state *os,ogg_page *og){ - return ogg_stream_flush_i(os,og,1,4096); -} - -/* Like the above, but an argument is provided to adjust the nominal - page size for applications which are smart enough to provide their - own delay based flushing */ - -int ogg_stream_flush_fill(ogg_stream_state *os,ogg_page *og, int nfill){ - return ogg_stream_flush_i(os,og,1,nfill); -} - -/* This constructs pages from buffered packet segments. The pointers -returned are to static buffers; do not free. The returned buffers are -good only until the next call (using the same ogg_stream_state) */ - -int ogg_stream_pageout(ogg_stream_state *os, ogg_page *og){ - int force=0; - if(ogg_stream_check(os)) return 0; - - if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ - (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ - force=1; - - return(ogg_stream_flush_i(os,og,force,4096)); -} - -/* Like the above, but an argument is provided to adjust the nominal -page size for applications which are smart enough to provide their -own delay based flushing */ - -int ogg_stream_pageout_fill(ogg_stream_state *os, ogg_page *og, int nfill){ - int force=0; - if(ogg_stream_check(os)) return 0; - - if((os->e_o_s&&os->lacing_fill) || /* 'were done, now flush' case */ - (os->lacing_fill&&!os->b_o_s)) /* 'initial header page' case */ - force=1; - - return(ogg_stream_flush_i(os,og,force,nfill)); -} - -int ogg_stream_eos(ogg_stream_state *os){ - if(ogg_stream_check(os)) return 1; - return os->e_o_s; -} - -/* DECODING PRIMITIVES: packet streaming layer **********************/ - -/* This has two layers to place more of the multi-serialno and paging - control in the application's hands. First, we expose a data buffer - using ogg_sync_buffer(). The app either copies into the - buffer, or passes it directly to read(), etc. We then call - ogg_sync_wrote() to tell how many bytes we just added. - - Pages are returned (pointers into the buffer in ogg_sync_state) - by ogg_sync_pageout(). The page is then submitted to - ogg_stream_pagein() along with the appropriate - ogg_stream_state* (ie, matching serialno). We then get raw - packets out calling ogg_stream_packetout() with a - ogg_stream_state. */ - -/* initialize the struct to a known state */ -int ogg_sync_init(ogg_sync_state *oy){ - if(oy){ - oy->storage = -1; /* used as a readiness flag */ - memset(oy,0,sizeof(*oy)); - } - return(0); -} - -/* clear non-flat storage within */ -int ogg_sync_clear(ogg_sync_state *oy){ - if(oy){ - if(oy->data)_ogg_free(oy->data); - memset(oy,0,sizeof(*oy)); - } - return(0); -} - -int ogg_sync_destroy(ogg_sync_state *oy){ - if(oy){ - ogg_sync_clear(oy); - _ogg_free(oy); - } - return(0); -} - -int ogg_sync_check(ogg_sync_state *oy){ - if(oy->storage<0) return -1; - return 0; -} - -char *ogg_sync_buffer(ogg_sync_state *oy, long size){ - if(ogg_sync_check(oy)) return NULL; - - /* first, clear out any space that has been previously returned */ - if(oy->returned){ - oy->fill-=oy->returned; - if(oy->fill>0) - memmove(oy->data,oy->data+oy->returned,oy->fill); - oy->returned=0; - } - - if(size>oy->storage-oy->fill){ - /* We need to extend the internal buffer */ - long newsize; - void *ret; - - if(size>INT_MAX-4096-oy->fill){ - ogg_sync_clear(oy); - return NULL; - } - newsize=size+oy->fill+4096; /* an extra page to be nice */ - if(oy->data) - ret=_ogg_realloc(oy->data,newsize); - else - ret=_ogg_malloc(newsize); - if(!ret){ - ogg_sync_clear(oy); - return NULL; - } - oy->data=ret; - oy->storage=newsize; - } - - /* expose a segment at least as large as requested at the fill mark */ - return((char *)oy->data+oy->fill); -} - -int ogg_sync_wrote(ogg_sync_state *oy, long bytes){ - if(ogg_sync_check(oy))return -1; - if(oy->fill+bytes>oy->storage)return -1; - oy->fill+=bytes; - return(0); -} - -/* sync the stream. This is meant to be useful for finding page - boundaries. - - return values for this: - -n) skipped n bytes - 0) page not ready; more data (no bytes skipped) - n) page synced at current location; page length n bytes - -*/ - -long ogg_sync_pageseek(ogg_sync_state *oy,ogg_page *og){ - unsigned char *page; - unsigned char *next; - long bytes; - - if(ogg_sync_check(oy))return 0; - - page=oy->data+oy->returned; - bytes=oy->fill-oy->returned; - - if(oy->headerbytes==0){ - int headerbytes,i; - if(bytes<27)return(0); /* not enough for a header */ - - /* verify capture pattern */ - if(memcmp(page,"OggS",4))goto sync_fail; - - headerbytes=page[26]+27; - if(bytesbodybytes+=page[27+i]; - oy->headerbytes=headerbytes; - } - - if(oy->bodybytes+oy->headerbytes>bytes)return(0); - - /* The whole test page is buffered. Verify the checksum */ - { - /* Grab the checksum bytes, set the header field to zero */ - char chksum[4]; - ogg_page log; - - memcpy(chksum,page+22,4); - memset(page+22,0,4); - - /* set up a temp page struct and recompute the checksum */ - log.header=page; - log.header_len=oy->headerbytes; - log.body=page+oy->headerbytes; - log.body_len=oy->bodybytes; - ogg_page_checksum_set(&log); - - /* Compare */ - if(memcmp(chksum,page+22,4)){ - /* D'oh. Mismatch! Corrupt page (or miscapture and not a page - at all) */ - /* replace the computed checksum with the one actually read in */ - memcpy(page+22,chksum,4); - -#ifndef DISABLE_CRC - /* Bad checksum. Lose sync */ - goto sync_fail; -#endif - } - } - - /* yes, have a whole page all ready to go */ - { - if(og){ - og->header=page; - og->header_len=oy->headerbytes; - og->body=page+oy->headerbytes; - og->body_len=oy->bodybytes; - } - - oy->unsynced=0; - oy->returned+=(bytes=oy->headerbytes+oy->bodybytes); - oy->headerbytes=0; - oy->bodybytes=0; - return(bytes); - } - - sync_fail: - - oy->headerbytes=0; - oy->bodybytes=0; - - /* search for possible capture */ - next=memchr(page+1,'O',bytes-1); - if(!next) - next=oy->data+oy->fill; - - oy->returned=(int)(next-oy->data); - return((long)-(next-page)); -} - -/* sync the stream and get a page. Keep trying until we find a page. - Suppress 'sync errors' after reporting the first. - - return values: - -1) recapture (hole in data) - 0) need more data - 1) page returned - - Returns pointers into buffered data; invalidated by next call to - _stream, _clear, _init, or _buffer */ - -int ogg_sync_pageout(ogg_sync_state *oy, ogg_page *og){ - - if(ogg_sync_check(oy))return 0; - - /* all we need to do is verify a page at the head of the stream - buffer. If it doesn't verify, we look for the next potential - frame */ - - for(;;){ - long ret=ogg_sync_pageseek(oy,og); - if(ret>0){ - /* have a page */ - return(1); - } - if(ret==0){ - /* need more data */ - return(0); - } - - /* head did not start a synced page... skipped some bytes */ - if(!oy->unsynced){ - oy->unsynced=1; - return(-1); - } - - /* loop. keep looking */ - - } -} - -/* add the incoming page to the stream state; we decompose the page - into packet segments here as well. */ - -int ogg_stream_pagein(ogg_stream_state *os, ogg_page *og){ - unsigned char *header=og->header; - unsigned char *body=og->body; - long bodysize=og->body_len; - int segptr=0; - - int version=ogg_page_version(og); - int continued=ogg_page_continued(og); - int bos=ogg_page_bos(og); - int eos=ogg_page_eos(og); - ogg_int64_t granulepos=ogg_page_granulepos(og); - int serialno=ogg_page_serialno(og); - long pageno=ogg_page_pageno(og); - int segments=header[26]; - - if(ogg_stream_check(os)) return -1; - - /* clean up 'returned data' */ - { - long lr=os->lacing_returned; - long br=os->body_returned; - - /* body data */ - if(br){ - os->body_fill-=br; - if(os->body_fill) - memmove(os->body_data,os->body_data+br,os->body_fill); - os->body_returned=0; - } - - if(lr){ - /* segment table */ - if(os->lacing_fill-lr){ - memmove(os->lacing_vals,os->lacing_vals+lr, - (os->lacing_fill-lr)*sizeof(*os->lacing_vals)); - memmove(os->granule_vals,os->granule_vals+lr, - (os->lacing_fill-lr)*sizeof(*os->granule_vals)); - } - os->lacing_fill-=lr; - os->lacing_packet-=lr; - os->lacing_returned=0; - } - } - - /* check the serial number */ - if(serialno!=os->serialno)return(-1); - if(version>0)return(-1); - - if(_os_lacing_expand(os,segments+1)) return -1; - - /* are we in sequence? */ - if(pageno!=os->pageno){ - int i; - - /* unroll previous partial packet (if any) */ - for(i=os->lacing_packet;ilacing_fill;i++) - os->body_fill-=os->lacing_vals[i]&0xff; - os->lacing_fill=os->lacing_packet; - - /* make a note of dropped data in segment table */ - if(os->pageno!=-1){ - os->lacing_vals[os->lacing_fill++]=0x400; - os->lacing_packet++; - } - } - - /* are we a 'continued packet' page? If so, we may need to skip - some segments */ - if(continued){ - if(os->lacing_fill<1 || - (os->lacing_vals[os->lacing_fill-1]&0xff)<255 || - os->lacing_vals[os->lacing_fill-1]==0x400){ - bos=0; - for(;segptrbody_data+os->body_fill,body,bodysize); - os->body_fill+=bodysize; - } - - { - int saved=-1; - while(segptrlacing_vals[os->lacing_fill]=val; - os->granule_vals[os->lacing_fill]=-1; - - if(bos){ - os->lacing_vals[os->lacing_fill]|=0x100; - bos=0; - } - - if(val<255)saved=os->lacing_fill; - - os->lacing_fill++; - segptr++; - - if(val<255)os->lacing_packet=os->lacing_fill; - } - - /* set the granulepos on the last granuleval of the last full packet */ - if(saved!=-1){ - os->granule_vals[saved]=granulepos; - } - - } - - if(eos){ - os->e_o_s=1; - if(os->lacing_fill>0) - os->lacing_vals[os->lacing_fill-1]|=0x200; - } - - os->pageno=pageno+1; - - return(0); -} - -/* clear things to an initial state. Good to call, eg, before seeking */ -int ogg_sync_reset(ogg_sync_state *oy){ - if(ogg_sync_check(oy))return -1; - - oy->fill=0; - oy->returned=0; - oy->unsynced=0; - oy->headerbytes=0; - oy->bodybytes=0; - return(0); -} - -int ogg_stream_reset(ogg_stream_state *os){ - if(ogg_stream_check(os)) return -1; - - os->body_fill=0; - os->body_returned=0; - - os->lacing_fill=0; - os->lacing_packet=0; - os->lacing_returned=0; - - os->header_fill=0; - - os->e_o_s=0; - os->b_o_s=0; - os->pageno=-1; - os->packetno=0; - os->granulepos=0; - - return(0); -} - -int ogg_stream_reset_serialno(ogg_stream_state *os,int serialno){ - if(ogg_stream_check(os)) return -1; - ogg_stream_reset(os); - os->serialno=serialno; - return(0); -} - -static int _packetout(ogg_stream_state *os,ogg_packet *op,int adv){ - - /* The last part of decode. We have the stream broken into packet - segments. Now we need to group them into packets (or return the - out of sync markers) */ - - int ptr=os->lacing_returned; - - if(os->lacing_packet<=ptr)return(0); - - if(os->lacing_vals[ptr]&0x400){ - /* we need to tell the codec there's a gap; it might need to - handle previous packet dependencies. */ - os->lacing_returned++; - os->packetno++; - return(-1); - } - - if(!op && !adv)return(1); /* just using peek as an inexpensive way - to ask if there's a whole packet - waiting */ - - /* Gather the whole packet. We'll have no holes or a partial packet */ - { - int size=os->lacing_vals[ptr]&0xff; - long bytes=size; - int eos=os->lacing_vals[ptr]&0x200; /* last packet of the stream? */ - int bos=os->lacing_vals[ptr]&0x100; /* first packet of the stream? */ - - while(size==255){ - int val=os->lacing_vals[++ptr]; - size=val&0xff; - if(val&0x200)eos=0x200; - bytes+=size; - } - - if(op){ - op->e_o_s=eos; - op->b_o_s=bos; - op->packet=os->body_data+os->body_returned; - op->packetno=os->packetno; - op->granulepos=os->granule_vals[ptr]; - op->bytes=bytes; - } - - if(adv){ - os->body_returned+=bytes; - os->lacing_returned=ptr+1; - os->packetno++; - } - } - return(1); -} - -int ogg_stream_packetout(ogg_stream_state *os,ogg_packet *op){ - if(ogg_stream_check(os)) return 0; - return _packetout(os,op,1); -} - -int ogg_stream_packetpeek(ogg_stream_state *os,ogg_packet *op){ - if(ogg_stream_check(os)) return 0; - return _packetout(os,op,0); -} - -void ogg_packet_clear(ogg_packet *op) { - _ogg_free(op->packet); - memset(op, 0, sizeof(*op)); -} - -#ifdef _V_SELFTEST -#include - -ogg_stream_state os_en, os_de; -ogg_sync_state oy; - -void checkpacket(ogg_packet *op,long len, int no, long pos){ - long j; - static int sequence=0; - static int lastno=0; - - if(op->bytes!=len){ - fprintf(stderr,"incorrect packet length (%ld != %ld)!\n",op->bytes,len); - exit(1); - } - if(op->granulepos!=pos){ - fprintf(stderr,"incorrect packet granpos (%ld != %ld)!\n",(long)op->granulepos,pos); - exit(1); - } - - /* packet number just follows sequence/gap; adjust the input number - for that */ - if(no==0){ - sequence=0; - }else{ - sequence++; - if(no>lastno+1) - sequence++; - } - lastno=no; - if(op->packetno!=sequence){ - fprintf(stderr,"incorrect packet sequence %ld != %d\n", - (long)(op->packetno),sequence); - exit(1); - } - - /* Test data */ - for(j=0;jbytes;j++) - if(op->packet[j]!=((j+no)&0xff)){ - fprintf(stderr,"body data mismatch (1) at pos %ld: %x!=%lx!\n\n", - j,op->packet[j],(j+no)&0xff); - exit(1); - } -} - -void check_page(unsigned char *data,const int *header,ogg_page *og){ - long j; - /* Test data */ - for(j=0;jbody_len;j++) - if(og->body[j]!=data[j]){ - fprintf(stderr,"body data mismatch (2) at pos %ld: %x!=%x!\n\n", - j,data[j],og->body[j]); - exit(1); - } - - /* Test header */ - for(j=0;jheader_len;j++){ - if(og->header[j]!=header[j]){ - fprintf(stderr,"header content mismatch at pos %ld:\n",j); - for(j=0;jheader[j]); - fprintf(stderr,"\n"); - exit(1); - } - } - if(og->header_len!=header[26]+27){ - fprintf(stderr,"header length incorrect! (%ld!=%d)\n", - og->header_len,header[26]+27); - exit(1); - } -} - -void print_header(ogg_page *og){ - int j; - fprintf(stderr,"\nHEADER:\n"); - fprintf(stderr," capture: %c %c %c %c version: %d flags: %x\n", - og->header[0],og->header[1],og->header[2],og->header[3], - (int)og->header[4],(int)og->header[5]); - - fprintf(stderr," granulepos: %d serialno: %d pageno: %ld\n", - ((unsigned)og->header[9]<<24)|(og->header[8]<<16)| - (og->header[7]<<8)|og->header[6], - ((unsigned)og->header[17]<<24)|(og->header[16]<<16)| - (og->header[15]<<8)|og->header[14], - ((long)((unsigned)og->header[21])<<24)|(og->header[20]<<16)| - (og->header[19]<<8)|og->header[18]); - - fprintf(stderr," checksum: %02x:%02x:%02x:%02x\n segments: %d (", - (int)og->header[22],(int)og->header[23], - (int)og->header[24],(int)og->header[25], - (int)og->header[26]); - - for(j=27;jheader_len;j++) - fprintf(stderr,"%d ",(int)og->header[j]); - fprintf(stderr,")\n\n"); -} - -static int copy_page(ogg_page *og){ - unsigned char *temp=_ogg_malloc(og->header_len); - if (!temp) - return -1; - memcpy(temp,og->header,og->header_len); - og->header=temp; - - temp=_ogg_malloc(og->body_len); - if (!temp) - return -1; - memcpy(temp,og->body,og->body_len); - og->body=temp; - return 0; -} - -static void free_page(ogg_page *og){ - _ogg_free (og->header); - og->header=NULL; - _ogg_free (og->body); - og->body=NULL; -} - -void error(void){ - fprintf(stderr,"error!\n"); - exit(1); -} - -/* 17 only */ -const int head1_0[] = {0x4f,0x67,0x67,0x53,0,0x06, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0x15,0xed,0xec,0x91, - 1, - 17}; - -/* 17, 254, 255, 256, 500, 510, 600 byte, pad */ -const int head1_1[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0x59,0x10,0x6c,0x2c, - 1, - 17}; -const int head2_1[] = {0x4f,0x67,0x67,0x53,0,0x04, - 0x07,0x18,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0x89,0x33,0x85,0xce, - 13, - 254,255,0,255,1,255,245,255,255,0, - 255,255,90}; - -/* nil packets; beginning,middle,end */ -const int head1_2[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0xff,0x7b,0x23,0x17, - 1, - 0}; -const int head2_2[] = {0x4f,0x67,0x67,0x53,0,0x04, - 0x07,0x28,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0x5c,0x3f,0x66,0xcb, - 17, - 17,254,255,0,0,255,1,0,255,245,255,255,0, - 255,255,90,0}; - -/* large initial packet */ -const int head1_3[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0x01,0x27,0x31,0xaa, - 18, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,10}; - -const int head2_3[] = {0x4f,0x67,0x67,0x53,0,0x04, - 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0x7f,0x4e,0x8a,0xd2, - 4, - 255,4,255,0}; - - -/* continuing packet test */ -const int head1_4[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0xff,0x7b,0x23,0x17, - 1, - 0}; - -const int head2_4[] = {0x4f,0x67,0x67,0x53,0,0x00, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0xf8,0x3c,0x19,0x79, - 255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255}; - -const int head3_4[] = {0x4f,0x67,0x67,0x53,0,0x05, - 0x07,0x0c,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,2,0,0,0, - 0x38,0xe6,0xb6,0x28, - 6, - 255,220,255,4,255,0}; - - -/* spill expansion test */ -const int head1_4b[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0xff,0x7b,0x23,0x17, - 1, - 0}; - -const int head2_4b[] = {0x4f,0x67,0x67,0x53,0,0x00, - 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0xce,0x8f,0x17,0x1a, - 23, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255,255,10,255,4,255,0,0}; - - -const int head3_4b[] = {0x4f,0x67,0x67,0x53,0,0x04, - 0x07,0x14,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,2,0,0,0, - 0x9b,0xb2,0x50,0xa1, - 1, - 0}; - -/* page with the 255 segment limit */ -const int head1_5[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0xff,0x7b,0x23,0x17, - 1, - 0}; - -const int head2_5[] = {0x4f,0x67,0x67,0x53,0,0x00, - 0x07,0xfc,0x03,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0xed,0x2a,0x2e,0xa7, - 255, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10}; - -const int head3_5[] = {0x4f,0x67,0x67,0x53,0,0x04, - 0x07,0x00,0x04,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,2,0,0,0, - 0x6c,0x3b,0x82,0x3d, - 1, - 50}; - - -/* packet that overspans over an entire page */ -const int head1_6[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0xff,0x7b,0x23,0x17, - 1, - 0}; - -const int head2_6[] = {0x4f,0x67,0x67,0x53,0,0x00, - 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0x68,0x22,0x7c,0x3d, - 255, - 100, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255}; - -const int head3_6[] = {0x4f,0x67,0x67,0x53,0,0x01, - 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF, - 0x01,0x02,0x03,0x04,2,0,0,0, - 0xf4,0x87,0xba,0xf3, - 255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255}; - -const int head4_6[] = {0x4f,0x67,0x67,0x53,0,0x05, - 0x07,0x10,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,3,0,0,0, - 0xf7,0x2f,0x6c,0x60, - 5, - 254,255,4,255,0}; - -/* packet that overspans over an entire page */ -const int head1_7[] = {0x4f,0x67,0x67,0x53,0,0x02, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,0,0,0,0, - 0xff,0x7b,0x23,0x17, - 1, - 0}; - -const int head2_7[] = {0x4f,0x67,0x67,0x53,0,0x00, - 0x07,0x04,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,1,0,0,0, - 0x68,0x22,0x7c,0x3d, - 255, - 100, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255,255,255, - 255,255,255,255,255,255}; - -const int head3_7[] = {0x4f,0x67,0x67,0x53,0,0x05, - 0x07,0x08,0x00,0x00,0x00,0x00,0x00,0x00, - 0x01,0x02,0x03,0x04,2,0,0,0, - 0xd4,0xe0,0x60,0xe5, - 1, - 0}; - -int compare_packet(const ogg_packet *op1, const ogg_packet *op2){ - if(op1->packet!=op2->packet){ - fprintf(stderr,"op1->packet != op2->packet\n"); - return(1); - } - if(op1->bytes!=op2->bytes){ - fprintf(stderr,"op1->bytes != op2->bytes\n"); - return(1); - } - if(op1->b_o_s!=op2->b_o_s){ - fprintf(stderr,"op1->b_o_s != op2->b_o_s\n"); - return(1); - } - if(op1->e_o_s!=op2->e_o_s){ - fprintf(stderr,"op1->e_o_s != op2->e_o_s\n"); - return(1); - } - if(op1->granulepos!=op2->granulepos){ - fprintf(stderr,"op1->granulepos != op2->granulepos\n"); - return(1); - } - if(op1->packetno!=op2->packetno){ - fprintf(stderr,"op1->packetno != op2->packetno\n"); - return(1); - } - return(0); -} - -void test_pack(const int *pl, const int **headers, int byteskip, - int pageskip, int packetskip){ - unsigned char *data=_ogg_malloc(1024*1024); /* for scripted test cases only */ - long inptr=0; - long outptr=0; - long deptr=0; - long depacket=0; - long granule_pos=7,pageno=0; - int i,j,packets,pageout=pageskip; - int eosflag=0; - int bosflag=0; - - int byteskipcount=0; - - if (!data) { - fprintf(stderr,"unable to allocate requried data buffer!\n"); - exit(1); - } - - ogg_stream_reset(&os_en); - ogg_stream_reset(&os_de); - ogg_sync_reset(&oy); - - for(packets=0;packetsbyteskip){ - memcpy(next,og.header,byteskipcount-byteskip); - next+=byteskipcount-byteskip; - byteskipcount=byteskip; - } - - byteskipcount+=og.body_len; - if(byteskipcount>byteskip){ - memcpy(next,og.body,byteskipcount-byteskip); - next+=byteskipcount-byteskip; - byteskipcount=byteskip; - } - - ogg_sync_wrote(&oy,(long)(next-buf)); - - while(1){ - int ret=ogg_sync_pageout(&oy,&og_de); - if(ret==0)break; - if(ret<0)continue; - /* got a page. Happy happy. Verify that it's good. */ - - fprintf(stderr,"(%d), ",pageout); - - check_page(data+deptr,headers[pageout],&og_de); - deptr+=og_de.body_len; - pageout++; - - /* submit it to deconstitution */ - ogg_stream_pagein(&os_de,&og_de); - - /* packets out? */ - while(ogg_stream_packetpeek(&os_de,&op_de2)>0){ - ogg_stream_packetpeek(&os_de,NULL); - ogg_stream_packetout(&os_de,&op_de); /* just catching them all */ - - /* verify peek and out match */ - if(compare_packet(&op_de,&op_de2)){ - fprintf(stderr,"packetout != packetpeek! pos=%ld\n", - depacket); - exit(1); - } - - /* verify the packet! */ - /* check data */ - if(memcmp(data+depacket,op_de.packet,op_de.bytes)){ - fprintf(stderr,"packet data mismatch in decode! pos=%ld\n", - depacket); - exit(1); - } - /* check bos flag */ - if(bosflag==0 && op_de.b_o_s==0){ - fprintf(stderr,"b_o_s flag not set on packet!\n"); - exit(1); - } - if(bosflag && op_de.b_o_s){ - fprintf(stderr,"b_o_s flag incorrectly set on packet!\n"); - exit(1); - } - bosflag=1; - depacket+=op_de.bytes; - - /* check eos flag */ - if(eosflag){ - fprintf(stderr,"Multiple decoded packets with eos flag!\n"); - exit(1); - } - - if(op_de.e_o_s)eosflag=1; - - /* check granulepos flag */ - if(op_de.granulepos!=-1){ - fprintf(stderr," granule:%ld ",(long)op_de.granulepos); - } - } - } - } - } - } - } - _ogg_free(data); - if(headers[pageno]!=NULL){ - fprintf(stderr,"did not write last page!\n"); - exit(1); - } - if(headers[pageout]!=NULL){ - fprintf(stderr,"did not decode last page!\n"); - exit(1); - } - if(inptr!=outptr){ - fprintf(stderr,"encoded page data incomplete!\n"); - exit(1); - } - if(inptr!=deptr){ - fprintf(stderr,"decoded page data incomplete!\n"); - exit(1); - } - if(inptr!=depacket){ - fprintf(stderr,"decoded packet data incomplete!\n"); - exit(1); - } - if(!eosflag){ - fprintf(stderr,"Never got a packet with EOS set!\n"); - exit(1); - } - fprintf(stderr,"ok.\n"); -} - -int main(void){ - - ogg_stream_init(&os_en,0x04030201); - ogg_stream_init(&os_de,0x04030201); - ogg_sync_init(&oy); - - /* Exercise each code path in the framing code. Also verify that - the checksums are working. */ - - { - /* 17 only */ - const int packets[]={17, -1}; - const int *headret[]={head1_0,NULL}; - - fprintf(stderr,"testing single page encoding... "); - test_pack(packets,headret,0,0,0); - } - - { - /* 17, 254, 255, 256, 500, 510, 600 byte, pad */ - const int packets[]={17, 254, 255, 256, 500, 510, 600, -1}; - const int *headret[]={head1_1,head2_1,NULL}; - - fprintf(stderr,"testing basic page encoding... "); - test_pack(packets,headret,0,0,0); - } - - { - /* nil packets; beginning,middle,end */ - const int packets[]={0,17, 254, 255, 0, 256, 0, 500, 510, 600, 0, -1}; - const int *headret[]={head1_2,head2_2,NULL}; - - fprintf(stderr,"testing basic nil packets... "); - test_pack(packets,headret,0,0,0); - } - - { - /* large initial packet */ - const int packets[]={4345,259,255,-1}; - const int *headret[]={head1_3,head2_3,NULL}; - - fprintf(stderr,"testing initial-packet lacing > 4k... "); - test_pack(packets,headret,0,0,0); - } - - { - /* continuing packet test; with page spill expansion, we have to - overflow the lacing table. */ - const int packets[]={0,65500,259,255,-1}; - const int *headret[]={head1_4,head2_4,head3_4,NULL}; - - fprintf(stderr,"testing single packet page span... "); - test_pack(packets,headret,0,0,0); - } - - { - /* spill expand packet test */ - const int packets[]={0,4345,259,255,0,0,-1}; - const int *headret[]={head1_4b,head2_4b,head3_4b,NULL}; - - fprintf(stderr,"testing page spill expansion... "); - test_pack(packets,headret,0,0,0); - } - - /* page with the 255 segment limit */ - { - - const int packets[]={0,10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,10, - 10,10,10,10,10,10,10,50,-1}; - const int *headret[]={head1_5,head2_5,head3_5,NULL}; - - fprintf(stderr,"testing max packet segments... "); - test_pack(packets,headret,0,0,0); - } - - { - /* packet that overspans over an entire page */ - const int packets[]={0,100,130049,259,255,-1}; - const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; - - fprintf(stderr,"testing very large packets... "); - test_pack(packets,headret,0,0,0); - } - -#ifndef DISABLE_CRC - { - /* test for the libogg 1.1.1 resync in large continuation bug - found by Josh Coalson) */ - const int packets[]={0,100,130049,259,255,-1}; - const int *headret[]={head1_6,head2_6,head3_6,head4_6,NULL}; - - fprintf(stderr,"testing continuation resync in very large packets... "); - test_pack(packets,headret,100,2,3); - } -#else - fprintf(stderr,"Skipping continuation resync test due to --disable-crc\n"); -#endif - - { - /* term only page. why not? */ - const int packets[]={0,100,64770,-1}; - const int *headret[]={head1_7,head2_7,head3_7,NULL}; - - fprintf(stderr,"testing zero data page (1 nil packet)... "); - test_pack(packets,headret,0,0,0); - } - - - - { - /* build a bunch of pages for testing */ - unsigned char *data=_ogg_malloc(1024*1024); - int pl[]={0, 1,1,98,4079, 1,1,2954,2057, 76,34,912,0,234,1000,1000, 1000,300,-1}; - int inptr=0,i,j; - ogg_page og[5]; - - if (!data) { - fprintf(stderr,"unable to allocate requried packet data buffer!\n"); - exit(1); - } - - ogg_stream_reset(&os_en); - - for(i=0;pl[i]!=-1;i++){ - ogg_packet op; - int len=pl[i]; - - op.packet=data+inptr; - op.bytes=len; - op.e_o_s=(pl[i+1]<0?1:0); - op.granulepos=(i+1)*1000; - - for(j=0;j0)error(); - - /* Test fractional page inputs: incomplete fixed header */ - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+3, - 20); - ogg_sync_wrote(&oy,20); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - - /* Test fractional page inputs: incomplete header */ - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+23, - 5); - ogg_sync_wrote(&oy,5); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - - /* Test fractional page inputs: incomplete body */ - - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+28, - og[1].header_len-28); - ogg_sync_wrote(&oy,og[1].header_len-28); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body,1000); - ogg_sync_wrote(&oy,1000); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body+1000, - og[1].body_len-1000); - ogg_sync_wrote(&oy,og[1].body_len-1000); - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - - fprintf(stderr,"ok.\n"); - } - - /* Test fractional page inputs: page + incomplete capture */ - { - ogg_page og_de; - fprintf(stderr,"Testing sync on 1+partial inputs... "); - ogg_sync_reset(&oy); - - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, - og[1].header_len); - ogg_sync_wrote(&oy,og[1].header_len); - - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, - og[1].body_len); - ogg_sync_wrote(&oy,og[1].body_len); - - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, - 20); - ogg_sync_wrote(&oy,20); - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header+20, - og[1].header_len-20); - ogg_sync_wrote(&oy,og[1].header_len-20); - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, - og[1].body_len); - ogg_sync_wrote(&oy,og[1].body_len); - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - - fprintf(stderr,"ok.\n"); - } - - /* Test recapture: garbage + page */ - { - ogg_page og_de; - fprintf(stderr,"Testing search for capture... "); - ogg_sync_reset(&oy); - - /* 'garbage' */ - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, - og[1].body_len); - ogg_sync_wrote(&oy,og[1].body_len); - - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, - og[1].header_len); - ogg_sync_wrote(&oy,og[1].header_len); - - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, - og[1].body_len); - ogg_sync_wrote(&oy,og[1].body_len); - - memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, - 20); - ogg_sync_wrote(&oy,20); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - - memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header+20, - og[2].header_len-20); - ogg_sync_wrote(&oy,og[2].header_len-20); - memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, - og[2].body_len); - ogg_sync_wrote(&oy,og[2].body_len); - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - - fprintf(stderr,"ok.\n"); - } - -#ifndef DISABLE_CRC - /* Test recapture: page + garbage + page */ - { - ogg_page og_de; - fprintf(stderr,"Testing recapture... "); - ogg_sync_reset(&oy); - - memcpy(ogg_sync_buffer(&oy,og[1].header_len),og[1].header, - og[1].header_len); - ogg_sync_wrote(&oy,og[1].header_len); - - memcpy(ogg_sync_buffer(&oy,og[1].body_len),og[1].body, - og[1].body_len); - ogg_sync_wrote(&oy,og[1].body_len); - - memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, - og[2].header_len); - ogg_sync_wrote(&oy,og[2].header_len); - - memcpy(ogg_sync_buffer(&oy,og[2].header_len),og[2].header, - og[2].header_len); - ogg_sync_wrote(&oy,og[2].header_len); - - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - - memcpy(ogg_sync_buffer(&oy,og[2].body_len),og[2].body, - og[2].body_len-5); - ogg_sync_wrote(&oy,og[2].body_len-5); - - memcpy(ogg_sync_buffer(&oy,og[3].header_len),og[3].header, - og[3].header_len); - ogg_sync_wrote(&oy,og[3].header_len); - - memcpy(ogg_sync_buffer(&oy,og[3].body_len),og[3].body, - og[3].body_len); - ogg_sync_wrote(&oy,og[3].body_len); - - if(ogg_sync_pageout(&oy,&og_de)>0)error(); - if(ogg_sync_pageout(&oy,&og_de)<=0)error(); - - fprintf(stderr,"ok.\n"); - } -#else - fprintf(stderr,"Skipping recapture test due to --disable-crc\n"); -#endif - - /* Free page data that was previously copied */ - { - for(i=0;i<5;i++){ - free_page(&og[i]); - } - } - } - ogg_sync_clear(&oy); - ogg_stream_clear(&os_en); - ogg_stream_clear(&os_de); - - return(0); -} - -#endif diff --git a/src/lib/stb_vorbis/CMakeLists.txt b/src/lib/stb_vorbis/CMakeLists.txt new file mode 100644 index 00000000..2ffaad86 --- /dev/null +++ b/src/lib/stb_vorbis/CMakeLists.txt @@ -0,0 +1,23 @@ +# bstone +cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) +# ====================================== +project(bstone_lib_stb_vorbis VERSION 1.0.0 LANGUAGES C) +message(STATUS "[${PROJECT_NAME}] v${PROJECT_VERSION}") +add_library(${PROJECT_NAME} STATIC) +add_library(bstone::lib::stb_vorbis ALIAS ${PROJECT_NAME}) +set_target_properties(${PROJECT_NAME} PROPERTIES + C_STANDARD 99 + C_STANDARD_REQUIRED ON + C_EXTENSIONS OFF +) +target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:_CRT_SECURE_NO_WARNINGS>) +target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W1>) +target_include_directories(${PROJECT_NAME} PUBLIC .) +# stb_vorbis.c is the amalgamated source; only stb_vorbis_impl.c compiles it (the +# others are listed for IDE visibility but must not be compiled on their own). +set_source_files_properties(stb_vorbis.c stb_vorbis.h PROPERTIES HEADER_FILE_ONLY TRUE) +target_sources(${PROJECT_NAME} PRIVATE + stb_vorbis_impl.c + stb_vorbis.c + stb_vorbis.h +) diff --git a/src/lib/stb_vorbis/stb_vorbis.c b/src/lib/stb_vorbis/stb_vorbis.c new file mode 100644 index 00000000..3e5c2504 --- /dev/null +++ b/src/lib/stb_vorbis/stb_vorbis.c @@ -0,0 +1,5584 @@ +// Ogg Vorbis audio decoder - v1.22 - public domain +// http://nothings.org/stb_vorbis/ +// +// Original version written by Sean Barrett in 2007. +// +// Originally sponsored by RAD Game Tools. Seeking implementation +// sponsored by Phillip Bennefall, Marc Andersen, Aaron Baker, +// Elias Software, Aras Pranckevicius, and Sean Barrett. +// +// LICENSE +// +// See end of file for license information. +// +// Limitations: +// +// - floor 0 not supported (used in old ogg vorbis files pre-2004) +// - lossless sample-truncation at beginning ignored +// - cannot concatenate multiple vorbis streams +// - sample positions are 32-bit, limiting seekable 192Khz +// files to around 6 hours (Ogg supports 64-bit) +// +// Feature contributors: +// Dougall Johnson (sample-exact seeking) +// +// Bugfix/warning contributors: +// Terje Mathisen Niklas Frykholm Andy Hill +// Casey Muratori John Bolton Gargaj +// Laurent Gomila Marc LeBlanc Ronny Chevalier +// Bernhard Wodo Evan Balster github:alxprd +// Tom Beaumont Ingo Leitgeb Nicolas Guillemot +// Phillip Bennefall Rohit Thiago Goulart +// github:manxorist Saga Musix github:infatum +// Timur Gagiev Maxwell Koo Peter Waller +// github:audinowho Dougall Johnson David Reid +// github:Clownacy Pedro J. Estebanez Remi Verschelde +// AnthoFoxo github:morlat Gabriel Ravier +// +// Partial history: +// 1.22 - 2021-07-11 - various small fixes +// 1.21 - 2021-07-02 - fix bug for files with no comments +// 1.20 - 2020-07-11 - several small fixes +// 1.19 - 2020-02-05 - warnings +// 1.18 - 2020-02-02 - fix seek bugs; parse header comments; misc warnings etc. +// 1.17 - 2019-07-08 - fix CVE-2019-13217..CVE-2019-13223 (by ForAllSecure) +// 1.16 - 2019-03-04 - fix warnings +// 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found +// 1.14 - 2018-02-11 - delete bogus dealloca usage +// 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) +// 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files +// 1.11 - 2017-07-23 - fix MinGW compilation +// 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory +// 1.09 - 2016-04-04 - back out 'truncation of last frame' fix from previous version +// 1.08 - 2016-04-02 - warnings; setup memory leaks; truncation of last frame +// 1.07 - 2015-01-16 - fixes for crashes on invalid files; warning fixes; const +// 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) +// some crash fixes when out of memory or with corrupt files +// fix some inappropriately signed shifts +// 1.05 - 2015-04-19 - don't define __forceinline if it's redundant +// 1.04 - 2014-08-27 - fix missing const-correct case in API +// 1.03 - 2014-08-07 - warning fixes +// 1.02 - 2014-07-09 - declare qsort comparison as explicitly _cdecl in Windows +// 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float (interleaved was correct) +// 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in >2-channel; +// (API change) report sample rate for decode-full-file funcs +// +// See end of file for full version history. + + +////////////////////////////////////////////////////////////////////////////// +// +// HEADER BEGINS HERE +// + +#ifndef STB_VORBIS_INCLUDE_STB_VORBIS_H +#define STB_VORBIS_INCLUDE_STB_VORBIS_H + +#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) +#define STB_VORBIS_NO_STDIO 1 +#endif + +#ifndef STB_VORBIS_NO_STDIO +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/////////// THREAD SAFETY + +// Individual stb_vorbis* handles are not thread-safe; you cannot decode from +// them from multiple threads at the same time. However, you can have multiple +// stb_vorbis* handles and decode from them independently in multiple thrads. + + +/////////// MEMORY ALLOCATION + +// normally stb_vorbis uses malloc() to allocate memory at startup, +// and alloca() to allocate temporary memory during a frame on the +// stack. (Memory consumption will depend on the amount of setup +// data in the file and how you set the compile flags for speed +// vs. size. In my test files the maximal-size usage is ~150KB.) +// +// You can modify the wrapper functions in the source (setup_malloc, +// setup_temp_malloc, temp_malloc) to change this behavior, or you +// can use a simpler allocation model: you pass in a buffer from +// which stb_vorbis will allocate _all_ its memory (including the +// temp memory). "open" may fail with a VORBIS_outofmem if you +// do not pass in enough data; there is no way to determine how +// much you do need except to succeed (at which point you can +// query get_info to find the exact amount required. yes I know +// this is lame). +// +// If you pass in a non-NULL buffer of the type below, allocation +// will occur from it as described above. Otherwise just pass NULL +// to use malloc()/alloca() + +typedef struct +{ + char *alloc_buffer; + int alloc_buffer_length_in_bytes; +} stb_vorbis_alloc; + + +/////////// FUNCTIONS USEABLE WITH ALL INPUT MODES + +typedef struct stb_vorbis stb_vorbis; + +typedef struct +{ + unsigned int sample_rate; + int channels; + + unsigned int setup_memory_required; + unsigned int setup_temp_memory_required; + unsigned int temp_memory_required; + + int max_frame_size; +} stb_vorbis_info; + +typedef struct +{ + char *vendor; + + int comment_list_length; + char **comment_list; +} stb_vorbis_comment; + +// get general information about the file +extern stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f); + +// get ogg comments +extern stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f); + +// get the last error detected (clears it, too) +extern int stb_vorbis_get_error(stb_vorbis *f); + +// close an ogg vorbis file and free all memory in use +extern void stb_vorbis_close(stb_vorbis *f); + +// this function returns the offset (in samples) from the beginning of the +// file that will be returned by the next decode, if it is known, or -1 +// otherwise. after a flush_pushdata() call, this may take a while before +// it becomes valid again. +// NOT WORKING YET after a seek with PULLDATA API +extern int stb_vorbis_get_sample_offset(stb_vorbis *f); + +// returns the current seek point within the file, or offset from the beginning +// of the memory buffer. In pushdata mode it returns 0. +extern unsigned int stb_vorbis_get_file_offset(stb_vorbis *f); + +/////////// PUSHDATA API + +#ifndef STB_VORBIS_NO_PUSHDATA_API + +// this API allows you to get blocks of data from any source and hand +// them to stb_vorbis. you have to buffer them; stb_vorbis will tell +// you how much it used, and you have to give it the rest next time; +// and stb_vorbis may not have enough data to work with and you will +// need to give it the same data again PLUS more. Note that the Vorbis +// specification does not bound the size of an individual frame. + +extern stb_vorbis *stb_vorbis_open_pushdata( + const unsigned char * datablock, int datablock_length_in_bytes, + int *datablock_memory_consumed_in_bytes, + int *error, + const stb_vorbis_alloc *alloc_buffer); +// create a vorbis decoder by passing in the initial data block containing +// the ogg&vorbis headers (you don't need to do parse them, just provide +// the first N bytes of the file--you're told if it's not enough, see below) +// on success, returns an stb_vorbis *, does not set error, returns the amount of +// data parsed/consumed on this call in *datablock_memory_consumed_in_bytes; +// on failure, returns NULL on error and sets *error, does not change *datablock_memory_consumed +// if returns NULL and *error is VORBIS_need_more_data, then the input block was +// incomplete and you need to pass in a larger block from the start of the file + +extern int stb_vorbis_decode_frame_pushdata( + stb_vorbis *f, + const unsigned char *datablock, int datablock_length_in_bytes, + int *channels, // place to write number of float * buffers + float ***output, // place to write float ** array of float * buffers + int *samples // place to write number of output samples + ); +// decode a frame of audio sample data if possible from the passed-in data block +// +// return value: number of bytes we used from datablock +// +// possible cases: +// 0 bytes used, 0 samples output (need more data) +// N bytes used, 0 samples output (resynching the stream, keep going) +// N bytes used, M samples output (one frame of data) +// note that after opening a file, you will ALWAYS get one N-bytes,0-sample +// frame, because Vorbis always "discards" the first frame. +// +// Note that on resynch, stb_vorbis will rarely consume all of the buffer, +// instead only datablock_length_in_bytes-3 or less. This is because it wants +// to avoid missing parts of a page header if they cross a datablock boundary, +// without writing state-machiney code to record a partial detection. +// +// The number of channels returned are stored in *channels (which can be +// NULL--it is always the same as the number of channels reported by +// get_info). *output will contain an array of float* buffers, one per +// channel. In other words, (*output)[0][0] contains the first sample from +// the first channel, and (*output)[1][0] contains the first sample from +// the second channel. +// +// *output points into stb_vorbis's internal output buffer storage; these +// buffers are owned by stb_vorbis and application code should not free +// them or modify their contents. They are transient and will be overwritten +// once you ask for more data to get decoded, so be sure to grab any data +// you need before then. + +extern void stb_vorbis_flush_pushdata(stb_vorbis *f); +// inform stb_vorbis that your next datablock will not be contiguous with +// previous ones (e.g. you've seeked in the data); future attempts to decode +// frames will cause stb_vorbis to resynchronize (as noted above), and +// once it sees a valid Ogg page (typically 4-8KB, as large as 64KB), it +// will begin decoding the _next_ frame. +// +// if you want to seek using pushdata, you need to seek in your file, then +// call stb_vorbis_flush_pushdata(), then start calling decoding, then once +// decoding is returning you data, call stb_vorbis_get_sample_offset, and +// if you don't like the result, seek your file again and repeat. +#endif + + +////////// PULLING INPUT API + +#ifndef STB_VORBIS_NO_PULLDATA_API +// This API assumes stb_vorbis is allowed to pull data from a source-- +// either a block of memory containing the _entire_ vorbis stream, or a +// FILE * that you or it create, or possibly some other reading mechanism +// if you go modify the source to replace the FILE * case with some kind +// of callback to your code. (But if you don't support seeking, you may +// just want to go ahead and use pushdata.) + +#if !defined(STB_VORBIS_NO_STDIO) && !defined(STB_VORBIS_NO_INTEGER_CONVERSION) +extern int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output); +#endif +#if !defined(STB_VORBIS_NO_INTEGER_CONVERSION) +extern int stb_vorbis_decode_memory(const unsigned char *mem, int len, int *channels, int *sample_rate, short **output); +#endif +// decode an entire file and output the data interleaved into a malloc()ed +// buffer stored in *output. The return value is the number of samples +// decoded, or -1 if the file could not be opened or was not an ogg vorbis file. +// When you're done with it, just free() the pointer returned in *output. + +extern stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, + int *error, const stb_vorbis_alloc *alloc_buffer); +// create an ogg vorbis decoder from an ogg vorbis stream in memory (note +// this must be the entire stream!). on failure, returns NULL and sets *error + +#ifndef STB_VORBIS_NO_STDIO +extern stb_vorbis * stb_vorbis_open_filename(const char *filename, + int *error, const stb_vorbis_alloc *alloc_buffer); +// create an ogg vorbis decoder from a filename via fopen(). on failure, +// returns NULL and sets *error (possibly to VORBIS_file_open_failure). + +extern stb_vorbis * stb_vorbis_open_file(FILE *f, int close_handle_on_close, + int *error, const stb_vorbis_alloc *alloc_buffer); +// create an ogg vorbis decoder from an open FILE *, looking for a stream at +// the _current_ seek point (ftell). on failure, returns NULL and sets *error. +// note that stb_vorbis must "own" this stream; if you seek it in between +// calls to stb_vorbis, it will become confused. Moreover, if you attempt to +// perform stb_vorbis_seek_*() operations on this file, it will assume it +// owns the _entire_ rest of the file after the start point. Use the next +// function, stb_vorbis_open_file_section(), to limit it. + +extern stb_vorbis * stb_vorbis_open_file_section(FILE *f, int close_handle_on_close, + int *error, const stb_vorbis_alloc *alloc_buffer, unsigned int len); +// create an ogg vorbis decoder from an open FILE *, looking for a stream at +// the _current_ seek point (ftell); the stream will be of length 'len' bytes. +// on failure, returns NULL and sets *error. note that stb_vorbis must "own" +// this stream; if you seek it in between calls to stb_vorbis, it will become +// confused. +#endif + +extern int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number); +extern int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number); +// these functions seek in the Vorbis file to (approximately) 'sample_number'. +// after calling seek_frame(), the next call to get_frame_*() will include +// the specified sample. after calling stb_vorbis_seek(), the next call to +// stb_vorbis_get_samples_* will start with the specified sample. If you +// do not need to seek to EXACTLY the target sample when using get_samples_*, +// you can also use seek_frame(). + +extern int stb_vorbis_seek_start(stb_vorbis *f); +// this function is equivalent to stb_vorbis_seek(f,0) + +extern unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f); +extern float stb_vorbis_stream_length_in_seconds(stb_vorbis *f); +// these functions return the total length of the vorbis stream + +extern int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output); +// decode the next frame and return the number of samples. the number of +// channels returned are stored in *channels (which can be NULL--it is always +// the same as the number of channels reported by get_info). *output will +// contain an array of float* buffers, one per channel. These outputs will +// be overwritten on the next call to stb_vorbis_get_frame_*. +// +// You generally should not intermix calls to stb_vorbis_get_frame_*() +// and stb_vorbis_get_samples_*(), since the latter calls the former. + +#ifndef STB_VORBIS_NO_INTEGER_CONVERSION +extern int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts); +extern int stb_vorbis_get_frame_short (stb_vorbis *f, int num_c, short **buffer, int num_samples); +#endif +// decode the next frame and return the number of *samples* per channel. +// Note that for interleaved data, you pass in the number of shorts (the +// size of your array), but the return value is the number of samples per +// channel, not the total number of samples. +// +// The data is coerced to the number of channels you request according to the +// channel coercion rules (see below). You must pass in the size of your +// buffer(s) so that stb_vorbis will not overwrite the end of the buffer. +// The maximum buffer size needed can be gotten from get_info(); however, +// the Vorbis I specification implies an absolute maximum of 4096 samples +// per channel. + +// Channel coercion rules: +// Let M be the number of channels requested, and N the number of channels present, +// and Cn be the nth channel; let stereo L be the sum of all L and center channels, +// and stereo R be the sum of all R and center channels (channel assignment from the +// vorbis spec). +// M N output +// 1 k sum(Ck) for all k +// 2 * stereo L, stereo R +// k l k > l, the first l channels, then 0s +// k l k <= l, the first k channels +// Note that this is not _good_ surround etc. mixing at all! It's just so +// you get something useful. + +extern int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats); +extern int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples); +// gets num_samples samples, not necessarily on a frame boundary--this requires +// buffering so you have to supply the buffers. DOES NOT APPLY THE COERCION RULES. +// Returns the number of samples stored per channel; it may be less than requested +// at the end of the file. If there are no more samples in the file, returns 0. + +#ifndef STB_VORBIS_NO_INTEGER_CONVERSION +extern int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts); +extern int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int num_samples); +#endif +// gets num_samples samples, not necessarily on a frame boundary--this requires +// buffering so you have to supply the buffers. Applies the coercion rules above +// to produce 'channels' channels. Returns the number of samples stored per channel; +// it may be less than requested at the end of the file. If there are no more +// samples in the file, returns 0. + +#endif + +//////// ERROR CODES + +enum STBVorbisError +{ + VORBIS__no_error, + + VORBIS_need_more_data=1, // not a real error + + VORBIS_invalid_api_mixing, // can't mix API modes + VORBIS_outofmem, // not enough memory + VORBIS_feature_not_supported, // uses floor 0 + VORBIS_too_many_channels, // STB_VORBIS_MAX_CHANNELS is too small + VORBIS_file_open_failure, // fopen() failed + VORBIS_seek_without_length, // can't seek in unknown-length file + + VORBIS_unexpected_eof=10, // file is truncated? + VORBIS_seek_invalid, // seek past EOF + + // decoding errors (corrupt/invalid stream) -- you probably + // don't care about the exact details of these + + // vorbis errors: + VORBIS_invalid_setup=20, + VORBIS_invalid_stream, + + // ogg errors: + VORBIS_missing_capture_pattern=30, + VORBIS_invalid_stream_structure_version, + VORBIS_continued_packet_flag_invalid, + VORBIS_incorrect_stream_serial_number, + VORBIS_invalid_first_page, + VORBIS_bad_packet_type, + VORBIS_cant_find_last_page, + VORBIS_seek_failed, + VORBIS_ogg_skeleton_not_supported +}; + + +#ifdef __cplusplus +} +#endif + +#endif // STB_VORBIS_INCLUDE_STB_VORBIS_H +// +// HEADER ENDS HERE +// +////////////////////////////////////////////////////////////////////////////// + +#ifndef STB_VORBIS_HEADER_ONLY + +// global configuration settings (e.g. set these in the project/makefile), +// or just set them in this file at the top (although ideally the first few +// should be visible when the header file is compiled too, although it's not +// crucial) + +// STB_VORBIS_NO_PUSHDATA_API +// does not compile the code for the various stb_vorbis_*_pushdata() +// functions +// #define STB_VORBIS_NO_PUSHDATA_API + +// STB_VORBIS_NO_PULLDATA_API +// does not compile the code for the non-pushdata APIs +// #define STB_VORBIS_NO_PULLDATA_API + +// STB_VORBIS_NO_STDIO +// does not compile the code for the APIs that use FILE *s internally +// or externally (implied by STB_VORBIS_NO_PULLDATA_API) +// #define STB_VORBIS_NO_STDIO + +// STB_VORBIS_NO_INTEGER_CONVERSION +// does not compile the code for converting audio sample data from +// float to integer (implied by STB_VORBIS_NO_PULLDATA_API) +// #define STB_VORBIS_NO_INTEGER_CONVERSION + +// STB_VORBIS_NO_FAST_SCALED_FLOAT +// does not use a fast float-to-int trick to accelerate float-to-int on +// most platforms which requires endianness be defined correctly. +//#define STB_VORBIS_NO_FAST_SCALED_FLOAT + + +// STB_VORBIS_MAX_CHANNELS [number] +// globally define this to the maximum number of channels you need. +// The spec does not put a restriction on channels except that +// the count is stored in a byte, so 255 is the hard limit. +// Reducing this saves about 16 bytes per value, so using 16 saves +// (255-16)*16 or around 4KB. Plus anything other memory usage +// I forgot to account for. Can probably go as low as 8 (7.1 audio), +// 6 (5.1 audio), or 2 (stereo only). +#ifndef STB_VORBIS_MAX_CHANNELS +#define STB_VORBIS_MAX_CHANNELS 16 // enough for anyone? +#endif + +// STB_VORBIS_PUSHDATA_CRC_COUNT [number] +// after a flush_pushdata(), stb_vorbis begins scanning for the +// next valid page, without backtracking. when it finds something +// that looks like a page, it streams through it and verifies its +// CRC32. Should that validation fail, it keeps scanning. But it's +// possible that _while_ streaming through to check the CRC32 of +// one candidate page, it sees another candidate page. This #define +// determines how many "overlapping" candidate pages it can search +// at once. Note that "real" pages are typically ~4KB to ~8KB, whereas +// garbage pages could be as big as 64KB, but probably average ~16KB. +// So don't hose ourselves by scanning an apparent 64KB page and +// missing a ton of real ones in the interim; so minimum of 2 +#ifndef STB_VORBIS_PUSHDATA_CRC_COUNT +#define STB_VORBIS_PUSHDATA_CRC_COUNT 4 +#endif + +// STB_VORBIS_FAST_HUFFMAN_LENGTH [number] +// sets the log size of the huffman-acceleration table. Maximum +// supported value is 24. with larger numbers, more decodings are O(1), +// but the table size is larger so worse cache missing, so you'll have +// to probe (and try multiple ogg vorbis files) to find the sweet spot. +#ifndef STB_VORBIS_FAST_HUFFMAN_LENGTH +#define STB_VORBIS_FAST_HUFFMAN_LENGTH 10 +#endif + +// STB_VORBIS_FAST_BINARY_LENGTH [number] +// sets the log size of the binary-search acceleration table. this +// is used in similar fashion to the fast-huffman size to set initial +// parameters for the binary search + +// STB_VORBIS_FAST_HUFFMAN_INT +// The fast huffman tables are much more efficient if they can be +// stored as 16-bit results instead of 32-bit results. This restricts +// the codebooks to having only 65535 possible outcomes, though. +// (At least, accelerated by the huffman table.) +#ifndef STB_VORBIS_FAST_HUFFMAN_INT +#define STB_VORBIS_FAST_HUFFMAN_SHORT +#endif + +// STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH +// If the 'fast huffman' search doesn't succeed, then stb_vorbis falls +// back on binary searching for the correct one. This requires storing +// extra tables with the huffman codes in sorted order. Defining this +// symbol trades off space for speed by forcing a linear search in the +// non-fast case, except for "sparse" codebooks. +// #define STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH + +// STB_VORBIS_DIVIDES_IN_RESIDUE +// stb_vorbis precomputes the result of the scalar residue decoding +// that would otherwise require a divide per chunk. you can trade off +// space for time by defining this symbol. +// #define STB_VORBIS_DIVIDES_IN_RESIDUE + +// STB_VORBIS_DIVIDES_IN_CODEBOOK +// vorbis VQ codebooks can be encoded two ways: with every case explicitly +// stored, or with all elements being chosen from a small range of values, +// and all values possible in all elements. By default, stb_vorbis expands +// this latter kind out to look like the former kind for ease of decoding, +// because otherwise an integer divide-per-vector-element is required to +// unpack the index. If you define STB_VORBIS_DIVIDES_IN_CODEBOOK, you can +// trade off storage for speed. +//#define STB_VORBIS_DIVIDES_IN_CODEBOOK + +#ifdef STB_VORBIS_CODEBOOK_SHORTS +#error "STB_VORBIS_CODEBOOK_SHORTS is no longer supported as it produced incorrect results for some input formats" +#endif + +// STB_VORBIS_DIVIDE_TABLE +// this replaces small integer divides in the floor decode loop with +// table lookups. made less than 1% difference, so disabled by default. + +// STB_VORBIS_NO_INLINE_DECODE +// disables the inlining of the scalar codebook fast-huffman decode. +// might save a little codespace; useful for debugging +// #define STB_VORBIS_NO_INLINE_DECODE + +// STB_VORBIS_NO_DEFER_FLOOR +// Normally we only decode the floor without synthesizing the actual +// full curve. We can instead synthesize the curve immediately. This +// requires more memory and is very likely slower, so I don't think +// you'd ever want to do it except for debugging. +// #define STB_VORBIS_NO_DEFER_FLOOR + + + + +////////////////////////////////////////////////////////////////////////////// + +#ifdef STB_VORBIS_NO_PULLDATA_API + #define STB_VORBIS_NO_INTEGER_CONVERSION + #define STB_VORBIS_NO_STDIO +#endif + +#if defined(STB_VORBIS_NO_CRT) && !defined(STB_VORBIS_NO_STDIO) + #define STB_VORBIS_NO_STDIO 1 +#endif + +#ifndef STB_VORBIS_NO_INTEGER_CONVERSION +#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT + + // only need endianness for fast-float-to-int, which we don't + // use for pushdata + + #ifndef STB_VORBIS_BIG_ENDIAN + #define STB_VORBIS_ENDIAN 0 + #else + #define STB_VORBIS_ENDIAN 1 + #endif + +#endif +#endif + + +#ifndef STB_VORBIS_NO_STDIO +#include +#endif + +#ifndef STB_VORBIS_NO_CRT + #include + #include + #include + #include + + // find definition of alloca if it's not in stdlib.h: + #if defined(_MSC_VER) || defined(__MINGW32__) + #include + #endif + #if defined(__linux__) || defined(__linux) || defined(__sun__) || defined(__EMSCRIPTEN__) || defined(__NEWLIB__) + #include + #endif +#else // STB_VORBIS_NO_CRT + #define NULL 0 + #define malloc(s) 0 + #define free(s) ((void) 0) + #define realloc(s) 0 +#endif // STB_VORBIS_NO_CRT + +#include + +#ifdef __MINGW32__ + // eff you mingw: + // "fixed": + // http://sourceforge.net/p/mingw-w64/mailman/message/32882927/ + // "no that broke the build, reverted, who cares about C": + // http://sourceforge.net/p/mingw-w64/mailman/message/32890381/ + #ifdef __forceinline + #undef __forceinline + #endif + #define __forceinline + #ifndef alloca + #define alloca __builtin_alloca + #endif +#elif !defined(_MSC_VER) + #if __GNUC__ + #define __forceinline inline + #else + #define __forceinline + #endif +#endif + +#if STB_VORBIS_MAX_CHANNELS > 256 +#error "Value of STB_VORBIS_MAX_CHANNELS outside of allowed range" +#endif + +#if STB_VORBIS_FAST_HUFFMAN_LENGTH > 24 +#error "Value of STB_VORBIS_FAST_HUFFMAN_LENGTH outside of allowed range" +#endif + + +#if 0 +#include +#define CHECK(f) _CrtIsValidHeapPointer(f->channel_buffers[1]) +#else +#define CHECK(f) ((void) 0) +#endif + +#define MAX_BLOCKSIZE_LOG 13 // from specification +#define MAX_BLOCKSIZE (1 << MAX_BLOCKSIZE_LOG) + + +typedef unsigned char uint8; +typedef signed char int8; +typedef unsigned short uint16; +typedef signed short int16; +typedef unsigned int uint32; +typedef signed int int32; + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +typedef float codetype; + +#ifdef _MSC_VER +#define STBV_NOTUSED(v) (void)(v) +#else +#define STBV_NOTUSED(v) (void)sizeof(v) +#endif + +// @NOTE +// +// Some arrays below are tagged "//varies", which means it's actually +// a variable-sized piece of data, but rather than malloc I assume it's +// small enough it's better to just allocate it all together with the +// main thing +// +// Most of the variables are specified with the smallest size I could pack +// them into. It might give better performance to make them all full-sized +// integers. It should be safe to freely rearrange the structures or change +// the sizes larger--nothing relies on silently truncating etc., nor the +// order of variables. + +#define FAST_HUFFMAN_TABLE_SIZE (1 << STB_VORBIS_FAST_HUFFMAN_LENGTH) +#define FAST_HUFFMAN_TABLE_MASK (FAST_HUFFMAN_TABLE_SIZE - 1) + +typedef struct +{ + int dimensions, entries; + uint8 *codeword_lengths; + float minimum_value; + float delta_value; + uint8 value_bits; + uint8 lookup_type; + uint8 sequence_p; + uint8 sparse; + uint32 lookup_values; + codetype *multiplicands; + uint32 *codewords; + #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT + int16 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; + #else + int32 fast_huffman[FAST_HUFFMAN_TABLE_SIZE]; + #endif + uint32 *sorted_codewords; + int *sorted_values; + int sorted_entries; +} Codebook; + +typedef struct +{ + uint8 order; + uint16 rate; + uint16 bark_map_size; + uint8 amplitude_bits; + uint8 amplitude_offset; + uint8 number_of_books; + uint8 book_list[16]; // varies +} Floor0; + +typedef struct +{ + uint8 partitions; + uint8 partition_class_list[32]; // varies + uint8 class_dimensions[16]; // varies + uint8 class_subclasses[16]; // varies + uint8 class_masterbooks[16]; // varies + int16 subclass_books[16][8]; // varies + uint16 Xlist[31*8+2]; // varies + uint8 sorted_order[31*8+2]; + uint8 neighbors[31*8+2][2]; + uint8 floor1_multiplier; + uint8 rangebits; + int values; +} Floor1; + +typedef union +{ + Floor0 floor0; + Floor1 floor1; +} Floor; + +typedef struct +{ + uint32 begin, end; + uint32 part_size; + uint8 classifications; + uint8 classbook; + uint8 **classdata; + int16 (*residue_books)[8]; +} Residue; + +typedef struct +{ + uint8 magnitude; + uint8 angle; + uint8 mux; +} MappingChannel; + +typedef struct +{ + uint16 coupling_steps; + MappingChannel *chan; + uint8 submaps; + uint8 submap_floor[15]; // varies + uint8 submap_residue[15]; // varies +} Mapping; + +typedef struct +{ + uint8 blockflag; + uint8 mapping; + uint16 windowtype; + uint16 transformtype; +} Mode; + +typedef struct +{ + uint32 goal_crc; // expected crc if match + int bytes_left; // bytes left in packet + uint32 crc_so_far; // running crc + int bytes_done; // bytes processed in _current_ chunk + uint32 sample_loc; // granule pos encoded in page +} CRCscan; + +typedef struct +{ + uint32 page_start, page_end; + uint32 last_decoded_sample; +} ProbedPage; + +struct stb_vorbis +{ + // user-accessible info + unsigned int sample_rate; + int channels; + + unsigned int setup_memory_required; + unsigned int temp_memory_required; + unsigned int setup_temp_memory_required; + + char *vendor; + int comment_list_length; + char **comment_list; + + // input config +#ifndef STB_VORBIS_NO_STDIO + FILE *f; + uint32 f_start; + int close_on_free; +#endif + + uint8 *stream; + uint8 *stream_start; + uint8 *stream_end; + + uint32 stream_len; + + uint8 push_mode; + + // the page to seek to when seeking to start, may be zero + uint32 first_audio_page_offset; + + // p_first is the page on which the first audio packet ends + // (but not necessarily the page on which it starts) + ProbedPage p_first, p_last; + + // memory management + stb_vorbis_alloc alloc; + int setup_offset; + int temp_offset; + + // run-time results + int eof; + enum STBVorbisError error; + + // user-useful data + + // header info + int blocksize[2]; + int blocksize_0, blocksize_1; + int codebook_count; + Codebook *codebooks; + int floor_count; + uint16 floor_types[64]; // varies + Floor *floor_config; + int residue_count; + uint16 residue_types[64]; // varies + Residue *residue_config; + int mapping_count; + Mapping *mapping; + int mode_count; + Mode mode_config[64]; // varies + + uint32 total_samples; + + // decode buffer + float *channel_buffers[STB_VORBIS_MAX_CHANNELS]; + float *outputs [STB_VORBIS_MAX_CHANNELS]; + + float *previous_window[STB_VORBIS_MAX_CHANNELS]; + int previous_length; + + #ifndef STB_VORBIS_NO_DEFER_FLOOR + int16 *finalY[STB_VORBIS_MAX_CHANNELS]; + #else + float *floor_buffers[STB_VORBIS_MAX_CHANNELS]; + #endif + + uint32 current_loc; // sample location of next frame to decode + int current_loc_valid; + + // per-blocksize precomputed data + + // twiddle factors + float *A[2],*B[2],*C[2]; + float *window[2]; + uint16 *bit_reverse[2]; + + // current page/packet/segment streaming info + uint32 serial; // stream serial number for verification + int last_page; + int segment_count; + uint8 segments[255]; + uint8 page_flag; + uint8 bytes_in_seg; + uint8 first_decode; + int next_seg; + int last_seg; // flag that we're on the last segment + int last_seg_which; // what was the segment number of the last seg? + uint32 acc; + int valid_bits; + int packet_bytes; + int end_seg_with_known_loc; + uint32 known_loc_for_packet; + int discard_samples_deferred; + uint32 samples_output; + + // push mode scanning + int page_crc_tests; // only in push_mode: number of tests active; -1 if not searching +#ifndef STB_VORBIS_NO_PUSHDATA_API + CRCscan scan[STB_VORBIS_PUSHDATA_CRC_COUNT]; +#endif + + // sample-access + int channel_buffer_start; + int channel_buffer_end; +}; + +#if defined(STB_VORBIS_NO_PUSHDATA_API) + #define IS_PUSH_MODE(f) FALSE +#elif defined(STB_VORBIS_NO_PULLDATA_API) + #define IS_PUSH_MODE(f) TRUE +#else + #define IS_PUSH_MODE(f) ((f)->push_mode) +#endif + +typedef struct stb_vorbis vorb; + +static int error(vorb *f, enum STBVorbisError e) +{ + f->error = e; + if (!f->eof && e != VORBIS_need_more_data) { + f->error=e; // breakpoint for debugging + } + return 0; +} + + +// these functions are used for allocating temporary memory +// while decoding. if you can afford the stack space, use +// alloca(); otherwise, provide a temp buffer and it will +// allocate out of those. + +#define array_size_required(count,size) (count*(sizeof(void *)+(size))) + +#define temp_alloc(f,size) (f->alloc.alloc_buffer ? setup_temp_malloc(f,size) : alloca(size)) +#define temp_free(f,p) (void)0 +#define temp_alloc_save(f) ((f)->temp_offset) +#define temp_alloc_restore(f,p) ((f)->temp_offset = (p)) + +#define temp_block_array(f,count,size) make_block_array(temp_alloc(f,array_size_required(count,size)), count, size) + +// given a sufficiently large block of memory, make an array of pointers to subblocks of it +static void *make_block_array(void *mem, int count, int size) +{ + int i; + void ** p = (void **) mem; + char *q = (char *) (p + count); + for (i=0; i < count; ++i) { + p[i] = q; + q += size; + } + return p; +} + +static void *setup_malloc(vorb *f, int sz) +{ + sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. + f->setup_memory_required += sz; + if (f->alloc.alloc_buffer) { + void *p = (char *) f->alloc.alloc_buffer + f->setup_offset; + if (f->setup_offset + sz > f->temp_offset) return NULL; + f->setup_offset += sz; + return p; + } + return sz ? malloc(sz) : NULL; +} + +static void setup_free(vorb *f, void *p) +{ + if (f->alloc.alloc_buffer) return; // do nothing; setup mem is a stack + free(p); +} + +static void *setup_temp_malloc(vorb *f, int sz) +{ + sz = (sz+7) & ~7; // round up to nearest 8 for alignment of future allocs. + if (f->alloc.alloc_buffer) { + if (f->temp_offset - sz < f->setup_offset) return NULL; + f->temp_offset -= sz; + return (char *) f->alloc.alloc_buffer + f->temp_offset; + } + return malloc(sz); +} + +static void setup_temp_free(vorb *f, void *p, int sz) +{ + if (f->alloc.alloc_buffer) { + f->temp_offset += (sz+7)&~7; + return; + } + free(p); +} + +#define CRC32_POLY 0x04c11db7 // from spec + +static uint32 crc_table[256]; +static void crc32_init(void) +{ + int i,j; + uint32 s; + for(i=0; i < 256; i++) { + for (s=(uint32) i << 24, j=0; j < 8; ++j) + s = (s << 1) ^ (s >= (1U<<31) ? CRC32_POLY : 0); + crc_table[i] = s; + } +} + +static __forceinline uint32 crc32_update(uint32 crc, uint8 byte) +{ + return (crc << 8) ^ crc_table[byte ^ (crc >> 24)]; +} + + +// used in setup, and for huffman that doesn't go fast path +static unsigned int bit_reverse(unsigned int n) +{ + n = ((n & 0xAAAAAAAA) >> 1) | ((n & 0x55555555) << 1); + n = ((n & 0xCCCCCCCC) >> 2) | ((n & 0x33333333) << 2); + n = ((n & 0xF0F0F0F0) >> 4) | ((n & 0x0F0F0F0F) << 4); + n = ((n & 0xFF00FF00) >> 8) | ((n & 0x00FF00FF) << 8); + return (n >> 16) | (n << 16); +} + +static float square(float x) +{ + return x*x; +} + +// this is a weird definition of log2() for which log2(1) = 1, log2(2) = 2, log2(4) = 3 +// as required by the specification. fast(?) implementation from stb.h +// @OPTIMIZE: called multiple times per-packet with "constants"; move to setup +static int ilog(int32 n) +{ + static signed char log2_4[16] = { 0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4 }; + + if (n < 0) return 0; // signed n returns 0 + + // 2 compares if n < 16, 3 compares otherwise (4 if signed or n > 1<<29) + if (n < (1 << 14)) + if (n < (1 << 4)) return 0 + log2_4[n ]; + else if (n < (1 << 9)) return 5 + log2_4[n >> 5]; + else return 10 + log2_4[n >> 10]; + else if (n < (1 << 24)) + if (n < (1 << 19)) return 15 + log2_4[n >> 15]; + else return 20 + log2_4[n >> 20]; + else if (n < (1 << 29)) return 25 + log2_4[n >> 25]; + else return 30 + log2_4[n >> 30]; +} + +#ifndef M_PI + #define M_PI 3.14159265358979323846264f // from CRC +#endif + +// code length assigned to a value with no huffman encoding +#define NO_CODE 255 + +/////////////////////// LEAF SETUP FUNCTIONS ////////////////////////// +// +// these functions are only called at setup, and only a few times +// per file + +static float float32_unpack(uint32 x) +{ + // from the specification + uint32 mantissa = x & 0x1fffff; + uint32 sign = x & 0x80000000; + uint32 exp = (x & 0x7fe00000) >> 21; + double res = sign ? -(double)mantissa : (double)mantissa; + return (float) ldexp((float)res, (int)exp-788); +} + + +// zlib & jpeg huffman tables assume that the output symbols +// can either be arbitrarily arranged, or have monotonically +// increasing frequencies--they rely on the lengths being sorted; +// this makes for a very simple generation algorithm. +// vorbis allows a huffman table with non-sorted lengths. This +// requires a more sophisticated construction, since symbols in +// order do not map to huffman codes "in order". +static void add_entry(Codebook *c, uint32 huff_code, int symbol, int count, int len, uint32 *values) +{ + if (!c->sparse) { + c->codewords [symbol] = huff_code; + } else { + c->codewords [count] = huff_code; + c->codeword_lengths[count] = len; + values [count] = symbol; + } +} + +static int compute_codewords(Codebook *c, uint8 *len, int n, uint32 *values) +{ + int i,k,m=0; + uint32 available[32]; + + memset(available, 0, sizeof(available)); + // find the first entry + for (k=0; k < n; ++k) if (len[k] < NO_CODE) break; + if (k == n) { assert(c->sorted_entries == 0); return TRUE; } + assert(len[k] < 32); // no error return required, code reading lens checks this + // add to the list + add_entry(c, 0, k, m++, len[k], values); + // add all available leaves + for (i=1; i <= len[k]; ++i) + available[i] = 1U << (32-i); + // note that the above code treats the first case specially, + // but it's really the same as the following code, so they + // could probably be combined (except the initial code is 0, + // and I use 0 in available[] to mean 'empty') + for (i=k+1; i < n; ++i) { + uint32 res; + int z = len[i], y; + if (z == NO_CODE) continue; + assert(z < 32); // no error return required, code reading lens checks this + // find lowest available leaf (should always be earliest, + // which is what the specification calls for) + // note that this property, and the fact we can never have + // more than one free leaf at a given level, isn't totally + // trivial to prove, but it seems true and the assert never + // fires, so! + while (z > 0 && !available[z]) --z; + if (z == 0) { return FALSE; } + res = available[z]; + available[z] = 0; + add_entry(c, bit_reverse(res), i, m++, len[i], values); + // propagate availability up the tree + if (z != len[i]) { + for (y=len[i]; y > z; --y) { + assert(available[y] == 0); + available[y] = res + (1 << (32-y)); + } + } + } + return TRUE; +} + +// accelerated huffman table allows fast O(1) match of all symbols +// of length <= STB_VORBIS_FAST_HUFFMAN_LENGTH +static void compute_accelerated_huffman(Codebook *c) +{ + int i, len; + for (i=0; i < FAST_HUFFMAN_TABLE_SIZE; ++i) + c->fast_huffman[i] = -1; + + len = c->sparse ? c->sorted_entries : c->entries; + #ifdef STB_VORBIS_FAST_HUFFMAN_SHORT + if (len > 32767) len = 32767; // largest possible value we can encode! + #endif + for (i=0; i < len; ++i) { + if (c->codeword_lengths[i] <= STB_VORBIS_FAST_HUFFMAN_LENGTH) { + uint32 z = c->sparse ? bit_reverse(c->sorted_codewords[i]) : c->codewords[i]; + // set table entries for all bit combinations in the higher bits + while (z < FAST_HUFFMAN_TABLE_SIZE) { + c->fast_huffman[z] = i; + z += 1 << c->codeword_lengths[i]; + } + } + } +} + +#ifdef _MSC_VER +#define STBV_CDECL __cdecl +#else +#define STBV_CDECL +#endif + +static int STBV_CDECL uint32_compare(const void *p, const void *q) +{ + uint32 x = * (uint32 *) p; + uint32 y = * (uint32 *) q; + return x < y ? -1 : x > y; +} + +static int include_in_sort(Codebook *c, uint8 len) +{ + if (c->sparse) { assert(len != NO_CODE); return TRUE; } + if (len == NO_CODE) return FALSE; + if (len > STB_VORBIS_FAST_HUFFMAN_LENGTH) return TRUE; + return FALSE; +} + +// if the fast table above doesn't work, we want to binary +// search them... need to reverse the bits +static void compute_sorted_huffman(Codebook *c, uint8 *lengths, uint32 *values) +{ + int i, len; + // build a list of all the entries + // OPTIMIZATION: don't include the short ones, since they'll be caught by FAST_HUFFMAN. + // this is kind of a frivolous optimization--I don't see any performance improvement, + // but it's like 4 extra lines of code, so. + if (!c->sparse) { + int k = 0; + for (i=0; i < c->entries; ++i) + if (include_in_sort(c, lengths[i])) + c->sorted_codewords[k++] = bit_reverse(c->codewords[i]); + assert(k == c->sorted_entries); + } else { + for (i=0; i < c->sorted_entries; ++i) + c->sorted_codewords[i] = bit_reverse(c->codewords[i]); + } + + qsort(c->sorted_codewords, c->sorted_entries, sizeof(c->sorted_codewords[0]), uint32_compare); + c->sorted_codewords[c->sorted_entries] = 0xffffffff; + + len = c->sparse ? c->sorted_entries : c->entries; + // now we need to indicate how they correspond; we could either + // #1: sort a different data structure that says who they correspond to + // #2: for each sorted entry, search the original list to find who corresponds + // #3: for each original entry, find the sorted entry + // #1 requires extra storage, #2 is slow, #3 can use binary search! + for (i=0; i < len; ++i) { + int huff_len = c->sparse ? lengths[values[i]] : lengths[i]; + if (include_in_sort(c,huff_len)) { + uint32 code = bit_reverse(c->codewords[i]); + int x=0, n=c->sorted_entries; + while (n > 1) { + // invariant: sc[x] <= code < sc[x+n] + int m = x + (n >> 1); + if (c->sorted_codewords[m] <= code) { + x = m; + n -= (n>>1); + } else { + n >>= 1; + } + } + assert(c->sorted_codewords[x] == code); + if (c->sparse) { + c->sorted_values[x] = values[i]; + c->codeword_lengths[x] = huff_len; + } else { + c->sorted_values[x] = i; + } + } + } +} + +// only run while parsing the header (3 times) +static int vorbis_validate(uint8 *data) +{ + static uint8 vorbis[6] = { 'v', 'o', 'r', 'b', 'i', 's' }; + return memcmp(data, vorbis, 6) == 0; +} + +// called from setup only, once per code book +// (formula implied by specification) +static int lookup1_values(int entries, int dim) +{ + int r = (int) floor(exp((float) log((float) entries) / dim)); + if ((int) floor(pow((float) r+1, dim)) <= entries) // (int) cast for MinGW warning; + ++r; // floor() to avoid _ftol() when non-CRT + if (pow((float) r+1, dim) <= entries) + return -1; + if ((int) floor(pow((float) r, dim)) > entries) + return -1; + return r; +} + +// called twice per file +static void compute_twiddle_factors(int n, float *A, float *B, float *C) +{ + int n4 = n >> 2, n8 = n >> 3; + int k,k2; + + for (k=k2=0; k < n4; ++k,k2+=2) { + A[k2 ] = (float) cos(4*k*M_PI/n); + A[k2+1] = (float) -sin(4*k*M_PI/n); + B[k2 ] = (float) cos((k2+1)*M_PI/n/2) * 0.5f; + B[k2+1] = (float) sin((k2+1)*M_PI/n/2) * 0.5f; + } + for (k=k2=0; k < n8; ++k,k2+=2) { + C[k2 ] = (float) cos(2*(k2+1)*M_PI/n); + C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n); + } +} + +static void compute_window(int n, float *window) +{ + int n2 = n >> 1, i; + for (i=0; i < n2; ++i) + window[i] = (float) sin(0.5 * M_PI * square((float) sin((i - 0 + 0.5) / n2 * 0.5 * M_PI))); +} + +static void compute_bitreverse(int n, uint16 *rev) +{ + int ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + int i, n8 = n >> 3; + for (i=0; i < n8; ++i) + rev[i] = (bit_reverse(i) >> (32-ld+3)) << 2; +} + +static int init_blocksize(vorb *f, int b, int n) +{ + int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3; + f->A[b] = (float *) setup_malloc(f, sizeof(float) * n2); + f->B[b] = (float *) setup_malloc(f, sizeof(float) * n2); + f->C[b] = (float *) setup_malloc(f, sizeof(float) * n4); + if (!f->A[b] || !f->B[b] || !f->C[b]) return error(f, VORBIS_outofmem); + compute_twiddle_factors(n, f->A[b], f->B[b], f->C[b]); + f->window[b] = (float *) setup_malloc(f, sizeof(float) * n2); + if (!f->window[b]) return error(f, VORBIS_outofmem); + compute_window(n, f->window[b]); + f->bit_reverse[b] = (uint16 *) setup_malloc(f, sizeof(uint16) * n8); + if (!f->bit_reverse[b]) return error(f, VORBIS_outofmem); + compute_bitreverse(n, f->bit_reverse[b]); + return TRUE; +} + +static void neighbors(uint16 *x, int n, int *plow, int *phigh) +{ + int low = -1; + int high = 65536; + int i; + for (i=0; i < n; ++i) { + if (x[i] > low && x[i] < x[n]) { *plow = i; low = x[i]; } + if (x[i] < high && x[i] > x[n]) { *phigh = i; high = x[i]; } + } +} + +// this has been repurposed so y is now the original index instead of y +typedef struct +{ + uint16 x,id; +} stbv__floor_ordering; + +static int STBV_CDECL point_compare(const void *p, const void *q) +{ + stbv__floor_ordering *a = (stbv__floor_ordering *) p; + stbv__floor_ordering *b = (stbv__floor_ordering *) q; + return a->x < b->x ? -1 : a->x > b->x; +} + +// +/////////////////////// END LEAF SETUP FUNCTIONS ////////////////////////// + + +#if defined(STB_VORBIS_NO_STDIO) + #define USE_MEMORY(z) TRUE +#else + #define USE_MEMORY(z) ((z)->stream) +#endif + +static uint8 get8(vorb *z) +{ + if (USE_MEMORY(z)) { + if (z->stream >= z->stream_end) { z->eof = TRUE; return 0; } + return *z->stream++; + } + + #ifndef STB_VORBIS_NO_STDIO + { + int c = fgetc(z->f); + if (c == EOF) { z->eof = TRUE; return 0; } + return c; + } + #endif +} + +static uint32 get32(vorb *f) +{ + uint32 x; + x = get8(f); + x += get8(f) << 8; + x += get8(f) << 16; + x += (uint32) get8(f) << 24; + return x; +} + +static int getn(vorb *z, uint8 *data, int n) +{ + if (USE_MEMORY(z)) { + if (z->stream+n > z->stream_end) { z->eof = 1; return 0; } + memcpy(data, z->stream, n); + z->stream += n; + return 1; + } + + #ifndef STB_VORBIS_NO_STDIO + if (fread(data, n, 1, z->f) == 1) + return 1; + else { + z->eof = 1; + return 0; + } + #endif +} + +static void skip(vorb *z, int n) +{ + if (USE_MEMORY(z)) { + z->stream += n; + if (z->stream >= z->stream_end) z->eof = 1; + return; + } + #ifndef STB_VORBIS_NO_STDIO + { + long x = ftell(z->f); + fseek(z->f, x+n, SEEK_SET); + } + #endif +} + +static int set_file_offset(stb_vorbis *f, unsigned int loc) +{ + #ifndef STB_VORBIS_NO_PUSHDATA_API + if (f->push_mode) return 0; + #endif + f->eof = 0; + if (USE_MEMORY(f)) { + if (f->stream_start + loc >= f->stream_end || f->stream_start + loc < f->stream_start) { + f->stream = f->stream_end; + f->eof = 1; + return 0; + } else { + f->stream = f->stream_start + loc; + return 1; + } + } + #ifndef STB_VORBIS_NO_STDIO + if (loc + f->f_start < loc || loc >= 0x80000000) { + loc = 0x7fffffff; + f->eof = 1; + } else { + loc += f->f_start; + } + if (!fseek(f->f, loc, SEEK_SET)) + return 1; + f->eof = 1; + fseek(f->f, f->f_start, SEEK_END); + return 0; + #endif +} + + +static uint8 ogg_page_header[4] = { 0x4f, 0x67, 0x67, 0x53 }; + +static int capture_pattern(vorb *f) +{ + if (0x4f != get8(f)) return FALSE; + if (0x67 != get8(f)) return FALSE; + if (0x67 != get8(f)) return FALSE; + if (0x53 != get8(f)) return FALSE; + return TRUE; +} + +#define PAGEFLAG_continued_packet 1 +#define PAGEFLAG_first_page 2 +#define PAGEFLAG_last_page 4 + +static int start_page_no_capturepattern(vorb *f) +{ + uint32 loc0,loc1,n; + if (f->first_decode && !IS_PUSH_MODE(f)) { + f->p_first.page_start = stb_vorbis_get_file_offset(f) - 4; + } + // stream structure version + if (0 != get8(f)) return error(f, VORBIS_invalid_stream_structure_version); + // header flag + f->page_flag = get8(f); + // absolute granule position + loc0 = get32(f); + loc1 = get32(f); + // @TODO: validate loc0,loc1 as valid positions? + // stream serial number -- vorbis doesn't interleave, so discard + get32(f); + //if (f->serial != get32(f)) return error(f, VORBIS_incorrect_stream_serial_number); + // page sequence number + n = get32(f); + f->last_page = n; + // CRC32 + get32(f); + // page_segments + f->segment_count = get8(f); + if (!getn(f, f->segments, f->segment_count)) + return error(f, VORBIS_unexpected_eof); + // assume we _don't_ know any the sample position of any segments + f->end_seg_with_known_loc = -2; + if (loc0 != ~0U || loc1 != ~0U) { + int i; + // determine which packet is the last one that will complete + for (i=f->segment_count-1; i >= 0; --i) + if (f->segments[i] < 255) + break; + // 'i' is now the index of the _last_ segment of a packet that ends + if (i >= 0) { + f->end_seg_with_known_loc = i; + f->known_loc_for_packet = loc0; + } + } + if (f->first_decode) { + int i,len; + len = 0; + for (i=0; i < f->segment_count; ++i) + len += f->segments[i]; + len += 27 + f->segment_count; + f->p_first.page_end = f->p_first.page_start + len; + f->p_first.last_decoded_sample = loc0; + } + f->next_seg = 0; + return TRUE; +} + +static int start_page(vorb *f) +{ + if (!capture_pattern(f)) return error(f, VORBIS_missing_capture_pattern); + return start_page_no_capturepattern(f); +} + +static int start_packet(vorb *f) +{ + while (f->next_seg == -1) { + if (!start_page(f)) return FALSE; + if (f->page_flag & PAGEFLAG_continued_packet) + return error(f, VORBIS_continued_packet_flag_invalid); + } + f->last_seg = FALSE; + f->valid_bits = 0; + f->packet_bytes = 0; + f->bytes_in_seg = 0; + // f->next_seg is now valid + return TRUE; +} + +static int maybe_start_packet(vorb *f) +{ + if (f->next_seg == -1) { + int x = get8(f); + if (f->eof) return FALSE; // EOF at page boundary is not an error! + if (0x4f != x ) return error(f, VORBIS_missing_capture_pattern); + if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (0x67 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (0x53 != get8(f)) return error(f, VORBIS_missing_capture_pattern); + if (!start_page_no_capturepattern(f)) return FALSE; + if (f->page_flag & PAGEFLAG_continued_packet) { + // set up enough state that we can read this packet if we want, + // e.g. during recovery + f->last_seg = FALSE; + f->bytes_in_seg = 0; + return error(f, VORBIS_continued_packet_flag_invalid); + } + } + return start_packet(f); +} + +static int next_segment(vorb *f) +{ + int len; + if (f->last_seg) return 0; + if (f->next_seg == -1) { + f->last_seg_which = f->segment_count-1; // in case start_page fails + if (!start_page(f)) { f->last_seg = 1; return 0; } + if (!(f->page_flag & PAGEFLAG_continued_packet)) return error(f, VORBIS_continued_packet_flag_invalid); + } + len = f->segments[f->next_seg++]; + if (len < 255) { + f->last_seg = TRUE; + f->last_seg_which = f->next_seg-1; + } + if (f->next_seg >= f->segment_count) + f->next_seg = -1; + assert(f->bytes_in_seg == 0); + f->bytes_in_seg = len; + return len; +} + +#define EOP (-1) +#define INVALID_BITS (-1) + +static int get8_packet_raw(vorb *f) +{ + if (!f->bytes_in_seg) { // CLANG! + if (f->last_seg) return EOP; + else if (!next_segment(f)) return EOP; + } + assert(f->bytes_in_seg > 0); + --f->bytes_in_seg; + ++f->packet_bytes; + return get8(f); +} + +static int get8_packet(vorb *f) +{ + int x = get8_packet_raw(f); + f->valid_bits = 0; + return x; +} + +static int get32_packet(vorb *f) +{ + uint32 x; + x = get8_packet(f); + x += get8_packet(f) << 8; + x += get8_packet(f) << 16; + x += (uint32) get8_packet(f) << 24; + return x; +} + +static void flush_packet(vorb *f) +{ + while (get8_packet_raw(f) != EOP); +} + +// @OPTIMIZE: this is the secondary bit decoder, so it's probably not as important +// as the huffman decoder? +static uint32 get_bits(vorb *f, int n) +{ + uint32 z; + + if (f->valid_bits < 0) return 0; + if (f->valid_bits < n) { + if (n > 24) { + // the accumulator technique below would not work correctly in this case + z = get_bits(f, 24); + z += get_bits(f, n-24) << 24; + return z; + } + if (f->valid_bits == 0) f->acc = 0; + while (f->valid_bits < n) { + int z = get8_packet_raw(f); + if (z == EOP) { + f->valid_bits = INVALID_BITS; + return 0; + } + f->acc += z << f->valid_bits; + f->valid_bits += 8; + } + } + + assert(f->valid_bits >= n); + z = f->acc & ((1 << n)-1); + f->acc >>= n; + f->valid_bits -= n; + return z; +} + +// @OPTIMIZE: primary accumulator for huffman +// expand the buffer to as many bits as possible without reading off end of packet +// it might be nice to allow f->valid_bits and f->acc to be stored in registers, +// e.g. cache them locally and decode locally +static __forceinline void prep_huffman(vorb *f) +{ + if (f->valid_bits <= 24) { + if (f->valid_bits == 0) f->acc = 0; + do { + int z; + if (f->last_seg && !f->bytes_in_seg) return; + z = get8_packet_raw(f); + if (z == EOP) return; + f->acc += (unsigned) z << f->valid_bits; + f->valid_bits += 8; + } while (f->valid_bits <= 24); + } +} + +enum +{ + VORBIS_packet_id = 1, + VORBIS_packet_comment = 3, + VORBIS_packet_setup = 5 +}; + +static int codebook_decode_scalar_raw(vorb *f, Codebook *c) +{ + int i; + prep_huffman(f); + + if (c->codewords == NULL && c->sorted_codewords == NULL) + return -1; + + // cases to use binary search: sorted_codewords && !c->codewords + // sorted_codewords && c->entries > 8 + if (c->entries > 8 ? c->sorted_codewords!=NULL : !c->codewords) { + // binary search + uint32 code = bit_reverse(f->acc); + int x=0, n=c->sorted_entries, len; + + while (n > 1) { + // invariant: sc[x] <= code < sc[x+n] + int m = x + (n >> 1); + if (c->sorted_codewords[m] <= code) { + x = m; + n -= (n>>1); + } else { + n >>= 1; + } + } + // x is now the sorted index + if (!c->sparse) x = c->sorted_values[x]; + // x is now sorted index if sparse, or symbol otherwise + len = c->codeword_lengths[x]; + if (f->valid_bits >= len) { + f->acc >>= len; + f->valid_bits -= len; + return x; + } + + f->valid_bits = 0; + return -1; + } + + // if small, linear search + assert(!c->sparse); + for (i=0; i < c->entries; ++i) { + if (c->codeword_lengths[i] == NO_CODE) continue; + if (c->codewords[i] == (f->acc & ((1 << c->codeword_lengths[i])-1))) { + if (f->valid_bits >= c->codeword_lengths[i]) { + f->acc >>= c->codeword_lengths[i]; + f->valid_bits -= c->codeword_lengths[i]; + return i; + } + f->valid_bits = 0; + return -1; + } + } + + error(f, VORBIS_invalid_stream); + f->valid_bits = 0; + return -1; +} + +#ifndef STB_VORBIS_NO_INLINE_DECODE + +#define DECODE_RAW(var, f,c) \ + if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) \ + prep_huffman(f); \ + var = f->acc & FAST_HUFFMAN_TABLE_MASK; \ + var = c->fast_huffman[var]; \ + if (var >= 0) { \ + int n = c->codeword_lengths[var]; \ + f->acc >>= n; \ + f->valid_bits -= n; \ + if (f->valid_bits < 0) { f->valid_bits = 0; var = -1; } \ + } else { \ + var = codebook_decode_scalar_raw(f,c); \ + } + +#else + +static int codebook_decode_scalar(vorb *f, Codebook *c) +{ + int i; + if (f->valid_bits < STB_VORBIS_FAST_HUFFMAN_LENGTH) + prep_huffman(f); + // fast huffman table lookup + i = f->acc & FAST_HUFFMAN_TABLE_MASK; + i = c->fast_huffman[i]; + if (i >= 0) { + f->acc >>= c->codeword_lengths[i]; + f->valid_bits -= c->codeword_lengths[i]; + if (f->valid_bits < 0) { f->valid_bits = 0; return -1; } + return i; + } + return codebook_decode_scalar_raw(f,c); +} + +#define DECODE_RAW(var,f,c) var = codebook_decode_scalar(f,c); + +#endif + +#define DECODE(var,f,c) \ + DECODE_RAW(var,f,c) \ + if (c->sparse) var = c->sorted_values[var]; + +#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK + #define DECODE_VQ(var,f,c) DECODE_RAW(var,f,c) +#else + #define DECODE_VQ(var,f,c) DECODE(var,f,c) +#endif + + + + + + +// CODEBOOK_ELEMENT_FAST is an optimization for the CODEBOOK_FLOATS case +// where we avoid one addition +#define CODEBOOK_ELEMENT(c,off) (c->multiplicands[off]) +#define CODEBOOK_ELEMENT_FAST(c,off) (c->multiplicands[off]) +#define CODEBOOK_ELEMENT_BASE(c) (0) + +static int codebook_decode_start(vorb *f, Codebook *c) +{ + int z = -1; + + // type 0 is only legal in a scalar context + if (c->lookup_type == 0) + error(f, VORBIS_invalid_stream); + else { + DECODE_VQ(z,f,c); + if (c->sparse) assert(z < c->sorted_entries); + if (z < 0) { // check for EOP + if (!f->bytes_in_seg) + if (f->last_seg) + return z; + error(f, VORBIS_invalid_stream); + } + } + return z; +} + +static int codebook_decode(vorb *f, Codebook *c, float *output, int len) +{ + int i,z = codebook_decode_start(f,c); + if (z < 0) return FALSE; + if (len > c->dimensions) len = c->dimensions; + +#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK + if (c->lookup_type == 1) { + float last = CODEBOOK_ELEMENT_BASE(c); + int div = 1; + for (i=0; i < len; ++i) { + int off = (z / div) % c->lookup_values; + float val = CODEBOOK_ELEMENT_FAST(c,off) + last; + output[i] += val; + if (c->sequence_p) last = val + c->minimum_value; + div *= c->lookup_values; + } + return TRUE; + } +#endif + + z *= c->dimensions; + if (c->sequence_p) { + float last = CODEBOOK_ELEMENT_BASE(c); + for (i=0; i < len; ++i) { + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + output[i] += val; + last = val + c->minimum_value; + } + } else { + float last = CODEBOOK_ELEMENT_BASE(c); + for (i=0; i < len; ++i) { + output[i] += CODEBOOK_ELEMENT_FAST(c,z+i) + last; + } + } + + return TRUE; +} + +static int codebook_decode_step(vorb *f, Codebook *c, float *output, int len, int step) +{ + int i,z = codebook_decode_start(f,c); + float last = CODEBOOK_ELEMENT_BASE(c); + if (z < 0) return FALSE; + if (len > c->dimensions) len = c->dimensions; + +#ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK + if (c->lookup_type == 1) { + int div = 1; + for (i=0; i < len; ++i) { + int off = (z / div) % c->lookup_values; + float val = CODEBOOK_ELEMENT_FAST(c,off) + last; + output[i*step] += val; + if (c->sequence_p) last = val; + div *= c->lookup_values; + } + return TRUE; + } +#endif + + z *= c->dimensions; + for (i=0; i < len; ++i) { + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + output[i*step] += val; + if (c->sequence_p) last = val; + } + + return TRUE; +} + +static int codebook_decode_deinterleave_repeat(vorb *f, Codebook *c, float **outputs, int ch, int *c_inter_p, int *p_inter_p, int len, int total_decode) +{ + int c_inter = *c_inter_p; + int p_inter = *p_inter_p; + int i,z, effective = c->dimensions; + + // type 0 is only legal in a scalar context + if (c->lookup_type == 0) return error(f, VORBIS_invalid_stream); + + while (total_decode > 0) { + float last = CODEBOOK_ELEMENT_BASE(c); + DECODE_VQ(z,f,c); + #ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK + assert(!c->sparse || z < c->sorted_entries); + #endif + if (z < 0) { + if (!f->bytes_in_seg) + if (f->last_seg) return FALSE; + return error(f, VORBIS_invalid_stream); + } + + // if this will take us off the end of the buffers, stop short! + // we check by computing the length of the virtual interleaved + // buffer (len*ch), our current offset within it (p_inter*ch)+(c_inter), + // and the length we'll be using (effective) + if (c_inter + p_inter*ch + effective > len * ch) { + effective = len*ch - (p_inter*ch - c_inter); + } + + #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK + if (c->lookup_type == 1) { + int div = 1; + for (i=0; i < effective; ++i) { + int off = (z / div) % c->lookup_values; + float val = CODEBOOK_ELEMENT_FAST(c,off) + last; + if (outputs[c_inter]) + outputs[c_inter][p_inter] += val; + if (++c_inter == ch) { c_inter = 0; ++p_inter; } + if (c->sequence_p) last = val; + div *= c->lookup_values; + } + } else + #endif + { + z *= c->dimensions; + if (c->sequence_p) { + for (i=0; i < effective; ++i) { + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + if (outputs[c_inter]) + outputs[c_inter][p_inter] += val; + if (++c_inter == ch) { c_inter = 0; ++p_inter; } + last = val; + } + } else { + for (i=0; i < effective; ++i) { + float val = CODEBOOK_ELEMENT_FAST(c,z+i) + last; + if (outputs[c_inter]) + outputs[c_inter][p_inter] += val; + if (++c_inter == ch) { c_inter = 0; ++p_inter; } + } + } + } + + total_decode -= effective; + } + *c_inter_p = c_inter; + *p_inter_p = p_inter; + return TRUE; +} + +static int predict_point(int x, int x0, int x1, int y0, int y1) +{ + int dy = y1 - y0; + int adx = x1 - x0; + // @OPTIMIZE: force int division to round in the right direction... is this necessary on x86? + int err = abs(dy) * (x - x0); + int off = err / adx; + return dy < 0 ? y0 - off : y0 + off; +} + +// the following table is block-copied from the specification +static float inverse_db_table[256] = +{ + 1.0649863e-07f, 1.1341951e-07f, 1.2079015e-07f, 1.2863978e-07f, + 1.3699951e-07f, 1.4590251e-07f, 1.5538408e-07f, 1.6548181e-07f, + 1.7623575e-07f, 1.8768855e-07f, 1.9988561e-07f, 2.1287530e-07f, + 2.2670913e-07f, 2.4144197e-07f, 2.5713223e-07f, 2.7384213e-07f, + 2.9163793e-07f, 3.1059021e-07f, 3.3077411e-07f, 3.5226968e-07f, + 3.7516214e-07f, 3.9954229e-07f, 4.2550680e-07f, 4.5315863e-07f, + 4.8260743e-07f, 5.1396998e-07f, 5.4737065e-07f, 5.8294187e-07f, + 6.2082472e-07f, 6.6116941e-07f, 7.0413592e-07f, 7.4989464e-07f, + 7.9862701e-07f, 8.5052630e-07f, 9.0579828e-07f, 9.6466216e-07f, + 1.0273513e-06f, 1.0941144e-06f, 1.1652161e-06f, 1.2409384e-06f, + 1.3215816e-06f, 1.4074654e-06f, 1.4989305e-06f, 1.5963394e-06f, + 1.7000785e-06f, 1.8105592e-06f, 1.9282195e-06f, 2.0535261e-06f, + 2.1869758e-06f, 2.3290978e-06f, 2.4804557e-06f, 2.6416497e-06f, + 2.8133190e-06f, 2.9961443e-06f, 3.1908506e-06f, 3.3982101e-06f, + 3.6190449e-06f, 3.8542308e-06f, 4.1047004e-06f, 4.3714470e-06f, + 4.6555282e-06f, 4.9580707e-06f, 5.2802740e-06f, 5.6234160e-06f, + 5.9888572e-06f, 6.3780469e-06f, 6.7925283e-06f, 7.2339451e-06f, + 7.7040476e-06f, 8.2047000e-06f, 8.7378876e-06f, 9.3057248e-06f, + 9.9104632e-06f, 1.0554501e-05f, 1.1240392e-05f, 1.1970856e-05f, + 1.2748789e-05f, 1.3577278e-05f, 1.4459606e-05f, 1.5399272e-05f, + 1.6400004e-05f, 1.7465768e-05f, 1.8600792e-05f, 1.9809576e-05f, + 2.1096914e-05f, 2.2467911e-05f, 2.3928002e-05f, 2.5482978e-05f, + 2.7139006e-05f, 2.8902651e-05f, 3.0780908e-05f, 3.2781225e-05f, + 3.4911534e-05f, 3.7180282e-05f, 3.9596466e-05f, 4.2169667e-05f, + 4.4910090e-05f, 4.7828601e-05f, 5.0936773e-05f, 5.4246931e-05f, + 5.7772202e-05f, 6.1526565e-05f, 6.5524908e-05f, 6.9783085e-05f, + 7.4317983e-05f, 7.9147585e-05f, 8.4291040e-05f, 8.9768747e-05f, + 9.5602426e-05f, 0.00010181521f, 0.00010843174f, 0.00011547824f, + 0.00012298267f, 0.00013097477f, 0.00013948625f, 0.00014855085f, + 0.00015820453f, 0.00016848555f, 0.00017943469f, 0.00019109536f, + 0.00020351382f, 0.00021673929f, 0.00023082423f, 0.00024582449f, + 0.00026179955f, 0.00027881276f, 0.00029693158f, 0.00031622787f, + 0.00033677814f, 0.00035866388f, 0.00038197188f, 0.00040679456f, + 0.00043323036f, 0.00046138411f, 0.00049136745f, 0.00052329927f, + 0.00055730621f, 0.00059352311f, 0.00063209358f, 0.00067317058f, + 0.00071691700f, 0.00076350630f, 0.00081312324f, 0.00086596457f, + 0.00092223983f, 0.00098217216f, 0.0010459992f, 0.0011139742f, + 0.0011863665f, 0.0012634633f, 0.0013455702f, 0.0014330129f, + 0.0015261382f, 0.0016253153f, 0.0017309374f, 0.0018434235f, + 0.0019632195f, 0.0020908006f, 0.0022266726f, 0.0023713743f, + 0.0025254795f, 0.0026895994f, 0.0028643847f, 0.0030505286f, + 0.0032487691f, 0.0034598925f, 0.0036847358f, 0.0039241906f, + 0.0041792066f, 0.0044507950f, 0.0047400328f, 0.0050480668f, + 0.0053761186f, 0.0057254891f, 0.0060975636f, 0.0064938176f, + 0.0069158225f, 0.0073652516f, 0.0078438871f, 0.0083536271f, + 0.0088964928f, 0.009474637f, 0.010090352f, 0.010746080f, + 0.011444421f, 0.012188144f, 0.012980198f, 0.013823725f, + 0.014722068f, 0.015678791f, 0.016697687f, 0.017782797f, + 0.018938423f, 0.020169149f, 0.021479854f, 0.022875735f, + 0.024362330f, 0.025945531f, 0.027631618f, 0.029427276f, + 0.031339626f, 0.033376252f, 0.035545228f, 0.037855157f, + 0.040315199f, 0.042935108f, 0.045725273f, 0.048696758f, + 0.051861348f, 0.055231591f, 0.058820850f, 0.062643361f, + 0.066714279f, 0.071049749f, 0.075666962f, 0.080584227f, + 0.085821044f, 0.091398179f, 0.097337747f, 0.10366330f, + 0.11039993f, 0.11757434f, 0.12521498f, 0.13335215f, + 0.14201813f, 0.15124727f, 0.16107617f, 0.17154380f, + 0.18269168f, 0.19456402f, 0.20720788f, 0.22067342f, + 0.23501402f, 0.25028656f, 0.26655159f, 0.28387361f, + 0.30232132f, 0.32196786f, 0.34289114f, 0.36517414f, + 0.38890521f, 0.41417847f, 0.44109412f, 0.46975890f, + 0.50028648f, 0.53279791f, 0.56742212f, 0.60429640f, + 0.64356699f, 0.68538959f, 0.72993007f, 0.77736504f, + 0.82788260f, 0.88168307f, 0.9389798f, 1.0f +}; + + +// @OPTIMIZE: if you want to replace this bresenham line-drawing routine, +// note that you must produce bit-identical output to decode correctly; +// this specific sequence of operations is specified in the spec (it's +// drawing integer-quantized frequency-space lines that the encoder +// expects to be exactly the same) +// ... also, isn't the whole point of Bresenham's algorithm to NOT +// have to divide in the setup? sigh. +#ifndef STB_VORBIS_NO_DEFER_FLOOR +#define LINE_OP(a,b) a *= b +#else +#define LINE_OP(a,b) a = b +#endif + +#ifdef STB_VORBIS_DIVIDE_TABLE +#define DIVTAB_NUMER 32 +#define DIVTAB_DENOM 64 +int8 integer_divide_table[DIVTAB_NUMER][DIVTAB_DENOM]; // 2KB +#endif + +static __forceinline void draw_line(float *output, int x0, int y0, int x1, int y1, int n) +{ + int dy = y1 - y0; + int adx = x1 - x0; + int ady = abs(dy); + int base; + int x=x0,y=y0; + int err = 0; + int sy; + +#ifdef STB_VORBIS_DIVIDE_TABLE + if (adx < DIVTAB_DENOM && ady < DIVTAB_NUMER) { + if (dy < 0) { + base = -integer_divide_table[ady][adx]; + sy = base-1; + } else { + base = integer_divide_table[ady][adx]; + sy = base+1; + } + } else { + base = dy / adx; + if (dy < 0) + sy = base - 1; + else + sy = base+1; + } +#else + base = dy / adx; + if (dy < 0) + sy = base - 1; + else + sy = base+1; +#endif + ady -= abs(base) * adx; + if (x1 > n) x1 = n; + if (x < x1) { + LINE_OP(output[x], inverse_db_table[y&255]); + for (++x; x < x1; ++x) { + err += ady; + if (err >= adx) { + err -= adx; + y += sy; + } else + y += base; + LINE_OP(output[x], inverse_db_table[y&255]); + } + } +} + +static int residue_decode(vorb *f, Codebook *book, float *target, int offset, int n, int rtype) +{ + int k; + if (rtype == 0) { + int step = n / book->dimensions; + for (k=0; k < step; ++k) + if (!codebook_decode_step(f, book, target+offset+k, n-offset-k, step)) + return FALSE; + } else { + for (k=0; k < n; ) { + if (!codebook_decode(f, book, target+offset, n-k)) + return FALSE; + k += book->dimensions; + offset += book->dimensions; + } + } + return TRUE; +} + +// n is 1/2 of the blocksize -- +// specification: "Correct per-vector decode length is [n]/2" +static void decode_residue(vorb *f, float *residue_buffers[], int ch, int n, int rn, uint8 *do_not_decode) +{ + int i,j,pass; + Residue *r = f->residue_config + rn; + int rtype = f->residue_types[rn]; + int c = r->classbook; + int classwords = f->codebooks[c].dimensions; + unsigned int actual_size = rtype == 2 ? n*2 : n; + unsigned int limit_r_begin = (r->begin < actual_size ? r->begin : actual_size); + unsigned int limit_r_end = (r->end < actual_size ? r->end : actual_size); + int n_read = limit_r_end - limit_r_begin; + int part_read = n_read / r->part_size; + int temp_alloc_point = temp_alloc_save(f); + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + uint8 ***part_classdata = (uint8 ***) temp_block_array(f,f->channels, part_read * sizeof(**part_classdata)); + #else + int **classifications = (int **) temp_block_array(f,f->channels, part_read * sizeof(**classifications)); + #endif + + CHECK(f); + + for (i=0; i < ch; ++i) + if (!do_not_decode[i]) + memset(residue_buffers[i], 0, sizeof(float) * n); + + if (rtype == 2 && ch != 1) { + for (j=0; j < ch; ++j) + if (!do_not_decode[j]) + break; + if (j == ch) + goto done; + + for (pass=0; pass < 8; ++pass) { + int pcount = 0, class_set = 0; + if (ch == 2) { + while (pcount < part_read) { + int z = r->begin + pcount*r->part_size; + int c_inter = (z & 1), p_inter = z>>1; + if (pass == 0) { + Codebook *c = f->codebooks+r->classbook; + int q; + DECODE(q,f,c); + if (q == EOP) goto done; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[0][class_set] = r->classdata[q]; + #else + for (i=classwords-1; i >= 0; --i) { + classifications[0][i+pcount] = q % r->classifications; + q /= r->classifications; + } + #endif + } + for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { + int z = r->begin + pcount*r->part_size; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[0][class_set][i]; + #else + int c = classifications[0][pcount]; + #endif + int b = r->residue_books[c][pass]; + if (b >= 0) { + Codebook *book = f->codebooks + b; + #ifdef STB_VORBIS_DIVIDES_IN_CODEBOOK + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + goto done; + #else + // saves 1% + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + goto done; + #endif + } else { + z += r->part_size; + c_inter = z & 1; + p_inter = z >> 1; + } + } + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; + #endif + } + } else if (ch > 2) { + while (pcount < part_read) { + int z = r->begin + pcount*r->part_size; + int c_inter = z % ch, p_inter = z/ch; + if (pass == 0) { + Codebook *c = f->codebooks+r->classbook; + int q; + DECODE(q,f,c); + if (q == EOP) goto done; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[0][class_set] = r->classdata[q]; + #else + for (i=classwords-1; i >= 0; --i) { + classifications[0][i+pcount] = q % r->classifications; + q /= r->classifications; + } + #endif + } + for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { + int z = r->begin + pcount*r->part_size; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[0][class_set][i]; + #else + int c = classifications[0][pcount]; + #endif + int b = r->residue_books[c][pass]; + if (b >= 0) { + Codebook *book = f->codebooks + b; + if (!codebook_decode_deinterleave_repeat(f, book, residue_buffers, ch, &c_inter, &p_inter, n, r->part_size)) + goto done; + } else { + z += r->part_size; + c_inter = z % ch; + p_inter = z / ch; + } + } + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; + #endif + } + } + } + goto done; + } + CHECK(f); + + for (pass=0; pass < 8; ++pass) { + int pcount = 0, class_set=0; + while (pcount < part_read) { + if (pass == 0) { + for (j=0; j < ch; ++j) { + if (!do_not_decode[j]) { + Codebook *c = f->codebooks+r->classbook; + int temp; + DECODE(temp,f,c); + if (temp == EOP) goto done; + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + part_classdata[j][class_set] = r->classdata[temp]; + #else + for (i=classwords-1; i >= 0; --i) { + classifications[j][i+pcount] = temp % r->classifications; + temp /= r->classifications; + } + #endif + } + } + } + for (i=0; i < classwords && pcount < part_read; ++i, ++pcount) { + for (j=0; j < ch; ++j) { + if (!do_not_decode[j]) { + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + int c = part_classdata[j][class_set][i]; + #else + int c = classifications[j][pcount]; + #endif + int b = r->residue_books[c][pass]; + if (b >= 0) { + float *target = residue_buffers[j]; + int offset = r->begin + pcount * r->part_size; + int n = r->part_size; + Codebook *book = f->codebooks + b; + if (!residue_decode(f, book, target, offset, n, rtype)) + goto done; + } + } + } + } + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + ++class_set; + #endif + } + } + done: + CHECK(f); + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + temp_free(f,part_classdata); + #else + temp_free(f,classifications); + #endif + temp_alloc_restore(f,temp_alloc_point); +} + + +#if 0 +// slow way for debugging +void inverse_mdct_slow(float *buffer, int n) +{ + int i,j; + int n2 = n >> 1; + float *x = (float *) malloc(sizeof(*x) * n2); + memcpy(x, buffer, sizeof(*x) * n2); + for (i=0; i < n; ++i) { + float acc = 0; + for (j=0; j < n2; ++j) + // formula from paper: + //acc += n/4.0f * x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1)); + // formula from wikipedia + //acc += 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5)); + // these are equivalent, except the formula from the paper inverts the multiplier! + // however, what actually works is NO MULTIPLIER!?! + //acc += 64 * 2.0f / n2 * x[j] * (float) cos(M_PI/n2 * (i + 0.5 + n2/2)*(j + 0.5)); + acc += x[j] * (float) cos(M_PI / 2 / n * (2 * i + 1 + n/2.0)*(2*j+1)); + buffer[i] = acc; + } + free(x); +} +#elif 0 +// same as above, but just barely able to run in real time on modern machines +void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) +{ + float mcos[16384]; + int i,j; + int n2 = n >> 1, nmask = (n << 2) -1; + float *x = (float *) malloc(sizeof(*x) * n2); + memcpy(x, buffer, sizeof(*x) * n2); + for (i=0; i < 4*n; ++i) + mcos[i] = (float) cos(M_PI / 2 * i / n); + + for (i=0; i < n; ++i) { + float acc = 0; + for (j=0; j < n2; ++j) + acc += x[j] * mcos[(2 * i + 1 + n2)*(2*j+1) & nmask]; + buffer[i] = acc; + } + free(x); +} +#elif 0 +// transform to use a slow dct-iv; this is STILL basically trivial, +// but only requires half as many ops +void dct_iv_slow(float *buffer, int n) +{ + float mcos[16384]; + float x[2048]; + int i,j; + int n2 = n >> 1, nmask = (n << 3) - 1; + memcpy(x, buffer, sizeof(*x) * n); + for (i=0; i < 8*n; ++i) + mcos[i] = (float) cos(M_PI / 4 * i / n); + for (i=0; i < n; ++i) { + float acc = 0; + for (j=0; j < n; ++j) + acc += x[j] * mcos[((2 * i + 1)*(2*j+1)) & nmask]; + buffer[i] = acc; + } +} + +void inverse_mdct_slow(float *buffer, int n, vorb *f, int blocktype) +{ + int i, n4 = n >> 2, n2 = n >> 1, n3_4 = n - n4; + float temp[4096]; + + memcpy(temp, buffer, n2 * sizeof(float)); + dct_iv_slow(temp, n2); // returns -c'-d, a-b' + + for (i=0; i < n4 ; ++i) buffer[i] = temp[i+n4]; // a-b' + for ( ; i < n3_4; ++i) buffer[i] = -temp[n3_4 - i - 1]; // b-a', c+d' + for ( ; i < n ; ++i) buffer[i] = -temp[i - n3_4]; // c'+d +} +#endif + +#ifndef LIBVORBIS_MDCT +#define LIBVORBIS_MDCT 0 +#endif + +#if LIBVORBIS_MDCT +// directly call the vorbis MDCT using an interface documented +// by Jeff Roberts... useful for performance comparison +typedef struct +{ + int n; + int log2n; + + float *trig; + int *bitrev; + + float scale; +} mdct_lookup; + +extern void mdct_init(mdct_lookup *lookup, int n); +extern void mdct_clear(mdct_lookup *l); +extern void mdct_backward(mdct_lookup *init, float *in, float *out); + +mdct_lookup M1,M2; + +void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) +{ + mdct_lookup *M; + if (M1.n == n) M = &M1; + else if (M2.n == n) M = &M2; + else if (M1.n == 0) { mdct_init(&M1, n); M = &M1; } + else { + if (M2.n) __asm int 3; + mdct_init(&M2, n); + M = &M2; + } + + mdct_backward(M, buffer, buffer); +} +#endif + + +// the following were split out into separate functions while optimizing; +// they could be pushed back up but eh. __forceinline showed no change; +// they're probably already being inlined. +static void imdct_step3_iter0_loop(int n, float *e, int i_off, int k_off, float *A) +{ + float *ee0 = e + i_off; + float *ee2 = ee0 + k_off; + int i; + + assert((n & 3) == 0); + for (i=(n>>2); i > 0; --i) { + float k00_20, k01_21; + k00_20 = ee0[ 0] - ee2[ 0]; + k01_21 = ee0[-1] - ee2[-1]; + ee0[ 0] += ee2[ 0];//ee0[ 0] = ee0[ 0] + ee2[ 0]; + ee0[-1] += ee2[-1];//ee0[-1] = ee0[-1] + ee2[-1]; + ee2[ 0] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-1] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; + + k00_20 = ee0[-2] - ee2[-2]; + k01_21 = ee0[-3] - ee2[-3]; + ee0[-2] += ee2[-2];//ee0[-2] = ee0[-2] + ee2[-2]; + ee0[-3] += ee2[-3];//ee0[-3] = ee0[-3] + ee2[-3]; + ee2[-2] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-3] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; + + k00_20 = ee0[-4] - ee2[-4]; + k01_21 = ee0[-5] - ee2[-5]; + ee0[-4] += ee2[-4];//ee0[-4] = ee0[-4] + ee2[-4]; + ee0[-5] += ee2[-5];//ee0[-5] = ee0[-5] + ee2[-5]; + ee2[-4] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-5] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; + + k00_20 = ee0[-6] - ee2[-6]; + k01_21 = ee0[-7] - ee2[-7]; + ee0[-6] += ee2[-6];//ee0[-6] = ee0[-6] + ee2[-6]; + ee0[-7] += ee2[-7];//ee0[-7] = ee0[-7] + ee2[-7]; + ee2[-6] = k00_20 * A[0] - k01_21 * A[1]; + ee2[-7] = k01_21 * A[0] + k00_20 * A[1]; + A += 8; + ee0 -= 8; + ee2 -= 8; + } +} + +static void imdct_step3_inner_r_loop(int lim, float *e, int d0, int k_off, float *A, int k1) +{ + int i; + float k00_20, k01_21; + + float *e0 = e + d0; + float *e2 = e0 + k_off; + + for (i=lim >> 2; i > 0; --i) { + k00_20 = e0[-0] - e2[-0]; + k01_21 = e0[-1] - e2[-1]; + e0[-0] += e2[-0];//e0[-0] = e0[-0] + e2[-0]; + e0[-1] += e2[-1];//e0[-1] = e0[-1] + e2[-1]; + e2[-0] = (k00_20)*A[0] - (k01_21) * A[1]; + e2[-1] = (k01_21)*A[0] + (k00_20) * A[1]; + + A += k1; + + k00_20 = e0[-2] - e2[-2]; + k01_21 = e0[-3] - e2[-3]; + e0[-2] += e2[-2];//e0[-2] = e0[-2] + e2[-2]; + e0[-3] += e2[-3];//e0[-3] = e0[-3] + e2[-3]; + e2[-2] = (k00_20)*A[0] - (k01_21) * A[1]; + e2[-3] = (k01_21)*A[0] + (k00_20) * A[1]; + + A += k1; + + k00_20 = e0[-4] - e2[-4]; + k01_21 = e0[-5] - e2[-5]; + e0[-4] += e2[-4];//e0[-4] = e0[-4] + e2[-4]; + e0[-5] += e2[-5];//e0[-5] = e0[-5] + e2[-5]; + e2[-4] = (k00_20)*A[0] - (k01_21) * A[1]; + e2[-5] = (k01_21)*A[0] + (k00_20) * A[1]; + + A += k1; + + k00_20 = e0[-6] - e2[-6]; + k01_21 = e0[-7] - e2[-7]; + e0[-6] += e2[-6];//e0[-6] = e0[-6] + e2[-6]; + e0[-7] += e2[-7];//e0[-7] = e0[-7] + e2[-7]; + e2[-6] = (k00_20)*A[0] - (k01_21) * A[1]; + e2[-7] = (k01_21)*A[0] + (k00_20) * A[1]; + + e0 -= 8; + e2 -= 8; + + A += k1; + } +} + +static void imdct_step3_inner_s_loop(int n, float *e, int i_off, int k_off, float *A, int a_off, int k0) +{ + int i; + float A0 = A[0]; + float A1 = A[0+1]; + float A2 = A[0+a_off]; + float A3 = A[0+a_off+1]; + float A4 = A[0+a_off*2+0]; + float A5 = A[0+a_off*2+1]; + float A6 = A[0+a_off*3+0]; + float A7 = A[0+a_off*3+1]; + + float k00,k11; + + float *ee0 = e +i_off; + float *ee2 = ee0+k_off; + + for (i=n; i > 0; --i) { + k00 = ee0[ 0] - ee2[ 0]; + k11 = ee0[-1] - ee2[-1]; + ee0[ 0] = ee0[ 0] + ee2[ 0]; + ee0[-1] = ee0[-1] + ee2[-1]; + ee2[ 0] = (k00) * A0 - (k11) * A1; + ee2[-1] = (k11) * A0 + (k00) * A1; + + k00 = ee0[-2] - ee2[-2]; + k11 = ee0[-3] - ee2[-3]; + ee0[-2] = ee0[-2] + ee2[-2]; + ee0[-3] = ee0[-3] + ee2[-3]; + ee2[-2] = (k00) * A2 - (k11) * A3; + ee2[-3] = (k11) * A2 + (k00) * A3; + + k00 = ee0[-4] - ee2[-4]; + k11 = ee0[-5] - ee2[-5]; + ee0[-4] = ee0[-4] + ee2[-4]; + ee0[-5] = ee0[-5] + ee2[-5]; + ee2[-4] = (k00) * A4 - (k11) * A5; + ee2[-5] = (k11) * A4 + (k00) * A5; + + k00 = ee0[-6] - ee2[-6]; + k11 = ee0[-7] - ee2[-7]; + ee0[-6] = ee0[-6] + ee2[-6]; + ee0[-7] = ee0[-7] + ee2[-7]; + ee2[-6] = (k00) * A6 - (k11) * A7; + ee2[-7] = (k11) * A6 + (k00) * A7; + + ee0 -= k0; + ee2 -= k0; + } +} + +static __forceinline void iter_54(float *z) +{ + float k00,k11,k22,k33; + float y0,y1,y2,y3; + + k00 = z[ 0] - z[-4]; + y0 = z[ 0] + z[-4]; + y2 = z[-2] + z[-6]; + k22 = z[-2] - z[-6]; + + z[-0] = y0 + y2; // z0 + z4 + z2 + z6 + z[-2] = y0 - y2; // z0 + z4 - z2 - z6 + + // done with y0,y2 + + k33 = z[-3] - z[-7]; + + z[-4] = k00 + k33; // z0 - z4 + z3 - z7 + z[-6] = k00 - k33; // z0 - z4 - z3 + z7 + + // done with k33 + + k11 = z[-1] - z[-5]; + y1 = z[-1] + z[-5]; + y3 = z[-3] + z[-7]; + + z[-1] = y1 + y3; // z1 + z5 + z3 + z7 + z[-3] = y1 - y3; // z1 + z5 - z3 - z7 + z[-5] = k11 - k22; // z1 - z5 + z2 - z6 + z[-7] = k11 + k22; // z1 - z5 - z2 + z6 +} + +static void imdct_step3_inner_s_loop_ld654(int n, float *e, int i_off, float *A, int base_n) +{ + int a_off = base_n >> 3; + float A2 = A[0+a_off]; + float *z = e + i_off; + float *base = z - 16 * n; + + while (z > base) { + float k00,k11; + float l00,l11; + + k00 = z[-0] - z[ -8]; + k11 = z[-1] - z[ -9]; + l00 = z[-2] - z[-10]; + l11 = z[-3] - z[-11]; + z[ -0] = z[-0] + z[ -8]; + z[ -1] = z[-1] + z[ -9]; + z[ -2] = z[-2] + z[-10]; + z[ -3] = z[-3] + z[-11]; + z[ -8] = k00; + z[ -9] = k11; + z[-10] = (l00+l11) * A2; + z[-11] = (l11-l00) * A2; + + k00 = z[ -4] - z[-12]; + k11 = z[ -5] - z[-13]; + l00 = z[ -6] - z[-14]; + l11 = z[ -7] - z[-15]; + z[ -4] = z[ -4] + z[-12]; + z[ -5] = z[ -5] + z[-13]; + z[ -6] = z[ -6] + z[-14]; + z[ -7] = z[ -7] + z[-15]; + z[-12] = k11; + z[-13] = -k00; + z[-14] = (l11-l00) * A2; + z[-15] = (l00+l11) * -A2; + + iter_54(z); + iter_54(z-8); + z -= 16; + } +} + +static void inverse_mdct(float *buffer, int n, vorb *f, int blocktype) +{ + int n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; + int ld; + // @OPTIMIZE: reduce register pressure by using fewer variables? + int save_point = temp_alloc_save(f); + float *buf2 = (float *) temp_alloc(f, n2 * sizeof(*buf2)); + float *u=NULL,*v=NULL; + // twiddle factors + float *A = f->A[blocktype]; + + // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" + // See notes about bugs in that paper in less-optimal implementation 'inverse_mdct_old' after this function. + + // kernel from paper + + + // merged: + // copy and reflect spectral data + // step 0 + + // note that it turns out that the items added together during + // this step are, in fact, being added to themselves (as reflected + // by step 0). inexplicable inefficiency! this became obvious + // once I combined the passes. + + // so there's a missing 'times 2' here (for adding X to itself). + // this propagates through linearly to the end, where the numbers + // are 1/2 too small, and need to be compensated for. + + { + float *d,*e, *AA, *e_stop; + d = &buf2[n2-2]; + AA = A; + e = &buffer[0]; + e_stop = &buffer[n2]; + while (e != e_stop) { + d[1] = (e[0] * AA[0] - e[2]*AA[1]); + d[0] = (e[0] * AA[1] + e[2]*AA[0]); + d -= 2; + AA += 2; + e += 4; + } + + e = &buffer[n2-3]; + while (d >= buf2) { + d[1] = (-e[2] * AA[0] - -e[0]*AA[1]); + d[0] = (-e[2] * AA[1] + -e[0]*AA[0]); + d -= 2; + AA += 2; + e -= 4; + } + } + + // now we use symbolic names for these, so that we can + // possibly swap their meaning as we change which operations + // are in place + + u = buffer; + v = buf2; + + // step 2 (paper output is w, now u) + // this could be in place, but the data ends up in the wrong + // place... _somebody_'s got to swap it, so this is nominated + { + float *AA = &A[n2-8]; + float *d0,*d1, *e0, *e1; + + e0 = &v[n4]; + e1 = &v[0]; + + d0 = &u[n4]; + d1 = &u[0]; + + while (AA >= A) { + float v40_20, v41_21; + + v41_21 = e0[1] - e1[1]; + v40_20 = e0[0] - e1[0]; + d0[1] = e0[1] + e1[1]; + d0[0] = e0[0] + e1[0]; + d1[1] = v41_21*AA[4] - v40_20*AA[5]; + d1[0] = v40_20*AA[4] + v41_21*AA[5]; + + v41_21 = e0[3] - e1[3]; + v40_20 = e0[2] - e1[2]; + d0[3] = e0[3] + e1[3]; + d0[2] = e0[2] + e1[2]; + d1[3] = v41_21*AA[0] - v40_20*AA[1]; + d1[2] = v40_20*AA[0] + v41_21*AA[1]; + + AA -= 8; + + d0 += 4; + d1 += 4; + e0 += 4; + e1 += 4; + } + } + + // step 3 + ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + + // optimized step 3: + + // the original step3 loop can be nested r inside s or s inside r; + // it's written originally as s inside r, but this is dumb when r + // iterates many times, and s few. So I have two copies of it and + // switch between them halfway. + + // this is iteration 0 of step 3 + imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*0, -(n >> 3), A); + imdct_step3_iter0_loop(n >> 4, u, n2-1-n4*1, -(n >> 3), A); + + // this is iteration 1 of step 3 + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*0, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*1, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*2, -(n >> 4), A, 16); + imdct_step3_inner_r_loop(n >> 5, u, n2-1 - n8*3, -(n >> 4), A, 16); + + l=2; + for (; l < (ld-3)>>1; ++l) { + int k0 = n >> (l+2), k0_2 = k0>>1; + int lim = 1 << (l+1); + int i; + for (i=0; i < lim; ++i) + imdct_step3_inner_r_loop(n >> (l+4), u, n2-1 - k0*i, -k0_2, A, 1 << (l+3)); + } + + for (; l < ld-6; ++l) { + int k0 = n >> (l+2), k1 = 1 << (l+3), k0_2 = k0>>1; + int rlim = n >> (l+6), r; + int lim = 1 << (l+1); + int i_off; + float *A0 = A; + i_off = n2-1; + for (r=rlim; r > 0; --r) { + imdct_step3_inner_s_loop(lim, u, i_off, -k0_2, A0, k1, k0); + A0 += k1*4; + i_off -= 8; + } + } + + // iterations with count: + // ld-6,-5,-4 all interleaved together + // the big win comes from getting rid of needless flops + // due to the constants on pass 5 & 4 being all 1 and 0; + // combining them to be simultaneous to improve cache made little difference + imdct_step3_inner_s_loop_ld654(n >> 5, u, n2-1, A, n); + + // output is u + + // step 4, 5, and 6 + // cannot be in-place because of step 5 + { + uint16 *bitrev = f->bit_reverse[blocktype]; + // weirdly, I'd have thought reading sequentially and writing + // erratically would have been better than vice-versa, but in + // fact that's not what my testing showed. (That is, with + // j = bitreverse(i), do you read i and write j, or read j and write i.) + + float *d0 = &v[n4-4]; + float *d1 = &v[n2-4]; + while (d0 >= v) { + int k4; + + k4 = bitrev[0]; + d1[3] = u[k4+0]; + d1[2] = u[k4+1]; + d0[3] = u[k4+2]; + d0[2] = u[k4+3]; + + k4 = bitrev[1]; + d1[1] = u[k4+0]; + d1[0] = u[k4+1]; + d0[1] = u[k4+2]; + d0[0] = u[k4+3]; + + d0 -= 4; + d1 -= 4; + bitrev += 2; + } + } + // (paper output is u, now v) + + + // data must be in buf2 + assert(v == buf2); + + // step 7 (paper output is v, now v) + // this is now in place + { + float *C = f->C[blocktype]; + float *d, *e; + + d = v; + e = v + n2 - 4; + + while (d < e) { + float a02,a11,b0,b1,b2,b3; + + a02 = d[0] - e[2]; + a11 = d[1] + e[3]; + + b0 = C[1]*a02 + C[0]*a11; + b1 = C[1]*a11 - C[0]*a02; + + b2 = d[0] + e[ 2]; + b3 = d[1] - e[ 3]; + + d[0] = b2 + b0; + d[1] = b3 + b1; + e[2] = b2 - b0; + e[3] = b1 - b3; + + a02 = d[2] - e[0]; + a11 = d[3] + e[1]; + + b0 = C[3]*a02 + C[2]*a11; + b1 = C[3]*a11 - C[2]*a02; + + b2 = d[2] + e[ 0]; + b3 = d[3] - e[ 1]; + + d[2] = b2 + b0; + d[3] = b3 + b1; + e[0] = b2 - b0; + e[1] = b1 - b3; + + C += 4; + d += 4; + e -= 4; + } + } + + // data must be in buf2 + + + // step 8+decode (paper output is X, now buffer) + // this generates pairs of data a la 8 and pushes them directly through + // the decode kernel (pushing rather than pulling) to avoid having + // to make another pass later + + // this cannot POSSIBLY be in place, so we refer to the buffers directly + + { + float *d0,*d1,*d2,*d3; + + float *B = f->B[blocktype] + n2 - 8; + float *e = buf2 + n2 - 8; + d0 = &buffer[0]; + d1 = &buffer[n2-4]; + d2 = &buffer[n2]; + d3 = &buffer[n-4]; + while (e >= v) { + float p0,p1,p2,p3; + + p3 = e[6]*B[7] - e[7]*B[6]; + p2 = -e[6]*B[6] - e[7]*B[7]; + + d0[0] = p3; + d1[3] = - p3; + d2[0] = p2; + d3[3] = p2; + + p1 = e[4]*B[5] - e[5]*B[4]; + p0 = -e[4]*B[4] - e[5]*B[5]; + + d0[1] = p1; + d1[2] = - p1; + d2[1] = p0; + d3[2] = p0; + + p3 = e[2]*B[3] - e[3]*B[2]; + p2 = -e[2]*B[2] - e[3]*B[3]; + + d0[2] = p3; + d1[1] = - p3; + d2[2] = p2; + d3[1] = p2; + + p1 = e[0]*B[1] - e[1]*B[0]; + p0 = -e[0]*B[0] - e[1]*B[1]; + + d0[3] = p1; + d1[0] = - p1; + d2[3] = p0; + d3[0] = p0; + + B -= 8; + e -= 8; + d0 += 4; + d2 += 4; + d1 -= 4; + d3 -= 4; + } + } + + temp_free(f,buf2); + temp_alloc_restore(f,save_point); +} + +#if 0 +// this is the original version of the above code, if you want to optimize it from scratch +void inverse_mdct_naive(float *buffer, int n) +{ + float s; + float A[1 << 12], B[1 << 12], C[1 << 11]; + int i,k,k2,k4, n2 = n >> 1, n4 = n >> 2, n8 = n >> 3, l; + int n3_4 = n - n4, ld; + // how can they claim this only uses N words?! + // oh, because they're only used sparsely, whoops + float u[1 << 13], X[1 << 13], v[1 << 13], w[1 << 13]; + // set up twiddle factors + + for (k=k2=0; k < n4; ++k,k2+=2) { + A[k2 ] = (float) cos(4*k*M_PI/n); + A[k2+1] = (float) -sin(4*k*M_PI/n); + B[k2 ] = (float) cos((k2+1)*M_PI/n/2); + B[k2+1] = (float) sin((k2+1)*M_PI/n/2); + } + for (k=k2=0; k < n8; ++k,k2+=2) { + C[k2 ] = (float) cos(2*(k2+1)*M_PI/n); + C[k2+1] = (float) -sin(2*(k2+1)*M_PI/n); + } + + // IMDCT algorithm from "The use of multirate filter banks for coding of high quality digital audio" + // Note there are bugs in that pseudocode, presumably due to them attempting + // to rename the arrays nicely rather than representing the way their actual + // implementation bounces buffers back and forth. As a result, even in the + // "some formulars corrected" version, a direct implementation fails. These + // are noted below as "paper bug". + + // copy and reflect spectral data + for (k=0; k < n2; ++k) u[k] = buffer[k]; + for ( ; k < n ; ++k) u[k] = -buffer[n - k - 1]; + // kernel from paper + // step 1 + for (k=k2=k4=0; k < n4; k+=1, k2+=2, k4+=4) { + v[n-k4-1] = (u[k4] - u[n-k4-1]) * A[k2] - (u[k4+2] - u[n-k4-3])*A[k2+1]; + v[n-k4-3] = (u[k4] - u[n-k4-1]) * A[k2+1] + (u[k4+2] - u[n-k4-3])*A[k2]; + } + // step 2 + for (k=k4=0; k < n8; k+=1, k4+=4) { + w[n2+3+k4] = v[n2+3+k4] + v[k4+3]; + w[n2+1+k4] = v[n2+1+k4] + v[k4+1]; + w[k4+3] = (v[n2+3+k4] - v[k4+3])*A[n2-4-k4] - (v[n2+1+k4]-v[k4+1])*A[n2-3-k4]; + w[k4+1] = (v[n2+1+k4] - v[k4+1])*A[n2-4-k4] + (v[n2+3+k4]-v[k4+3])*A[n2-3-k4]; + } + // step 3 + ld = ilog(n) - 1; // ilog is off-by-one from normal definitions + for (l=0; l < ld-3; ++l) { + int k0 = n >> (l+2), k1 = 1 << (l+3); + int rlim = n >> (l+4), r4, r; + int s2lim = 1 << (l+2), s2; + for (r=r4=0; r < rlim; r4+=4,++r) { + for (s2=0; s2 < s2lim; s2+=2) { + u[n-1-k0*s2-r4] = w[n-1-k0*s2-r4] + w[n-1-k0*(s2+1)-r4]; + u[n-3-k0*s2-r4] = w[n-3-k0*s2-r4] + w[n-3-k0*(s2+1)-r4]; + u[n-1-k0*(s2+1)-r4] = (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1] + - (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1+1]; + u[n-3-k0*(s2+1)-r4] = (w[n-3-k0*s2-r4] - w[n-3-k0*(s2+1)-r4]) * A[r*k1] + + (w[n-1-k0*s2-r4] - w[n-1-k0*(s2+1)-r4]) * A[r*k1+1]; + } + } + if (l+1 < ld-3) { + // paper bug: ping-ponging of u&w here is omitted + memcpy(w, u, sizeof(u)); + } + } + + // step 4 + for (i=0; i < n8; ++i) { + int j = bit_reverse(i) >> (32-ld+3); + assert(j < n8); + if (i == j) { + // paper bug: original code probably swapped in place; if copying, + // need to directly copy in this case + int i8 = i << 3; + v[i8+1] = u[i8+1]; + v[i8+3] = u[i8+3]; + v[i8+5] = u[i8+5]; + v[i8+7] = u[i8+7]; + } else if (i < j) { + int i8 = i << 3, j8 = j << 3; + v[j8+1] = u[i8+1], v[i8+1] = u[j8 + 1]; + v[j8+3] = u[i8+3], v[i8+3] = u[j8 + 3]; + v[j8+5] = u[i8+5], v[i8+5] = u[j8 + 5]; + v[j8+7] = u[i8+7], v[i8+7] = u[j8 + 7]; + } + } + // step 5 + for (k=0; k < n2; ++k) { + w[k] = v[k*2+1]; + } + // step 6 + for (k=k2=k4=0; k < n8; ++k, k2 += 2, k4 += 4) { + u[n-1-k2] = w[k4]; + u[n-2-k2] = w[k4+1]; + u[n3_4 - 1 - k2] = w[k4+2]; + u[n3_4 - 2 - k2] = w[k4+3]; + } + // step 7 + for (k=k2=0; k < n8; ++k, k2 += 2) { + v[n2 + k2 ] = ( u[n2 + k2] + u[n-2-k2] + C[k2+1]*(u[n2+k2]-u[n-2-k2]) + C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2; + v[n-2 - k2] = ( u[n2 + k2] + u[n-2-k2] - C[k2+1]*(u[n2+k2]-u[n-2-k2]) - C[k2]*(u[n2+k2+1]+u[n-2-k2+1]))/2; + v[n2+1+ k2] = ( u[n2+1+k2] - u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2; + v[n-1 - k2] = (-u[n2+1+k2] + u[n-1-k2] + C[k2+1]*(u[n2+1+k2]+u[n-1-k2]) - C[k2]*(u[n2+k2]-u[n-2-k2]))/2; + } + // step 8 + for (k=k2=0; k < n4; ++k,k2 += 2) { + X[k] = v[k2+n2]*B[k2 ] + v[k2+1+n2]*B[k2+1]; + X[n2-1-k] = v[k2+n2]*B[k2+1] - v[k2+1+n2]*B[k2 ]; + } + + // decode kernel to output + // determined the following value experimentally + // (by first figuring out what made inverse_mdct_slow work); then matching that here + // (probably vorbis encoder premultiplies by n or n/2, to save it on the decoder?) + s = 0.5; // theoretically would be n4 + + // [[[ note! the s value of 0.5 is compensated for by the B[] in the current code, + // so it needs to use the "old" B values to behave correctly, or else + // set s to 1.0 ]]] + for (i=0; i < n4 ; ++i) buffer[i] = s * X[i+n4]; + for ( ; i < n3_4; ++i) buffer[i] = -s * X[n3_4 - i - 1]; + for ( ; i < n ; ++i) buffer[i] = -s * X[i - n3_4]; +} +#endif + +static float *get_window(vorb *f, int len) +{ + len <<= 1; + if (len == f->blocksize_0) return f->window[0]; + if (len == f->blocksize_1) return f->window[1]; + return NULL; +} + +#ifndef STB_VORBIS_NO_DEFER_FLOOR +typedef int16 YTYPE; +#else +typedef int YTYPE; +#endif +static int do_floor(vorb *f, Mapping *map, int i, int n, float *target, YTYPE *finalY, uint8 *step2_flag) +{ + int n2 = n >> 1; + int s = map->chan[i].mux, floor; + floor = map->submap_floor[s]; + if (f->floor_types[floor] == 0) { + return error(f, VORBIS_invalid_stream); + } else { + Floor1 *g = &f->floor_config[floor].floor1; + int j,q; + int lx = 0, ly = finalY[0] * g->floor1_multiplier; + for (q=1; q < g->values; ++q) { + j = g->sorted_order[q]; + #ifndef STB_VORBIS_NO_DEFER_FLOOR + STBV_NOTUSED(step2_flag); + if (finalY[j] >= 0) + #else + if (step2_flag[j]) + #endif + { + int hy = finalY[j] * g->floor1_multiplier; + int hx = g->Xlist[j]; + if (lx != hx) + draw_line(target, lx,ly, hx,hy, n2); + CHECK(f); + lx = hx, ly = hy; + } + } + if (lx < n2) { + // optimization of: draw_line(target, lx,ly, n,ly, n2); + for (j=lx; j < n2; ++j) + LINE_OP(target[j], inverse_db_table[ly]); + CHECK(f); + } + } + return TRUE; +} + +// The meaning of "left" and "right" +// +// For a given frame: +// we compute samples from 0..n +// window_center is n/2 +// we'll window and mix the samples from left_start to left_end with data from the previous frame +// all of the samples from left_end to right_start can be output without mixing; however, +// this interval is 0-length except when transitioning between short and long frames +// all of the samples from right_start to right_end need to be mixed with the next frame, +// which we don't have, so those get saved in a buffer +// frame N's right_end-right_start, the number of samples to mix with the next frame, +// has to be the same as frame N+1's left_end-left_start (which they are by +// construction) + +static int vorbis_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +{ + Mode *m; + int i, n, prev, next, window_center; + f->channel_buffer_start = f->channel_buffer_end = 0; + + retry: + if (f->eof) return FALSE; + if (!maybe_start_packet(f)) + return FALSE; + // check packet type + if (get_bits(f,1) != 0) { + if (IS_PUSH_MODE(f)) + return error(f,VORBIS_bad_packet_type); + while (EOP != get8_packet(f)); + goto retry; + } + + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + + i = get_bits(f, ilog(f->mode_count-1)); + if (i == EOP) return FALSE; + if (i >= f->mode_count) return FALSE; + *mode = i; + m = f->mode_config + i; + if (m->blockflag) { + n = f->blocksize_1; + prev = get_bits(f,1); + next = get_bits(f,1); + } else { + prev = next = 0; + n = f->blocksize_0; + } + +// WINDOWING + + window_center = n >> 1; + if (m->blockflag && !prev) { + *p_left_start = (n - f->blocksize_0) >> 2; + *p_left_end = (n + f->blocksize_0) >> 2; + } else { + *p_left_start = 0; + *p_left_end = window_center; + } + if (m->blockflag && !next) { + *p_right_start = (n*3 - f->blocksize_0) >> 2; + *p_right_end = (n*3 + f->blocksize_0) >> 2; + } else { + *p_right_start = window_center; + *p_right_end = n; + } + + return TRUE; +} + +static int vorbis_decode_packet_rest(vorb *f, int *len, Mode *m, int left_start, int left_end, int right_start, int right_end, int *p_left) +{ + Mapping *map; + int i,j,k,n,n2; + int zero_channel[256]; + int really_zero_channel[256]; + +// WINDOWING + + STBV_NOTUSED(left_end); + n = f->blocksize[m->blockflag]; + map = &f->mapping[m->mapping]; + +// FLOORS + n2 = n >> 1; + + CHECK(f); + + for (i=0; i < f->channels; ++i) { + int s = map->chan[i].mux, floor; + zero_channel[i] = FALSE; + floor = map->submap_floor[s]; + if (f->floor_types[floor] == 0) { + return error(f, VORBIS_invalid_stream); + } else { + Floor1 *g = &f->floor_config[floor].floor1; + if (get_bits(f, 1)) { + short *finalY; + uint8 step2_flag[256]; + static int range_list[4] = { 256, 128, 86, 64 }; + int range = range_list[g->floor1_multiplier-1]; + int offset = 2; + finalY = f->finalY[i]; + finalY[0] = get_bits(f, ilog(range)-1); + finalY[1] = get_bits(f, ilog(range)-1); + for (j=0; j < g->partitions; ++j) { + int pclass = g->partition_class_list[j]; + int cdim = g->class_dimensions[pclass]; + int cbits = g->class_subclasses[pclass]; + int csub = (1 << cbits)-1; + int cval = 0; + if (cbits) { + Codebook *c = f->codebooks + g->class_masterbooks[pclass]; + DECODE(cval,f,c); + } + for (k=0; k < cdim; ++k) { + int book = g->subclass_books[pclass][cval & csub]; + cval = cval >> cbits; + if (book >= 0) { + int temp; + Codebook *c = f->codebooks + book; + DECODE(temp,f,c); + finalY[offset++] = temp; + } else + finalY[offset++] = 0; + } + } + if (f->valid_bits == INVALID_BITS) goto error; // behavior according to spec + step2_flag[0] = step2_flag[1] = 1; + for (j=2; j < g->values; ++j) { + int low, high, pred, highroom, lowroom, room, val; + low = g->neighbors[j][0]; + high = g->neighbors[j][1]; + //neighbors(g->Xlist, j, &low, &high); + pred = predict_point(g->Xlist[j], g->Xlist[low], g->Xlist[high], finalY[low], finalY[high]); + val = finalY[j]; + highroom = range - pred; + lowroom = pred; + if (highroom < lowroom) + room = highroom * 2; + else + room = lowroom * 2; + if (val) { + step2_flag[low] = step2_flag[high] = 1; + step2_flag[j] = 1; + if (val >= room) + if (highroom > lowroom) + finalY[j] = val - lowroom + pred; + else + finalY[j] = pred - val + highroom - 1; + else + if (val & 1) + finalY[j] = pred - ((val+1)>>1); + else + finalY[j] = pred + (val>>1); + } else { + step2_flag[j] = 0; + finalY[j] = pred; + } + } + +#ifdef STB_VORBIS_NO_DEFER_FLOOR + do_floor(f, map, i, n, f->floor_buffers[i], finalY, step2_flag); +#else + // defer final floor computation until _after_ residue + for (j=0; j < g->values; ++j) { + if (!step2_flag[j]) + finalY[j] = -1; + } +#endif + } else { + error: + zero_channel[i] = TRUE; + } + // So we just defer everything else to later + + // at this point we've decoded the floor into buffer + } + } + CHECK(f); + // at this point we've decoded all floors + + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + + // re-enable coupled channels if necessary + memcpy(really_zero_channel, zero_channel, sizeof(really_zero_channel[0]) * f->channels); + for (i=0; i < map->coupling_steps; ++i) + if (!zero_channel[map->chan[i].magnitude] || !zero_channel[map->chan[i].angle]) { + zero_channel[map->chan[i].magnitude] = zero_channel[map->chan[i].angle] = FALSE; + } + + CHECK(f); +// RESIDUE DECODE + for (i=0; i < map->submaps; ++i) { + float *residue_buffers[STB_VORBIS_MAX_CHANNELS]; + int r; + uint8 do_not_decode[256]; + int ch = 0; + for (j=0; j < f->channels; ++j) { + if (map->chan[j].mux == i) { + if (zero_channel[j]) { + do_not_decode[ch] = TRUE; + residue_buffers[ch] = NULL; + } else { + do_not_decode[ch] = FALSE; + residue_buffers[ch] = f->channel_buffers[j]; + } + ++ch; + } + } + r = map->submap_residue[i]; + decode_residue(f, residue_buffers, ch, n2, r, do_not_decode); + } + + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + CHECK(f); + +// INVERSE COUPLING + for (i = map->coupling_steps-1; i >= 0; --i) { + int n2 = n >> 1; + float *m = f->channel_buffers[map->chan[i].magnitude]; + float *a = f->channel_buffers[map->chan[i].angle ]; + for (j=0; j < n2; ++j) { + float a2,m2; + if (m[j] > 0) + if (a[j] > 0) + m2 = m[j], a2 = m[j] - a[j]; + else + a2 = m[j], m2 = m[j] + a[j]; + else + if (a[j] > 0) + m2 = m[j], a2 = m[j] + a[j]; + else + a2 = m[j], m2 = m[j] - a[j]; + m[j] = m2; + a[j] = a2; + } + } + CHECK(f); + + // finish decoding the floors +#ifndef STB_VORBIS_NO_DEFER_FLOOR + for (i=0; i < f->channels; ++i) { + if (really_zero_channel[i]) { + memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); + } else { + do_floor(f, map, i, n, f->channel_buffers[i], f->finalY[i], NULL); + } + } +#else + for (i=0; i < f->channels; ++i) { + if (really_zero_channel[i]) { + memset(f->channel_buffers[i], 0, sizeof(*f->channel_buffers[i]) * n2); + } else { + for (j=0; j < n2; ++j) + f->channel_buffers[i][j] *= f->floor_buffers[i][j]; + } + } +#endif + +// INVERSE MDCT + CHECK(f); + for (i=0; i < f->channels; ++i) + inverse_mdct(f->channel_buffers[i], n, f, m->blockflag); + CHECK(f); + + // this shouldn't be necessary, unless we exited on an error + // and want to flush to get to the next packet + flush_packet(f); + + if (f->first_decode) { + // assume we start so first non-discarded sample is sample 0 + // this isn't to spec, but spec would require us to read ahead + // and decode the size of all current frames--could be done, + // but presumably it's not a commonly used feature + f->current_loc = 0u - n2; // start of first frame is positioned for discard (NB this is an intentional unsigned overflow/wrap-around) + // we might have to discard samples "from" the next frame too, + // if we're lapping a large block then a small at the start? + f->discard_samples_deferred = n - right_end; + f->current_loc_valid = TRUE; + f->first_decode = FALSE; + } else if (f->discard_samples_deferred) { + if (f->discard_samples_deferred >= right_start - left_start) { + f->discard_samples_deferred -= (right_start - left_start); + left_start = right_start; + *p_left = left_start; + } else { + left_start += f->discard_samples_deferred; + *p_left = left_start; + f->discard_samples_deferred = 0; + } + } else if (f->previous_length == 0 && f->current_loc_valid) { + // we're recovering from a seek... that means we're going to discard + // the samples from this packet even though we know our position from + // the last page header, so we need to update the position based on + // the discarded samples here + // but wait, the code below is going to add this in itself even + // on a discard, so we don't need to do it here... + } + + // check if we have ogg information about the sample # for this packet + if (f->last_seg_which == f->end_seg_with_known_loc) { + // if we have a valid current loc, and this is final: + if (f->current_loc_valid && (f->page_flag & PAGEFLAG_last_page)) { + uint32 current_end = f->known_loc_for_packet; + // then let's infer the size of the (probably) short final frame + if (current_end < f->current_loc + (right_end-left_start)) { + if (current_end < f->current_loc) { + // negative truncation, that's impossible! + *len = 0; + } else { + *len = current_end - f->current_loc; + } + *len += left_start; // this doesn't seem right, but has no ill effect on my test files + if (*len > right_end) *len = right_end; // this should never happen + f->current_loc += *len; + return TRUE; + } + } + // otherwise, just set our sample loc + // guess that the ogg granule pos refers to the _middle_ of the + // last frame? + // set f->current_loc to the position of left_start + f->current_loc = f->known_loc_for_packet - (n2-left_start); + f->current_loc_valid = TRUE; + } + if (f->current_loc_valid) + f->current_loc += (right_start - left_start); + + if (f->alloc.alloc_buffer) + assert(f->alloc.alloc_buffer_length_in_bytes == f->temp_offset); + *len = right_end; // ignore samples after the window goes to 0 + CHECK(f); + + return TRUE; +} + +static int vorbis_decode_packet(vorb *f, int *len, int *p_left, int *p_right) +{ + int mode, left_end, right_end; + if (!vorbis_decode_initial(f, p_left, &left_end, p_right, &right_end, &mode)) return 0; + return vorbis_decode_packet_rest(f, len, f->mode_config + mode, *p_left, left_end, *p_right, right_end, p_left); +} + +static int vorbis_finish_frame(stb_vorbis *f, int len, int left, int right) +{ + int prev,i,j; + // we use right&left (the start of the right- and left-window sin()-regions) + // to determine how much to return, rather than inferring from the rules + // (same result, clearer code); 'left' indicates where our sin() window + // starts, therefore where the previous window's right edge starts, and + // therefore where to start mixing from the previous buffer. 'right' + // indicates where our sin() ending-window starts, therefore that's where + // we start saving, and where our returned-data ends. + + // mixin from previous window + if (f->previous_length) { + int i,j, n = f->previous_length; + float *w = get_window(f, n); + if (w == NULL) return 0; + for (i=0; i < f->channels; ++i) { + for (j=0; j < n; ++j) + f->channel_buffers[i][left+j] = + f->channel_buffers[i][left+j]*w[ j] + + f->previous_window[i][ j]*w[n-1-j]; + } + } + + prev = f->previous_length; + + // last half of this data becomes previous window + f->previous_length = len - right; + + // @OPTIMIZE: could avoid this copy by double-buffering the + // output (flipping previous_window with channel_buffers), but + // then previous_window would have to be 2x as large, and + // channel_buffers couldn't be temp mem (although they're NOT + // currently temp mem, they could be (unless we want to level + // performance by spreading out the computation)) + for (i=0; i < f->channels; ++i) + for (j=0; right+j < len; ++j) + f->previous_window[i][j] = f->channel_buffers[i][right+j]; + + if (!prev) + // there was no previous packet, so this data isn't valid... + // this isn't entirely true, only the would-have-overlapped data + // isn't valid, but this seems to be what the spec requires + return 0; + + // truncate a short frame + if (len < right) right = len; + + f->samples_output += right-left; + + return right - left; +} + +static int vorbis_pump_first_frame(stb_vorbis *f) +{ + int len, right, left, res; + res = vorbis_decode_packet(f, &len, &left, &right); + if (res) + vorbis_finish_frame(f, len, left, right); + return res; +} + +#ifndef STB_VORBIS_NO_PUSHDATA_API +static int is_whole_packet_present(stb_vorbis *f) +{ + // make sure that we have the packet available before continuing... + // this requires a full ogg parse, but we know we can fetch from f->stream + + // instead of coding this out explicitly, we could save the current read state, + // read the next packet with get8() until end-of-packet, check f->eof, then + // reset the state? but that would be slower, esp. since we'd have over 256 bytes + // of state to restore (primarily the page segment table) + + int s = f->next_seg, first = TRUE; + uint8 *p = f->stream; + + if (s != -1) { // if we're not starting the packet with a 'continue on next page' flag + for (; s < f->segment_count; ++s) { + p += f->segments[s]; + if (f->segments[s] < 255) // stop at first short segment + break; + } + // either this continues, or it ends it... + if (s == f->segment_count) + s = -1; // set 'crosses page' flag + if (p > f->stream_end) return error(f, VORBIS_need_more_data); + first = FALSE; + } + for (; s == -1;) { + uint8 *q; + int n; + + // check that we have the page header ready + if (p + 26 >= f->stream_end) return error(f, VORBIS_need_more_data); + // validate the page + if (memcmp(p, ogg_page_header, 4)) return error(f, VORBIS_invalid_stream); + if (p[4] != 0) return error(f, VORBIS_invalid_stream); + if (first) { // the first segment must NOT have 'continued_packet', later ones MUST + if (f->previous_length) + if ((p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); + // if no previous length, we're resynching, so we can come in on a continued-packet, + // which we'll just drop + } else { + if (!(p[5] & PAGEFLAG_continued_packet)) return error(f, VORBIS_invalid_stream); + } + n = p[26]; // segment counts + q = p+27; // q points to segment table + p = q + n; // advance past header + // make sure we've read the segment table + if (p > f->stream_end) return error(f, VORBIS_need_more_data); + for (s=0; s < n; ++s) { + p += q[s]; + if (q[s] < 255) + break; + } + if (s == n) + s = -1; // set 'crosses page' flag + if (p > f->stream_end) return error(f, VORBIS_need_more_data); + first = FALSE; + } + return TRUE; +} +#endif // !STB_VORBIS_NO_PUSHDATA_API + +static int start_decoder(vorb *f) +{ + uint8 header[6], x,y; + int len,i,j,k, max_submaps = 0; + int longest_floorlist=0; + + // first page, first packet + f->first_decode = TRUE; + + if (!start_page(f)) return FALSE; + // validate page flag + if (!(f->page_flag & PAGEFLAG_first_page)) return error(f, VORBIS_invalid_first_page); + if (f->page_flag & PAGEFLAG_last_page) return error(f, VORBIS_invalid_first_page); + if (f->page_flag & PAGEFLAG_continued_packet) return error(f, VORBIS_invalid_first_page); + // check for expected packet length + if (f->segment_count != 1) return error(f, VORBIS_invalid_first_page); + if (f->segments[0] != 30) { + // check for the Ogg skeleton fishead identifying header to refine our error + if (f->segments[0] == 64 && + getn(f, header, 6) && + header[0] == 'f' && + header[1] == 'i' && + header[2] == 's' && + header[3] == 'h' && + header[4] == 'e' && + header[5] == 'a' && + get8(f) == 'd' && + get8(f) == '\0') return error(f, VORBIS_ogg_skeleton_not_supported); + else + return error(f, VORBIS_invalid_first_page); + } + + // read packet + // check packet header + if (get8(f) != VORBIS_packet_id) return error(f, VORBIS_invalid_first_page); + if (!getn(f, header, 6)) return error(f, VORBIS_unexpected_eof); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_first_page); + // vorbis_version + if (get32(f) != 0) return error(f, VORBIS_invalid_first_page); + f->channels = get8(f); if (!f->channels) return error(f, VORBIS_invalid_first_page); + if (f->channels > STB_VORBIS_MAX_CHANNELS) return error(f, VORBIS_too_many_channels); + f->sample_rate = get32(f); if (!f->sample_rate) return error(f, VORBIS_invalid_first_page); + get32(f); // bitrate_maximum + get32(f); // bitrate_nominal + get32(f); // bitrate_minimum + x = get8(f); + { + int log0,log1; + log0 = x & 15; + log1 = x >> 4; + f->blocksize_0 = 1 << log0; + f->blocksize_1 = 1 << log1; + if (log0 < 6 || log0 > 13) return error(f, VORBIS_invalid_setup); + if (log1 < 6 || log1 > 13) return error(f, VORBIS_invalid_setup); + if (log0 > log1) return error(f, VORBIS_invalid_setup); + } + + // framing_flag + x = get8(f); + if (!(x & 1)) return error(f, VORBIS_invalid_first_page); + + // second packet! + if (!start_page(f)) return FALSE; + + if (!start_packet(f)) return FALSE; + + if (!next_segment(f)) return FALSE; + + if (get8_packet(f) != VORBIS_packet_comment) return error(f, VORBIS_invalid_setup); + for (i=0; i < 6; ++i) header[i] = get8_packet(f); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); + //file vendor + len = get32_packet(f); + f->vendor = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->vendor == NULL) return error(f, VORBIS_outofmem); + for(i=0; i < len; ++i) { + f->vendor[i] = get8_packet(f); + } + f->vendor[len] = (char)'\0'; + //user comments + f->comment_list_length = get32_packet(f); + f->comment_list = NULL; + if (f->comment_list_length > 0) + { + f->comment_list = (char**) setup_malloc(f, sizeof(char*) * (f->comment_list_length)); + if (f->comment_list == NULL) return error(f, VORBIS_outofmem); + } + + for(i=0; i < f->comment_list_length; ++i) { + len = get32_packet(f); + f->comment_list[i] = (char*)setup_malloc(f, sizeof(char) * (len+1)); + if (f->comment_list[i] == NULL) return error(f, VORBIS_outofmem); + + for(j=0; j < len; ++j) { + f->comment_list[i][j] = get8_packet(f); + } + f->comment_list[i][len] = (char)'\0'; + } + + // framing_flag + x = get8_packet(f); + if (!(x & 1)) return error(f, VORBIS_invalid_setup); + + + skip(f, f->bytes_in_seg); + f->bytes_in_seg = 0; + + do { + len = next_segment(f); + skip(f, len); + f->bytes_in_seg = 0; + } while (len); + + // third packet! + if (!start_packet(f)) return FALSE; + + #ifndef STB_VORBIS_NO_PUSHDATA_API + if (IS_PUSH_MODE(f)) { + if (!is_whole_packet_present(f)) { + // convert error in ogg header to write type + if (f->error == VORBIS_invalid_stream) + f->error = VORBIS_invalid_setup; + return FALSE; + } + } + #endif + + crc32_init(); // always init it, to avoid multithread race conditions + + if (get8_packet(f) != VORBIS_packet_setup) return error(f, VORBIS_invalid_setup); + for (i=0; i < 6; ++i) header[i] = get8_packet(f); + if (!vorbis_validate(header)) return error(f, VORBIS_invalid_setup); + + // codebooks + + f->codebook_count = get_bits(f,8) + 1; + f->codebooks = (Codebook *) setup_malloc(f, sizeof(*f->codebooks) * f->codebook_count); + if (f->codebooks == NULL) return error(f, VORBIS_outofmem); + memset(f->codebooks, 0, sizeof(*f->codebooks) * f->codebook_count); + for (i=0; i < f->codebook_count; ++i) { + uint32 *values; + int ordered, sorted_count; + int total=0; + uint8 *lengths; + Codebook *c = f->codebooks+i; + CHECK(f); + x = get_bits(f, 8); if (x != 0x42) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); if (x != 0x43) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); if (x != 0x56) return error(f, VORBIS_invalid_setup); + x = get_bits(f, 8); + c->dimensions = (get_bits(f, 8)<<8) + x; + x = get_bits(f, 8); + y = get_bits(f, 8); + c->entries = (get_bits(f, 8)<<16) + (y<<8) + x; + ordered = get_bits(f,1); + c->sparse = ordered ? 0 : get_bits(f,1); + + if (c->dimensions == 0 && c->entries != 0) return error(f, VORBIS_invalid_setup); + + if (c->sparse) + lengths = (uint8 *) setup_temp_malloc(f, c->entries); + else + lengths = c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); + + if (!lengths) return error(f, VORBIS_outofmem); + + if (ordered) { + int current_entry = 0; + int current_length = get_bits(f,5) + 1; + while (current_entry < c->entries) { + int limit = c->entries - current_entry; + int n = get_bits(f, ilog(limit)); + if (current_length >= 32) return error(f, VORBIS_invalid_setup); + if (current_entry + n > (int) c->entries) { return error(f, VORBIS_invalid_setup); } + memset(lengths + current_entry, current_length, n); + current_entry += n; + ++current_length; + } + } else { + for (j=0; j < c->entries; ++j) { + int present = c->sparse ? get_bits(f,1) : 1; + if (present) { + lengths[j] = get_bits(f, 5) + 1; + ++total; + if (lengths[j] == 32) + return error(f, VORBIS_invalid_setup); + } else { + lengths[j] = NO_CODE; + } + } + } + + if (c->sparse && total >= c->entries >> 2) { + // convert sparse items to non-sparse! + if (c->entries > (int) f->setup_temp_memory_required) + f->setup_temp_memory_required = c->entries; + + c->codeword_lengths = (uint8 *) setup_malloc(f, c->entries); + if (c->codeword_lengths == NULL) return error(f, VORBIS_outofmem); + memcpy(c->codeword_lengths, lengths, c->entries); + setup_temp_free(f, lengths, c->entries); // note this is only safe if there have been no intervening temp mallocs! + lengths = c->codeword_lengths; + c->sparse = 0; + } + + // compute the size of the sorted tables + if (c->sparse) { + sorted_count = total; + } else { + sorted_count = 0; + #ifndef STB_VORBIS_NO_HUFFMAN_BINARY_SEARCH + for (j=0; j < c->entries; ++j) + if (lengths[j] > STB_VORBIS_FAST_HUFFMAN_LENGTH && lengths[j] != NO_CODE) + ++sorted_count; + #endif + } + + c->sorted_entries = sorted_count; + values = NULL; + + CHECK(f); + if (!c->sparse) { + c->codewords = (uint32 *) setup_malloc(f, sizeof(c->codewords[0]) * c->entries); + if (!c->codewords) return error(f, VORBIS_outofmem); + } else { + unsigned int size; + if (c->sorted_entries) { + c->codeword_lengths = (uint8 *) setup_malloc(f, c->sorted_entries); + if (!c->codeword_lengths) return error(f, VORBIS_outofmem); + c->codewords = (uint32 *) setup_temp_malloc(f, sizeof(*c->codewords) * c->sorted_entries); + if (!c->codewords) return error(f, VORBIS_outofmem); + values = (uint32 *) setup_temp_malloc(f, sizeof(*values) * c->sorted_entries); + if (!values) return error(f, VORBIS_outofmem); + } + size = c->entries + (sizeof(*c->codewords) + sizeof(*values)) * c->sorted_entries; + if (size > f->setup_temp_memory_required) + f->setup_temp_memory_required = size; + } + + if (!compute_codewords(c, lengths, c->entries, values)) { + if (c->sparse) setup_temp_free(f, values, 0); + return error(f, VORBIS_invalid_setup); + } + + if (c->sorted_entries) { + // allocate an extra slot for sentinels + c->sorted_codewords = (uint32 *) setup_malloc(f, sizeof(*c->sorted_codewords) * (c->sorted_entries+1)); + if (c->sorted_codewords == NULL) return error(f, VORBIS_outofmem); + // allocate an extra slot at the front so that c->sorted_values[-1] is defined + // so that we can catch that case without an extra if + c->sorted_values = ( int *) setup_malloc(f, sizeof(*c->sorted_values ) * (c->sorted_entries+1)); + if (c->sorted_values == NULL) return error(f, VORBIS_outofmem); + ++c->sorted_values; + c->sorted_values[-1] = -1; + compute_sorted_huffman(c, lengths, values); + } + + if (c->sparse) { + setup_temp_free(f, values, sizeof(*values)*c->sorted_entries); + setup_temp_free(f, c->codewords, sizeof(*c->codewords)*c->sorted_entries); + setup_temp_free(f, lengths, c->entries); + c->codewords = NULL; + } + + compute_accelerated_huffman(c); + + CHECK(f); + c->lookup_type = get_bits(f, 4); + if (c->lookup_type > 2) return error(f, VORBIS_invalid_setup); + if (c->lookup_type > 0) { + uint16 *mults; + c->minimum_value = float32_unpack(get_bits(f, 32)); + c->delta_value = float32_unpack(get_bits(f, 32)); + c->value_bits = get_bits(f, 4)+1; + c->sequence_p = get_bits(f,1); + if (c->lookup_type == 1) { + int values = lookup1_values(c->entries, c->dimensions); + if (values < 0) return error(f, VORBIS_invalid_setup); + c->lookup_values = (uint32) values; + } else { + c->lookup_values = c->entries * c->dimensions; + } + if (c->lookup_values == 0) return error(f, VORBIS_invalid_setup); + mults = (uint16 *) setup_temp_malloc(f, sizeof(mults[0]) * c->lookup_values); + if (mults == NULL) return error(f, VORBIS_outofmem); + for (j=0; j < (int) c->lookup_values; ++j) { + int q = get_bits(f, c->value_bits); + if (q == EOP) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_invalid_setup); } + mults[j] = q; + } + +#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK + if (c->lookup_type == 1) { + int len, sparse = c->sparse; + float last=0; + // pre-expand the lookup1-style multiplicands, to avoid a divide in the inner loop + if (sparse) { + if (c->sorted_entries == 0) goto skip; + c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->sorted_entries * c->dimensions); + } else + c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->entries * c->dimensions); + if (c->multiplicands == NULL) { setup_temp_free(f,mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } + len = sparse ? c->sorted_entries : c->entries; + for (j=0; j < len; ++j) { + unsigned int z = sparse ? c->sorted_values[j] : j; + unsigned int div=1; + for (k=0; k < c->dimensions; ++k) { + int off = (z / div) % c->lookup_values; + float val = mults[off]*c->delta_value + c->minimum_value + last; + c->multiplicands[j*c->dimensions + k] = val; + if (c->sequence_p) + last = val; + if (k+1 < c->dimensions) { + if (div > UINT_MAX / (unsigned int) c->lookup_values) { + setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); + return error(f, VORBIS_invalid_setup); + } + div *= c->lookup_values; + } + } + } + c->lookup_type = 2; + } + else +#endif + { + float last=0; + CHECK(f); + c->multiplicands = (codetype *) setup_malloc(f, sizeof(c->multiplicands[0]) * c->lookup_values); + if (c->multiplicands == NULL) { setup_temp_free(f, mults,sizeof(mults[0])*c->lookup_values); return error(f, VORBIS_outofmem); } + for (j=0; j < (int) c->lookup_values; ++j) { + float val = mults[j] * c->delta_value + c->minimum_value + last; + c->multiplicands[j] = val; + if (c->sequence_p) + last = val; + } + } +#ifndef STB_VORBIS_DIVIDES_IN_CODEBOOK + skip:; +#endif + setup_temp_free(f, mults, sizeof(mults[0])*c->lookup_values); + + CHECK(f); + } + CHECK(f); + } + + // time domain transfers (notused) + + x = get_bits(f, 6) + 1; + for (i=0; i < x; ++i) { + uint32 z = get_bits(f, 16); + if (z != 0) return error(f, VORBIS_invalid_setup); + } + + // Floors + f->floor_count = get_bits(f, 6)+1; + f->floor_config = (Floor *) setup_malloc(f, f->floor_count * sizeof(*f->floor_config)); + if (f->floor_config == NULL) return error(f, VORBIS_outofmem); + for (i=0; i < f->floor_count; ++i) { + f->floor_types[i] = get_bits(f, 16); + if (f->floor_types[i] > 1) return error(f, VORBIS_invalid_setup); + if (f->floor_types[i] == 0) { + Floor0 *g = &f->floor_config[i].floor0; + g->order = get_bits(f,8); + g->rate = get_bits(f,16); + g->bark_map_size = get_bits(f,16); + g->amplitude_bits = get_bits(f,6); + g->amplitude_offset = get_bits(f,8); + g->number_of_books = get_bits(f,4) + 1; + for (j=0; j < g->number_of_books; ++j) + g->book_list[j] = get_bits(f,8); + return error(f, VORBIS_feature_not_supported); + } else { + stbv__floor_ordering p[31*8+2]; + Floor1 *g = &f->floor_config[i].floor1; + int max_class = -1; + g->partitions = get_bits(f, 5); + for (j=0; j < g->partitions; ++j) { + g->partition_class_list[j] = get_bits(f, 4); + if (g->partition_class_list[j] > max_class) + max_class = g->partition_class_list[j]; + } + for (j=0; j <= max_class; ++j) { + g->class_dimensions[j] = get_bits(f, 3)+1; + g->class_subclasses[j] = get_bits(f, 2); + if (g->class_subclasses[j]) { + g->class_masterbooks[j] = get_bits(f, 8); + if (g->class_masterbooks[j] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + } + for (k=0; k < 1 << g->class_subclasses[j]; ++k) { + g->subclass_books[j][k] = (int16)get_bits(f,8)-1; + if (g->subclass_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + } + } + g->floor1_multiplier = get_bits(f,2)+1; + g->rangebits = get_bits(f,4); + g->Xlist[0] = 0; + g->Xlist[1] = 1 << g->rangebits; + g->values = 2; + for (j=0; j < g->partitions; ++j) { + int c = g->partition_class_list[j]; + for (k=0; k < g->class_dimensions[c]; ++k) { + g->Xlist[g->values] = get_bits(f, g->rangebits); + ++g->values; + } + } + // precompute the sorting + for (j=0; j < g->values; ++j) { + p[j].x = g->Xlist[j]; + p[j].id = j; + } + qsort(p, g->values, sizeof(p[0]), point_compare); + for (j=0; j < g->values-1; ++j) + if (p[j].x == p[j+1].x) + return error(f, VORBIS_invalid_setup); + for (j=0; j < g->values; ++j) + g->sorted_order[j] = (uint8) p[j].id; + // precompute the neighbors + for (j=2; j < g->values; ++j) { + int low = 0,hi = 0; + neighbors(g->Xlist, j, &low,&hi); + g->neighbors[j][0] = low; + g->neighbors[j][1] = hi; + } + + if (g->values > longest_floorlist) + longest_floorlist = g->values; + } + } + + // Residue + f->residue_count = get_bits(f, 6)+1; + f->residue_config = (Residue *) setup_malloc(f, f->residue_count * sizeof(f->residue_config[0])); + if (f->residue_config == NULL) return error(f, VORBIS_outofmem); + memset(f->residue_config, 0, f->residue_count * sizeof(f->residue_config[0])); + for (i=0; i < f->residue_count; ++i) { + uint8 residue_cascade[64]; + Residue *r = f->residue_config+i; + f->residue_types[i] = get_bits(f, 16); + if (f->residue_types[i] > 2) return error(f, VORBIS_invalid_setup); + r->begin = get_bits(f, 24); + r->end = get_bits(f, 24); + if (r->end < r->begin) return error(f, VORBIS_invalid_setup); + r->part_size = get_bits(f,24)+1; + r->classifications = get_bits(f,6)+1; + r->classbook = get_bits(f,8); + if (r->classbook >= f->codebook_count) return error(f, VORBIS_invalid_setup); + for (j=0; j < r->classifications; ++j) { + uint8 high_bits=0; + uint8 low_bits=get_bits(f,3); + if (get_bits(f,1)) + high_bits = get_bits(f,5); + residue_cascade[j] = high_bits*8 + low_bits; + } + r->residue_books = (short (*)[8]) setup_malloc(f, sizeof(r->residue_books[0]) * r->classifications); + if (r->residue_books == NULL) return error(f, VORBIS_outofmem); + for (j=0; j < r->classifications; ++j) { + for (k=0; k < 8; ++k) { + if (residue_cascade[j] & (1 << k)) { + r->residue_books[j][k] = get_bits(f, 8); + if (r->residue_books[j][k] >= f->codebook_count) return error(f, VORBIS_invalid_setup); + } else { + r->residue_books[j][k] = -1; + } + } + } + // precompute the classifications[] array to avoid inner-loop mod/divide + // call it 'classdata' since we already have r->classifications + r->classdata = (uint8 **) setup_malloc(f, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); + if (!r->classdata) return error(f, VORBIS_outofmem); + memset(r->classdata, 0, sizeof(*r->classdata) * f->codebooks[r->classbook].entries); + for (j=0; j < f->codebooks[r->classbook].entries; ++j) { + int classwords = f->codebooks[r->classbook].dimensions; + int temp = j; + r->classdata[j] = (uint8 *) setup_malloc(f, sizeof(r->classdata[j][0]) * classwords); + if (r->classdata[j] == NULL) return error(f, VORBIS_outofmem); + for (k=classwords-1; k >= 0; --k) { + r->classdata[j][k] = temp % r->classifications; + temp /= r->classifications; + } + } + } + + f->mapping_count = get_bits(f,6)+1; + f->mapping = (Mapping *) setup_malloc(f, f->mapping_count * sizeof(*f->mapping)); + if (f->mapping == NULL) return error(f, VORBIS_outofmem); + memset(f->mapping, 0, f->mapping_count * sizeof(*f->mapping)); + for (i=0; i < f->mapping_count; ++i) { + Mapping *m = f->mapping + i; + int mapping_type = get_bits(f,16); + if (mapping_type != 0) return error(f, VORBIS_invalid_setup); + m->chan = (MappingChannel *) setup_malloc(f, f->channels * sizeof(*m->chan)); + if (m->chan == NULL) return error(f, VORBIS_outofmem); + if (get_bits(f,1)) + m->submaps = get_bits(f,4)+1; + else + m->submaps = 1; + if (m->submaps > max_submaps) + max_submaps = m->submaps; + if (get_bits(f,1)) { + m->coupling_steps = get_bits(f,8)+1; + if (m->coupling_steps > f->channels) return error(f, VORBIS_invalid_setup); + for (k=0; k < m->coupling_steps; ++k) { + m->chan[k].magnitude = get_bits(f, ilog(f->channels-1)); + m->chan[k].angle = get_bits(f, ilog(f->channels-1)); + if (m->chan[k].magnitude >= f->channels) return error(f, VORBIS_invalid_setup); + if (m->chan[k].angle >= f->channels) return error(f, VORBIS_invalid_setup); + if (m->chan[k].magnitude == m->chan[k].angle) return error(f, VORBIS_invalid_setup); + } + } else + m->coupling_steps = 0; + + // reserved field + if (get_bits(f,2)) return error(f, VORBIS_invalid_setup); + if (m->submaps > 1) { + for (j=0; j < f->channels; ++j) { + m->chan[j].mux = get_bits(f, 4); + if (m->chan[j].mux >= m->submaps) return error(f, VORBIS_invalid_setup); + } + } else + // @SPECIFICATION: this case is missing from the spec + for (j=0; j < f->channels; ++j) + m->chan[j].mux = 0; + + for (j=0; j < m->submaps; ++j) { + get_bits(f,8); // discard + m->submap_floor[j] = get_bits(f,8); + m->submap_residue[j] = get_bits(f,8); + if (m->submap_floor[j] >= f->floor_count) return error(f, VORBIS_invalid_setup); + if (m->submap_residue[j] >= f->residue_count) return error(f, VORBIS_invalid_setup); + } + } + + // Modes + f->mode_count = get_bits(f, 6)+1; + for (i=0; i < f->mode_count; ++i) { + Mode *m = f->mode_config+i; + m->blockflag = get_bits(f,1); + m->windowtype = get_bits(f,16); + m->transformtype = get_bits(f,16); + m->mapping = get_bits(f,8); + if (m->windowtype != 0) return error(f, VORBIS_invalid_setup); + if (m->transformtype != 0) return error(f, VORBIS_invalid_setup); + if (m->mapping >= f->mapping_count) return error(f, VORBIS_invalid_setup); + } + + flush_packet(f); + + f->previous_length = 0; + + for (i=0; i < f->channels; ++i) { + f->channel_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1); + f->previous_window[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); + f->finalY[i] = (int16 *) setup_malloc(f, sizeof(int16) * longest_floorlist); + if (f->channel_buffers[i] == NULL || f->previous_window[i] == NULL || f->finalY[i] == NULL) return error(f, VORBIS_outofmem); + memset(f->channel_buffers[i], 0, sizeof(float) * f->blocksize_1); + #ifdef STB_VORBIS_NO_DEFER_FLOOR + f->floor_buffers[i] = (float *) setup_malloc(f, sizeof(float) * f->blocksize_1/2); + if (f->floor_buffers[i] == NULL) return error(f, VORBIS_outofmem); + #endif + } + + if (!init_blocksize(f, 0, f->blocksize_0)) return FALSE; + if (!init_blocksize(f, 1, f->blocksize_1)) return FALSE; + f->blocksize[0] = f->blocksize_0; + f->blocksize[1] = f->blocksize_1; + +#ifdef STB_VORBIS_DIVIDE_TABLE + if (integer_divide_table[1][1]==0) + for (i=0; i < DIVTAB_NUMER; ++i) + for (j=1; j < DIVTAB_DENOM; ++j) + integer_divide_table[i][j] = i / j; +#endif + + // compute how much temporary memory is needed + + // 1. + { + uint32 imdct_mem = (f->blocksize_1 * sizeof(float) >> 1); + uint32 classify_mem; + int i,max_part_read=0; + for (i=0; i < f->residue_count; ++i) { + Residue *r = f->residue_config + i; + unsigned int actual_size = f->blocksize_1 / 2; + unsigned int limit_r_begin = r->begin < actual_size ? r->begin : actual_size; + unsigned int limit_r_end = r->end < actual_size ? r->end : actual_size; + int n_read = limit_r_end - limit_r_begin; + int part_read = n_read / r->part_size; + if (part_read > max_part_read) + max_part_read = part_read; + } + #ifndef STB_VORBIS_DIVIDES_IN_RESIDUE + classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(uint8 *)); + #else + classify_mem = f->channels * (sizeof(void*) + max_part_read * sizeof(int *)); + #endif + + // maximum reasonable partition size is f->blocksize_1 + + f->temp_memory_required = classify_mem; + if (imdct_mem > f->temp_memory_required) + f->temp_memory_required = imdct_mem; + } + + + if (f->alloc.alloc_buffer) { + assert(f->temp_offset == f->alloc.alloc_buffer_length_in_bytes); + // check if there's enough temp memory so we don't error later + if (f->setup_offset + sizeof(*f) + f->temp_memory_required > (unsigned) f->temp_offset) + return error(f, VORBIS_outofmem); + } + + // @TODO: stb_vorbis_seek_start expects first_audio_page_offset to point to a page + // without PAGEFLAG_continued_packet, so this either points to the first page, or + // the page after the end of the headers. It might be cleaner to point to a page + // in the middle of the headers, when that's the page where the first audio packet + // starts, but we'd have to also correctly skip the end of any continued packet in + // stb_vorbis_seek_start. + if (f->next_seg == -1) { + f->first_audio_page_offset = stb_vorbis_get_file_offset(f); + } else { + f->first_audio_page_offset = 0; + } + + return TRUE; +} + +static void vorbis_deinit(stb_vorbis *p) +{ + int i,j; + + setup_free(p, p->vendor); + for (i=0; i < p->comment_list_length; ++i) { + setup_free(p, p->comment_list[i]); + } + setup_free(p, p->comment_list); + + if (p->residue_config) { + for (i=0; i < p->residue_count; ++i) { + Residue *r = p->residue_config+i; + if (r->classdata) { + for (j=0; j < p->codebooks[r->classbook].entries; ++j) + setup_free(p, r->classdata[j]); + setup_free(p, r->classdata); + } + setup_free(p, r->residue_books); + } + } + + if (p->codebooks) { + CHECK(p); + for (i=0; i < p->codebook_count; ++i) { + Codebook *c = p->codebooks + i; + setup_free(p, c->codeword_lengths); + setup_free(p, c->multiplicands); + setup_free(p, c->codewords); + setup_free(p, c->sorted_codewords); + // c->sorted_values[-1] is the first entry in the array + setup_free(p, c->sorted_values ? c->sorted_values-1 : NULL); + } + setup_free(p, p->codebooks); + } + setup_free(p, p->floor_config); + setup_free(p, p->residue_config); + if (p->mapping) { + for (i=0; i < p->mapping_count; ++i) + setup_free(p, p->mapping[i].chan); + setup_free(p, p->mapping); + } + CHECK(p); + for (i=0; i < p->channels && i < STB_VORBIS_MAX_CHANNELS; ++i) { + setup_free(p, p->channel_buffers[i]); + setup_free(p, p->previous_window[i]); + #ifdef STB_VORBIS_NO_DEFER_FLOOR + setup_free(p, p->floor_buffers[i]); + #endif + setup_free(p, p->finalY[i]); + } + for (i=0; i < 2; ++i) { + setup_free(p, p->A[i]); + setup_free(p, p->B[i]); + setup_free(p, p->C[i]); + setup_free(p, p->window[i]); + setup_free(p, p->bit_reverse[i]); + } + #ifndef STB_VORBIS_NO_STDIO + if (p->close_on_free) fclose(p->f); + #endif +} + +void stb_vorbis_close(stb_vorbis *p) +{ + if (p == NULL) return; + vorbis_deinit(p); + setup_free(p,p); +} + +static void vorbis_init(stb_vorbis *p, const stb_vorbis_alloc *z) +{ + memset(p, 0, sizeof(*p)); // NULL out all malloc'd pointers to start + if (z) { + p->alloc = *z; + p->alloc.alloc_buffer_length_in_bytes &= ~7; + p->temp_offset = p->alloc.alloc_buffer_length_in_bytes; + } + p->eof = 0; + p->error = VORBIS__no_error; + p->stream = NULL; + p->codebooks = NULL; + p->page_crc_tests = -1; + #ifndef STB_VORBIS_NO_STDIO + p->close_on_free = FALSE; + p->f = NULL; + #endif +} + +int stb_vorbis_get_sample_offset(stb_vorbis *f) +{ + if (f->current_loc_valid) + return f->current_loc; + else + return -1; +} + +stb_vorbis_info stb_vorbis_get_info(stb_vorbis *f) +{ + stb_vorbis_info d; + d.channels = f->channels; + d.sample_rate = f->sample_rate; + d.setup_memory_required = f->setup_memory_required; + d.setup_temp_memory_required = f->setup_temp_memory_required; + d.temp_memory_required = f->temp_memory_required; + d.max_frame_size = f->blocksize_1 >> 1; + return d; +} + +stb_vorbis_comment stb_vorbis_get_comment(stb_vorbis *f) +{ + stb_vorbis_comment d; + d.vendor = f->vendor; + d.comment_list_length = f->comment_list_length; + d.comment_list = f->comment_list; + return d; +} + +int stb_vorbis_get_error(stb_vorbis *f) +{ + int e = f->error; + f->error = VORBIS__no_error; + return e; +} + +static stb_vorbis * vorbis_alloc(stb_vorbis *f) +{ + stb_vorbis *p = (stb_vorbis *) setup_malloc(f, sizeof(*p)); + return p; +} + +#ifndef STB_VORBIS_NO_PUSHDATA_API + +void stb_vorbis_flush_pushdata(stb_vorbis *f) +{ + f->previous_length = 0; + f->page_crc_tests = 0; + f->discard_samples_deferred = 0; + f->current_loc_valid = FALSE; + f->first_decode = FALSE; + f->samples_output = 0; + f->channel_buffer_start = 0; + f->channel_buffer_end = 0; +} + +static int vorbis_search_for_page_pushdata(vorb *f, uint8 *data, int data_len) +{ + int i,n; + for (i=0; i < f->page_crc_tests; ++i) + f->scan[i].bytes_done = 0; + + // if we have room for more scans, search for them first, because + // they may cause us to stop early if their header is incomplete + if (f->page_crc_tests < STB_VORBIS_PUSHDATA_CRC_COUNT) { + if (data_len < 4) return 0; + data_len -= 3; // need to look for 4-byte sequence, so don't miss + // one that straddles a boundary + for (i=0; i < data_len; ++i) { + if (data[i] == 0x4f) { + if (0==memcmp(data+i, ogg_page_header, 4)) { + int j,len; + uint32 crc; + // make sure we have the whole page header + if (i+26 >= data_len || i+27+data[i+26] >= data_len) { + // only read up to this page start, so hopefully we'll + // have the whole page header start next time + data_len = i; + break; + } + // ok, we have it all; compute the length of the page + len = 27 + data[i+26]; + for (j=0; j < data[i+26]; ++j) + len += data[i+27+j]; + // scan everything up to the embedded crc (which we must 0) + crc = 0; + for (j=0; j < 22; ++j) + crc = crc32_update(crc, data[i+j]); + // now process 4 0-bytes + for ( ; j < 26; ++j) + crc = crc32_update(crc, 0); + // len is the total number of bytes we need to scan + n = f->page_crc_tests++; + f->scan[n].bytes_left = len-j; + f->scan[n].crc_so_far = crc; + f->scan[n].goal_crc = data[i+22] + (data[i+23] << 8) + (data[i+24]<<16) + (data[i+25]<<24); + // if the last frame on a page is continued to the next, then + // we can't recover the sample_loc immediately + if (data[i+27+data[i+26]-1] == 255) + f->scan[n].sample_loc = ~0; + else + f->scan[n].sample_loc = data[i+6] + (data[i+7] << 8) + (data[i+ 8]<<16) + (data[i+ 9]<<24); + f->scan[n].bytes_done = i+j; + if (f->page_crc_tests == STB_VORBIS_PUSHDATA_CRC_COUNT) + break; + // keep going if we still have room for more + } + } + } + } + + for (i=0; i < f->page_crc_tests;) { + uint32 crc; + int j; + int n = f->scan[i].bytes_done; + int m = f->scan[i].bytes_left; + if (m > data_len - n) m = data_len - n; + // m is the bytes to scan in the current chunk + crc = f->scan[i].crc_so_far; + for (j=0; j < m; ++j) + crc = crc32_update(crc, data[n+j]); + f->scan[i].bytes_left -= m; + f->scan[i].crc_so_far = crc; + if (f->scan[i].bytes_left == 0) { + // does it match? + if (f->scan[i].crc_so_far == f->scan[i].goal_crc) { + // Houston, we have page + data_len = n+m; // consumption amount is wherever that scan ended + f->page_crc_tests = -1; // drop out of page scan mode + f->previous_length = 0; // decode-but-don't-output one frame + f->next_seg = -1; // start a new page + f->current_loc = f->scan[i].sample_loc; // set the current sample location + // to the amount we'd have decoded had we decoded this page + f->current_loc_valid = f->current_loc != ~0U; + return data_len; + } + // delete entry + f->scan[i] = f->scan[--f->page_crc_tests]; + } else { + ++i; + } + } + + return data_len; +} + +// return value: number of bytes we used +int stb_vorbis_decode_frame_pushdata( + stb_vorbis *f, // the file we're decoding + const uint8 *data, int data_len, // the memory available for decoding + int *channels, // place to write number of float * buffers + float ***output, // place to write float ** array of float * buffers + int *samples // place to write number of output samples + ) +{ + int i; + int len,right,left; + + if (!IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + + if (f->page_crc_tests >= 0) { + *samples = 0; + return vorbis_search_for_page_pushdata(f, (uint8 *) data, data_len); + } + + f->stream = (uint8 *) data; + f->stream_end = (uint8 *) data + data_len; + f->error = VORBIS__no_error; + + // check that we have the entire packet in memory + if (!is_whole_packet_present(f)) { + *samples = 0; + return 0; + } + + if (!vorbis_decode_packet(f, &len, &left, &right)) { + // save the actual error we encountered + enum STBVorbisError error = f->error; + if (error == VORBIS_bad_packet_type) { + // flush and resynch + f->error = VORBIS__no_error; + while (get8_packet(f) != EOP) + if (f->eof) break; + *samples = 0; + return (int) (f->stream - data); + } + if (error == VORBIS_continued_packet_flag_invalid) { + if (f->previous_length == 0) { + // we may be resynching, in which case it's ok to hit one + // of these; just discard the packet + f->error = VORBIS__no_error; + while (get8_packet(f) != EOP) + if (f->eof) break; + *samples = 0; + return (int) (f->stream - data); + } + } + // if we get an error while parsing, what to do? + // well, it DEFINITELY won't work to continue from where we are! + stb_vorbis_flush_pushdata(f); + // restore the error that actually made us bail + f->error = error; + *samples = 0; + return 1; + } + + // success! + len = vorbis_finish_frame(f, len, left, right); + for (i=0; i < f->channels; ++i) + f->outputs[i] = f->channel_buffers[i] + left; + + if (channels) *channels = f->channels; + *samples = len; + *output = f->outputs; + return (int) (f->stream - data); +} + +stb_vorbis *stb_vorbis_open_pushdata( + const unsigned char *data, int data_len, // the memory available for decoding + int *data_used, // only defined if result is not NULL + int *error, const stb_vorbis_alloc *alloc) +{ + stb_vorbis *f, p; + vorbis_init(&p, alloc); + p.stream = (uint8 *) data; + p.stream_end = (uint8 *) data + data_len; + p.push_mode = TRUE; + if (!start_decoder(&p)) { + if (p.eof) + *error = VORBIS_need_more_data; + else + *error = p.error; + vorbis_deinit(&p); + return NULL; + } + f = vorbis_alloc(&p); + if (f) { + *f = p; + *data_used = (int) (f->stream - data); + *error = 0; + return f; + } else { + vorbis_deinit(&p); + return NULL; + } +} +#endif // STB_VORBIS_NO_PUSHDATA_API + +unsigned int stb_vorbis_get_file_offset(stb_vorbis *f) +{ + #ifndef STB_VORBIS_NO_PUSHDATA_API + if (f->push_mode) return 0; + #endif + if (USE_MEMORY(f)) return (unsigned int) (f->stream - f->stream_start); + #ifndef STB_VORBIS_NO_STDIO + return (unsigned int) (ftell(f->f) - f->f_start); + #endif +} + +#ifndef STB_VORBIS_NO_PULLDATA_API +// +// DATA-PULLING API +// + +static uint32 vorbis_find_page(stb_vorbis *f, uint32 *end, uint32 *last) +{ + for(;;) { + int n; + if (f->eof) return 0; + n = get8(f); + if (n == 0x4f) { // page header candidate + unsigned int retry_loc = stb_vorbis_get_file_offset(f); + int i; + // check if we're off the end of a file_section stream + if (retry_loc - 25 > f->stream_len) + return 0; + // check the rest of the header + for (i=1; i < 4; ++i) + if (get8(f) != ogg_page_header[i]) + break; + if (f->eof) return 0; + if (i == 4) { + uint8 header[27]; + uint32 i, crc, goal, len; + for (i=0; i < 4; ++i) + header[i] = ogg_page_header[i]; + for (; i < 27; ++i) + header[i] = get8(f); + if (f->eof) return 0; + if (header[4] != 0) goto invalid; + goal = header[22] + (header[23] << 8) + (header[24]<<16) + ((uint32)header[25]<<24); + for (i=22; i < 26; ++i) + header[i] = 0; + crc = 0; + for (i=0; i < 27; ++i) + crc = crc32_update(crc, header[i]); + len = 0; + for (i=0; i < header[26]; ++i) { + int s = get8(f); + crc = crc32_update(crc, s); + len += s; + } + if (len && f->eof) return 0; + for (i=0; i < len; ++i) + crc = crc32_update(crc, get8(f)); + // finished parsing probable page + if (crc == goal) { + // we could now check that it's either got the last + // page flag set, OR it's followed by the capture + // pattern, but I guess TECHNICALLY you could have + // a file with garbage between each ogg page and recover + // from it automatically? So even though that paranoia + // might decrease the chance of an invalid decode by + // another 2^32, not worth it since it would hose those + // invalid-but-useful files? + if (end) + *end = stb_vorbis_get_file_offset(f); + if (last) { + if (header[5] & 0x04) + *last = 1; + else + *last = 0; + } + set_file_offset(f, retry_loc-1); + return 1; + } + } + invalid: + // not a valid page, so rewind and look for next one + set_file_offset(f, retry_loc); + } + } +} + + +#define SAMPLE_unknown 0xffffffff + +// seeking is implemented with a binary search, which narrows down the range to +// 64K, before using a linear search (because finding the synchronization +// pattern can be expensive, and the chance we'd find the end page again is +// relatively high for small ranges) +// +// two initial interpolation-style probes are used at the start of the search +// to try to bound either side of the binary search sensibly, while still +// working in O(log n) time if they fail. + +static int get_seek_page_info(stb_vorbis *f, ProbedPage *z) +{ + uint8 header[27], lacing[255]; + int i,len; + + // record where the page starts + z->page_start = stb_vorbis_get_file_offset(f); + + // parse the header + getn(f, header, 27); + if (header[0] != 'O' || header[1] != 'g' || header[2] != 'g' || header[3] != 'S') + return 0; + getn(f, lacing, header[26]); + + // determine the length of the payload + len = 0; + for (i=0; i < header[26]; ++i) + len += lacing[i]; + + // this implies where the page ends + z->page_end = z->page_start + 27 + header[26] + len; + + // read the last-decoded sample out of the data + z->last_decoded_sample = header[6] + (header[7] << 8) + (header[8] << 16) + (header[9] << 24); + + // restore file state to where we were + set_file_offset(f, z->page_start); + return 1; +} + +// rarely used function to seek back to the preceding page while finding the +// start of a packet +static int go_to_page_before(stb_vorbis *f, unsigned int limit_offset) +{ + unsigned int previous_safe, end; + + // now we want to seek back 64K from the limit + if (limit_offset >= 65536 && limit_offset-65536 >= f->first_audio_page_offset) + previous_safe = limit_offset - 65536; + else + previous_safe = f->first_audio_page_offset; + + set_file_offset(f, previous_safe); + + while (vorbis_find_page(f, &end, NULL)) { + if (end >= limit_offset && stb_vorbis_get_file_offset(f) < limit_offset) + return 1; + set_file_offset(f, end); + } + + return 0; +} + +// implements the search logic for finding a page and starting decoding. if +// the function succeeds, current_loc_valid will be true and current_loc will +// be less than or equal to the provided sample number (the closer the +// better). +static int seek_to_sample_coarse(stb_vorbis *f, uint32 sample_number) +{ + ProbedPage left, right, mid; + int i, start_seg_with_known_loc, end_pos, page_start; + uint32 delta, stream_length, padding, last_sample_limit; + double offset = 0.0, bytes_per_sample = 0.0; + int probe = 0; + + // find the last page and validate the target sample + stream_length = stb_vorbis_stream_length_in_samples(f); + if (stream_length == 0) return error(f, VORBIS_seek_without_length); + if (sample_number > stream_length) return error(f, VORBIS_seek_invalid); + + // this is the maximum difference between the window-center (which is the + // actual granule position value), and the right-start (which the spec + // indicates should be the granule position (give or take one)). + padding = ((f->blocksize_1 - f->blocksize_0) >> 2); + if (sample_number < padding) + last_sample_limit = 0; + else + last_sample_limit = sample_number - padding; + + left = f->p_first; + while (left.last_decoded_sample == ~0U) { + // (untested) the first page does not have a 'last_decoded_sample' + set_file_offset(f, left.page_end); + if (!get_seek_page_info(f, &left)) goto error; + } + + right = f->p_last; + assert(right.last_decoded_sample != ~0U); + + // starting from the start is handled differently + if (last_sample_limit <= left.last_decoded_sample) { + if (stb_vorbis_seek_start(f)) { + if (f->current_loc > sample_number) + return error(f, VORBIS_seek_failed); + return 1; + } + return 0; + } + + while (left.page_end != right.page_start) { + assert(left.page_end < right.page_start); + // search range in bytes + delta = right.page_start - left.page_end; + if (delta <= 65536) { + // there's only 64K left to search - handle it linearly + set_file_offset(f, left.page_end); + } else { + if (probe < 2) { + if (probe == 0) { + // first probe (interpolate) + double data_bytes = right.page_end - left.page_start; + bytes_per_sample = data_bytes / right.last_decoded_sample; + offset = left.page_start + bytes_per_sample * (last_sample_limit - left.last_decoded_sample); + } else { + // second probe (try to bound the other side) + double error = ((double) last_sample_limit - mid.last_decoded_sample) * bytes_per_sample; + if (error >= 0 && error < 8000) error = 8000; + if (error < 0 && error > -8000) error = -8000; + offset += error * 2; + } + + // ensure the offset is valid + if (offset < left.page_end) + offset = left.page_end; + if (offset > right.page_start - 65536) + offset = right.page_start - 65536; + + set_file_offset(f, (unsigned int) offset); + } else { + // binary search for large ranges (offset by 32K to ensure + // we don't hit the right page) + set_file_offset(f, left.page_end + (delta / 2) - 32768); + } + + if (!vorbis_find_page(f, NULL, NULL)) goto error; + } + + for (;;) { + if (!get_seek_page_info(f, &mid)) goto error; + if (mid.last_decoded_sample != ~0U) break; + // (untested) no frames end on this page + set_file_offset(f, mid.page_end); + assert(mid.page_start < right.page_start); + } + + // if we've just found the last page again then we're in a tricky file, + // and we're close enough (if it wasn't an interpolation probe). + if (mid.page_start == right.page_start) { + if (probe >= 2 || delta <= 65536) + break; + } else { + if (last_sample_limit < mid.last_decoded_sample) + right = mid; + else + left = mid; + } + + ++probe; + } + + // seek back to start of the last packet + page_start = left.page_start; + set_file_offset(f, page_start); + if (!start_page(f)) return error(f, VORBIS_seek_failed); + end_pos = f->end_seg_with_known_loc; + assert(end_pos >= 0); + + for (;;) { + for (i = end_pos; i > 0; --i) + if (f->segments[i-1] != 255) + break; + + start_seg_with_known_loc = i; + + if (start_seg_with_known_loc > 0 || !(f->page_flag & PAGEFLAG_continued_packet)) + break; + + // (untested) the final packet begins on an earlier page + if (!go_to_page_before(f, page_start)) + goto error; + + page_start = stb_vorbis_get_file_offset(f); + if (!start_page(f)) goto error; + end_pos = f->segment_count - 1; + } + + // prepare to start decoding + f->current_loc_valid = FALSE; + f->last_seg = FALSE; + f->valid_bits = 0; + f->packet_bytes = 0; + f->bytes_in_seg = 0; + f->previous_length = 0; + f->next_seg = start_seg_with_known_loc; + + for (i = 0; i < start_seg_with_known_loc; i++) + skip(f, f->segments[i]); + + // start decoding (optimizable - this frame is generally discarded) + if (!vorbis_pump_first_frame(f)) + return 0; + if (f->current_loc > sample_number) + return error(f, VORBIS_seek_failed); + return 1; + +error: + // try to restore the file to a valid state + stb_vorbis_seek_start(f); + return error(f, VORBIS_seek_failed); +} + +// the same as vorbis_decode_initial, but without advancing +static int peek_decode_initial(vorb *f, int *p_left_start, int *p_left_end, int *p_right_start, int *p_right_end, int *mode) +{ + int bits_read, bytes_read; + + if (!vorbis_decode_initial(f, p_left_start, p_left_end, p_right_start, p_right_end, mode)) + return 0; + + // either 1 or 2 bytes were read, figure out which so we can rewind + bits_read = 1 + ilog(f->mode_count-1); + if (f->mode_config[*mode].blockflag) + bits_read += 2; + bytes_read = (bits_read + 7) / 8; + + f->bytes_in_seg += bytes_read; + f->packet_bytes -= bytes_read; + skip(f, -bytes_read); + if (f->next_seg == -1) + f->next_seg = f->segment_count - 1; + else + f->next_seg--; + f->valid_bits = 0; + + return 1; +} + +int stb_vorbis_seek_frame(stb_vorbis *f, unsigned int sample_number) +{ + uint32 max_frame_samples; + + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + + // fast page-level search + if (!seek_to_sample_coarse(f, sample_number)) + return 0; + + assert(f->current_loc_valid); + assert(f->current_loc <= sample_number); + + // linear search for the relevant packet + max_frame_samples = (f->blocksize_1*3 - f->blocksize_0) >> 2; + while (f->current_loc < sample_number) { + int left_start, left_end, right_start, right_end, mode, frame_samples; + if (!peek_decode_initial(f, &left_start, &left_end, &right_start, &right_end, &mode)) + return error(f, VORBIS_seek_failed); + // calculate the number of samples returned by the next frame + frame_samples = right_start - left_start; + if (f->current_loc + frame_samples > sample_number) { + return 1; // the next frame will contain the sample + } else if (f->current_loc + frame_samples + max_frame_samples > sample_number) { + // there's a chance the frame after this could contain the sample + vorbis_pump_first_frame(f); + } else { + // this frame is too early to be relevant + f->current_loc += frame_samples; + f->previous_length = 0; + maybe_start_packet(f); + flush_packet(f); + } + } + // the next frame should start with the sample + if (f->current_loc != sample_number) return error(f, VORBIS_seek_failed); + return 1; +} + +int stb_vorbis_seek(stb_vorbis *f, unsigned int sample_number) +{ + if (!stb_vorbis_seek_frame(f, sample_number)) + return 0; + + if (sample_number != f->current_loc) { + int n; + uint32 frame_start = f->current_loc; + stb_vorbis_get_frame_float(f, &n, NULL); + assert(sample_number > frame_start); + assert(f->channel_buffer_start + (int) (sample_number-frame_start) <= f->channel_buffer_end); + f->channel_buffer_start += (sample_number - frame_start); + } + + return 1; +} + +int stb_vorbis_seek_start(stb_vorbis *f) +{ + if (IS_PUSH_MODE(f)) { return error(f, VORBIS_invalid_api_mixing); } + set_file_offset(f, f->first_audio_page_offset); + f->previous_length = 0; + f->first_decode = TRUE; + f->next_seg = -1; + return vorbis_pump_first_frame(f); +} + +unsigned int stb_vorbis_stream_length_in_samples(stb_vorbis *f) +{ + unsigned int restore_offset, previous_safe; + unsigned int end, last_page_loc; + + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + if (!f->total_samples) { + unsigned int last; + uint32 lo,hi; + char header[6]; + + // first, store the current decode position so we can restore it + restore_offset = stb_vorbis_get_file_offset(f); + + // now we want to seek back 64K from the end (the last page must + // be at most a little less than 64K, but let's allow a little slop) + if (f->stream_len >= 65536 && f->stream_len-65536 >= f->first_audio_page_offset) + previous_safe = f->stream_len - 65536; + else + previous_safe = f->first_audio_page_offset; + + set_file_offset(f, previous_safe); + // previous_safe is now our candidate 'earliest known place that seeking + // to will lead to the final page' + + if (!vorbis_find_page(f, &end, &last)) { + // if we can't find a page, we're hosed! + f->error = VORBIS_cant_find_last_page; + f->total_samples = 0xffffffff; + goto done; + } + + // check if there are more pages + last_page_loc = stb_vorbis_get_file_offset(f); + + // stop when the last_page flag is set, not when we reach eof; + // this allows us to stop short of a 'file_section' end without + // explicitly checking the length of the section + while (!last) { + set_file_offset(f, end); + if (!vorbis_find_page(f, &end, &last)) { + // the last page we found didn't have the 'last page' flag + // set. whoops! + break; + } + //previous_safe = last_page_loc+1; // NOTE: not used after this point, but note for debugging + last_page_loc = stb_vorbis_get_file_offset(f); + } + + set_file_offset(f, last_page_loc); + + // parse the header + getn(f, (unsigned char *)header, 6); + // extract the absolute granule position + lo = get32(f); + hi = get32(f); + if (lo == 0xffffffff && hi == 0xffffffff) { + f->error = VORBIS_cant_find_last_page; + f->total_samples = SAMPLE_unknown; + goto done; + } + if (hi) + lo = 0xfffffffe; // saturate + f->total_samples = lo; + + f->p_last.page_start = last_page_loc; + f->p_last.page_end = end; + f->p_last.last_decoded_sample = lo; + + done: + set_file_offset(f, restore_offset); + } + return f->total_samples == SAMPLE_unknown ? 0 : f->total_samples; +} + +float stb_vorbis_stream_length_in_seconds(stb_vorbis *f) +{ + return stb_vorbis_stream_length_in_samples(f) / (float) f->sample_rate; +} + + + +int stb_vorbis_get_frame_float(stb_vorbis *f, int *channels, float ***output) +{ + int len, right,left,i; + if (IS_PUSH_MODE(f)) return error(f, VORBIS_invalid_api_mixing); + + if (!vorbis_decode_packet(f, &len, &left, &right)) { + f->channel_buffer_start = f->channel_buffer_end = 0; + return 0; + } + + len = vorbis_finish_frame(f, len, left, right); + for (i=0; i < f->channels; ++i) + f->outputs[i] = f->channel_buffers[i] + left; + + f->channel_buffer_start = left; + f->channel_buffer_end = left+len; + + if (channels) *channels = f->channels; + if (output) *output = f->outputs; + return len; +} + +#ifndef STB_VORBIS_NO_STDIO + +stb_vorbis * stb_vorbis_open_file_section(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc, unsigned int length) +{ + stb_vorbis *f, p; + vorbis_init(&p, alloc); + p.f = file; + p.f_start = (uint32) ftell(file); + p.stream_len = length; + p.close_on_free = close_on_free; + if (start_decoder(&p)) { + f = vorbis_alloc(&p); + if (f) { + *f = p; + vorbis_pump_first_frame(f); + return f; + } + } + if (error) *error = p.error; + vorbis_deinit(&p); + return NULL; +} + +stb_vorbis * stb_vorbis_open_file(FILE *file, int close_on_free, int *error, const stb_vorbis_alloc *alloc) +{ + unsigned int len, start; + start = (unsigned int) ftell(file); + fseek(file, 0, SEEK_END); + len = (unsigned int) (ftell(file) - start); + fseek(file, start, SEEK_SET); + return stb_vorbis_open_file_section(file, close_on_free, error, alloc, len); +} + +stb_vorbis * stb_vorbis_open_filename(const char *filename, int *error, const stb_vorbis_alloc *alloc) +{ + FILE *f; +#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) + if (0 != fopen_s(&f, filename, "rb")) + f = NULL; +#else + f = fopen(filename, "rb"); +#endif + if (f) + return stb_vorbis_open_file(f, TRUE, error, alloc); + if (error) *error = VORBIS_file_open_failure; + return NULL; +} +#endif // STB_VORBIS_NO_STDIO + +stb_vorbis * stb_vorbis_open_memory(const unsigned char *data, int len, int *error, const stb_vorbis_alloc *alloc) +{ + stb_vorbis *f, p; + if (!data) { + if (error) *error = VORBIS_unexpected_eof; + return NULL; + } + vorbis_init(&p, alloc); + p.stream = (uint8 *) data; + p.stream_end = (uint8 *) data + len; + p.stream_start = (uint8 *) p.stream; + p.stream_len = len; + p.push_mode = FALSE; + if (start_decoder(&p)) { + f = vorbis_alloc(&p); + if (f) { + *f = p; + vorbis_pump_first_frame(f); + if (error) *error = VORBIS__no_error; + return f; + } + } + if (error) *error = p.error; + vorbis_deinit(&p); + return NULL; +} + +#ifndef STB_VORBIS_NO_INTEGER_CONVERSION +#define PLAYBACK_MONO 1 +#define PLAYBACK_LEFT 2 +#define PLAYBACK_RIGHT 4 + +#define L (PLAYBACK_LEFT | PLAYBACK_MONO) +#define C (PLAYBACK_LEFT | PLAYBACK_RIGHT | PLAYBACK_MONO) +#define R (PLAYBACK_RIGHT | PLAYBACK_MONO) + +static int8 channel_position[7][6] = +{ + { 0 }, + { C }, + { L, R }, + { L, C, R }, + { L, R, L, R }, + { L, C, R, L, R }, + { L, C, R, L, R, C }, +}; + + +#ifndef STB_VORBIS_NO_FAST_SCALED_FLOAT + typedef union { + float f; + int i; + } float_conv; + typedef char stb_vorbis_float_size_test[sizeof(float)==4 && sizeof(int) == 4]; + #define FASTDEF(x) float_conv x + // add (1<<23) to convert to int, then divide by 2^SHIFT, then add 0.5/2^SHIFT to round + #define MAGIC(SHIFT) (1.5f * (1 << (23-SHIFT)) + 0.5f/(1 << SHIFT)) + #define ADDEND(SHIFT) (((150-SHIFT) << 23) + (1 << 22)) + #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) (temp.f = (x) + MAGIC(s), temp.i - ADDEND(s)) + #define check_endianness() +#else + #define FAST_SCALED_FLOAT_TO_INT(temp,x,s) ((int) ((x) * (1 << (s)))) + #define check_endianness() + #define FASTDEF(x) +#endif + +static void copy_samples(short *dest, float *src, int len) +{ + int i; + check_endianness(); + for (i=0; i < len; ++i) { + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp, src[i],15); + if ((unsigned int) (v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + dest[i] = v; + } +} + +static void compute_samples(int mask, short *output, int num_c, float **data, int d_offset, int len) +{ + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE; + check_endianness(); + for (o = 0; o < len; o += STB_BUFFER_SIZE) { + memset(buffer, 0, sizeof(buffer)); + if (o + n > len) n = len - o; + for (j=0; j < num_c; ++j) { + if (channel_position[num_c][j] & mask) { + for (i=0; i < n; ++i) + buffer[i] += data[j][d_offset+o+i]; + } + } + for (i=0; i < n; ++i) { + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); + if ((unsigned int) (v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + output[o+i] = v; + } + } + #undef STB_BUFFER_SIZE +} + +static void compute_stereo_samples(short *output, int num_c, float **data, int d_offset, int len) +{ + #define STB_BUFFER_SIZE 32 + float buffer[STB_BUFFER_SIZE]; + int i,j,o,n = STB_BUFFER_SIZE >> 1; + // o is the offset in the source data + check_endianness(); + for (o = 0; o < len; o += STB_BUFFER_SIZE >> 1) { + // o2 is the offset in the output data + int o2 = o << 1; + memset(buffer, 0, sizeof(buffer)); + if (o + n > len) n = len - o; + for (j=0; j < num_c; ++j) { + int m = channel_position[num_c][j] & (PLAYBACK_LEFT | PLAYBACK_RIGHT); + if (m == (PLAYBACK_LEFT | PLAYBACK_RIGHT)) { + for (i=0; i < n; ++i) { + buffer[i*2+0] += data[j][d_offset+o+i]; + buffer[i*2+1] += data[j][d_offset+o+i]; + } + } else if (m == PLAYBACK_LEFT) { + for (i=0; i < n; ++i) { + buffer[i*2+0] += data[j][d_offset+o+i]; + } + } else if (m == PLAYBACK_RIGHT) { + for (i=0; i < n; ++i) { + buffer[i*2+1] += data[j][d_offset+o+i]; + } + } + } + for (i=0; i < (n<<1); ++i) { + FASTDEF(temp); + int v = FAST_SCALED_FLOAT_TO_INT(temp,buffer[i],15); + if ((unsigned int) (v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + output[o2+i] = v; + } + } + #undef STB_BUFFER_SIZE +} + +static void convert_samples_short(int buf_c, short **buffer, int b_offset, int data_c, float **data, int d_offset, int samples) +{ + int i; + if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { + static int channel_selector[3][2] = { {0}, {PLAYBACK_MONO}, {PLAYBACK_LEFT, PLAYBACK_RIGHT} }; + for (i=0; i < buf_c; ++i) + compute_samples(channel_selector[buf_c][i], buffer[i]+b_offset, data_c, data, d_offset, samples); + } else { + int limit = buf_c < data_c ? buf_c : data_c; + for (i=0; i < limit; ++i) + copy_samples(buffer[i]+b_offset, data[i]+d_offset, samples); + for ( ; i < buf_c; ++i) + memset(buffer[i]+b_offset, 0, sizeof(short) * samples); + } +} + +int stb_vorbis_get_frame_short(stb_vorbis *f, int num_c, short **buffer, int num_samples) +{ + float **output = NULL; + int len = stb_vorbis_get_frame_float(f, NULL, &output); + if (len > num_samples) len = num_samples; + if (len) + convert_samples_short(num_c, buffer, 0, f->channels, output, 0, len); + return len; +} + +static void convert_channels_short_interleaved(int buf_c, short *buffer, int data_c, float **data, int d_offset, int len) +{ + int i; + check_endianness(); + if (buf_c != data_c && buf_c <= 2 && data_c <= 6) { + assert(buf_c == 2); + for (i=0; i < buf_c; ++i) + compute_stereo_samples(buffer, data_c, data, d_offset, len); + } else { + int limit = buf_c < data_c ? buf_c : data_c; + int j; + for (j=0; j < len; ++j) { + for (i=0; i < limit; ++i) { + FASTDEF(temp); + float f = data[i][d_offset+j]; + int v = FAST_SCALED_FLOAT_TO_INT(temp, f,15);//data[i][d_offset+j],15); + if ((unsigned int) (v + 32768) > 65535) + v = v < 0 ? -32768 : 32767; + *buffer++ = v; + } + for ( ; i < buf_c; ++i) + *buffer++ = 0; + } + } +} + +int stb_vorbis_get_frame_short_interleaved(stb_vorbis *f, int num_c, short *buffer, int num_shorts) +{ + float **output; + int len; + if (num_c == 1) return stb_vorbis_get_frame_short(f,num_c,&buffer, num_shorts); + len = stb_vorbis_get_frame_float(f, NULL, &output); + if (len) { + if (len*num_c > num_shorts) len = num_shorts / num_c; + convert_channels_short_interleaved(num_c, buffer, f->channels, output, 0, len); + } + return len; +} + +int stb_vorbis_get_samples_short_interleaved(stb_vorbis *f, int channels, short *buffer, int num_shorts) +{ + float **outputs; + int len = num_shorts / channels; + int n=0; + while (n < len) { + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n+k >= len) k = len - n; + if (k) + convert_channels_short_interleaved(channels, buffer, f->channels, f->channel_buffers, f->channel_buffer_start, k); + buffer += k*channels; + n += k; + f->channel_buffer_start += k; + if (n == len) break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; + } + return n; +} + +int stb_vorbis_get_samples_short(stb_vorbis *f, int channels, short **buffer, int len) +{ + float **outputs; + int n=0; + while (n < len) { + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n+k >= len) k = len - n; + if (k) + convert_samples_short(channels, buffer, n, f->channels, f->channel_buffers, f->channel_buffer_start, k); + n += k; + f->channel_buffer_start += k; + if (n == len) break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) break; + } + return n; +} + +#ifndef STB_VORBIS_NO_STDIO +int stb_vorbis_decode_filename(const char *filename, int *channels, int *sample_rate, short **output) +{ + int data_len, offset, total, limit, error; + short *data; + stb_vorbis *v = stb_vorbis_open_filename(filename, &error, NULL); + if (v == NULL) return -1; + limit = v->channels * 4096; + *channels = v->channels; + if (sample_rate) + *sample_rate = v->sample_rate; + offset = data_len = 0; + total = limit; + data = (short *) malloc(total * sizeof(*data)); + if (data == NULL) { + stb_vorbis_close(v); + return -2; + } + for (;;) { + int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset); + if (n == 0) break; + data_len += n; + offset += n * v->channels; + if (offset + limit > total) { + short *data2; + total *= 2; + data2 = (short *) realloc(data, total * sizeof(*data)); + if (data2 == NULL) { + free(data); + stb_vorbis_close(v); + return -2; + } + data = data2; + } + } + *output = data; + stb_vorbis_close(v); + return data_len; +} +#endif // NO_STDIO + +int stb_vorbis_decode_memory(const uint8 *mem, int len, int *channels, int *sample_rate, short **output) +{ + int data_len, offset, total, limit, error; + short *data; + stb_vorbis *v = stb_vorbis_open_memory(mem, len, &error, NULL); + if (v == NULL) return -1; + limit = v->channels * 4096; + *channels = v->channels; + if (sample_rate) + *sample_rate = v->sample_rate; + offset = data_len = 0; + total = limit; + data = (short *) malloc(total * sizeof(*data)); + if (data == NULL) { + stb_vorbis_close(v); + return -2; + } + for (;;) { + int n = stb_vorbis_get_frame_short_interleaved(v, v->channels, data+offset, total-offset); + if (n == 0) break; + data_len += n; + offset += n * v->channels; + if (offset + limit > total) { + short *data2; + total *= 2; + data2 = (short *) realloc(data, total * sizeof(*data)); + if (data2 == NULL) { + free(data); + stb_vorbis_close(v); + return -2; + } + data = data2; + } + } + *output = data; + stb_vorbis_close(v); + return data_len; +} +#endif // STB_VORBIS_NO_INTEGER_CONVERSION + +int stb_vorbis_get_samples_float_interleaved(stb_vorbis *f, int channels, float *buffer, int num_floats) +{ + float **outputs; + int len = num_floats / channels; + int n=0; + int z = f->channels; + if (z > channels) z = channels; + while (n < len) { + int i,j; + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n+k >= len) k = len - n; + for (j=0; j < k; ++j) { + for (i=0; i < z; ++i) + *buffer++ = f->channel_buffers[i][f->channel_buffer_start+j]; + for ( ; i < channels; ++i) + *buffer++ = 0; + } + n += k; + f->channel_buffer_start += k; + if (n == len) + break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) + break; + } + return n; +} + +int stb_vorbis_get_samples_float(stb_vorbis *f, int channels, float **buffer, int num_samples) +{ + float **outputs; + int n=0; + int z = f->channels; + if (z > channels) z = channels; + while (n < num_samples) { + int i; + int k = f->channel_buffer_end - f->channel_buffer_start; + if (n+k >= num_samples) k = num_samples - n; + if (k) { + for (i=0; i < z; ++i) + memcpy(buffer[i]+n, f->channel_buffers[i]+f->channel_buffer_start, sizeof(float)*k); + for ( ; i < channels; ++i) + memset(buffer[i]+n, 0, sizeof(float) * k); + } + n += k; + f->channel_buffer_start += k; + if (n == num_samples) + break; + if (!stb_vorbis_get_frame_float(f, NULL, &outputs)) + break; + } + return n; +} +#endif // STB_VORBIS_NO_PULLDATA_API + +/* Version history + 1.17 - 2019-07-08 - fix CVE-2019-13217, -13218, -13219, -13220, -13221, -13222, -13223 + found with Mayhem by ForAllSecure + 1.16 - 2019-03-04 - fix warnings + 1.15 - 2019-02-07 - explicit failure if Ogg Skeleton data is found + 1.14 - 2018-02-11 - delete bogus dealloca usage + 1.13 - 2018-01-29 - fix truncation of last frame (hopefully) + 1.12 - 2017-11-21 - limit residue begin/end to blocksize/2 to avoid large temp allocs in bad/corrupt files + 1.11 - 2017-07-23 - fix MinGW compilation + 1.10 - 2017-03-03 - more robust seeking; fix negative ilog(); clear error in open_memory + 1.09 - 2016-04-04 - back out 'avoid discarding last frame' fix from previous version + 1.08 - 2016-04-02 - fixed multiple warnings; fix setup memory leaks; + avoid discarding last frame of audio data + 1.07 - 2015-01-16 - fixed some warnings, fix mingw, const-correct API + some more crash fixes when out of memory or with corrupt files + 1.06 - 2015-08-31 - full, correct support for seeking API (Dougall Johnson) + some crash fixes when out of memory or with corrupt files + 1.05 - 2015-04-19 - don't define __forceinline if it's redundant + 1.04 - 2014-08-27 - fix missing const-correct case in API + 1.03 - 2014-08-07 - Warning fixes + 1.02 - 2014-07-09 - Declare qsort compare function _cdecl on windows + 1.01 - 2014-06-18 - fix stb_vorbis_get_samples_float + 1.0 - 2014-05-26 - fix memory leaks; fix warnings; fix bugs in multichannel + (API change) report sample rate for decode-full-file funcs + 0.99996 - bracket #include for macintosh compilation by Laurent Gomila + 0.99995 - use union instead of pointer-cast for fast-float-to-int to avoid alias-optimization problem + 0.99994 - change fast-float-to-int to work in single-precision FPU mode, remove endian-dependence + 0.99993 - remove assert that fired on legal files with empty tables + 0.99992 - rewind-to-start + 0.99991 - bugfix to stb_vorbis_get_samples_short by Bernhard Wodo + 0.9999 - (should have been 0.99990) fix no-CRT support, compiling as C++ + 0.9998 - add a full-decode function with a memory source + 0.9997 - fix a bug in the read-from-FILE case in 0.9996 addition + 0.9996 - query length of vorbis stream in samples/seconds + 0.9995 - bugfix to another optimization that only happened in certain files + 0.9994 - bugfix to one of the optimizations that caused significant (but inaudible?) errors + 0.9993 - performance improvements; runs in 99% to 104% of time of reference implementation + 0.9992 - performance improvement of IMDCT; now performs close to reference implementation + 0.9991 - performance improvement of IMDCT + 0.999 - (should have been 0.9990) performance improvement of IMDCT + 0.998 - no-CRT support from Casey Muratori + 0.997 - bugfixes for bugs found by Terje Mathisen + 0.996 - bugfix: fast-huffman decode initialized incorrectly for sparse codebooks; fixing gives 10% speedup - found by Terje Mathisen + 0.995 - bugfix: fix to 'effective' overrun detection - found by Terje Mathisen + 0.994 - bugfix: garbage decode on final VQ symbol of a non-multiple - found by Terje Mathisen + 0.993 - bugfix: pushdata API required 1 extra byte for empty page (failed to consume final page if empty) - found by Terje Mathisen + 0.992 - fixes for MinGW warning + 0.991 - turn fast-float-conversion on by default + 0.990 - fix push-mode seek recovery if you seek into the headers + 0.98b - fix to bad release of 0.98 + 0.98 - fix push-mode seek recovery; robustify float-to-int and support non-fast mode + 0.97 - builds under c++ (typecasting, don't use 'class' keyword) + 0.96 - somehow MY 0.95 was right, but the web one was wrong, so here's my 0.95 rereleased as 0.96, fixes a typo in the clamping code + 0.95 - clamping code for 16-bit functions + 0.94 - not publically released + 0.93 - fixed all-zero-floor case (was decoding garbage) + 0.92 - fixed a memory leak + 0.91 - conditional compiles to omit parts of the API and the infrastructure to support them: STB_VORBIS_NO_PULLDATA_API, STB_VORBIS_NO_PUSHDATA_API, STB_VORBIS_NO_STDIO, STB_VORBIS_NO_INTEGER_CONVERSION + 0.90 - first public release +*/ + +#endif // STB_VORBIS_HEADER_ONLY + + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +This is free and unencumbered software released into the public domain. +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this +software, either in source code form or as a compiled binary, for any purpose, +commercial or non-commercial, and by any means. +In jurisdictions that recognize copyright laws, the author or authors of this +software dedicate any and all copyright interest in the software to the public +domain. We make this dedication for the benefit of the public at large and to +the detriment of our heirs and successors. We intend this dedication to be an +overt act of relinquishment in perpetuity of all present and future rights to +this software under copyright law. +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +------------------------------------------------------------------------------ +*/ diff --git a/src/lib/stb_vorbis/stb_vorbis.h b/src/lib/stb_vorbis/stb_vorbis.h new file mode 100644 index 00000000..2747148c --- /dev/null +++ b/src/lib/stb_vorbis/stb_vorbis.h @@ -0,0 +1,17 @@ +/* +Public header shim for stb_vorbis. + +Upstream ships the interface inside stb_vorbis.c and exposes only the +declarations when STB_VORBIS_HEADER_ONLY is defined. The configuration macros +here must match stb_vorbis_impl.c so the declared API matches the compiled one. +*/ + +#ifndef BSTONE_STB_VORBIS_INCLUDED +#define BSTONE_STB_VORBIS_INCLUDED + +#define STB_VORBIS_NO_STDIO +#define STB_VORBIS_HEADER_ONLY + +#include "stb_vorbis.c" + +#endif // BSTONE_STB_VORBIS_INCLUDED diff --git a/src/lib/stb_vorbis/stb_vorbis_impl.c b/src/lib/stb_vorbis/stb_vorbis_impl.c new file mode 100644 index 00000000..bcbafdd5 --- /dev/null +++ b/src/lib/stb_vorbis/stb_vorbis_impl.c @@ -0,0 +1,12 @@ +/* +Implementation translation unit for stb_vorbis. + +stb_vorbis.c is both the public interface and the implementation; this file +compiles the implementation with the configuration bstone needs. Consumers pull +in the declarations through stb_vorbis.h, which defines the same macros so the +two agree on the exposed API surface. +*/ + +#define STB_VORBIS_NO_STDIO + +#include "stb_vorbis.c" diff --git a/src/lib/vorbis/CMakeLists.txt b/src/lib/vorbis/CMakeLists.txt deleted file mode 100644 index 3d98b1d9..00000000 --- a/src/lib/vorbis/CMakeLists.txt +++ /dev/null @@ -1,74 +0,0 @@ -# bstone -cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -# ====================================== -project(bstone_lib_vorbis VERSION 1.0.0 LANGUAGES C) -message(STATUS "[${PROJECT_NAME}] v${PROJECT_VERSION}") -add_library(${PROJECT_NAME} STATIC) -add_library(bstone::lib::vorbis ALIAS ${PROJECT_NAME}) -set_target_properties(${PROJECT_NAME} PROPERTIES - C_STANDARD 99 - C_STANDARD_REQUIRED ON - C_EXTENSIONS OFF -) -target_compile_definitions(${PROJECT_NAME} PRIVATE $<$:_CRT_SECURE_NO_WARNINGS>) -target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W1>) -target_link_libraries(${PROJECT_NAME} PUBLIC bstone::lib::ogg) -target_include_directories(${PROJECT_NAME} PUBLIC include) -target_sources(${PROJECT_NAME} PRIVATE - include/vorbis/codec.h - include/vorbis/vorbisfile.h - src/analysis.c - src/backends.h - src/bitrate.c - src/bitrate.h - src/block.c - src/codebook.c - src/codebook.h - src/codec_internal.h - src/envelope.c - src/envelope.h - src/floor0.c - src/floor1.c - src/highlevel.h - src/info.c - src/lookup.c - src/lookup.h - src/lookup_data.h - src/lpc.c - src/lpc.h - src/lsp.c - src/lsp.h - src/mapping0.c - src/masking.h - src/mdct.c - src/mdct.h - src/misc.h - src/os.h - src/psy.c - src/psy.h - src/registry.c - src/registry.h - src/res0.c - src/scales.h - src/sharedbook.c - src/smallft.c - src/smallft.h - src/synthesis.c - src/window.c - src/window.h -) -# ====================================== -cmake_minimum_required(VERSION 3.24.0 FATAL_ERROR) -project(bstone_lib_vorbisfile VERSION 1.0.0 LANGUAGES C) -message(STATUS "[${PROJECT_NAME}] v${PROJECT_VERSION}") -add_library(${PROJECT_NAME} STATIC) -add_library(bstone::lib::vorbisfile ALIAS ${PROJECT_NAME}) -set_target_properties(${PROJECT_NAME} PROPERTIES - C_STANDARD 99 - C_STANDARD_REQUIRED ON - C_EXTENSIONS OFF -) -target_compile_options(${PROJECT_NAME} PRIVATE $<$:/W1>) -target_link_libraries(${PROJECT_NAME} PUBLIC bstone::lib::vorbis) -target_include_directories(${PROJECT_NAME} PRIVATE src) -target_sources(${PROJECT_NAME} PRIVATE src/vorbisfile.c) diff --git a/src/lib/vorbis/COPYING b/src/lib/vorbis/COPYING deleted file mode 100644 index fb456a87..00000000 --- a/src/lib/vorbis/COPYING +++ /dev/null @@ -1,28 +0,0 @@ -Copyright (c) 2002-2020 Xiph.org Foundation - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -- Redistributions of source code must retain the above copyright -notice, this list of conditions and the following disclaimer. - -- Redistributions in binary form must reproduce the above copyright -notice, this list of conditions and the following disclaimer in the -documentation and/or other materials provided with the distribution. - -- Neither the name of the Xiph.org Foundation nor the names of its -contributors may be used to endorse or promote products derived from -this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION -OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/lib/vorbis/bstone_vorbis_changelog.txt b/src/lib/vorbis/bstone_vorbis_changelog.txt deleted file mode 100644 index 47aee486..00000000 --- a/src/lib/vorbis/bstone_vorbis_changelog.txt +++ /dev/null @@ -1,5 +0,0 @@ -Based on https://downloads.xiph.org/releases/vorbis/libvorbis-1.3.7.zip -Lookup "/* bstone */" for changes. - -- Essential files related to decoding only. -- Custom CMake scripts. diff --git a/src/lib/vorbis/include/vorbis/codec.h b/src/lib/vorbis/include/vorbis/codec.h deleted file mode 100644 index f8a912bc..00000000 --- a/src/lib/vorbis/include/vorbis/codec.h +++ /dev/null @@ -1,242 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2001 * - * by the Xiph.Org Foundation https://xiph.org/ * - - ******************************************************************** - - function: libvorbis codec headers - - ********************************************************************/ - -#ifndef _vorbis_codec_h_ -#define _vorbis_codec_h_ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#include - -typedef struct vorbis_info{ - int version; - int channels; - long rate; - - /* The below bitrate declarations are *hints*. - Combinations of the three values carry the following implications: - - all three set to the same value: - implies a fixed rate bitstream - only nominal set: - implies a VBR stream that averages the nominal bitrate. No hard - upper/lower limit - upper and or lower set: - implies a VBR bitstream that obeys the bitrate limits. nominal - may also be set to give a nominal rate. - none set: - the coder does not care to speculate. - */ - - long bitrate_upper; - long bitrate_nominal; - long bitrate_lower; - long bitrate_window; - - void *codec_setup; -} vorbis_info; - -/* vorbis_dsp_state buffers the current vorbis audio - analysis/synthesis state. The DSP state belongs to a specific - logical bitstream ****************************************************/ -typedef struct vorbis_dsp_state{ - int analysisp; - vorbis_info *vi; - - float **pcm; - float **pcmret; - int pcm_storage; - int pcm_current; - int pcm_returned; - - int preextrapolate; - int eofflag; - - long lW; - long W; - long nW; - long centerW; - - ogg_int64_t granulepos; - ogg_int64_t sequence; - - ogg_int64_t glue_bits; - ogg_int64_t time_bits; - ogg_int64_t floor_bits; - ogg_int64_t res_bits; - - void *backend_state; -} vorbis_dsp_state; - -typedef struct vorbis_block{ - /* necessary stream state for linking to the framing abstraction */ - float **pcm; /* this is a pointer into local storage */ - oggpack_buffer opb; - - long lW; - long W; - long nW; - int pcmend; - int mode; - - int eofflag; - ogg_int64_t granulepos; - ogg_int64_t sequence; - vorbis_dsp_state *vd; /* For read-only access of configuration */ - - /* local storage to avoid remallocing; it's up to the mapping to - structure it */ - void *localstore; - long localtop; - long localalloc; - long totaluse; - struct alloc_chain *reap; - - /* bitmetrics for the frame */ - long glue_bits; - long time_bits; - long floor_bits; - long res_bits; - - void *internal; - -} vorbis_block; - -/* vorbis_block is a single block of data to be processed as part of -the analysis/synthesis stream; it belongs to a specific logical -bitstream, but is independent from other vorbis_blocks belonging to -that logical bitstream. *************************************************/ - -struct alloc_chain{ - void *ptr; - struct alloc_chain *next; -}; - -/* vorbis_info contains all the setup information specific to the - specific compression/decompression mode in progress (eg, - psychoacoustic settings, channel setup, options, codebook - etc). vorbis_info and substructures are in backends.h. -*********************************************************************/ - -/* the comments are not part of vorbis_info so that vorbis_info can be - static storage */ -typedef struct vorbis_comment{ - /* unlimited user comment fields. libvorbis writes 'libvorbis' - whatever vendor is set to in encode */ - char **user_comments; - int *comment_lengths; - int comments; - char *vendor; - -} vorbis_comment; - - -/* libvorbis encodes in two abstraction layers; first we perform DSP - and produce a packet (see docs/analysis.txt). The packet is then - coded into a framed OggSquish bitstream by the second layer (see - docs/framing.txt). Decode is the reverse process; we sync/frame - the bitstream and extract individual packets, then decode the - packet back into PCM audio. - - The extra framing/packetizing is used in streaming formats, such as - files. Over the net (such as with UDP), the framing and - packetization aren't necessary as they're provided by the transport - and the streaming layer is not used */ - -/* Vorbis PRIMITIVES: general ***************************************/ - -extern void vorbis_info_init(vorbis_info *vi); -extern void vorbis_info_clear(vorbis_info *vi); -extern int vorbis_info_blocksize(vorbis_info *vi,int zo); -extern void vorbis_comment_init(vorbis_comment *vc); -extern void vorbis_comment_add(vorbis_comment *vc, const char *comment); -extern void vorbis_comment_add_tag(vorbis_comment *vc, - const char *tag, const char *contents); -extern char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count); -extern int vorbis_comment_query_count(vorbis_comment *vc, const char *tag); -extern void vorbis_comment_clear(vorbis_comment *vc); - -extern int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb); -extern int vorbis_block_clear(vorbis_block *vb); -extern void vorbis_dsp_clear(vorbis_dsp_state *v); -extern double vorbis_granule_time(vorbis_dsp_state *v, - ogg_int64_t granulepos); - -extern const char *vorbis_version_string(void); - -/* Vorbis PRIMITIVES: analysis/DSP layer ****************************/ - -extern int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi); -extern int vorbis_commentheader_out(vorbis_comment *vc, ogg_packet *op); -extern int vorbis_analysis_headerout(vorbis_dsp_state *v, - vorbis_comment *vc, - ogg_packet *op, - ogg_packet *op_comm, - ogg_packet *op_code); -extern float **vorbis_analysis_buffer(vorbis_dsp_state *v,int vals); -extern int vorbis_analysis_wrote(vorbis_dsp_state *v,int vals); -extern int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb); -extern int vorbis_analysis(vorbis_block *vb,ogg_packet *op); - -extern int vorbis_bitrate_addblock(vorbis_block *vb); -extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, - ogg_packet *op); - -/* Vorbis PRIMITIVES: synthesis layer *******************************/ -extern int vorbis_synthesis_idheader(ogg_packet *op); -extern int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc, - ogg_packet *op); - -extern int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi); -extern int vorbis_synthesis_restart(vorbis_dsp_state *v); -extern int vorbis_synthesis(vorbis_block *vb,ogg_packet *op); -extern int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op); -extern int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb); -extern int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm); -extern int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm); -extern int vorbis_synthesis_read(vorbis_dsp_state *v,int samples); -extern long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op); - -extern int vorbis_synthesis_halfrate(vorbis_info *v,int flag); -extern int vorbis_synthesis_halfrate_p(vorbis_info *v); - -/* Vorbis ERRORS and return codes ***********************************/ - -#define OV_FALSE -1 -#define OV_EOF -2 -#define OV_HOLE -3 - -#define OV_EREAD -128 -#define OV_EFAULT -129 -#define OV_EIMPL -130 -#define OV_EINVAL -131 -#define OV_ENOTVORBIS -132 -#define OV_EBADHEADER -133 -#define OV_EVERSION -134 -#define OV_ENOTAUDIO -135 -#define OV_EBADPACKET -136 -#define OV_EBADLINK -137 -#define OV_ENOSEEK -138 - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif - diff --git a/src/lib/vorbis/include/vorbis/vorbisfile.h b/src/lib/vorbis/include/vorbis/vorbisfile.h deleted file mode 100644 index fa27845c..00000000 --- a/src/lib/vorbis/include/vorbis/vorbisfile.h +++ /dev/null @@ -1,207 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: stdio-based convenience library for opening/seeking/decoding - - ********************************************************************/ - -#ifndef _OV_FILE_H_ -#define _OV_FILE_H_ - -#ifdef __cplusplus -extern "C" -{ -#endif /* __cplusplus */ - -#include -#include "codec.h" - -/* The function prototypes for the callbacks are basically the same as for - * the stdio functions fread, fseek, fclose, ftell. - * The one difference is that the FILE * arguments have been replaced with - * a void * - this is to be used as a pointer to whatever internal data these - * functions might need. In the stdio case, it's just a FILE * cast to a void * - * - * If you use other functions, check the docs for these functions and return - * the right values. For seek_func(), you *MUST* return -1 if the stream is - * unseekable - */ -typedef struct { - size_t (*read_func) (void *ptr, size_t size, size_t nmemb, void *datasource); - int (*seek_func) (void *datasource, ogg_int64_t offset, int whence); - int (*close_func) (void *datasource); - long (*tell_func) (void *datasource); -} ov_callbacks; - -#if 0 /* bstone */ -#ifndef OV_EXCLUDE_STATIC_CALLBACKS - -/* a few sets of convenient callbacks, especially for use under - * Windows where ov_open_callbacks() should always be used instead of - * ov_open() to avoid problems with incompatible crt.o version linking - * issues. */ - -static int _ov_header_fseek_wrap(FILE *f,ogg_int64_t off,int whence){ - if(f==NULL)return(-1); - -#ifdef __MINGW32__ - return fseeko64(f,off,whence); -#elif defined (_WIN32) - return _fseeki64(f,off,whence); -#else - return fseek(f,off,whence); -#endif -} - -/* These structs below (OV_CALLBACKS_DEFAULT etc) are defined here as - * static data. That means that every file which includes this header - * will get its own copy of these structs whether it uses them or - * not unless it #defines OV_EXCLUDE_STATIC_CALLBACKS. - * These static symbols are essential on platforms such as Windows on - * which several different versions of stdio support may be linked to - * by different DLLs, and we need to be certain we know which one - * we're using (the same one as the main application). - */ - -static ov_callbacks OV_CALLBACKS_DEFAULT = { - (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap, - (int (*)(void *)) fclose, - (long (*)(void *)) ftell -}; - -static ov_callbacks OV_CALLBACKS_NOCLOSE = { - (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) _ov_header_fseek_wrap, - (int (*)(void *)) NULL, - (long (*)(void *)) ftell -}; - -static ov_callbacks OV_CALLBACKS_STREAMONLY = { - (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) NULL, - (int (*)(void *)) fclose, - (long (*)(void *)) NULL -}; - -static ov_callbacks OV_CALLBACKS_STREAMONLY_NOCLOSE = { - (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) NULL, - (int (*)(void *)) NULL, - (long (*)(void *)) NULL -}; - -#endif -#endif /* bstone */ - -#define NOTOPEN 0 -#define PARTOPEN 1 -#define OPENED 2 -#define STREAMSET 3 -#define INITSET 4 - -typedef struct OggVorbis_File { - void *datasource; /* Pointer to a FILE *, etc. */ - int seekable; - ogg_int64_t offset; - ogg_int64_t end; - ogg_sync_state oy; - - /* If the FILE handle isn't seekable (eg, a pipe), only the current - stream appears */ - int links; - ogg_int64_t *offsets; - ogg_int64_t *dataoffsets; - long *serialnos; - ogg_int64_t *pcmlengths; /* overloaded to maintain binary - compatibility; x2 size, stores both - beginning and end values */ - vorbis_info *vi; - vorbis_comment *vc; - - /* Decoding working state local storage */ - ogg_int64_t pcm_offset; - int ready_state; - long current_serialno; - int current_link; - - double bittrack; - double samptrack; - - ogg_stream_state os; /* take physical pages, weld into a logical - stream of packets */ - vorbis_dsp_state vd; /* central working state for the packet->PCM decoder */ - vorbis_block vb; /* local working space for packet->PCM decode */ - - ov_callbacks callbacks; - -} OggVorbis_File; - - -extern int ov_clear(OggVorbis_File *vf); -extern int ov_fopen(const char *path,OggVorbis_File *vf); -extern int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); -extern int ov_open_callbacks(void *datasource, OggVorbis_File *vf, - const char *initial, long ibytes, ov_callbacks callbacks); - -extern int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes); -extern int ov_test_callbacks(void *datasource, OggVorbis_File *vf, - const char *initial, long ibytes, ov_callbacks callbacks); -extern int ov_test_open(OggVorbis_File *vf); - -extern long ov_bitrate(OggVorbis_File *vf,int i); -extern long ov_bitrate_instant(OggVorbis_File *vf); -extern long ov_streams(OggVorbis_File *vf); -extern long ov_seekable(OggVorbis_File *vf); -extern long ov_serialnumber(OggVorbis_File *vf,int i); - -extern ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i); -extern ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i); -extern double ov_time_total(OggVorbis_File *vf,int i); - -extern int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_time_seek(OggVorbis_File *vf,double pos); -extern int ov_time_seek_page(OggVorbis_File *vf,double pos); - -extern int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos); -extern int ov_time_seek_lap(OggVorbis_File *vf,double pos); -extern int ov_time_seek_page_lap(OggVorbis_File *vf,double pos); - -extern ogg_int64_t ov_raw_tell(OggVorbis_File *vf); -extern ogg_int64_t ov_pcm_tell(OggVorbis_File *vf); -extern double ov_time_tell(OggVorbis_File *vf); - -extern vorbis_info *ov_info(OggVorbis_File *vf,int link); -extern vorbis_comment *ov_comment(OggVorbis_File *vf,int link); - -extern long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int samples, - int *bitstream); -extern long ov_read_filter(OggVorbis_File *vf,char *buffer,int length, - int bigendianp,int word,int sgned,int *bitstream, - void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param); -extern long ov_read(OggVorbis_File *vf,char *buffer,int length, - int bigendianp,int word,int sgned,int *bitstream); -extern int ov_crosslap(OggVorbis_File *vf1,OggVorbis_File *vf2); - -extern int ov_halfrate(OggVorbis_File *vf,int flag); -extern int ov_halfrate_p(OggVorbis_File *vf); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif - diff --git a/src/lib/vorbis/src/analysis.c b/src/lib/vorbis/src/analysis.c deleted file mode 100644 index 14919737..00000000 --- a/src/lib/vorbis/src/analysis.c +++ /dev/null @@ -1,119 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: single-block PCM analysis mode dispatch - - ********************************************************************/ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "registry.h" -#include "scales.h" -#include "os.h" -#include "misc.h" - -/* decides between modes, dispatches to the appropriate mapping. */ -int vorbis_analysis(vorbis_block *vb, ogg_packet *op){ - int ret,i; - vorbis_block_internal *vbi=vb->internal; - - vb->glue_bits=0; - vb->time_bits=0; - vb->floor_bits=0; - vb->res_bits=0; - - /* first things first. Make sure encode is ready */ - for(i=0;ipacketblob[i]); - - /* we only have one mapping type (0), and we let the mapping code - itself figure out what soft mode to use. This allows easier - bitrate management */ - - if((ret=_mapping_P[0]->forward(vb))) - return(ret); - - if(op){ - if(vorbis_bitrate_managed(vb)) - /* The app is using a bitmanaged mode... but not using the - bitrate management interface. */ - return(OV_EINVAL); - - op->packet=oggpack_get_buffer(&vb->opb); - op->bytes=oggpack_bytes(&vb->opb); - op->b_o_s=0; - op->e_o_s=vb->eofflag; - op->granulepos=vb->granulepos; - op->packetno=vb->sequence; /* for sake of completeness */ - } - return(0); -} - -#ifdef ANALYSIS -int analysis_noisy=1; - -/* there was no great place to put this.... */ -void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB,ogg_int64_t off){ - int j; - FILE *of; - char buffer[80]; - - sprintf(buffer,"%s_%d.m",base,i); - of=fopen(buffer,"w"); - - if(!of)perror("failed to open data dump file"); - - for(j=0;j -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "os.h" -#include "misc.h" -#include "bitrate.h" - -/* compute bitrate tracking setup */ -void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bm){ - codec_setup_info *ci=vi->codec_setup; - bitrate_manager_info *bi=&ci->bi; - - memset(bm,0,sizeof(*bm)); - - if(bi && (bi->reservoir_bits>0)){ - long ratesamples=vi->rate; - int halfsamples=ci->blocksizes[0]>>1; - - bm->short_per_long=ci->blocksizes[1]/ci->blocksizes[0]; - bm->managed=1; - - bm->avg_bitsper= rint(1.*bi->avg_rate*halfsamples/ratesamples); - bm->min_bitsper= rint(1.*bi->min_rate*halfsamples/ratesamples); - bm->max_bitsper= rint(1.*bi->max_rate*halfsamples/ratesamples); - - bm->avgfloat=PACKETBLOBS/2; - - /* not a necessary fix, but one that leads to a more balanced - typical initialization */ - { - long desired_fill=bi->reservoir_bits*bi->reservoir_bias; - bm->minmax_reservoir=desired_fill; - bm->avg_reservoir=desired_fill; - } - - } -} - -void vorbis_bitrate_clear(bitrate_manager_state *bm){ - memset(bm,0,sizeof(*bm)); - return; -} - -int vorbis_bitrate_managed(vorbis_block *vb){ - vorbis_dsp_state *vd=vb->vd; - private_state *b=vd->backend_state; - bitrate_manager_state *bm=&b->bms; - - if(bm && bm->managed)return(1); - return(0); -} - -/* finish taking in the block we just processed */ -int vorbis_bitrate_addblock(vorbis_block *vb){ - vorbis_block_internal *vbi=vb->internal; - vorbis_dsp_state *vd=vb->vd; - private_state *b=vd->backend_state; - bitrate_manager_state *bm=&b->bms; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=vi->codec_setup; - bitrate_manager_info *bi=&ci->bi; - - int choice=rint(bm->avgfloat); - long this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - long min_target_bits=(vb->W?bm->min_bitsper*bm->short_per_long:bm->min_bitsper); - long max_target_bits=(vb->W?bm->max_bitsper*bm->short_per_long:bm->max_bitsper); - int samples=ci->blocksizes[vb->W]>>1; - long desired_fill=bi->reservoir_bits*bi->reservoir_bias; - if(!bm->managed){ - /* not a bitrate managed stream, but for API simplicity, we'll - buffer the packet to keep the code path clean */ - - if(bm->vb)return(-1); /* one has been submitted without - being claimed */ - bm->vb=vb; - return(0); - } - - bm->vb=vb; - - /* look ahead for avg floater */ - if(bm->avg_bitsper>0){ - double slew=0.; - long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); - double slewlimit= 15./bi->slew_damp; - - /* choosing a new floater: - if we're over target, we slew down - if we're under target, we slew up - - choose slew as follows: look through packetblobs of this frame - and set slew as the first in the appropriate direction that - gives us the slew we want. This may mean no slew if delta is - already favorable. - - Then limit slew to slew max */ - - if(bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ - while(choice>0 && this_bits>avg_target_bits && - bm->avg_reservoir+(this_bits-avg_target_bits)>desired_fill){ - choice--; - this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - } - }else if(bm->avg_reservoir+(this_bits-avg_target_bits)avg_reservoir+(this_bits-avg_target_bits)packetblob[choice])*8; - } - } - - slew=rint(choice-bm->avgfloat)/samples*vi->rate; - if(slew<-slewlimit)slew=-slewlimit; - if(slew>slewlimit)slew=slewlimit; - choice=rint(bm->avgfloat+= slew/vi->rate*samples); - this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - } - - - - /* enforce min(if used) on the current floater (if used) */ - if(bm->min_bitsper>0){ - /* do we need to force the bitrate up? */ - if(this_bitsminmax_reservoir-(min_target_bits-this_bits)<0){ - choice++; - if(choice>=PACKETBLOBS)break; - this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - } - } - } - - /* enforce max (if used) on the current floater (if used) */ - if(bm->max_bitsper>0){ - /* do we need to force the bitrate down? */ - if(this_bits>max_target_bits){ - while(bm->minmax_reservoir+(this_bits-max_target_bits)>bi->reservoir_bits){ - choice--; - if(choice<0)break; - this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - } - } - } - - /* Choice of packetblobs now made based on floater, and min/max - requirements. Now boundary check extreme choices */ - - if(choice<0){ - /* choosing a smaller packetblob is insufficient to trim bitrate. - frame will need to be truncated */ - long maxsize=(max_target_bits+(bi->reservoir_bits-bm->minmax_reservoir))/8; - bm->choice=choice=0; - - if(oggpack_bytes(vbi->packetblob[choice])>maxsize){ - - oggpack_writetrunc(vbi->packetblob[choice],maxsize*8); - this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - } - }else{ - long minsize=(min_target_bits-bm->minmax_reservoir+7)/8; - if(choice>=PACKETBLOBS) - choice=PACKETBLOBS-1; - - bm->choice=choice; - - /* prop up bitrate according to demand. pad this frame out with zeroes */ - minsize-=oggpack_bytes(vbi->packetblob[choice]); - while(minsize-->0)oggpack_write(vbi->packetblob[choice],0,8); - this_bits=oggpack_bytes(vbi->packetblob[choice])*8; - - } - - /* now we have the final packet and the final packet size. Update statistics */ - /* min and max reservoir */ - if(bm->min_bitsper>0 || bm->max_bitsper>0){ - - if(max_target_bits>0 && this_bits>max_target_bits){ - bm->minmax_reservoir+=(this_bits-max_target_bits); - }else if(min_target_bits>0 && this_bitsminmax_reservoir+=(this_bits-min_target_bits); - }else{ - /* inbetween; we want to take reservoir toward but not past desired_fill */ - if(bm->minmax_reservoir>desired_fill){ - if(max_target_bits>0){ /* logical bulletproofing against initialization state */ - bm->minmax_reservoir+=(this_bits-max_target_bits); - if(bm->minmax_reservoirminmax_reservoir=desired_fill; - }else{ - bm->minmax_reservoir=desired_fill; - } - }else{ - if(min_target_bits>0){ /* logical bulletproofing against initialization state */ - bm->minmax_reservoir+=(this_bits-min_target_bits); - if(bm->minmax_reservoir>desired_fill)bm->minmax_reservoir=desired_fill; - }else{ - bm->minmax_reservoir=desired_fill; - } - } - } - } - - /* avg reservoir */ - if(bm->avg_bitsper>0){ - long avg_target_bits=(vb->W?bm->avg_bitsper*bm->short_per_long:bm->avg_bitsper); - bm->avg_reservoir+=this_bits-avg_target_bits; - } - - return(0); -} - -int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd,ogg_packet *op){ - private_state *b=vd->backend_state; - bitrate_manager_state *bm=&b->bms; - vorbis_block *vb=bm->vb; - int choice=PACKETBLOBS/2; - if(!vb)return 0; - - if(op){ - vorbis_block_internal *vbi=vb->internal; - - if(vorbis_bitrate_managed(vb)) - choice=bm->choice; - - op->packet=oggpack_get_buffer(vbi->packetblob[choice]); - op->bytes=oggpack_bytes(vbi->packetblob[choice]); - op->b_o_s=0; - op->e_o_s=vb->eofflag; - op->granulepos=vb->granulepos; - op->packetno=vb->sequence; /* for sake of completeness */ - } - - bm->vb=0; - return(1); -} diff --git a/src/lib/vorbis/src/bitrate.h b/src/lib/vorbis/src/bitrate.h deleted file mode 100644 index 48fa1505..00000000 --- a/src/lib/vorbis/src/bitrate.h +++ /dev/null @@ -1,58 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: bitrate tracking and management - - ********************************************************************/ - -#ifndef _V_BITRATE_H_ -#define _V_BITRATE_H_ - -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "os.h" - -/* encode side bitrate tracking */ -typedef struct bitrate_manager_state { - int managed; - - long avg_reservoir; - long minmax_reservoir; - long avg_bitsper; - long min_bitsper; - long max_bitsper; - - long short_per_long; - double avgfloat; - - vorbis_block *vb; - int choice; -} bitrate_manager_state; - -typedef struct bitrate_manager_info{ - long avg_rate; - long min_rate; - long max_rate; - long reservoir_bits; - double reservoir_bias; - - double slew_damp; - -} bitrate_manager_info; - -extern void vorbis_bitrate_init(vorbis_info *vi,bitrate_manager_state *bs); -extern void vorbis_bitrate_clear(bitrate_manager_state *bs); -extern int vorbis_bitrate_managed(vorbis_block *vb); -extern int vorbis_bitrate_addblock(vorbis_block *vb); -extern int vorbis_bitrate_flushpacket(vorbis_dsp_state *vd, ogg_packet *op); - -#endif diff --git a/src/lib/vorbis/src/block.c b/src/lib/vorbis/src/block.c deleted file mode 100644 index 6a50da08..00000000 --- a/src/lib/vorbis/src/block.c +++ /dev/null @@ -1,1046 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: PCM data vector blocking, windowing and dis/reassembly - - Handle windowing, overlap-add, etc of the PCM vectors. This is made - more amusing by Vorbis' current two allowed block sizes. - - ********************************************************************/ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" - -#include "window.h" -#include "mdct.h" -#include "lpc.h" -#include "registry.h" -#include "misc.h" - -/* pcm accumulator examples (not exhaustive): - - <-------------- lW ----------------> - <--------------- W ----------------> -: .....|..... _______________ | -: .''' | '''_--- | |\ | -:.....''' |_____--- '''......| | \_______| -:.................|__________________|_______|__|______| - |<------ Sl ------>| > Sr < |endW - |beginSl |endSl | |endSr - |beginW |endlW |beginSr - - - |< lW >| - <--------------- W ----------------> - | | .. ______________ | - | | ' `/ | ---_ | - |___.'___/`. | ---_____| - |_______|__|_______|_________________| - | >|Sl|< |<------ Sr ----->|endW - | | |endSl |beginSr |endSr - |beginW | |endlW - mult[0] |beginSl mult[n] - - <-------------- lW -----------------> - |<--W-->| -: .............. ___ | | -: .''' |`/ \ | | -:.....''' |/`....\|...| -:.........................|___|___|___| - |Sl |Sr |endW - | | |endSr - | |beginSr - | |endSl - |beginSl - |beginW -*/ - -/* block abstraction setup *********************************************/ - -#ifndef WORD_ALIGN -#define WORD_ALIGN 8 -#endif - -int vorbis_block_init(vorbis_dsp_state *v, vorbis_block *vb){ - int i; - memset(vb,0,sizeof(*vb)); - vb->vd=v; - vb->localalloc=0; - vb->localstore=NULL; - if(v->analysisp){ - vorbis_block_internal *vbi= - vb->internal=_ogg_calloc(1,sizeof(vorbis_block_internal)); - vbi->ampmax=-9999; - - for(i=0;ipacketblob[i]=&vb->opb; - }else{ - vbi->packetblob[i]= - _ogg_calloc(1,sizeof(oggpack_buffer)); - } - oggpack_writeinit(vbi->packetblob[i]); - } - } - - return(0); -} - -void *_vorbis_block_alloc(vorbis_block *vb,long bytes){ - bytes=(bytes+(WORD_ALIGN-1)) & ~(WORD_ALIGN-1); - if(bytes+vb->localtop>vb->localalloc){ - /* can't just _ogg_realloc... there are outstanding pointers */ - if(vb->localstore){ - struct alloc_chain *link=_ogg_malloc(sizeof(*link)); - vb->totaluse+=vb->localtop; - link->next=vb->reap; - link->ptr=vb->localstore; - vb->reap=link; - } - /* highly conservative */ - vb->localalloc=bytes; - vb->localstore=_ogg_malloc(vb->localalloc); - vb->localtop=0; - } - { - void *ret=(void *)(((char *)vb->localstore)+vb->localtop); - vb->localtop+=bytes; - return ret; - } -} - -/* reap the chain, pull the ripcord */ -void _vorbis_block_ripcord(vorbis_block *vb){ - /* reap the chain */ - struct alloc_chain *reap=vb->reap; - while(reap){ - struct alloc_chain *next=reap->next; - _ogg_free(reap->ptr); - memset(reap,0,sizeof(*reap)); - _ogg_free(reap); - reap=next; - } - /* consolidate storage */ - if(vb->totaluse){ - vb->localstore=_ogg_realloc(vb->localstore,vb->totaluse+vb->localalloc); - vb->localalloc+=vb->totaluse; - vb->totaluse=0; - } - - /* pull the ripcord */ - vb->localtop=0; - vb->reap=NULL; -} - -int vorbis_block_clear(vorbis_block *vb){ - int i; - vorbis_block_internal *vbi=vb->internal; - - _vorbis_block_ripcord(vb); - if(vb->localstore)_ogg_free(vb->localstore); - - if(vbi){ - for(i=0;ipacketblob[i]); - if(i!=PACKETBLOBS/2)_ogg_free(vbi->packetblob[i]); - } - _ogg_free(vbi); - } - memset(vb,0,sizeof(*vb)); - return(0); -} - -/* Analysis side code, but directly related to blocking. Thus it's - here and not in analysis.c (which is for analysis transforms only). - The init is here because some of it is shared */ - -static int _vds_shared_init(vorbis_dsp_state *v,vorbis_info *vi,int encp){ - int i; - codec_setup_info *ci=vi->codec_setup; - private_state *b=NULL; - int hs; - - if(ci==NULL|| - ci->modes<=0|| - ci->blocksizes[0]<64|| - ci->blocksizes[1]blocksizes[0]){ - return 1; - } - hs=ci->halfrate_flag; - - memset(v,0,sizeof(*v)); - b=v->backend_state=_ogg_calloc(1,sizeof(*b)); - - v->vi=vi; - b->modebits=ov_ilog(ci->modes-1); - - b->transform[0]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[0])); - b->transform[1]=_ogg_calloc(VI_TRANSFORMB,sizeof(*b->transform[1])); - - /* MDCT is tranform 0 */ - - b->transform[0][0]=_ogg_calloc(1,sizeof(mdct_lookup)); - b->transform[1][0]=_ogg_calloc(1,sizeof(mdct_lookup)); - mdct_init(b->transform[0][0],ci->blocksizes[0]>>hs); - mdct_init(b->transform[1][0],ci->blocksizes[1]>>hs); - - /* Vorbis I uses only window type 0 */ - /* note that the correct computation below is technically: - b->window[0]=ov_ilog(ci->blocksizes[0]-1)-6; - b->window[1]=ov_ilog(ci->blocksizes[1]-1)-6; - but since blocksizes are always powers of two, - the below is equivalent. - */ - b->window[0]=ov_ilog(ci->blocksizes[0])-7; - b->window[1]=ov_ilog(ci->blocksizes[1])-7; - - if(encp){ /* encode/decode differ here */ - - /* analysis always needs an fft */ - drft_init(&b->fft_look[0],ci->blocksizes[0]); - drft_init(&b->fft_look[1],ci->blocksizes[1]); - - /* finish the codebooks */ - if(!ci->fullbooks){ - ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); - for(i=0;ibooks;i++) - vorbis_book_init_encode(ci->fullbooks+i,ci->book_param[i]); - } - - b->psy=_ogg_calloc(ci->psys,sizeof(*b->psy)); - for(i=0;ipsys;i++){ - _vp_psy_init(b->psy+i, - ci->psy_param[i], - &ci->psy_g_param, - ci->blocksizes[ci->psy_param[i]->blockflag]/2, - vi->rate); - } - - v->analysisp=1; - }else{ - /* finish the codebooks */ - if(!ci->fullbooks){ - ci->fullbooks=_ogg_calloc(ci->books,sizeof(*ci->fullbooks)); - for(i=0;ibooks;i++){ - if(ci->book_param[i]==NULL) - goto abort_books; - if(vorbis_book_init_decode(ci->fullbooks+i,ci->book_param[i])) - goto abort_books; - /* decode codebooks are now standalone after init */ - vorbis_staticbook_destroy(ci->book_param[i]); - ci->book_param[i]=NULL; - } - } - } - - /* initialize the storage vectors. blocksize[1] is small for encode, - but the correct size for decode */ - v->pcm_storage=ci->blocksizes[1]; - v->pcm=_ogg_malloc(vi->channels*sizeof(*v->pcm)); - v->pcmret=_ogg_malloc(vi->channels*sizeof(*v->pcmret)); - { - int i; - for(i=0;ichannels;i++) - v->pcm[i]=_ogg_calloc(v->pcm_storage,sizeof(*v->pcm[i])); - } - - /* all 1 (large block) or 0 (small block) */ - /* explicitly set for the sake of clarity */ - v->lW=0; /* previous window size */ - v->W=0; /* current window size */ - - /* all vector indexes */ - v->centerW=ci->blocksizes[1]/2; - - v->pcm_current=v->centerW; - - /* initialize all the backend lookups */ - b->flr=_ogg_calloc(ci->floors,sizeof(*b->flr)); - b->residue=_ogg_calloc(ci->residues,sizeof(*b->residue)); - - for(i=0;ifloors;i++) - b->flr[i]=_floor_P[ci->floor_type[i]]-> - look(v,ci->floor_param[i]); - - for(i=0;iresidues;i++) - b->residue[i]=_residue_P[ci->residue_type[i]]-> - look(v,ci->residue_param[i]); - - return 0; - abort_books: - for(i=0;ibooks;i++){ - if(ci->book_param[i]!=NULL){ - vorbis_staticbook_destroy(ci->book_param[i]); - ci->book_param[i]=NULL; - } - } - vorbis_dsp_clear(v); - return -1; -} - -/* arbitrary settings and spec-mandated numbers get filled in here */ -int vorbis_analysis_init(vorbis_dsp_state *v,vorbis_info *vi){ - private_state *b=NULL; - - if(_vds_shared_init(v,vi,1))return 1; - b=v->backend_state; - b->psy_g_look=_vp_global_look(vi); - - /* Initialize the envelope state storage */ - b->ve=_ogg_calloc(1,sizeof(*b->ve)); - _ve_envelope_init(b->ve,vi); - - vorbis_bitrate_init(vi,&b->bms); - - /* compressed audio packets start after the headers - with sequence number 3 */ - v->sequence=3; - - return(0); -} - -void vorbis_dsp_clear(vorbis_dsp_state *v){ - int i; - if(v){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=(vi?vi->codec_setup:NULL); - private_state *b=v->backend_state; - - if(b){ - - if(b->ve){ - _ve_envelope_clear(b->ve); - _ogg_free(b->ve); - } - - if(b->transform[0]){ - mdct_clear(b->transform[0][0]); - _ogg_free(b->transform[0][0]); - _ogg_free(b->transform[0]); - } - if(b->transform[1]){ - mdct_clear(b->transform[1][0]); - _ogg_free(b->transform[1][0]); - _ogg_free(b->transform[1]); - } - - if(b->flr){ - if(ci) - for(i=0;ifloors;i++) - _floor_P[ci->floor_type[i]]-> - free_look(b->flr[i]); - _ogg_free(b->flr); - } - if(b->residue){ - if(ci) - for(i=0;iresidues;i++) - _residue_P[ci->residue_type[i]]-> - free_look(b->residue[i]); - _ogg_free(b->residue); - } - if(b->psy){ - if(ci) - for(i=0;ipsys;i++) - _vp_psy_clear(b->psy+i); - _ogg_free(b->psy); - } - - if(b->psy_g_look)_vp_global_free(b->psy_g_look); - vorbis_bitrate_clear(&b->bms); - - drft_clear(&b->fft_look[0]); - drft_clear(&b->fft_look[1]); - - } - - if(v->pcm){ - if(vi) - for(i=0;ichannels;i++) - if(v->pcm[i])_ogg_free(v->pcm[i]); - _ogg_free(v->pcm); - if(v->pcmret)_ogg_free(v->pcmret); - } - - if(b){ - /* free header, header1, header2 */ - if(b->header)_ogg_free(b->header); - if(b->header1)_ogg_free(b->header1); - if(b->header2)_ogg_free(b->header2); - _ogg_free(b); - } - - memset(v,0,sizeof(*v)); - } -} - -float **vorbis_analysis_buffer(vorbis_dsp_state *v, int vals){ - int i; - vorbis_info *vi=v->vi; - private_state *b=v->backend_state; - - /* free header, header1, header2 */ - if(b->header)_ogg_free(b->header);b->header=NULL; - if(b->header1)_ogg_free(b->header1);b->header1=NULL; - if(b->header2)_ogg_free(b->header2);b->header2=NULL; - - /* Do we have enough storage space for the requested buffer? If not, - expand the PCM (and envelope) storage */ - - if(v->pcm_current+vals>=v->pcm_storage){ - v->pcm_storage=v->pcm_current+vals*2; - - for(i=0;ichannels;i++){ - v->pcm[i]=_ogg_realloc(v->pcm[i],v->pcm_storage*sizeof(*v->pcm[i])); - } - } - - for(i=0;ichannels;i++) - v->pcmret[i]=v->pcm[i]+v->pcm_current; - - return(v->pcmret); -} - -static void _preextrapolate_helper(vorbis_dsp_state *v){ - int i; - int order=16; - float *lpc=alloca(order*sizeof(*lpc)); - float *work=alloca(v->pcm_current*sizeof(*work)); - long j; - v->preextrapolate=1; - - if(v->pcm_current-v->centerW>order*2){ /* safety */ - for(i=0;ivi->channels;i++){ - /* need to run the extrapolation in reverse! */ - for(j=0;jpcm_current;j++) - work[j]=v->pcm[i][v->pcm_current-j-1]; - - /* prime as above */ - vorbis_lpc_from_data(work,lpc,v->pcm_current-v->centerW,order); - -#if 0 - if(v->vi->channels==2){ - if(i==0) - _analysis_output("predataL",0,work,v->pcm_current-v->centerW,0,0,0); - else - _analysis_output("predataR",0,work,v->pcm_current-v->centerW,0,0,0); - }else{ - _analysis_output("predata",0,work,v->pcm_current-v->centerW,0,0,0); - } -#endif - - /* run the predictor filter */ - vorbis_lpc_predict(lpc,work+v->pcm_current-v->centerW-order, - order, - work+v->pcm_current-v->centerW, - v->centerW); - - for(j=0;jpcm_current;j++) - v->pcm[i][v->pcm_current-j-1]=work[j]; - - } - } -} - - -/* call with val<=0 to set eof */ - -int vorbis_analysis_wrote(vorbis_dsp_state *v, int vals){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - - if(vals<=0){ - int order=32; - int i; - float *lpc=alloca(order*sizeof(*lpc)); - - /* if it wasn't done earlier (very short sample) */ - if(!v->preextrapolate) - _preextrapolate_helper(v); - - /* We're encoding the end of the stream. Just make sure we have - [at least] a few full blocks of zeroes at the end. */ - /* actually, we don't want zeroes; that could drop a large - amplitude off a cliff, creating spread spectrum noise that will - suck to encode. Extrapolate for the sake of cleanliness. */ - - vorbis_analysis_buffer(v,ci->blocksizes[1]*3); - v->eofflag=v->pcm_current; - v->pcm_current+=ci->blocksizes[1]*3; - - for(i=0;ichannels;i++){ - if(v->eofflag>order*2){ - /* extrapolate with LPC to fill in */ - long n; - - /* make a predictor filter */ - n=v->eofflag; - if(n>ci->blocksizes[1])n=ci->blocksizes[1]; - vorbis_lpc_from_data(v->pcm[i]+v->eofflag-n,lpc,n,order); - - /* run the predictor filter */ - vorbis_lpc_predict(lpc,v->pcm[i]+v->eofflag-order,order, - v->pcm[i]+v->eofflag,v->pcm_current-v->eofflag); - }else{ - /* not enough data to extrapolate (unlikely to happen due to - guarding the overlap, but bulletproof in case that - assumtion goes away). zeroes will do. */ - memset(v->pcm[i]+v->eofflag,0, - (v->pcm_current-v->eofflag)*sizeof(*v->pcm[i])); - - } - } - }else{ - - if(v->pcm_current+vals>v->pcm_storage) - return(OV_EINVAL); - - v->pcm_current+=vals; - - /* we may want to reverse extrapolate the beginning of a stream - too... in case we're beginning on a cliff! */ - /* clumsy, but simple. It only runs once, so simple is good. */ - if(!v->preextrapolate && v->pcm_current-v->centerW>ci->blocksizes[1]) - _preextrapolate_helper(v); - - } - return(0); -} - -/* do the deltas, envelope shaping, pre-echo and determine the size of - the next block on which to continue analysis */ -int vorbis_analysis_blockout(vorbis_dsp_state *v,vorbis_block *vb){ - int i; - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - private_state *b=v->backend_state; - vorbis_look_psy_global *g=b->psy_g_look; - long beginW=v->centerW-ci->blocksizes[v->W]/2,centerNext; - vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; - - /* check to see if we're started... */ - if(!v->preextrapolate)return(0); - - /* check to see if we're done... */ - if(v->eofflag==-1)return(0); - - /* By our invariant, we have lW, W and centerW set. Search for - the next boundary so we can determine nW (the next window size) - which lets us compute the shape of the current block's window */ - - /* we do an envelope search even on a single blocksize; we may still - be throwing more bits at impulses, and envelope search handles - marking impulses too. */ - { - long bp=_ve_envelope_search(v); - if(bp==-1){ - - if(v->eofflag==0)return(0); /* not enough data currently to search for a - full long block */ - v->nW=0; - }else{ - - if(ci->blocksizes[0]==ci->blocksizes[1]) - v->nW=0; - else - v->nW=bp; - } - } - - centerNext=v->centerW+ci->blocksizes[v->W]/4+ci->blocksizes[v->nW]/4; - - { - /* center of next block + next block maximum right side. */ - - long blockbound=centerNext+ci->blocksizes[v->nW]/2; - if(v->pcm_currentlW=v->lW; - vb->W=v->W; - vb->nW=v->nW; - - if(v->W){ - if(!v->lW || !v->nW){ - vbi->blocktype=BLOCKTYPE_TRANSITION; - /*fprintf(stderr,"-");*/ - }else{ - vbi->blocktype=BLOCKTYPE_LONG; - /*fprintf(stderr,"_");*/ - } - }else{ - if(_ve_envelope_mark(v)){ - vbi->blocktype=BLOCKTYPE_IMPULSE; - /*fprintf(stderr,"|");*/ - - }else{ - vbi->blocktype=BLOCKTYPE_PADDING; - /*fprintf(stderr,".");*/ - - } - } - - vb->vd=v; - vb->sequence=v->sequence++; - vb->granulepos=v->granulepos; - vb->pcmend=ci->blocksizes[v->W]; - - /* copy the vectors; this uses the local storage in vb */ - - /* this tracks 'strongest peak' for later psychoacoustics */ - /* moved to the global psy state; clean this mess up */ - if(vbi->ampmax>g->ampmax)g->ampmax=vbi->ampmax; - g->ampmax=_vp_ampmax_decay(g->ampmax,v); - vbi->ampmax=g->ampmax; - - vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels); - vbi->pcmdelay=_vorbis_block_alloc(vb,sizeof(*vbi->pcmdelay)*vi->channels); - for(i=0;ichannels;i++){ - vbi->pcmdelay[i]= - _vorbis_block_alloc(vb,(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i])); - memcpy(vbi->pcmdelay[i],v->pcm[i],(vb->pcmend+beginW)*sizeof(*vbi->pcmdelay[i])); - vb->pcm[i]=vbi->pcmdelay[i]+beginW; - - /* before we added the delay - vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i])); - memcpy(vb->pcm[i],v->pcm[i]+beginW,ci->blocksizes[v->W]*sizeof(*vb->pcm[i])); - */ - - } - - /* handle eof detection: eof==0 means that we've not yet received EOF - eof>0 marks the last 'real' sample in pcm[] - eof<0 'no more to do'; doesn't get here */ - - if(v->eofflag){ - if(v->centerW>=v->eofflag){ - v->eofflag=-1; - vb->eofflag=1; - return(1); - } - } - - /* advance storage vectors and clean up */ - { - int new_centerNext=ci->blocksizes[1]/2; - int movementW=centerNext-new_centerNext; - - if(movementW>0){ - - _ve_envelope_shift(b->ve,movementW); - v->pcm_current-=movementW; - - for(i=0;ichannels;i++) - memmove(v->pcm[i],v->pcm[i]+movementW, - v->pcm_current*sizeof(*v->pcm[i])); - - - v->lW=v->W; - v->W=v->nW; - v->centerW=new_centerNext; - - if(v->eofflag){ - v->eofflag-=movementW; - if(v->eofflag<=0)v->eofflag=-1; - /* do not add padding to end of stream! */ - if(v->centerW>=v->eofflag){ - v->granulepos+=movementW-(v->centerW-v->eofflag); - }else{ - v->granulepos+=movementW; - } - }else{ - v->granulepos+=movementW; - } - } - } - - /* done */ - return(1); -} - -int vorbis_synthesis_restart(vorbis_dsp_state *v){ - vorbis_info *vi=v->vi; - codec_setup_info *ci; - int hs; - - if(!v->backend_state)return -1; - if(!vi)return -1; - ci=vi->codec_setup; - if(!ci)return -1; - hs=ci->halfrate_flag; - - v->centerW=ci->blocksizes[1]>>(hs+1); - v->pcm_current=v->centerW>>hs; - - v->pcm_returned=-1; - v->granulepos=-1; - v->sequence=-1; - v->eofflag=0; - ((private_state *)(v->backend_state))->sample_count=-1; - - return(0); -} - -int vorbis_synthesis_init(vorbis_dsp_state *v,vorbis_info *vi){ - if(_vds_shared_init(v,vi,0)){ - vorbis_dsp_clear(v); - return 1; - } - vorbis_synthesis_restart(v); - return 0; -} - -/* Unlike in analysis, the window is only partially applied for each - block. The time domain envelope is not yet handled at the point of - calling (as it relies on the previous block). */ - -int vorbis_synthesis_blockin(vorbis_dsp_state *v,vorbis_block *vb){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - private_state *b=v->backend_state; - int hs=ci->halfrate_flag; - int i,j; - - if(!vb)return(OV_EINVAL); - if(v->pcm_current>v->pcm_returned && v->pcm_returned!=-1)return(OV_EINVAL); - - v->lW=v->W; - v->W=vb->W; - v->nW=-1; - - if((v->sequence==-1)|| - (v->sequence+1 != vb->sequence)){ - v->granulepos=-1; /* out of sequence; lose count */ - b->sample_count=-1; - } - - v->sequence=vb->sequence; - - if(vb->pcm){ /* no pcm to process if vorbis_synthesis_trackonly - was called on block */ - int n=ci->blocksizes[v->W]>>(hs+1); - int n0=ci->blocksizes[0]>>(hs+1); - int n1=ci->blocksizes[1]>>(hs+1); - - int thisCenter; - int prevCenter; - - v->glue_bits+=vb->glue_bits; - v->time_bits+=vb->time_bits; - v->floor_bits+=vb->floor_bits; - v->res_bits+=vb->res_bits; - - if(v->centerW){ - thisCenter=n1; - prevCenter=0; - }else{ - thisCenter=0; - prevCenter=n1; - } - - /* v->pcm is now used like a two-stage double buffer. We don't want - to have to constantly shift *or* adjust memory usage. Don't - accept a new block until the old is shifted out */ - - for(j=0;jchannels;j++){ - /* the overlap/add section */ - if(v->lW){ - if(v->W){ - /* large/large */ - const float *w=_vorbis_window_get(b->window[1]-hs); - float *pcm=v->pcm[j]+prevCenter; - float *p=vb->pcm[j]; - for(i=0;iwindow[0]-hs); - float *pcm=v->pcm[j]+prevCenter+n1/2-n0/2; - float *p=vb->pcm[j]; - for(i=0;iW){ - /* small/large */ - const float *w=_vorbis_window_get(b->window[0]-hs); - float *pcm=v->pcm[j]+prevCenter; - float *p=vb->pcm[j]+n1/2-n0/2; - for(i=0;iwindow[0]-hs); - float *pcm=v->pcm[j]+prevCenter; - float *p=vb->pcm[j]; - for(i=0;ipcm[j]+thisCenter; - float *p=vb->pcm[j]+n; - for(i=0;icenterW) - v->centerW=0; - else - v->centerW=n1; - - /* deal with initial packet state; we do this using the explicit - pcm_returned==-1 flag otherwise we're sensitive to first block - being short or long */ - - if(v->pcm_returned==-1){ - v->pcm_returned=thisCenter; - v->pcm_current=thisCenter; - }else{ - v->pcm_returned=prevCenter; - v->pcm_current=prevCenter+ - ((ci->blocksizes[v->lW]/4+ - ci->blocksizes[v->W]/4)>>hs); - } - - } - - /* track the frame number... This is for convenience, but also - making sure our last packet doesn't end with added padding. If - the last packet is partial, the number of samples we'll have to - return will be past the vb->granulepos. - - This is not foolproof! It will be confused if we begin - decoding at the last page after a seek or hole. In that case, - we don't have a starting point to judge where the last frame - is. For this reason, vorbisfile will always try to make sure - it reads the last two marked pages in proper sequence */ - - if(b->sample_count==-1){ - b->sample_count=0; - }else{ - b->sample_count+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; - } - - if(v->granulepos==-1){ - if(vb->granulepos!=-1){ /* only set if we have a position to set to */ - - v->granulepos=vb->granulepos; - - /* is this a short page? */ - if(b->sample_count>v->granulepos){ - /* corner case; if this is both the first and last audio page, - then spec says the end is cut, not beginning */ - long extra=b->sample_count-vb->granulepos; - - /* we use ogg_int64_t for granule positions because a - uint64 isn't universally available. Unfortunately, - that means granposes can be 'negative' and result in - extra being negative */ - if(extra<0) - extra=0; - - if(vb->eofflag){ - /* trim the end */ - /* no preceding granulepos; assume we started at zero (we'd - have to in a short single-page stream) */ - /* granulepos could be -1 due to a seek, but that would result - in a long count, not short count */ - - /* Guard against corrupt/malicious frames that set EOP and - a backdated granpos; don't rewind more samples than we - actually have */ - if(extra > (v->pcm_current - v->pcm_returned)<pcm_current - v->pcm_returned)<pcm_current-=extra>>hs; - }else{ - /* trim the beginning */ - v->pcm_returned+=extra>>hs; - if(v->pcm_returned>v->pcm_current) - v->pcm_returned=v->pcm_current; - } - - } - - } - }else{ - v->granulepos+=ci->blocksizes[v->lW]/4+ci->blocksizes[v->W]/4; - if(vb->granulepos!=-1 && v->granulepos!=vb->granulepos){ - - if(v->granulepos>vb->granulepos){ - long extra=v->granulepos-vb->granulepos; - - if(extra) - if(vb->eofflag){ - /* partial last frame. Strip the extra samples off */ - - /* Guard against corrupt/malicious frames that set EOP and - a backdated granpos; don't rewind more samples than we - actually have */ - if(extra > (v->pcm_current - v->pcm_returned)<pcm_current - v->pcm_returned)<pcm_current-=extra>>hs; - } /* else {Shouldn't happen *unless* the bitstream is out of - spec. Either way, believe the bitstream } */ - } /* else {Shouldn't happen *unless* the bitstream is out of - spec. Either way, believe the bitstream } */ - v->granulepos=vb->granulepos; - } - } - - /* Update, cleanup */ - - if(vb->eofflag)v->eofflag=1; - return(0); - -} - -/* pcm==NULL indicates we just want the pending samples, no more */ -int vorbis_synthesis_pcmout(vorbis_dsp_state *v,float ***pcm){ - vorbis_info *vi=v->vi; - - if(v->pcm_returned>-1 && v->pcm_returnedpcm_current){ - if(pcm){ - int i; - for(i=0;ichannels;i++) - v->pcmret[i]=v->pcm[i]+v->pcm_returned; - *pcm=v->pcmret; - } - return(v->pcm_current-v->pcm_returned); - } - return(0); -} - -int vorbis_synthesis_read(vorbis_dsp_state *v,int n){ - if(n && v->pcm_returned+n>v->pcm_current)return(OV_EINVAL); - v->pcm_returned+=n; - return(0); -} - -/* intended for use with a specific vorbisfile feature; we want access - to the [usually synthetic/postextrapolated] buffer and lapping at - the end of a decode cycle, specifically, a half-short-block worth. - This funtion works like pcmout above, except it will also expose - this implicit buffer data not normally decoded. */ -int vorbis_synthesis_lapout(vorbis_dsp_state *v,float ***pcm){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - int hs=ci->halfrate_flag; - - int n=ci->blocksizes[v->W]>>(hs+1); - int n0=ci->blocksizes[0]>>(hs+1); - int n1=ci->blocksizes[1]>>(hs+1); - int i,j; - - if(v->pcm_returned<0)return 0; - - /* our returned data ends at pcm_returned; because the synthesis pcm - buffer is a two-fragment ring, that means our data block may be - fragmented by buffering, wrapping or a short block not filling - out a buffer. To simplify things, we unfragment if it's at all - possibly needed. Otherwise, we'd need to call lapout more than - once as well as hold additional dsp state. Opt for - simplicity. */ - - /* centerW was advanced by blockin; it would be the center of the - *next* block */ - if(v->centerW==n1){ - /* the data buffer wraps; swap the halves */ - /* slow, sure, small */ - for(j=0;jchannels;j++){ - float *p=v->pcm[j]; - for(i=0;ipcm_current-=n1; - v->pcm_returned-=n1; - v->centerW=0; - } - - /* solidify buffer into contiguous space */ - if((v->lW^v->W)==1){ - /* long/short or short/long */ - for(j=0;jchannels;j++){ - float *s=v->pcm[j]; - float *d=v->pcm[j]+(n1-n0)/2; - for(i=(n1+n0)/2-1;i>=0;--i) - d[i]=s[i]; - } - v->pcm_returned+=(n1-n0)/2; - v->pcm_current+=(n1-n0)/2; - }else{ - if(v->lW==0){ - /* short/short */ - for(j=0;jchannels;j++){ - float *s=v->pcm[j]; - float *d=v->pcm[j]+n1-n0; - for(i=n0-1;i>=0;--i) - d[i]=s[i]; - } - v->pcm_returned+=n1-n0; - v->pcm_current+=n1-n0; - } - } - - if(pcm){ - int i; - for(i=0;ichannels;i++) - v->pcmret[i]=v->pcm[i]+v->pcm_returned; - *pcm=v->pcmret; - } - - return(n1+n-v->pcm_returned); - -} - -const float *vorbis_window(vorbis_dsp_state *v,int W){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - int hs=ci->halfrate_flag; - private_state *b=v->backend_state; - - if(b->window[W]-1<0)return NULL; - return _vorbis_window_get(b->window[W]-hs); -} diff --git a/src/lib/vorbis/src/codebook.c b/src/lib/vorbis/src/codebook.c deleted file mode 100644 index 7a0c2067..00000000 --- a/src/lib/vorbis/src/codebook.c +++ /dev/null @@ -1,461 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: basic codebook pack/unpack/code/decode operations - - ********************************************************************/ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codebook.h" -#include "scales.h" -#include "misc.h" -#include "os.h" - -/* packs the given codebook into the bitstream **************************/ - -int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *opb){ - long i,j; - int ordered=0; - - /* first the basic parameters */ - oggpack_write(opb,0x564342,24); - oggpack_write(opb,c->dim,16); - oggpack_write(opb,c->entries,24); - - /* pack the codewords. There are two packings; length ordered and - length random. Decide between the two now. */ - - for(i=1;ientries;i++) - if(c->lengthlist[i-1]==0 || c->lengthlist[i]lengthlist[i-1])break; - if(i==c->entries)ordered=1; - - if(ordered){ - /* length ordered. We only need to say how many codewords of - each length. The actual codewords are generated - deterministically */ - - long count=0; - oggpack_write(opb,1,1); /* ordered */ - oggpack_write(opb,c->lengthlist[0]-1,5); /* 1 to 32 */ - - for(i=1;ientries;i++){ - char this=c->lengthlist[i]; - char last=c->lengthlist[i-1]; - if(this>last){ - for(j=last;jentries-count)); - count=i; - } - } - } - oggpack_write(opb,i-count,ov_ilog(c->entries-count)); - - }else{ - /* length random. Again, we don't code the codeword itself, just - the length. This time, though, we have to encode each length */ - oggpack_write(opb,0,1); /* unordered */ - - /* algortihmic mapping has use for 'unused entries', which we tag - here. The algorithmic mapping happens as usual, but the unused - entry has no codeword. */ - for(i=0;ientries;i++) - if(c->lengthlist[i]==0)break; - - if(i==c->entries){ - oggpack_write(opb,0,1); /* no unused entries */ - for(i=0;ientries;i++) - oggpack_write(opb,c->lengthlist[i]-1,5); - }else{ - oggpack_write(opb,1,1); /* we have unused entries; thus we tag */ - for(i=0;ientries;i++){ - if(c->lengthlist[i]==0){ - oggpack_write(opb,0,1); - }else{ - oggpack_write(opb,1,1); - oggpack_write(opb,c->lengthlist[i]-1,5); - } - } - } - } - - /* is the entry number the desired return value, or do we have a - mapping? If we have a mapping, what type? */ - oggpack_write(opb,c->maptype,4); - switch(c->maptype){ - case 0: - /* no mapping */ - break; - case 1:case 2: - /* implicitly populated value mapping */ - /* explicitly populated value mapping */ - - if(!c->quantlist){ - /* no quantlist? error */ - return(-1); - } - - /* values that define the dequantization */ - oggpack_write(opb,c->q_min,32); - oggpack_write(opb,c->q_delta,32); - oggpack_write(opb,c->q_quant-1,4); - oggpack_write(opb,c->q_sequencep,1); - - { - int quantvals; - switch(c->maptype){ - case 1: - /* a single column of (c->entries/c->dim) quantized values for - building a full value list algorithmically (square lattice) */ - quantvals=_book_maptype1_quantvals(c); - break; - case 2: - /* every value (c->entries*c->dim total) specified explicitly */ - quantvals=c->entries*c->dim; - break; - default: /* NOT_REACHABLE */ - quantvals=-1; - } - - /* quantized values */ - for(i=0;iquantlist[i]),c->q_quant); - - } - break; - default: - /* error case; we don't have any other map types now */ - return(-1); - } - - return(0); -} - -/* unpacks a codebook from the packet buffer into the codebook struct, - readies the codebook auxiliary structures for decode *************/ -static_codebook *vorbis_staticbook_unpack(oggpack_buffer *opb){ - long i,j; - static_codebook *s=_ogg_calloc(1,sizeof(*s)); - s->allocedp=1; - - /* make sure alignment is correct */ - if(oggpack_read(opb,24)!=0x564342)goto _eofout; - - /* first the basic parameters */ - s->dim=oggpack_read(opb,16); - s->entries=oggpack_read(opb,24); - if(s->entries==-1)goto _eofout; - - if(ov_ilog(s->dim)+ov_ilog(s->entries)>24)goto _eofout; - - /* codeword ordering.... length ordered or unordered? */ - switch((int)oggpack_read(opb,1)){ - case 0:{ - long unused; - /* allocated but unused entries? */ - unused=oggpack_read(opb,1); - if((s->entries*(unused?1:5)+7)>>3>opb->storage-oggpack_bytes(opb)) - goto _eofout; - /* unordered */ - s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries); - - /* allocated but unused entries? */ - if(unused){ - /* yes, unused entries */ - - for(i=0;ientries;i++){ - if(oggpack_read(opb,1)){ - long num=oggpack_read(opb,5); - if(num==-1)goto _eofout; - s->lengthlist[i]=num+1; - }else - s->lengthlist[i]=0; - } - }else{ - /* all entries used; no tagging */ - for(i=0;ientries;i++){ - long num=oggpack_read(opb,5); - if(num==-1)goto _eofout; - s->lengthlist[i]=num+1; - } - } - - break; - } - case 1: - /* ordered */ - { - long length=oggpack_read(opb,5)+1; - if(length==0)goto _eofout; - s->lengthlist=_ogg_malloc(sizeof(*s->lengthlist)*s->entries); - - for(i=0;ientries;){ - long num=oggpack_read(opb,ov_ilog(s->entries-i)); - if(num==-1)goto _eofout; - if(length>32 || num>s->entries-i || - (num>0 && (num-1)>>(length-1)>1)){ - goto _errout; - } - if(length>32)goto _errout; - for(j=0;jlengthlist[i]=length; - length++; - } - } - break; - default: - /* EOF */ - goto _eofout; - } - - /* Do we have a mapping to unpack? */ - switch((s->maptype=oggpack_read(opb,4))){ - case 0: - /* no mapping */ - break; - case 1: case 2: - /* implicitly populated value mapping */ - /* explicitly populated value mapping */ - - s->q_min=oggpack_read(opb,32); - s->q_delta=oggpack_read(opb,32); - s->q_quant=oggpack_read(opb,4)+1; - s->q_sequencep=oggpack_read(opb,1); - if(s->q_sequencep==-1)goto _eofout; - - { - int quantvals=0; - switch(s->maptype){ - case 1: - quantvals=(s->dim==0?0:_book_maptype1_quantvals(s)); - break; - case 2: - quantvals=s->entries*s->dim; - break; - } - - /* quantized values */ - if(((quantvals*s->q_quant+7)>>3)>opb->storage-oggpack_bytes(opb)) - goto _eofout; - s->quantlist=_ogg_malloc(sizeof(*s->quantlist)*quantvals); - for(i=0;iquantlist[i]=oggpack_read(opb,s->q_quant); - - if(quantvals&&s->quantlist[quantvals-1]==-1)goto _eofout; - } - break; - default: - goto _errout; - } - - /* all set */ - return(s); - - _errout: - _eofout: - vorbis_staticbook_destroy(s); - return(NULL); -} - -/* returns the number of bits ************************************************/ -int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b){ - if(a<0 || a>=book->c->entries)return(0); - oggpack_write(b,book->codelist[a],book->c->lengthlist[a]); - return(book->c->lengthlist[a]); -} - -/* the 'eliminate the decode tree' optimization actually requires the - codewords to be MSb first, not LSb. This is an annoying inelegancy - (and one of the first places where carefully thought out design - turned out to be wrong; Vorbis II and future Ogg codecs should go - to an MSb bitpacker), but not actually the huge hit it appears to - be. The first-stage decode table catches most words so that - bitreverse is not in the main execution path. */ - -static ogg_uint32_t bitreverse(ogg_uint32_t x){ - x= ((x>>16)&0x0000ffff) | ((x<<16)&0xffff0000); - x= ((x>> 8)&0x00ff00ff) | ((x<< 8)&0xff00ff00); - x= ((x>> 4)&0x0f0f0f0f) | ((x<< 4)&0xf0f0f0f0); - x= ((x>> 2)&0x33333333) | ((x<< 2)&0xcccccccc); - return((x>> 1)&0x55555555) | ((x<< 1)&0xaaaaaaaa); -} - -STIN long decode_packed_entry_number(codebook *book, oggpack_buffer *b){ - int read=book->dec_maxlength; - long lo,hi; - long lok = oggpack_look(b,book->dec_firsttablen); - - if (lok >= 0) { - long entry = book->dec_firsttable[lok]; - if(entry&0x80000000UL){ - lo=(entry>>15)&0x7fff; - hi=book->used_entries-(entry&0x7fff); - }else{ - oggpack_adv(b, book->dec_codelengths[entry-1]); - return(entry-1); - } - }else{ - lo=0; - hi=book->used_entries; - } - - /* Single entry codebooks use a firsttablen of 1 and a - dec_maxlength of 1. If a single-entry codebook gets here (due to - failure to read one bit above), the next look attempt will also - fail and we'll correctly kick out instead of trying to walk the - underformed tree */ - - lok = oggpack_look(b, read); - - while(lok<0 && read>1) - lok = oggpack_look(b, --read); - if(lok<0)return -1; - - /* bisect search for the codeword in the ordered list */ - { - ogg_uint32_t testword=bitreverse((ogg_uint32_t)lok); - - while(hi-lo>1){ - long p=(hi-lo)>>1; - long test=book->codelist[lo+p]>testword; - lo+=p&(test-1); - hi-=p&(-test); - } - - if(book->dec_codelengths[lo]<=read){ - oggpack_adv(b, book->dec_codelengths[lo]); - return(lo); - } - } - - oggpack_adv(b, read); - - return(-1); -} - -/* Decode side is specced and easier, because we don't need to find - matches using different criteria; we simply read and map. There are - two things we need to do 'depending': - - We may need to support interleave. We don't really, but it's - convenient to do it here rather than rebuild the vector later. - - Cascades may be additive or multiplicitive; this is not inherent in - the codebook, but set in the code using the codebook. Like - interleaving, it's easiest to do it here. - addmul==0 -> declarative (set the value) - addmul==1 -> additive - addmul==2 -> multiplicitive */ - -/* returns the [original, not compacted] entry number or -1 on eof *********/ -long vorbis_book_decode(codebook *book, oggpack_buffer *b){ - if(book->used_entries>0){ - long packed_entry=decode_packed_entry_number(book,b); - if(packed_entry>=0) - return(book->dec_index[packed_entry]); - } - - /* if there's no dec_index, the codebook unpacking isn't collapsed */ - return(-1); -} - -/* returns 0 on OK or -1 on eof *************************************/ -/* decode vector / dim granularity gaurding is done in the upper layer */ -long vorbis_book_decodevs_add(codebook *book,float *a,oggpack_buffer *b,int n){ - if(book->used_entries>0){ - int step=n/book->dim; - long *entry = alloca(sizeof(*entry)*step); - float **t = alloca(sizeof(*t)*step); - int i,j,o; - - for (i = 0; i < step; i++) { - entry[i]=decode_packed_entry_number(book,b); - if(entry[i]==-1)return(-1); - t[i] = book->valuelist+entry[i]*book->dim; - } - for(i=0,o=0;idim;i++,o+=step) - for (j=0;o+jused_entries>0){ - int i,j,entry; - float *t; - - for(i=0;ivaluelist+entry*book->dim; - for(j=0;idim;) - a[i++]+=t[j++]; - } - } - return(0); -} - -/* unlike the others, we guard against n not being an integer number - of internally rather than in the upper layer (called only by - floor0) */ -long vorbis_book_decodev_set(codebook *book,float *a,oggpack_buffer *b,int n){ - if(book->used_entries>0){ - int i,j,entry; - float *t; - - for(i=0;ivaluelist+entry*book->dim; - for (j=0;idim;){ - a[i++]=t[j++]; - } - } - }else{ - int i; - - for(i=0;iused_entries>0){ - int m=(offset+n)/ch; - for(i=offset/ch;ivaluelist+entry*book->dim; - for (j=0;idim;j++){ - a[chptr++][i]+=t[j]; - if(chptr==ch){ - chptr=0; - i++; - } - } - } - } - } - return(0); -} diff --git a/src/lib/vorbis/src/codebook.h b/src/lib/vorbis/src/codebook.h deleted file mode 100644 index 7d4e2aae..00000000 --- a/src/lib/vorbis/src/codebook.h +++ /dev/null @@ -1,117 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: basic shared codebook operations - - ********************************************************************/ - -#ifndef _V_CODEBOOK_H_ -#define _V_CODEBOOK_H_ - -#include - -/* This structure encapsulates huffman and VQ style encoding books; it - doesn't do anything specific to either. - - valuelist/quantlist are nonNULL (and q_* significant) only if - there's entry->value mapping to be done. - - If encode-side mapping must be done (and thus the entry needs to be - hunted), the auxiliary encode pointer will point to a decision - tree. This is true of both VQ and huffman, but is mostly useful - with VQ. - -*/ - -typedef struct static_codebook{ - long dim; /* codebook dimensions (elements per vector) */ - long entries; /* codebook entries */ - char *lengthlist; /* codeword lengths in bits */ - - /* mapping ***************************************************************/ - int maptype; /* 0=none - 1=implicitly populated values from map column - 2=listed arbitrary values */ - - /* The below does a linear, single monotonic sequence mapping. */ - long q_min; /* packed 32 bit float; quant value 0 maps to minval */ - long q_delta; /* packed 32 bit float; val 1 - val 0 == delta */ - int q_quant; /* bits: 0 < quant <= 16 */ - int q_sequencep; /* bitflag */ - - long *quantlist; /* map == 1: (int)(entries^(1/dim)) element column map - map == 2: list of dim*entries quantized entry vals - */ - int allocedp; -} static_codebook; - -typedef struct codebook{ - long dim; /* codebook dimensions (elements per vector) */ - long entries; /* codebook entries */ - long used_entries; /* populated codebook entries */ - const static_codebook *c; - - /* for encode, the below are entry-ordered, fully populated */ - /* for decode, the below are ordered by bitreversed codeword and only - used entries are populated */ - float *valuelist; /* list of dim*entries actual entry values */ - ogg_uint32_t *codelist; /* list of bitstream codewords for each entry */ - - int *dec_index; /* only used if sparseness collapsed */ - char *dec_codelengths; - ogg_uint32_t *dec_firsttable; - int dec_firsttablen; - int dec_maxlength; - - /* The current encoder uses only centered, integer-only lattice books. */ - int quantvals; - int minval; - int delta; -} codebook; - -extern void vorbis_staticbook_destroy(static_codebook *b); -extern int vorbis_book_init_encode(codebook *dest,const static_codebook *source); -extern int vorbis_book_init_decode(codebook *dest,const static_codebook *source); -extern void vorbis_book_clear(codebook *b); - -extern float *_book_unquantize(const static_codebook *b,int n,int *map); -extern float *_book_logdist(const static_codebook *b,float *vals); -extern float _float32_unpack(long val); -extern long _float32_pack(float val); -extern int _best(codebook *book, float *a, int step); -extern long _book_maptype1_quantvals(const static_codebook *b); - -extern int vorbis_book_besterror(codebook *book,float *a,int step,int addmul); -extern long vorbis_book_codeword(codebook *book,int entry); -extern long vorbis_book_codelen(codebook *book,int entry); - - - -extern int vorbis_staticbook_pack(const static_codebook *c,oggpack_buffer *b); -extern static_codebook *vorbis_staticbook_unpack(oggpack_buffer *b); - -extern int vorbis_book_encode(codebook *book, int a, oggpack_buffer *b); - -extern long vorbis_book_decode(codebook *book, oggpack_buffer *b); -extern long vorbis_book_decodevs_add(codebook *book, float *a, - oggpack_buffer *b,int n); -extern long vorbis_book_decodev_set(codebook *book, float *a, - oggpack_buffer *b,int n); -extern long vorbis_book_decodev_add(codebook *book, float *a, - oggpack_buffer *b,int n); -extern long vorbis_book_decodevv_add(codebook *book, float **a, - long off,int ch, - oggpack_buffer *b,int n); - - - -#endif diff --git a/src/lib/vorbis/src/codec_internal.h b/src/lib/vorbis/src/codec_internal.h deleted file mode 100644 index 2ecf5e5c..00000000 --- a/src/lib/vorbis/src/codec_internal.h +++ /dev/null @@ -1,166 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: libvorbis codec headers - - ********************************************************************/ - -#ifndef _V_CODECI_H_ -#define _V_CODECI_H_ - -#include "envelope.h" -#include "codebook.h" - -#define BLOCKTYPE_IMPULSE 0 -#define BLOCKTYPE_PADDING 1 -#define BLOCKTYPE_TRANSITION 0 -#define BLOCKTYPE_LONG 1 - -#define PACKETBLOBS 15 - -typedef struct vorbis_block_internal{ - float **pcmdelay; /* this is a pointer into local storage */ - float ampmax; - int blocktype; - - oggpack_buffer *packetblob[PACKETBLOBS]; /* initialized, must be freed; - blob [PACKETBLOBS/2] points to - the oggpack_buffer in the - main vorbis_block */ -} vorbis_block_internal; - -typedef void vorbis_look_floor; -typedef void vorbis_look_residue; -typedef void vorbis_look_transform; - -/* mode ************************************************************/ -typedef struct { - int blockflag; - int windowtype; - int transformtype; - int mapping; -} vorbis_info_mode; - -typedef void vorbis_info_floor; -typedef void vorbis_info_residue; -typedef void vorbis_info_mapping; - -#include "psy.h" -#include "bitrate.h" - -typedef struct private_state { - /* local lookup storage */ - envelope_lookup *ve; /* envelope lookup */ - int window[2]; - vorbis_look_transform **transform[2]; /* block, type */ - drft_lookup fft_look[2]; - - int modebits; - vorbis_look_floor **flr; - vorbis_look_residue **residue; - vorbis_look_psy *psy; - vorbis_look_psy_global *psy_g_look; - - /* local storage, only used on the encoding side. This way the - application does not need to worry about freeing some packets' - memory and not others'; packet storage is always tracked. - Cleared next call to a _dsp_ function */ - unsigned char *header; - unsigned char *header1; - unsigned char *header2; - - bitrate_manager_state bms; - - ogg_int64_t sample_count; -} private_state; - -/* codec_setup_info contains all the setup information specific to the - specific compression/decompression mode in progress (eg, - psychoacoustic settings, channel setup, options, codebook - etc). -*********************************************************************/ - -#include "highlevel.h" -typedef struct codec_setup_info { - - /* Vorbis supports only short and long blocks, but allows the - encoder to choose the sizes */ - - long blocksizes[2]; - - /* modes are the primary means of supporting on-the-fly different - blocksizes, different channel mappings (LR or M/A), - different residue backends, etc. Each mode consists of a - blocksize flag and a mapping (along with the mapping setup */ - - int modes; - int maps; - int floors; - int residues; - int books; - int psys; /* encode only */ - - vorbis_info_mode *mode_param[64]; - int map_type[64]; - vorbis_info_mapping *map_param[64]; - int floor_type[64]; - vorbis_info_floor *floor_param[64]; - int residue_type[64]; - vorbis_info_residue *residue_param[64]; - static_codebook *book_param[256]; - codebook *fullbooks; - - vorbis_info_psy *psy_param[4]; /* encode only */ - vorbis_info_psy_global psy_g_param; - - bitrate_manager_info bi; - highlevel_encode_setup hi; /* used only by vorbisenc.c. It's a - highly redundant structure, but - improves clarity of program flow. */ - int halfrate_flag; /* painless downsample for decode */ -} codec_setup_info; - -extern vorbis_look_psy_global *_vp_global_look(vorbis_info *vi); -extern void _vp_global_free(vorbis_look_psy_global *look); - - - -typedef struct { - int sorted_index[VIF_POSIT+2]; - int forward_index[VIF_POSIT+2]; - int reverse_index[VIF_POSIT+2]; - - int hineighbor[VIF_POSIT]; - int loneighbor[VIF_POSIT]; - int posts; - - int n; - int quant_q; - vorbis_info_floor1 *vi; - - long phrasebits; - long postbits; - long frames; -} vorbis_look_floor1; - - - -extern int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look, - const float *logmdct, /* in */ - const float *logmask); -extern int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look, - int *A,int *B, - int del); -extern int floor1_encode(oggpack_buffer *opb,vorbis_block *vb, - vorbis_look_floor1 *look, - int *post,int *ilogmask); -#endif diff --git a/src/lib/vorbis/src/envelope.c b/src/lib/vorbis/src/envelope.c deleted file mode 100644 index 22d39aa6..00000000 --- a/src/lib/vorbis/src/envelope.c +++ /dev/null @@ -1,374 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: PCM data envelope analysis - - ********************************************************************/ - -#include -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" - -#include "os.h" -#include "scales.h" -#include "envelope.h" -#include "mdct.h" -#include "misc.h" - -void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi){ - codec_setup_info *ci=vi->codec_setup; - vorbis_info_psy_global *gi=&ci->psy_g_param; - int ch=vi->channels; - int i,j; - int n=e->winlength=128; - e->searchstep=64; /* not random */ - - e->minenergy=gi->preecho_minenergy; - e->ch=ch; - e->storage=128; - e->cursor=ci->blocksizes[1]/2; - e->mdct_win=_ogg_calloc(n,sizeof(*e->mdct_win)); - mdct_init(&e->mdct,n); - - for(i=0;imdct_win[i]=sin(i/(n-1.)*M_PI); - e->mdct_win[i]*=e->mdct_win[i]; - } - - /* magic follows */ - e->band[0].begin=2; e->band[0].end=4; - e->band[1].begin=4; e->band[1].end=5; - e->band[2].begin=6; e->band[2].end=6; - e->band[3].begin=9; e->band[3].end=8; - e->band[4].begin=13; e->band[4].end=8; - e->band[5].begin=17; e->band[5].end=8; - e->band[6].begin=22; e->band[6].end=8; - - for(j=0;jband[j].end; - e->band[j].window=_ogg_malloc(n*sizeof(*e->band[0].window)); - for(i=0;iband[j].window[i]=sin((i+.5)/n*M_PI); - e->band[j].total+=e->band[j].window[i]; - } - e->band[j].total=1./e->band[j].total; - } - - e->filter=_ogg_calloc(VE_BANDS*ch,sizeof(*e->filter)); - e->mark=_ogg_calloc(e->storage,sizeof(*e->mark)); - -} - -void _ve_envelope_clear(envelope_lookup *e){ - int i; - mdct_clear(&e->mdct); - for(i=0;iband[i].window); - _ogg_free(e->mdct_win); - _ogg_free(e->filter); - _ogg_free(e->mark); - memset(e,0,sizeof(*e)); -} - -/* fairly straight threshhold-by-band based until we find something - that works better and isn't patented. */ - -static int _ve_amp(envelope_lookup *ve, - vorbis_info_psy_global *gi, - float *data, - envelope_band *bands, - envelope_filter_state *filters){ - long n=ve->winlength; - int ret=0; - long i,j; - float decay; - - /* we want to have a 'minimum bar' for energy, else we're just - basing blocks on quantization noise that outweighs the signal - itself (for low power signals) */ - - float minV=ve->minenergy; - float *vec=alloca(n*sizeof(*vec)); - - /* stretch is used to gradually lengthen the number of windows - considered prevoius-to-potential-trigger */ - int stretch=max(VE_MINSTRETCH,ve->stretch/2); - float penalty=gi->stretch_penalty-(ve->stretch/2-VE_MINSTRETCH); - if(penalty<0.f)penalty=0.f; - if(penalty>gi->stretch_penalty)penalty=gi->stretch_penalty; - - /*_analysis_output_always("lpcm",seq2,data,n,0,0, - totalshift+pos*ve->searchstep);*/ - - /* window and transform */ - for(i=0;imdct_win[i]; - mdct_forward(&ve->mdct,vec,vec); - - /*_analysis_output_always("mdct",seq2,vec,n/2,0,1,0); */ - - /* near-DC spreading function; this has nothing to do with - psychoacoustics, just sidelobe leakage and window size */ - { - float temp=vec[0]*vec[0]+.7*vec[1]*vec[1]+.2*vec[2]*vec[2]; - int ptr=filters->nearptr; - - /* the accumulation is regularly refreshed from scratch to avoid - floating point creep */ - if(ptr==0){ - decay=filters->nearDC_acc=filters->nearDC_partialacc+temp; - filters->nearDC_partialacc=temp; - }else{ - decay=filters->nearDC_acc+=temp; - filters->nearDC_partialacc+=temp; - } - filters->nearDC_acc-=filters->nearDC[ptr]; - filters->nearDC[ptr]=temp; - - decay*=(1./(VE_NEARDC+1)); - filters->nearptr++; - if(filters->nearptr>=VE_NEARDC)filters->nearptr=0; - decay=todB(&decay)*.5-15.f; - } - - /* perform spreading and limiting, also smooth the spectrum. yes, - the MDCT results in all real coefficients, but it still *behaves* - like real/imaginary pairs */ - for(i=0;i>1]=val; - decay-=8.; - } - - /*_analysis_output_always("spread",seq2++,vec,n/4,0,0,0);*/ - - /* perform preecho/postecho triggering by band */ - for(j=0;j=VE_AMP)filters[j].ampptr=0; - } - - /* look at min/max, decide trigger */ - if(valmax>gi->preecho_thresh[j]+penalty){ - ret|=1; - ret|=4; - } - if(valminpostecho_thresh[j]-penalty)ret|=2; - } - - return(ret); -} - -#if 0 -static int seq=0; -static ogg_int64_t totalshift=-1024; -#endif - -long _ve_envelope_search(vorbis_dsp_state *v){ - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - vorbis_info_psy_global *gi=&ci->psy_g_param; - envelope_lookup *ve=((private_state *)(v->backend_state))->ve; - long i,j; - - int first=ve->current/ve->searchstep; - int last=v->pcm_current/ve->searchstep-VE_WIN; - if(first<0)first=0; - - /* make sure we have enough storage to match the PCM */ - if(last+VE_WIN+VE_POST>ve->storage){ - ve->storage=last+VE_WIN+VE_POST; /* be sure */ - ve->mark=_ogg_realloc(ve->mark,ve->storage*sizeof(*ve->mark)); - } - - for(j=first;jstretch++; - if(ve->stretch>VE_MAXSTRETCH*2) - ve->stretch=VE_MAXSTRETCH*2; - - for(i=0;ich;i++){ - float *pcm=v->pcm[i]+ve->searchstep*(j); - ret|=_ve_amp(ve,gi,pcm,ve->band,ve->filter+i*VE_BANDS); - } - - ve->mark[j+VE_POST]=0; - if(ret&1){ - ve->mark[j]=1; - ve->mark[j+1]=1; - } - - if(ret&2){ - ve->mark[j]=1; - if(j>0)ve->mark[j-1]=1; - } - - if(ret&4)ve->stretch=-1; - } - - ve->current=last*ve->searchstep; - - { - long centerW=v->centerW; - long testW= - centerW+ - ci->blocksizes[v->W]/4+ - ci->blocksizes[1]/2+ - ci->blocksizes[0]/4; - - j=ve->cursor; - - while(jcurrent-(ve->searchstep)){/* account for postecho - working back one window */ - if(j>=testW)return(1); - - ve->cursor=j; - - if(ve->mark[j/ve->searchstep]){ - if(j>centerW){ - -#if 0 - if(j>ve->curmark){ - float *marker=alloca(v->pcm_current*sizeof(*marker)); - int l,m; - memset(marker,0,sizeof(*marker)*v->pcm_current); - fprintf(stderr,"mark! seq=%d, cursor:%fs time:%fs\n", - seq, - (totalshift+ve->cursor)/44100., - (totalshift+j)/44100.); - _analysis_output_always("pcmL",seq,v->pcm[0],v->pcm_current,0,0,totalshift); - _analysis_output_always("pcmR",seq,v->pcm[1],v->pcm_current,0,0,totalshift); - - _analysis_output_always("markL",seq,v->pcm[0],j,0,0,totalshift); - _analysis_output_always("markR",seq,v->pcm[1],j,0,0,totalshift); - - for(m=0;msearchstep]=ve->filter[m].markers[l]*.1; - _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); - } - - for(m=0;msearchstep]=ve->filter[m+VE_BANDS].markers[l]*.1; - _analysis_output_always(buf,seq,marker,v->pcm_current,0,0,totalshift); - } - - for(l=0;lsearchstep]=ve->mark[l]*.4; - _analysis_output_always("mark",seq,marker,v->pcm_current,0,0,totalshift); - - - seq++; - - } -#endif - - ve->curmark=j; - if(j>=testW)return(1); - return(0); - } - } - j+=ve->searchstep; - } - } - - return(-1); -} - -int _ve_envelope_mark(vorbis_dsp_state *v){ - envelope_lookup *ve=((private_state *)(v->backend_state))->ve; - vorbis_info *vi=v->vi; - codec_setup_info *ci=vi->codec_setup; - long centerW=v->centerW; - long beginW=centerW-ci->blocksizes[v->W]/4; - long endW=centerW+ci->blocksizes[v->W]/4; - if(v->W){ - beginW-=ci->blocksizes[v->lW]/4; - endW+=ci->blocksizes[v->nW]/4; - }else{ - beginW-=ci->blocksizes[0]/4; - endW+=ci->blocksizes[0]/4; - } - - if(ve->curmark>=beginW && ve->curmarksearchstep; - long last=endW/ve->searchstep; - long i; - for(i=first;imark[i])return(1); - } - return(0); -} - -void _ve_envelope_shift(envelope_lookup *e,long shift){ - int smallsize=e->current/e->searchstep+VE_POST; /* adjust for placing marks - ahead of ve->current */ - int smallshift=shift/e->searchstep; - - memmove(e->mark,e->mark+smallshift,(smallsize-smallshift)*sizeof(*e->mark)); - -#if 0 - for(i=0;ich;i++) - memmove(e->filter[i].markers, - e->filter[i].markers+smallshift, - (1024-smallshift)*sizeof(*(*e->filter).markers)); - totalshift+=shift; -#endif - - e->current-=shift; - if(e->curmark>=0) - e->curmark-=shift; - e->cursor-=shift; -} diff --git a/src/lib/vorbis/src/envelope.h b/src/lib/vorbis/src/envelope.h deleted file mode 100644 index 2ef60a82..00000000 --- a/src/lib/vorbis/src/envelope.h +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: PCM data envelope analysis and manipulation - - ********************************************************************/ - -#ifndef _V_ENVELOPE_ -#define _V_ENVELOPE_ - -#include "mdct.h" - -#define VE_PRE 16 -#define VE_WIN 4 -#define VE_POST 2 -#define VE_AMP (VE_PRE+VE_POST-1) - -#define VE_BANDS 7 -#define VE_NEARDC 15 - -#define VE_MINSTRETCH 2 /* a bit less than short block */ -#define VE_MAXSTRETCH 12 /* one-third full block */ - -typedef struct { - float ampbuf[VE_AMP]; - int ampptr; - - float nearDC[VE_NEARDC]; - float nearDC_acc; - float nearDC_partialacc; - int nearptr; - -} envelope_filter_state; - -typedef struct { - int begin; - int end; - float *window; - float total; -} envelope_band; - -typedef struct { - int ch; - int winlength; - int searchstep; - float minenergy; - - mdct_lookup mdct; - float *mdct_win; - - envelope_band band[VE_BANDS]; - envelope_filter_state *filter; - int stretch; - - int *mark; - - long storage; - long current; - long curmark; - long cursor; -} envelope_lookup; - -extern void _ve_envelope_init(envelope_lookup *e,vorbis_info *vi); -extern void _ve_envelope_clear(envelope_lookup *e); -extern long _ve_envelope_search(vorbis_dsp_state *v); -extern void _ve_envelope_shift(envelope_lookup *e,long shift); -extern int _ve_envelope_mark(vorbis_dsp_state *v); - - -#endif diff --git a/src/lib/vorbis/src/floor0.c b/src/lib/vorbis/src/floor0.c deleted file mode 100644 index f4a6d4d5..00000000 --- a/src/lib/vorbis/src/floor0.c +++ /dev/null @@ -1,223 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: floor backend 0 implementation - - ********************************************************************/ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "registry.h" -#include "lpc.h" -#include "lsp.h" -#include "codebook.h" -#include "scales.h" -#include "misc.h" -#include "os.h" - -#include "misc.h" -#include - -typedef struct { - int ln; - int m; - int **linearmap; - int n[2]; - - vorbis_info_floor0 *vi; - - long bits; - long frames; -} vorbis_look_floor0; - - -/***********************************************/ - -static void floor0_free_info(vorbis_info_floor *i){ - vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; - if(info){ - memset(info,0,sizeof(*info)); - _ogg_free(info); - } -} - -static void floor0_free_look(vorbis_look_floor *i){ - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; - if(look){ - - if(look->linearmap){ - - if(look->linearmap[0])_ogg_free(look->linearmap[0]); - if(look->linearmap[1])_ogg_free(look->linearmap[1]); - - _ogg_free(look->linearmap); - } - memset(look,0,sizeof(*look)); - _ogg_free(look); - } -} - -static vorbis_info_floor *floor0_unpack (vorbis_info *vi,oggpack_buffer *opb){ - codec_setup_info *ci=vi->codec_setup; - int j; - - vorbis_info_floor0 *info=_ogg_malloc(sizeof(*info)); - info->order=oggpack_read(opb,8); - info->rate=oggpack_read(opb,16); - info->barkmap=oggpack_read(opb,16); - info->ampbits=oggpack_read(opb,6); - info->ampdB=oggpack_read(opb,8); - info->numbooks=oggpack_read(opb,4)+1; - - if(info->order<1)goto err_out; - if(info->rate<1)goto err_out; - if(info->barkmap<1)goto err_out; - if(info->numbooks<1)goto err_out; - - for(j=0;jnumbooks;j++){ - info->books[j]=oggpack_read(opb,8); - if(info->books[j]<0 || info->books[j]>=ci->books)goto err_out; - if(ci->book_param[info->books[j]]->maptype==0)goto err_out; - if(ci->book_param[info->books[j]]->dim<1)goto err_out; - } - return(info); - - err_out: - floor0_free_info(info); - return(NULL); -} - -/* initialize Bark scale and normalization lookups. We could do this - with static tables, but Vorbis allows a number of possible - combinations, so it's best to do it computationally. - - The below is authoritative in terms of defining scale mapping. - Note that the scale depends on the sampling rate as well as the - linear block and mapping sizes */ - -static void floor0_map_lazy_init(vorbis_block *vb, - vorbis_info_floor *infoX, - vorbis_look_floor0 *look){ - if(!look->linearmap[vb->W]){ - vorbis_dsp_state *vd=vb->vd; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=vi->codec_setup; - vorbis_info_floor0 *info=(vorbis_info_floor0 *)infoX; - int W=vb->W; - int n=ci->blocksizes[W]/2,j; - - /* we choose a scaling constant so that: - floor(bark(rate/2-1)*C)=mapped-1 - floor(bark(rate/2)*C)=mapped */ - float scale=look->ln/toBARK(info->rate/2.f); - - /* the mapping from a linear scale to a smaller bark scale is - straightforward. We do *not* make sure that the linear mapping - does not skip bark-scale bins; the decoder simply skips them and - the encoder may do what it wishes in filling them. They're - necessary in some mapping combinations to keep the scale spacing - accurate */ - look->linearmap[W]=_ogg_malloc((n+1)*sizeof(**look->linearmap)); - for(j=0;jrate/2.f)/n*j) - *scale); /* bark numbers represent band edges */ - if(val>=look->ln)val=look->ln-1; /* guard against the approximation */ - look->linearmap[W][j]=val; - } - look->linearmap[W][j]=-1; - look->n[W]=n; - } -} - -static vorbis_look_floor *floor0_look(vorbis_dsp_state *vd, - vorbis_info_floor *i){ - vorbis_info_floor0 *info=(vorbis_info_floor0 *)i; - vorbis_look_floor0 *look=_ogg_calloc(1,sizeof(*look)); - - (void)vd; - - look->m=info->order; - look->ln=info->barkmap; - look->vi=info; - - look->linearmap=_ogg_calloc(2,sizeof(*look->linearmap)); - - return look; -} - -static void *floor0_inverse1(vorbis_block *vb,vorbis_look_floor *i){ - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; - vorbis_info_floor0 *info=look->vi; - int j,k; - - int ampraw=oggpack_read(&vb->opb,info->ampbits); - if(ampraw>0){ /* also handles the -1 out of data case */ - long maxval=(1<ampbits)-1; - float amp=(float)ampraw/maxval*info->ampdB; - int booknum=oggpack_read(&vb->opb,ov_ilog(info->numbooks)); - - if(booknum!=-1 && booknumnumbooks){ /* be paranoid */ - codec_setup_info *ci=vb->vd->vi->codec_setup; - codebook *b=ci->fullbooks+info->books[booknum]; - float last=0.f; - - /* the additional b->dim is a guard against any possible stack - smash; b->dim is provably more than we can overflow the - vector */ - float *lsp=_vorbis_block_alloc(vb,sizeof(*lsp)*(look->m+b->dim+1)); - - if(vorbis_book_decodev_set(b,lsp,&vb->opb,look->m)==-1)goto eop; - for(j=0;jm;){ - for(k=0;jm && kdim;k++,j++)lsp[j]+=last; - last=lsp[j-1]; - } - - lsp[look->m]=amp; - return(lsp); - } - } - eop: - return(NULL); -} - -static int floor0_inverse2(vorbis_block *vb,vorbis_look_floor *i, - void *memo,float *out){ - vorbis_look_floor0 *look=(vorbis_look_floor0 *)i; - vorbis_info_floor0 *info=look->vi; - - floor0_map_lazy_init(vb,info,look); - - if(memo){ - float *lsp=(float *)memo; - float amp=lsp[look->m]; - - /* take the coefficients back to a spectral envelope curve */ - vorbis_lsp_to_curve(out, - look->linearmap[vb->W], - look->n[vb->W], - look->ln, - lsp,look->m,amp,(float)info->ampdB); - return(1); - } - memset(out,0,sizeof(*out)*look->n[vb->W]); - return(0); -} - -/* export hooks */ -const vorbis_func_floor floor0_exportbundle={ - NULL,&floor0_unpack,&floor0_look,&floor0_free_info, - &floor0_free_look,&floor0_inverse1,&floor0_inverse2 -}; diff --git a/src/lib/vorbis/src/floor1.c b/src/lib/vorbis/src/floor1.c deleted file mode 100644 index c4fe3ea7..00000000 --- a/src/lib/vorbis/src/floor1.c +++ /dev/null @@ -1,1086 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: floor backend 1 implementation - - ********************************************************************/ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "registry.h" -#include "codebook.h" -#include "misc.h" -#include "scales.h" - -#include - -#define floor1_rangedB 140 /* floor 1 fixed at -140dB to 0dB range */ - -typedef struct lsfit_acc{ - int x0; - int x1; - - int xa; - int ya; - int x2a; - int y2a; - int xya; - int an; - - int xb; - int yb; - int x2b; - int y2b; - int xyb; - int bn; -} lsfit_acc; - -/***********************************************/ - -static void floor1_free_info(vorbis_info_floor *i){ - vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; - if(info){ - memset(info,0,sizeof(*info)); - _ogg_free(info); - } -} - -static void floor1_free_look(vorbis_look_floor *i){ - vorbis_look_floor1 *look=(vorbis_look_floor1 *)i; - if(look){ - /*fprintf(stderr,"floor 1 bit usage %f:%f (%f total)\n", - (float)look->phrasebits/look->frames, - (float)look->postbits/look->frames, - (float)(look->postbits+look->phrasebits)/look->frames);*/ - - memset(look,0,sizeof(*look)); - _ogg_free(look); - } -} - -static void floor1_pack (vorbis_info_floor *i,oggpack_buffer *opb){ - vorbis_info_floor1 *info=(vorbis_info_floor1 *)i; - int j,k; - int count=0; - int rangebits; - int maxposit=info->postlist[1]; - int maxclass=-1; - - /* save out partitions */ - oggpack_write(opb,info->partitions,5); /* only 0 to 31 legal */ - for(j=0;jpartitions;j++){ - oggpack_write(opb,info->partitionclass[j],4); /* only 0 to 15 legal */ - if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; - } - - /* save out partition classes */ - for(j=0;jclass_dim[j]-1,3); /* 1 to 8 */ - oggpack_write(opb,info->class_subs[j],2); /* 0 to 3 */ - if(info->class_subs[j])oggpack_write(opb,info->class_book[j],8); - for(k=0;k<(1<class_subs[j]);k++) - oggpack_write(opb,info->class_subbook[j][k]+1,8); - } - - /* save out the post list */ - oggpack_write(opb,info->mult-1,2); /* only 1,2,3,4 legal now */ - /* maxposit cannot legally be less than 1; this is encode-side, we - can assume our setup is OK */ - oggpack_write(opb,ov_ilog(maxposit-1),4); - rangebits=ov_ilog(maxposit-1); - - for(j=0,k=0;jpartitions;j++){ - count+=info->class_dim[info->partitionclass[j]]; - for(;kpostlist[k+2],rangebits); - } -} - -static int icomp(const void *a,const void *b){ - return(**(int **)a-**(int **)b); -} - -static vorbis_info_floor *floor1_unpack (vorbis_info *vi,oggpack_buffer *opb){ - codec_setup_info *ci=vi->codec_setup; - int j,k,count=0,maxclass=-1,rangebits; - - vorbis_info_floor1 *info=_ogg_calloc(1,sizeof(*info)); - /* read partitions */ - info->partitions=oggpack_read(opb,5); /* only 0 to 31 legal */ - for(j=0;jpartitions;j++){ - info->partitionclass[j]=oggpack_read(opb,4); /* only 0 to 15 legal */ - if(info->partitionclass[j]<0)goto err_out; - if(maxclasspartitionclass[j])maxclass=info->partitionclass[j]; - } - - /* read partition classes */ - for(j=0;jclass_dim[j]=oggpack_read(opb,3)+1; /* 1 to 8 */ - info->class_subs[j]=oggpack_read(opb,2); /* 0,1,2,3 bits */ - if(info->class_subs[j]<0) - goto err_out; - if(info->class_subs[j])info->class_book[j]=oggpack_read(opb,8); - if(info->class_book[j]<0 || info->class_book[j]>=ci->books) - goto err_out; - for(k=0;k<(1<class_subs[j]);k++){ - info->class_subbook[j][k]=oggpack_read(opb,8)-1; - if(info->class_subbook[j][k]<-1 || info->class_subbook[j][k]>=ci->books) - goto err_out; - } - } - - /* read the post list */ - info->mult=oggpack_read(opb,2)+1; /* only 1,2,3,4 legal now */ - rangebits=oggpack_read(opb,4); - if(rangebits<0)goto err_out; - - for(j=0,k=0;jpartitions;j++){ - count+=info->class_dim[info->partitionclass[j]]; - if(count>VIF_POSIT) goto err_out; - for(;kpostlist[k+2]=oggpack_read(opb,rangebits); - if(t<0 || t>=(1<postlist[0]=0; - info->postlist[1]=1<postlist+j; - qsort(sortpointer,count+2,sizeof(*sortpointer),icomp); - - for(j=1;jvi=info; - look->n=info->postlist[1]; - - /* we drop each position value in-between already decoded values, - and use linear interpolation to predict each new value past the - edges. The positions are read in the order of the position - list... we precompute the bounding positions in the lookup. Of - course, the neighbors can change (if a position is declined), but - this is an initial mapping */ - - for(i=0;ipartitions;i++)n+=info->class_dim[info->partitionclass[i]]; - n+=2; - look->posts=n; - - /* also store a sorted position index */ - for(i=0;ipostlist+i; - qsort(sortpointer,n,sizeof(*sortpointer),icomp); - - /* points from sort order back to range number */ - for(i=0;iforward_index[i]=sortpointer[i]-info->postlist; - /* points from range order to sorted position */ - for(i=0;ireverse_index[look->forward_index[i]]=i; - /* we actually need the post values too */ - for(i=0;isorted_index[i]=info->postlist[look->forward_index[i]]; - - /* quantize values to multiplier spec */ - switch(info->mult){ - case 1: /* 1024 -> 256 */ - look->quant_q=256; - break; - case 2: /* 1024 -> 128 */ - look->quant_q=128; - break; - case 3: /* 1024 -> 86 */ - look->quant_q=86; - break; - case 4: /* 1024 -> 64 */ - look->quant_q=64; - break; - } - - /* discover our neighbors for decode where we don't use fit flags - (that would push the neighbors outward) */ - for(i=0;in; - int currentx=info->postlist[i+2]; - for(j=0;jpostlist[j]; - if(x>lx && xcurrentx){ - hi=j; - hx=x; - } - } - look->loneighbor[i]=lo; - look->hineighbor[i]=hi; - } - - return(look); -} - -static int render_point(int x0,int x1,int y0,int y1,int x){ - y0&=0x7fff; /* mask off flag */ - y1&=0x7fff; - - { - int dy=y1-y0; - int adx=x1-x0; - int ady=abs(dy); - int err=ady*(x-x0); - - int off=err/adx; - if(dy<0)return(y0-off); - return(y0+off); - } -} - -static int vorbis_dBquant(const float *x){ - int i= *x*7.3142857f+1023.5f; - if(i>1023)return(1023); - if(i<0)return(0); - return i; -} - -static const float FLOOR1_fromdB_LOOKUP[256]={ - 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, - 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, - 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, - 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, - 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, - 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, - 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, - 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, - 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, - 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, - 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, - 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, - 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, - 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, - 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, - 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, - 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, - 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, - 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, - 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, - 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, - 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, - 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, - 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, - 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, - 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, - 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, - 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, - 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, - 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, - 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, - 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, - 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, - 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, - 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, - 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, - 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, - 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, - 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, - 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, - 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, - 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, - 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, - 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, - 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, - 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, - 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, - 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, - 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, - 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, - 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, - 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, - 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, - 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, - 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, - 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, - 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, - 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, - 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, - 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, - 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, - 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, - 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, - 0.82788260F, 0.88168307F, 0.9389798F, 1.F, -}; - -static void render_line(int n, int x0,int x1,int y0,int y1,float *d){ - int dy=y1-y0; - int adx=x1-x0; - int ady=abs(dy); - int base=dy/adx; - int sy=(dy<0?base-1:base+1); - int x=x0; - int y=y0; - int err=0; - - ady-=abs(base*adx); - - if(n>x1)n=x1; - - if(x=adx){ - err-=adx; - y+=sy; - }else{ - y+=base; - } - d[x]*=FLOOR1_fromdB_LOOKUP[y]; - } -} - -static void render_line0(int n, int x0,int x1,int y0,int y1,int *d){ - int dy=y1-y0; - int adx=x1-x0; - int ady=abs(dy); - int base=dy/adx; - int sy=(dy<0?base-1:base+1); - int x=x0; - int y=y0; - int err=0; - - ady-=abs(base*adx); - - if(n>x1)n=x1; - - if(x=adx){ - err-=adx; - y+=sy; - }else{ - y+=base; - } - d[x]=y; - } -} - -/* the floor has already been filtered to only include relevant sections */ -static int accumulate_fit(const float *flr,const float *mdct, - int x0, int x1,lsfit_acc *a, - int n,vorbis_info_floor1 *info){ - long i; - - int xa=0,ya=0,x2a=0,y2a=0,xya=0,na=0, xb=0,yb=0,x2b=0,y2b=0,xyb=0,nb=0; - - memset(a,0,sizeof(*a)); - a->x0=x0; - a->x1=x1; - if(x1>=n)x1=n-1; - - for(i=x0;i<=x1;i++){ - int quantized=vorbis_dBquant(flr+i); - if(quantized){ - if(mdct[i]+info->twofitatten>=flr[i]){ - xa += i; - ya += quantized; - x2a += i*i; - y2a += quantized*quantized; - xya += i*quantized; - na++; - }else{ - xb += i; - yb += quantized; - x2b += i*i; - y2b += quantized*quantized; - xyb += i*quantized; - nb++; - } - } - } - - a->xa=xa; - a->ya=ya; - a->x2a=x2a; - a->y2a=y2a; - a->xya=xya; - a->an=na; - - a->xb=xb; - a->yb=yb; - a->x2b=x2b; - a->y2b=y2b; - a->xyb=xyb; - a->bn=nb; - - return(na); -} - -static int fit_line(lsfit_acc *a,int fits,int *y0,int *y1, - vorbis_info_floor1 *info){ - double xb=0,yb=0,x2b=0,y2b=0,xyb=0,bn=0; - int i; - int x0=a[0].x0; - int x1=a[fits-1].x1; - - for(i=0;itwofitweight/(a[i].an+1)+1.; - - xb+=a[i].xb + a[i].xa * weight; - yb+=a[i].yb + a[i].ya * weight; - x2b+=a[i].x2b + a[i].x2a * weight; - y2b+=a[i].y2b + a[i].y2a * weight; - xyb+=a[i].xyb + a[i].xya * weight; - bn+=a[i].bn + a[i].an * weight; - } - - if(*y0>=0){ - xb+= x0; - yb+= *y0; - x2b+= x0 * x0; - y2b+= *y0 * *y0; - xyb+= *y0 * x0; - bn++; - } - - if(*y1>=0){ - xb+= x1; - yb+= *y1; - x2b+= x1 * x1; - y2b+= *y1 * *y1; - xyb+= *y1 * x1; - bn++; - } - - { - double denom=(bn*x2b-xb*xb); - - if(denom>0.){ - double a=(yb*x2b-xyb*xb)/denom; - double b=(bn*xyb-xb*yb)/denom; - *y0=rint(a+b*x0); - *y1=rint(a+b*x1); - - /* limit to our range! */ - if(*y0>1023)*y0=1023; - if(*y1>1023)*y1=1023; - if(*y0<0)*y0=0; - if(*y1<0)*y1=0; - - return 0; - }else{ - *y0=0; - *y1=0; - return 1; - } - } -} - -static int inspect_error(int x0,int x1,int y0,int y1,const float *mask, - const float *mdct, - vorbis_info_floor1 *info){ - int dy=y1-y0; - int adx=x1-x0; - int ady=abs(dy); - int base=dy/adx; - int sy=(dy<0?base-1:base+1); - int x=x0; - int y=y0; - int err=0; - int val=vorbis_dBquant(mask+x); - int mse=0; - int n=0; - - ady-=abs(base*adx); - - mse=(y-val); - mse*=mse; - n++; - if(mdct[x]+info->twofitatten>=mask[x]){ - if(y+info->maxovermaxunder>val)return(1); - } - - while(++x=adx){ - err-=adx; - y+=sy; - }else{ - y+=base; - } - - val=vorbis_dBquant(mask+x); - mse+=((y-val)*(y-val)); - n++; - if(mdct[x]+info->twofitatten>=mask[x]){ - if(val){ - if(y+info->maxovermaxunder>val)return(1); - } - } - } - - if(info->maxover*info->maxover/n>info->maxerr)return(0); - if(info->maxunder*info->maxunder/n>info->maxerr)return(0); - if(mse/n>info->maxerr)return(1); - return(0); -} - -static int post_Y(int *A,int *B,int pos){ - if(A[pos]<0) - return B[pos]; - if(B[pos]<0) - return A[pos]; - - return (A[pos]+B[pos])>>1; -} - -int *floor1_fit(vorbis_block *vb,vorbis_look_floor1 *look, - const float *logmdct, /* in */ - const float *logmask){ - long i,j; - vorbis_info_floor1 *info=look->vi; - long n=look->n; - long posts=look->posts; - long nonzero=0; - lsfit_acc fits[VIF_POSIT+1]; - int fit_valueA[VIF_POSIT+2]; /* index by range list position */ - int fit_valueB[VIF_POSIT+2]; /* index by range list position */ - - int loneighbor[VIF_POSIT+2]; /* sorted index of range list position (+2) */ - int hineighbor[VIF_POSIT+2]; - int *output=NULL; - int memo[VIF_POSIT+2]; - - for(i=0;isorted_index[i], - look->sorted_index[i+1],fits+i, - n,info); - } - - if(nonzero){ - /* start by fitting the implicit base case.... */ - int y0=-200; - int y1=-200; - fit_line(fits,posts-1,&y0,&y1,info); - - fit_valueA[0]=y0; - fit_valueB[0]=y0; - fit_valueB[1]=y1; - fit_valueA[1]=y1; - - /* Non degenerate case */ - /* start progressive splitting. This is a greedy, non-optimal - algorithm, but simple and close enough to the best - answer. */ - for(i=2;ireverse_index[i]; - int ln=loneighbor[sortpos]; - int hn=hineighbor[sortpos]; - - /* eliminate repeat searches of a particular range with a memo */ - if(memo[ln]!=hn){ - /* haven't performed this error search yet */ - int lsortpos=look->reverse_index[ln]; - int hsortpos=look->reverse_index[hn]; - memo[ln]=hn; - - { - /* A note: we want to bound/minimize *local*, not global, error */ - int lx=info->postlist[ln]; - int hx=info->postlist[hn]; - int ly=post_Y(fit_valueA,fit_valueB,ln); - int hy=post_Y(fit_valueA,fit_valueB,hn); - - if(ly==-1 || hy==-1){ - exit(1); - } - - if(inspect_error(lx,hx,ly,hy,logmask,logmdct,info)){ - /* outside error bounds/begin search area. Split it. */ - int ly0=-200; - int ly1=-200; - int hy0=-200; - int hy1=-200; - int ret0=fit_line(fits+lsortpos,sortpos-lsortpos,&ly0,&ly1,info); - int ret1=fit_line(fits+sortpos,hsortpos-sortpos,&hy0,&hy1,info); - - if(ret0){ - ly0=ly; - ly1=hy0; - } - if(ret1){ - hy0=ly1; - hy1=hy; - } - - if(ret0 && ret1){ - fit_valueA[i]=-200; - fit_valueB[i]=-200; - }else{ - /* store new edge values */ - fit_valueB[ln]=ly0; - if(ln==0)fit_valueA[ln]=ly0; - fit_valueA[i]=ly1; - fit_valueB[i]=hy0; - fit_valueA[hn]=hy1; - if(hn==1)fit_valueB[hn]=hy1; - - if(ly1>=0 || hy0>=0){ - /* store new neighbor values */ - for(j=sortpos-1;j>=0;j--) - if(hineighbor[j]==hn) - hineighbor[j]=i; - else - break; - for(j=sortpos+1;jloneighbor[i-2]; - int hn=look->hineighbor[i-2]; - int x0=info->postlist[ln]; - int x1=info->postlist[hn]; - int y0=output[ln]; - int y1=output[hn]; - - int predicted=render_point(x0,x1,y0,y1,info->postlist[i]); - int vx=post_Y(fit_valueA,fit_valueB,i); - - if(vx>=0 && predicted!=vx){ - output[i]=vx; - }else{ - output[i]= predicted|0x8000; - } - } - } - - return(output); - -} - -int *floor1_interpolate_fit(vorbis_block *vb,vorbis_look_floor1 *look, - int *A,int *B, - int del){ - - long i; - long posts=look->posts; - int *output=NULL; - - if(A && B){ - output=_vorbis_block_alloc(vb,sizeof(*output)*posts); - - /* overly simpleminded--- look again post 1.2 */ - for(i=0;i>16; - if(A[i]&0x8000 && B[i]&0x8000)output[i]|=0x8000; - } - } - - return(output); -} - - -int floor1_encode(oggpack_buffer *opb,vorbis_block *vb, - vorbis_look_floor1 *look, - int *post,int *ilogmask){ - - long i,j; - vorbis_info_floor1 *info=look->vi; - long posts=look->posts; - codec_setup_info *ci=vb->vd->vi->codec_setup; - int out[VIF_POSIT+2]; - static_codebook **sbooks=ci->book_param; - codebook *books=ci->fullbooks; - - /* quantize values to multiplier spec */ - if(post){ - for(i=0;imult){ - case 1: /* 1024 -> 256 */ - val>>=2; - break; - case 2: /* 1024 -> 128 */ - val>>=3; - break; - case 3: /* 1024 -> 86 */ - val/=12; - break; - case 4: /* 1024 -> 64 */ - val>>=4; - break; - } - post[i]=val | (post[i]&0x8000); - } - - out[0]=post[0]; - out[1]=post[1]; - - /* find prediction values for each post and subtract them */ - for(i=2;iloneighbor[i-2]; - int hn=look->hineighbor[i-2]; - int x0=info->postlist[ln]; - int x1=info->postlist[hn]; - int y0=post[ln]; - int y1=post[hn]; - - int predicted=render_point(x0,x1,y0,y1,info->postlist[i]); - - if((post[i]&0x8000) || (predicted==post[i])){ - post[i]=predicted|0x8000; /* in case there was roundoff jitter - in interpolation */ - out[i]=0; - }else{ - int headroom=(look->quant_q-predictedquant_q-predicted:predicted); - - int val=post[i]-predicted; - - /* at this point the 'deviation' value is in the range +/- max - range, but the real, unique range can always be mapped to - only [0-maxrange). So we want to wrap the deviation into - this limited range, but do it in the way that least screws - an essentially gaussian probability distribution. */ - - if(val<0) - if(val<-headroom) - val=headroom-val-1; - else - val=-1-(val<<1); - else - if(val>=headroom) - val= val+headroom; - else - val<<=1; - - out[i]=val; - post[ln]&=0x7fff; - post[hn]&=0x7fff; - } - } - - /* we have everything we need. pack it out */ - /* mark nontrivial floor */ - oggpack_write(opb,1,1); - - /* beginning/end post */ - look->frames++; - look->postbits+=ov_ilog(look->quant_q-1)*2; - oggpack_write(opb,out[0],ov_ilog(look->quant_q-1)); - oggpack_write(opb,out[1],ov_ilog(look->quant_q-1)); - - - /* partition by partition */ - for(i=0,j=2;ipartitions;i++){ - int class=info->partitionclass[i]; - int cdim=info->class_dim[class]; - int csubbits=info->class_subs[class]; - int csub=1<class_subbook[class][k]; - if(booknum<0){ - maxval[k]=1; - }else{ - maxval[k]=sbooks[info->class_subbook[class][k]]->entries; - } - } - for(k=0;kphrasebits+= - vorbis_book_encode(books+info->class_book[class],cval,opb); - -#ifdef TRAIN_FLOOR1 - { - FILE *of; - char buffer[80]; - sprintf(buffer,"line_%dx%ld_class%d.vqd", - vb->pcmend/2,posts-2,class); - of=fopen(buffer,"a"); - fprintf(of,"%d\n",cval); - fclose(of); - } -#endif - } - - /* write post values */ - for(k=0;kclass_subbook[class][bookas[k]]; - if(book>=0){ - /* hack to allow training with 'bad' books */ - if(out[j+k]<(books+book)->entries) - look->postbits+=vorbis_book_encode(books+book, - out[j+k],opb); - /*else - fprintf(stderr,"+!");*/ - -#ifdef TRAIN_FLOOR1 - { - FILE *of; - char buffer[80]; - sprintf(buffer,"line_%dx%ld_%dsub%d.vqd", - vb->pcmend/2,posts-2,class,bookas[k]); - of=fopen(buffer,"a"); - fprintf(of,"%d\n",out[j+k]); - fclose(of); - } -#endif - } - } - j+=cdim; - } - - { - /* generate quantized floor equivalent to what we'd unpack in decode */ - /* render the lines */ - int hx=0; - int lx=0; - int ly=post[0]*info->mult; - int n=ci->blocksizes[vb->W]/2; - - for(j=1;jposts;j++){ - int current=look->forward_index[j]; - int hy=post[current]&0x7fff; - if(hy==post[current]){ - - hy*=info->mult; - hx=info->postlist[current]; - - render_line0(n,lx,hx,ly,hy,ilogmask); - - lx=hx; - ly=hy; - } - } - for(j=hx;jpcmend/2;j++)ilogmask[j]=ly; /* be certain */ - return(1); - } - }else{ - oggpack_write(opb,0,1); - memset(ilogmask,0,vb->pcmend/2*sizeof(*ilogmask)); - return(0); - } -} - -static void *floor1_inverse1(vorbis_block *vb,vorbis_look_floor *in){ - vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; - vorbis_info_floor1 *info=look->vi; - codec_setup_info *ci=vb->vd->vi->codec_setup; - - int i,j,k; - codebook *books=ci->fullbooks; - - /* unpack wrapped/predicted values from stream */ - if(oggpack_read(&vb->opb,1)==1){ - int *fit_value=_vorbis_block_alloc(vb,(look->posts)*sizeof(*fit_value)); - - fit_value[0]=oggpack_read(&vb->opb,ov_ilog(look->quant_q-1)); - fit_value[1]=oggpack_read(&vb->opb,ov_ilog(look->quant_q-1)); - - /* partition by partition */ - for(i=0,j=2;ipartitions;i++){ - int class=info->partitionclass[i]; - int cdim=info->class_dim[class]; - int csubbits=info->class_subs[class]; - int csub=1<class_book[class],&vb->opb); - - if(cval==-1)goto eop; - } - - for(k=0;kclass_subbook[class][cval&(csub-1)]; - cval>>=csubbits; - if(book>=0){ - if((fit_value[j+k]=vorbis_book_decode(books+book,&vb->opb))==-1) - goto eop; - }else{ - fit_value[j+k]=0; - } - } - j+=cdim; - } - - /* unwrap positive values and reconsitute via linear interpolation */ - for(i=2;iposts;i++){ - int predicted=render_point(info->postlist[look->loneighbor[i-2]], - info->postlist[look->hineighbor[i-2]], - fit_value[look->loneighbor[i-2]], - fit_value[look->hineighbor[i-2]], - info->postlist[i]); - int hiroom=look->quant_q-predicted; - int loroom=predicted; - int room=(hiroom=room){ - if(hiroom>loroom){ - val = val-loroom; - }else{ - val = -1-(val-hiroom); - } - }else{ - if(val&1){ - val= -((val+1)>>1); - }else{ - val>>=1; - } - } - - fit_value[i]=(val+predicted)&0x7fff; - fit_value[look->loneighbor[i-2]]&=0x7fff; - fit_value[look->hineighbor[i-2]]&=0x7fff; - - }else{ - fit_value[i]=predicted|0x8000; - } - - } - - return(fit_value); - } - eop: - return(NULL); -} - -static int floor1_inverse2(vorbis_block *vb,vorbis_look_floor *in,void *memo, - float *out){ - vorbis_look_floor1 *look=(vorbis_look_floor1 *)in; - vorbis_info_floor1 *info=look->vi; - - codec_setup_info *ci=vb->vd->vi->codec_setup; - int n=ci->blocksizes[vb->W]/2; - int j; - - if(memo){ - /* render the lines */ - int *fit_value=(int *)memo; - int hx=0; - int lx=0; - int ly=fit_value[0]*info->mult; - /* guard lookup against out-of-range values */ - ly=(ly<0?0:ly>255?255:ly); - - for(j=1;jposts;j++){ - int current=look->forward_index[j]; - int hy=fit_value[current]&0x7fff; - if(hy==fit_value[current]){ - - hx=info->postlist[current]; - hy*=info->mult; - /* guard lookup against out-of-range values */ - hy=(hy<0?0:hy>255?255:hy); - - render_line(n,lx,hx,ly,hy,out); - - lx=hx; - ly=hy; - } - } - for(j=hx;j header packets - - ********************************************************************/ - -/* general handling of the header and the vorbis_info structure (and - substructures) */ - -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "codebook.h" -#include "registry.h" -#include "window.h" -#include "psy.h" -#include "misc.h" -#include "os.h" - -#define GENERAL_VENDOR_STRING "Xiph.Org libVorbis 1.3.7" -#define ENCODE_VENDOR_STRING "Xiph.Org libVorbis I 20200704 (Reducing Environment)" - -/* helpers */ -static void _v_writestring(oggpack_buffer *o,const char *s, int bytes){ - - while(bytes--){ - oggpack_write(o,*s++,8); - } -} - -static void _v_readstring(oggpack_buffer *o,char *buf,int bytes){ - while(bytes--){ - *buf++=oggpack_read(o,8); - } -} - -static int _v_toupper(int c) { - return (c >= 'a' && c <= 'z') ? (c & ~('a' - 'A')) : c; -} - -void vorbis_comment_init(vorbis_comment *vc){ - memset(vc,0,sizeof(*vc)); -} - -void vorbis_comment_add(vorbis_comment *vc,const char *comment){ - vc->user_comments=_ogg_realloc(vc->user_comments, - (vc->comments+2)*sizeof(*vc->user_comments)); - vc->comment_lengths=_ogg_realloc(vc->comment_lengths, - (vc->comments+2)*sizeof(*vc->comment_lengths)); - vc->comment_lengths[vc->comments]=strlen(comment); - vc->user_comments[vc->comments]=_ogg_malloc(vc->comment_lengths[vc->comments]+1); - strcpy(vc->user_comments[vc->comments], comment); - vc->comments++; - vc->user_comments[vc->comments]=NULL; -} - -void vorbis_comment_add_tag(vorbis_comment *vc, const char *tag, const char *contents){ - /* Length for key and value +2 for = and \0 */ - char *comment=_ogg_malloc(strlen(tag)+strlen(contents)+2); - strcpy(comment, tag); - strcat(comment, "="); - strcat(comment, contents); - vorbis_comment_add(vc, comment); - _ogg_free(comment); -} - -/* This is more or less the same as strncasecmp - but that doesn't exist - * everywhere, and this is a fairly trivial function, so we include it */ -static int tagcompare(const char *s1, const char *s2, int n){ - int c=0; - while(c < n){ - if(_v_toupper(s1[c]) != _v_toupper(s2[c])) - return !0; - c++; - } - return 0; -} - -char *vorbis_comment_query(vorbis_comment *vc, const char *tag, int count){ - long i; - int found = 0; - int taglen = strlen(tag)+1; /* +1 for the = we append */ - char *fulltag = _ogg_malloc(taglen+1); - - strcpy(fulltag, tag); - strcat(fulltag, "="); - - for(i=0;icomments;i++){ - if(!tagcompare(vc->user_comments[i], fulltag, taglen)){ - if(count == found) { - /* We return a pointer to the data, not a copy */ - _ogg_free(fulltag); - return vc->user_comments[i] + taglen; - } else { - found++; - } - } - } - _ogg_free(fulltag); - return NULL; /* didn't find anything */ -} - -int vorbis_comment_query_count(vorbis_comment *vc, const char *tag){ - int i,count=0; - int taglen = strlen(tag)+1; /* +1 for the = we append */ - char *fulltag = _ogg_malloc(taglen+1); - strcpy(fulltag,tag); - strcat(fulltag, "="); - - for(i=0;icomments;i++){ - if(!tagcompare(vc->user_comments[i], fulltag, taglen)) - count++; - } - - _ogg_free(fulltag); - return count; -} - -void vorbis_comment_clear(vorbis_comment *vc){ - if(vc){ - long i; - if(vc->user_comments){ - for(i=0;icomments;i++) - if(vc->user_comments[i])_ogg_free(vc->user_comments[i]); - _ogg_free(vc->user_comments); - } - if(vc->comment_lengths)_ogg_free(vc->comment_lengths); - if(vc->vendor)_ogg_free(vc->vendor); - memset(vc,0,sizeof(*vc)); - } -} - -/* blocksize 0 is guaranteed to be short, 1 is guaranteed to be long. - They may be equal, but short will never ge greater than long */ -int vorbis_info_blocksize(vorbis_info *vi,int zo){ - codec_setup_info *ci = vi->codec_setup; - return ci ? ci->blocksizes[zo] : -1; -} - -/* used by synthesis, which has a full, alloced vi */ -void vorbis_info_init(vorbis_info *vi){ - memset(vi,0,sizeof(*vi)); - vi->codec_setup=_ogg_calloc(1,sizeof(codec_setup_info)); -} - -void vorbis_info_clear(vorbis_info *vi){ - codec_setup_info *ci=vi->codec_setup; - int i; - - if(ci){ - - for(i=0;imodes;i++) - if(ci->mode_param[i])_ogg_free(ci->mode_param[i]); - - for(i=0;imaps;i++) /* unpack does the range checking */ - if(ci->map_param[i]) /* this may be cleaning up an aborted - unpack, in which case the below type - cannot be trusted */ - _mapping_P[ci->map_type[i]]->free_info(ci->map_param[i]); - - for(i=0;ifloors;i++) /* unpack does the range checking */ - if(ci->floor_param[i]) /* this may be cleaning up an aborted - unpack, in which case the below type - cannot be trusted */ - _floor_P[ci->floor_type[i]]->free_info(ci->floor_param[i]); - - for(i=0;iresidues;i++) /* unpack does the range checking */ - if(ci->residue_param[i]) /* this may be cleaning up an aborted - unpack, in which case the below type - cannot be trusted */ - _residue_P[ci->residue_type[i]]->free_info(ci->residue_param[i]); - - for(i=0;ibooks;i++){ - if(ci->book_param[i]){ - /* knows if the book was not alloced */ - vorbis_staticbook_destroy(ci->book_param[i]); - } - if(ci->fullbooks) - vorbis_book_clear(ci->fullbooks+i); - } - if(ci->fullbooks) - _ogg_free(ci->fullbooks); - - for(i=0;ipsys;i++) - _vi_psy_free(ci->psy_param[i]); - - _ogg_free(ci); - } - - memset(vi,0,sizeof(*vi)); -} - -/* Header packing/unpacking ********************************************/ - -static int _vorbis_unpack_info(vorbis_info *vi,oggpack_buffer *opb){ - codec_setup_info *ci=vi->codec_setup; - int bs; - if(!ci)return(OV_EFAULT); - - vi->version=oggpack_read(opb,32); - if(vi->version!=0)return(OV_EVERSION); - - vi->channels=oggpack_read(opb,8); - vi->rate=oggpack_read(opb,32); - - vi->bitrate_upper=(ogg_int32_t)oggpack_read(opb,32); - vi->bitrate_nominal=(ogg_int32_t)oggpack_read(opb,32); - vi->bitrate_lower=(ogg_int32_t)oggpack_read(opb,32); - - bs = oggpack_read(opb,4); - if(bs<0)goto err_out; - ci->blocksizes[0]=1<blocksizes[1]=1<rate<1)goto err_out; - if(vi->channels<1)goto err_out; - if(ci->blocksizes[0]<64)goto err_out; - if(ci->blocksizes[1]blocksizes[0])goto err_out; - if(ci->blocksizes[1]>8192)goto err_out; - - if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ - - return(0); - err_out: - vorbis_info_clear(vi); - return(OV_EBADHEADER); -} - -static int _vorbis_unpack_comment(vorbis_comment *vc,oggpack_buffer *opb){ - int i; - int vendorlen=oggpack_read(opb,32); - if(vendorlen<0)goto err_out; - if(vendorlen>opb->storage-8)goto err_out; - vc->vendor=_ogg_calloc(vendorlen+1,1); - _v_readstring(opb,vc->vendor,vendorlen); - i=oggpack_read(opb,32); - if(i<0)goto err_out; - if(i>((opb->storage-oggpack_bytes(opb))>>2))goto err_out; - vc->comments=i; - vc->user_comments=_ogg_calloc(vc->comments+1,sizeof(*vc->user_comments)); - vc->comment_lengths=_ogg_calloc(vc->comments+1, sizeof(*vc->comment_lengths)); - - for(i=0;icomments;i++){ - int len=oggpack_read(opb,32); - if(len<0)goto err_out; - if(len>opb->storage-oggpack_bytes(opb))goto err_out; - vc->comment_lengths[i]=len; - vc->user_comments[i]=_ogg_calloc(len+1,1); - _v_readstring(opb,vc->user_comments[i],len); - } - if(oggpack_read(opb,1)!=1)goto err_out; /* EOP check */ - - return(0); - err_out: - vorbis_comment_clear(vc); - return(OV_EBADHEADER); -} - -/* all of the real encoding details are here. The modes, books, - everything */ -static int _vorbis_unpack_books(vorbis_info *vi,oggpack_buffer *opb){ - codec_setup_info *ci=vi->codec_setup; - int i; - - /* codebooks */ - ci->books=oggpack_read(opb,8)+1; - if(ci->books<=0)goto err_out; - for(i=0;ibooks;i++){ - ci->book_param[i]=vorbis_staticbook_unpack(opb); - if(!ci->book_param[i])goto err_out; - } - - /* time backend settings; hooks are unused */ - { - int times=oggpack_read(opb,6)+1; - if(times<=0)goto err_out; - for(i=0;i=VI_TIMEB)goto err_out; - } - } - - /* floor backend settings */ - ci->floors=oggpack_read(opb,6)+1; - if(ci->floors<=0)goto err_out; - for(i=0;ifloors;i++){ - ci->floor_type[i]=oggpack_read(opb,16); - if(ci->floor_type[i]<0 || ci->floor_type[i]>=VI_FLOORB)goto err_out; - ci->floor_param[i]=_floor_P[ci->floor_type[i]]->unpack(vi,opb); - if(!ci->floor_param[i])goto err_out; - } - - /* residue backend settings */ - ci->residues=oggpack_read(opb,6)+1; - if(ci->residues<=0)goto err_out; - for(i=0;iresidues;i++){ - ci->residue_type[i]=oggpack_read(opb,16); - if(ci->residue_type[i]<0 || ci->residue_type[i]>=VI_RESB)goto err_out; - ci->residue_param[i]=_residue_P[ci->residue_type[i]]->unpack(vi,opb); - if(!ci->residue_param[i])goto err_out; - } - - /* map backend settings */ - ci->maps=oggpack_read(opb,6)+1; - if(ci->maps<=0)goto err_out; - for(i=0;imaps;i++){ - ci->map_type[i]=oggpack_read(opb,16); - if(ci->map_type[i]<0 || ci->map_type[i]>=VI_MAPB)goto err_out; - ci->map_param[i]=_mapping_P[ci->map_type[i]]->unpack(vi,opb); - if(!ci->map_param[i])goto err_out; - } - - /* mode settings */ - ci->modes=oggpack_read(opb,6)+1; - if(ci->modes<=0)goto err_out; - for(i=0;imodes;i++){ - ci->mode_param[i]=_ogg_calloc(1,sizeof(*ci->mode_param[i])); - ci->mode_param[i]->blockflag=oggpack_read(opb,1); - ci->mode_param[i]->windowtype=oggpack_read(opb,16); - ci->mode_param[i]->transformtype=oggpack_read(opb,16); - ci->mode_param[i]->mapping=oggpack_read(opb,8); - - if(ci->mode_param[i]->windowtype>=VI_WINDOWB)goto err_out; - if(ci->mode_param[i]->transformtype>=VI_WINDOWB)goto err_out; - if(ci->mode_param[i]->mapping>=ci->maps)goto err_out; - if(ci->mode_param[i]->mapping<0)goto err_out; - } - - if(oggpack_read(opb,1)!=1)goto err_out; /* top level EOP check */ - - return(0); - err_out: - vorbis_info_clear(vi); - return(OV_EBADHEADER); -} - -/* Is this packet a vorbis ID header? */ -int vorbis_synthesis_idheader(ogg_packet *op){ - oggpack_buffer opb; - char buffer[6]; - - if(op){ - oggpack_readinit(&opb,op->packet,op->bytes); - - if(!op->b_o_s) - return(0); /* Not the initial packet */ - - if(oggpack_read(&opb,8) != 1) - return 0; /* not an ID header */ - - memset(buffer,0,6); - _v_readstring(&opb,buffer,6); - if(memcmp(buffer,"vorbis",6)) - return 0; /* not vorbis */ - - return 1; - } - - return 0; -} - -/* The Vorbis header is in three packets; the initial small packet in - the first page that identifies basic parameters, a second packet - with bitstream comments and a third packet that holds the - codebook. */ - -int vorbis_synthesis_headerin(vorbis_info *vi,vorbis_comment *vc,ogg_packet *op){ - oggpack_buffer opb; - - if(op){ - oggpack_readinit(&opb,op->packet,op->bytes); - - /* Which of the three types of header is this? */ - /* Also verify header-ness, vorbis */ - { - char buffer[6]; - int packtype=oggpack_read(&opb,8); - memset(buffer,0,6); - _v_readstring(&opb,buffer,6); - if(memcmp(buffer,"vorbis",6)){ - /* not a vorbis header */ - return(OV_ENOTVORBIS); - } - switch(packtype){ - case 0x01: /* least significant *bit* is read first */ - if(!op->b_o_s){ - /* Not the initial packet */ - return(OV_EBADHEADER); - } - if(vi->rate!=0){ - /* previously initialized info header */ - return(OV_EBADHEADER); - } - - return(_vorbis_unpack_info(vi,&opb)); - - case 0x03: /* least significant *bit* is read first */ - if(vi->rate==0){ - /* um... we didn't get the initial header */ - return(OV_EBADHEADER); - } - if(vc->vendor!=NULL){ - /* previously initialized comment header */ - return(OV_EBADHEADER); - } - - return(_vorbis_unpack_comment(vc,&opb)); - - case 0x05: /* least significant *bit* is read first */ - if(vi->rate==0 || vc->vendor==NULL){ - /* um... we didn;t get the initial header or comments yet */ - return(OV_EBADHEADER); - } - if(vi->codec_setup==NULL){ - /* improperly initialized vorbis_info */ - return(OV_EFAULT); - } - if(((codec_setup_info *)vi->codec_setup)->books>0){ - /* previously initialized setup header */ - return(OV_EBADHEADER); - } - - return(_vorbis_unpack_books(vi,&opb)); - - default: - /* Not a valid vorbis header type */ - return(OV_EBADHEADER); - break; - } - } - } - return(OV_EBADHEADER); -} - -/* pack side **********************************************************/ - -static int _vorbis_pack_info(oggpack_buffer *opb,vorbis_info *vi){ - codec_setup_info *ci=vi->codec_setup; - if(!ci|| - ci->blocksizes[0]<64|| - ci->blocksizes[1]blocksizes[0]){ - return(OV_EFAULT); - } - - /* preamble */ - oggpack_write(opb,0x01,8); - _v_writestring(opb,"vorbis", 6); - - /* basic information about the stream */ - oggpack_write(opb,0x00,32); - oggpack_write(opb,vi->channels,8); - oggpack_write(opb,vi->rate,32); - - oggpack_write(opb,vi->bitrate_upper,32); - oggpack_write(opb,vi->bitrate_nominal,32); - oggpack_write(opb,vi->bitrate_lower,32); - - oggpack_write(opb,ov_ilog(ci->blocksizes[0]-1),4); - oggpack_write(opb,ov_ilog(ci->blocksizes[1]-1),4); - oggpack_write(opb,1,1); - - return(0); -} - -static int _vorbis_pack_comment(oggpack_buffer *opb,vorbis_comment *vc){ - int bytes = strlen(ENCODE_VENDOR_STRING); - - /* preamble */ - oggpack_write(opb,0x03,8); - _v_writestring(opb,"vorbis", 6); - - /* vendor */ - oggpack_write(opb,bytes,32); - _v_writestring(opb,ENCODE_VENDOR_STRING, bytes); - - /* comments */ - - oggpack_write(opb,vc->comments,32); - if(vc->comments){ - int i; - for(i=0;icomments;i++){ - if(vc->user_comments[i]){ - oggpack_write(opb,vc->comment_lengths[i],32); - _v_writestring(opb,vc->user_comments[i], vc->comment_lengths[i]); - }else{ - oggpack_write(opb,0,32); - } - } - } - oggpack_write(opb,1,1); - - return(0); -} - -static int _vorbis_pack_books(oggpack_buffer *opb,vorbis_info *vi){ - codec_setup_info *ci=vi->codec_setup; - int i; - if(!ci)return(OV_EFAULT); - - oggpack_write(opb,0x05,8); - _v_writestring(opb,"vorbis", 6); - - /* books */ - oggpack_write(opb,ci->books-1,8); - for(i=0;ibooks;i++) - if(vorbis_staticbook_pack(ci->book_param[i],opb))goto err_out; - - /* times; hook placeholders */ - oggpack_write(opb,0,6); - oggpack_write(opb,0,16); - - /* floors */ - oggpack_write(opb,ci->floors-1,6); - for(i=0;ifloors;i++){ - oggpack_write(opb,ci->floor_type[i],16); - if(_floor_P[ci->floor_type[i]]->pack) - _floor_P[ci->floor_type[i]]->pack(ci->floor_param[i],opb); - else - goto err_out; - } - - /* residues */ - oggpack_write(opb,ci->residues-1,6); - for(i=0;iresidues;i++){ - oggpack_write(opb,ci->residue_type[i],16); - _residue_P[ci->residue_type[i]]->pack(ci->residue_param[i],opb); - } - - /* maps */ - oggpack_write(opb,ci->maps-1,6); - for(i=0;imaps;i++){ - oggpack_write(opb,ci->map_type[i],16); - _mapping_P[ci->map_type[i]]->pack(vi,ci->map_param[i],opb); - } - - /* modes */ - oggpack_write(opb,ci->modes-1,6); - for(i=0;imodes;i++){ - oggpack_write(opb,ci->mode_param[i]->blockflag,1); - oggpack_write(opb,ci->mode_param[i]->windowtype,16); - oggpack_write(opb,ci->mode_param[i]->transformtype,16); - oggpack_write(opb,ci->mode_param[i]->mapping,8); - } - oggpack_write(opb,1,1); - - return(0); -err_out: - return(-1); -} - -int vorbis_commentheader_out(vorbis_comment *vc, - ogg_packet *op){ - - oggpack_buffer opb; - - oggpack_writeinit(&opb); - if(_vorbis_pack_comment(&opb,vc)){ - oggpack_writeclear(&opb); - return OV_EIMPL; - } - - op->packet = _ogg_malloc(oggpack_bytes(&opb)); - memcpy(op->packet, opb.buffer, oggpack_bytes(&opb)); - - op->bytes=oggpack_bytes(&opb); - op->b_o_s=0; - op->e_o_s=0; - op->granulepos=0; - op->packetno=1; - - oggpack_writeclear(&opb); - return 0; -} - -int vorbis_analysis_headerout(vorbis_dsp_state *v, - vorbis_comment *vc, - ogg_packet *op, - ogg_packet *op_comm, - ogg_packet *op_code){ - int ret=OV_EIMPL; - vorbis_info *vi=v->vi; - oggpack_buffer opb; - private_state *b=v->backend_state; - - if(!b||vi->channels<=0||vi->channels>256){ - b = NULL; - ret=OV_EFAULT; - goto err_out; - } - - /* first header packet **********************************************/ - - oggpack_writeinit(&opb); - if(_vorbis_pack_info(&opb,vi))goto err_out; - - /* build the packet */ - if(b->header)_ogg_free(b->header); - b->header=_ogg_malloc(oggpack_bytes(&opb)); - memcpy(b->header,opb.buffer,oggpack_bytes(&opb)); - op->packet=b->header; - op->bytes=oggpack_bytes(&opb); - op->b_o_s=1; - op->e_o_s=0; - op->granulepos=0; - op->packetno=0; - - /* second header packet (comments) **********************************/ - - oggpack_reset(&opb); - if(_vorbis_pack_comment(&opb,vc))goto err_out; - - if(b->header1)_ogg_free(b->header1); - b->header1=_ogg_malloc(oggpack_bytes(&opb)); - memcpy(b->header1,opb.buffer,oggpack_bytes(&opb)); - op_comm->packet=b->header1; - op_comm->bytes=oggpack_bytes(&opb); - op_comm->b_o_s=0; - op_comm->e_o_s=0; - op_comm->granulepos=0; - op_comm->packetno=1; - - /* third header packet (modes/codebooks) ****************************/ - - oggpack_reset(&opb); - if(_vorbis_pack_books(&opb,vi))goto err_out; - - if(b->header2)_ogg_free(b->header2); - b->header2=_ogg_malloc(oggpack_bytes(&opb)); - memcpy(b->header2,opb.buffer,oggpack_bytes(&opb)); - op_code->packet=b->header2; - op_code->bytes=oggpack_bytes(&opb); - op_code->b_o_s=0; - op_code->e_o_s=0; - op_code->granulepos=0; - op_code->packetno=2; - - oggpack_writeclear(&opb); - return(0); - err_out: - memset(op,0,sizeof(*op)); - memset(op_comm,0,sizeof(*op_comm)); - memset(op_code,0,sizeof(*op_code)); - - if(b){ - if(vi->channels>0)oggpack_writeclear(&opb); - if(b->header)_ogg_free(b->header); - if(b->header1)_ogg_free(b->header1); - if(b->header2)_ogg_free(b->header2); - b->header=NULL; - b->header1=NULL; - b->header2=NULL; - } - return(ret); -} - -double vorbis_granule_time(vorbis_dsp_state *v,ogg_int64_t granulepos){ - if(granulepos == -1) return -1; - - /* We're not guaranteed a 64 bit unsigned type everywhere, so we - have to put the unsigned granpo in a signed type. */ - if(granulepos>=0){ - return((double)granulepos/v->vi->rate); - }else{ - ogg_int64_t granuleoff=0xffffffff; - granuleoff<<=31; - granuleoff|=0x7ffffffff; - return(((double)granulepos+2+granuleoff+granuleoff)/v->vi->rate); - } -} - -const char *vorbis_version_string(void){ - return GENERAL_VENDOR_STRING; -} diff --git a/src/lib/vorbis/src/lookup.c b/src/lib/vorbis/src/lookup.c deleted file mode 100644 index 7cd01a44..00000000 --- a/src/lib/vorbis/src/lookup.c +++ /dev/null @@ -1,93 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: lookup based functions - - ********************************************************************/ - -#include -#include "lookup.h" -#include "lookup_data.h" -#include "os.h" -#include "misc.h" - -#ifdef FLOAT_LOOKUP - -/* interpolated lookup based cos function, domain 0 to PI only */ -float vorbis_coslook(float a){ - double d=a*(.31830989*(float)COS_LOOKUP_SZ); - int i=vorbis_ftoi(d-.5); - - return COS_LOOKUP[i]+ (d-i)*(COS_LOOKUP[i+1]-COS_LOOKUP[i]); -} - -/* interpolated 1./sqrt(p) where .5 <= p < 1. */ -float vorbis_invsqlook(float a){ - double d=a*(2.f*(float)INVSQ_LOOKUP_SZ)-(float)INVSQ_LOOKUP_SZ; - int i=vorbis_ftoi(d-.5f); - return INVSQ_LOOKUP[i]+ (d-i)*(INVSQ_LOOKUP[i+1]-INVSQ_LOOKUP[i]); -} - -/* interpolated 1./sqrt(p) where .5 <= p < 1. */ -float vorbis_invsq2explook(int a){ - return INVSQ2EXP_LOOKUP[a-INVSQ2EXP_LOOKUP_MIN]; -} - -#include -/* interpolated lookup based fromdB function, domain -140dB to 0dB only */ -float vorbis_fromdBlook(float a){ - int i=vorbis_ftoi(a*((float)(-(1<=(FROMdB_LOOKUP_SZ<>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]); -} - -#endif - -#ifdef INT_LOOKUP -/* interpolated 1./sqrt(p) where .5 <= a < 1. (.100000... to .111111...) in - 16.16 format - - returns in m.8 format */ -long vorbis_invsqlook_i(long a,long e){ - long i=(a&0x7fff)>>(INVSQ_LOOKUP_I_SHIFT-1); - long d=(a&INVSQ_LOOKUP_I_MASK)<<(16-INVSQ_LOOKUP_I_SHIFT); /* 0.16 */ - long val=INVSQ_LOOKUP_I[i]- /* 1.16 */ - (((INVSQ_LOOKUP_I[i]-INVSQ_LOOKUP_I[i+1])* /* 0.16 */ - d)>>16); /* result 1.16 */ - - e+=32; - if(e&1)val=(val*5792)>>13; /* multiply val by 1/sqrt(2) */ - e=(e>>1)-8; - - return(val>>e); -} - -/* interpolated lookup based fromdB function, domain -140dB to 0dB only */ -/* a is in n.12 format */ -float vorbis_fromdBlook_i(long a){ - int i=(-a)>>(12-FROMdB2_SHIFT); - return (i<0)?1.f: - ((i>=(FROMdB_LOOKUP_SZ<>FROMdB_SHIFT]*FROMdB2_LOOKUP[i&FROMdB2_MASK]); -} - -/* interpolated lookup based cos function, domain 0 to PI only */ -/* a is in 0.16 format, where 0==0, 2^^16-1==PI, return 0.14 */ -long vorbis_coslook_i(long a){ - int i=a>>COS_LOOKUP_I_SHIFT; - int d=a&COS_LOOKUP_I_MASK; - return COS_LOOKUP_I[i]- ((d*(COS_LOOKUP_I[i]-COS_LOOKUP_I[i+1]))>> - COS_LOOKUP_I_SHIFT); -} - -#endif diff --git a/src/lib/vorbis/src/lookup.h b/src/lib/vorbis/src/lookup.h deleted file mode 100644 index ec05014f..00000000 --- a/src/lib/vorbis/src/lookup.h +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: lookup based functions - - ********************************************************************/ - -#ifndef _V_LOOKUP_H_ - -#ifdef FLOAT_LOOKUP -extern float vorbis_coslook(float a); -extern float vorbis_invsqlook(float a); -extern float vorbis_invsq2explook(int a); -extern float vorbis_fromdBlook(float a); -#endif -#ifdef INT_LOOKUP -extern long vorbis_invsqlook_i(long a,long e); -extern long vorbis_coslook_i(long a); -extern float vorbis_fromdBlook_i(long a); -#endif - -#endif diff --git a/src/lib/vorbis/src/lookup_data.h b/src/lib/vorbis/src/lookup_data.h deleted file mode 100644 index 7935715a..00000000 --- a/src/lib/vorbis/src/lookup_data.h +++ /dev/null @@ -1,191 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: lookup data; generated by lookups.pl; edit there - - ********************************************************************/ - -#ifndef _V_LOOKUP_DATA_H_ - -#ifdef FLOAT_LOOKUP -#define COS_LOOKUP_SZ 128 -static const float COS_LOOKUP[COS_LOOKUP_SZ+1]={ - +1.0000000000000f,+0.9996988186962f,+0.9987954562052f,+0.9972904566787f, - +0.9951847266722f,+0.9924795345987f,+0.9891765099648f,+0.9852776423889f, - +0.9807852804032f,+0.9757021300385f,+0.9700312531945f,+0.9637760657954f, - +0.9569403357322f,+0.9495281805930f,+0.9415440651830f,+0.9329927988347f, - +0.9238795325113f,+0.9142097557035f,+0.9039892931234f,+0.8932243011955f, - +0.8819212643484f,+0.8700869911087f,+0.8577286100003f,+0.8448535652497f, - +0.8314696123025f,+0.8175848131516f,+0.8032075314806f,+0.7883464276266f, - +0.7730104533627f,+0.7572088465065f,+0.7409511253550f,+0.7242470829515f, - +0.7071067811865f,+0.6895405447371f,+0.6715589548470f,+0.6531728429538f, - +0.6343932841636f,+0.6152315905806f,+0.5956993044924f,+0.5758081914178f, - +0.5555702330196f,+0.5349976198871f,+0.5141027441932f,+0.4928981922298f, - +0.4713967368260f,+0.4496113296546f,+0.4275550934303f,+0.4052413140050f, - +0.3826834323651f,+0.3598950365350f,+0.3368898533922f,+0.3136817403989f, - +0.2902846772545f,+0.2667127574749f,+0.2429801799033f,+0.2191012401569f, - +0.1950903220161f,+0.1709618887603f,+0.1467304744554f,+0.1224106751992f, - +0.0980171403296f,+0.0735645635997f,+0.0490676743274f,+0.0245412285229f, - +0.0000000000000f,-0.0245412285229f,-0.0490676743274f,-0.0735645635997f, - -0.0980171403296f,-0.1224106751992f,-0.1467304744554f,-0.1709618887603f, - -0.1950903220161f,-0.2191012401569f,-0.2429801799033f,-0.2667127574749f, - -0.2902846772545f,-0.3136817403989f,-0.3368898533922f,-0.3598950365350f, - -0.3826834323651f,-0.4052413140050f,-0.4275550934303f,-0.4496113296546f, - -0.4713967368260f,-0.4928981922298f,-0.5141027441932f,-0.5349976198871f, - -0.5555702330196f,-0.5758081914178f,-0.5956993044924f,-0.6152315905806f, - -0.6343932841636f,-0.6531728429538f,-0.6715589548470f,-0.6895405447371f, - -0.7071067811865f,-0.7242470829515f,-0.7409511253550f,-0.7572088465065f, - -0.7730104533627f,-0.7883464276266f,-0.8032075314806f,-0.8175848131516f, - -0.8314696123025f,-0.8448535652497f,-0.8577286100003f,-0.8700869911087f, - -0.8819212643484f,-0.8932243011955f,-0.9039892931234f,-0.9142097557035f, - -0.9238795325113f,-0.9329927988347f,-0.9415440651830f,-0.9495281805930f, - -0.9569403357322f,-0.9637760657954f,-0.9700312531945f,-0.9757021300385f, - -0.9807852804032f,-0.9852776423889f,-0.9891765099648f,-0.9924795345987f, - -0.9951847266722f,-0.9972904566787f,-0.9987954562052f,-0.9996988186962f, - -1.0000000000000f, -}; - -#define INVSQ_LOOKUP_SZ 32 -static const float INVSQ_LOOKUP[INVSQ_LOOKUP_SZ+1]={ - 1.414213562373f,1.392621247646f,1.371988681140f,1.352246807566f, - 1.333333333333f,1.315191898443f,1.297771369046f,1.281025230441f, - 1.264911064067f,1.249390095109f,1.234426799697f,1.219988562661f, - 1.206045378311f,1.192569588000f,1.179535649239f,1.166919931983f, - 1.154700538379f,1.142857142857f,1.131370849898f,1.120224067222f, - 1.109400392450f,1.098884511590f,1.088662107904f,1.078719779941f, - 1.069044967650f,1.059625885652f,1.050451462878f,1.041511287847f, - 1.032795558989f,1.024295039463f,1.016001016002f,1.007905261358f, - 1.000000000000f, -}; - -#define INVSQ2EXP_LOOKUP_MIN (-32) -#define INVSQ2EXP_LOOKUP_MAX 32 -static const float INVSQ2EXP_LOOKUP[INVSQ2EXP_LOOKUP_MAX-\ - INVSQ2EXP_LOOKUP_MIN+1]={ - 65536.f, 46340.95001f, 32768.f, 23170.47501f, - 16384.f, 11585.2375f, 8192.f, 5792.618751f, - 4096.f, 2896.309376f, 2048.f, 1448.154688f, - 1024.f, 724.0773439f, 512.f, 362.038672f, - 256.f, 181.019336f, 128.f, 90.50966799f, - 64.f, 45.254834f, 32.f, 22.627417f, - 16.f, 11.3137085f, 8.f, 5.656854249f, - 4.f, 2.828427125f, 2.f, 1.414213562f, - 1.f, 0.7071067812f, 0.5f, 0.3535533906f, - 0.25f, 0.1767766953f, 0.125f, 0.08838834765f, - 0.0625f, 0.04419417382f, 0.03125f, 0.02209708691f, - 0.015625f, 0.01104854346f, 0.0078125f, 0.005524271728f, - 0.00390625f, 0.002762135864f, 0.001953125f, 0.001381067932f, - 0.0009765625f, 0.000690533966f, 0.00048828125f, 0.000345266983f, - 0.000244140625f,0.0001726334915f,0.0001220703125f,8.631674575e-05f, - 6.103515625e-05f,4.315837288e-05f,3.051757812e-05f,2.157918644e-05f, - 1.525878906e-05f, -}; - -#endif - -#define FROMdB_LOOKUP_SZ 35 -#define FROMdB2_LOOKUP_SZ 32 -#define FROMdB_SHIFT 5 -#define FROMdB2_SHIFT 3 -#define FROMdB2_MASK 31 - -#ifdef FLOAT_LOOKUP -static const float FROMdB_LOOKUP[FROMdB_LOOKUP_SZ]={ - 1.f, 0.6309573445f, 0.3981071706f, 0.2511886432f, - 0.1584893192f, 0.1f, 0.06309573445f, 0.03981071706f, - 0.02511886432f, 0.01584893192f, 0.01f, 0.006309573445f, - 0.003981071706f, 0.002511886432f, 0.001584893192f, 0.001f, - 0.0006309573445f,0.0003981071706f,0.0002511886432f,0.0001584893192f, - 0.0001f,6.309573445e-05f,3.981071706e-05f,2.511886432e-05f, - 1.584893192e-05f, 1e-05f,6.309573445e-06f,3.981071706e-06f, - 2.511886432e-06f,1.584893192e-06f, 1e-06f,6.309573445e-07f, - 3.981071706e-07f,2.511886432e-07f,1.584893192e-07f, -}; - -static const float FROMdB2_LOOKUP[FROMdB2_LOOKUP_SZ]={ - 0.9928302478f, 0.9786445908f, 0.9646616199f, 0.9508784391f, - 0.9372921937f, 0.92390007f, 0.9106992942f, 0.8976871324f, - 0.8848608897f, 0.8722179097f, 0.8597555737f, 0.8474713009f, - 0.835362547f, 0.8234268041f, 0.8116616003f, 0.8000644989f, - 0.7886330981f, 0.7773650302f, 0.7662579617f, 0.755309592f, - 0.7445176537f, 0.7338799116f, 0.7233941627f, 0.7130582353f, - 0.7028699885f, 0.6928273125f, 0.6829281272f, 0.6731703824f, - 0.6635520573f, 0.6540711597f, 0.6447257262f, 0.6355138211f, -}; -#endif - -#ifdef INT_LOOKUP - -#define INVSQ_LOOKUP_I_SHIFT 10 -#define INVSQ_LOOKUP_I_MASK 1023 -static const long INVSQ_LOOKUP_I[64+1]={ - 92682l, 91966l, 91267l, 90583l, - 89915l, 89261l, 88621l, 87995l, - 87381l, 86781l, 86192l, 85616l, - 85051l, 84497l, 83953l, 83420l, - 82897l, 82384l, 81880l, 81385l, - 80899l, 80422l, 79953l, 79492l, - 79039l, 78594l, 78156l, 77726l, - 77302l, 76885l, 76475l, 76072l, - 75674l, 75283l, 74898l, 74519l, - 74146l, 73778l, 73415l, 73058l, - 72706l, 72359l, 72016l, 71679l, - 71347l, 71019l, 70695l, 70376l, - 70061l, 69750l, 69444l, 69141l, - 68842l, 68548l, 68256l, 67969l, - 67685l, 67405l, 67128l, 66855l, - 66585l, 66318l, 66054l, 65794l, - 65536l, -}; - -#define COS_LOOKUP_I_SHIFT 9 -#define COS_LOOKUP_I_MASK 511 -#define COS_LOOKUP_I_SZ 128 -static const long COS_LOOKUP_I[COS_LOOKUP_I_SZ+1]={ - 16384l, 16379l, 16364l, 16340l, - 16305l, 16261l, 16207l, 16143l, - 16069l, 15986l, 15893l, 15791l, - 15679l, 15557l, 15426l, 15286l, - 15137l, 14978l, 14811l, 14635l, - 14449l, 14256l, 14053l, 13842l, - 13623l, 13395l, 13160l, 12916l, - 12665l, 12406l, 12140l, 11866l, - 11585l, 11297l, 11003l, 10702l, - 10394l, 10080l, 9760l, 9434l, - 9102l, 8765l, 8423l, 8076l, - 7723l, 7366l, 7005l, 6639l, - 6270l, 5897l, 5520l, 5139l, - 4756l, 4370l, 3981l, 3590l, - 3196l, 2801l, 2404l, 2006l, - 1606l, 1205l, 804l, 402l, - 0l, -401l, -803l, -1204l, - -1605l, -2005l, -2403l, -2800l, - -3195l, -3589l, -3980l, -4369l, - -4755l, -5138l, -5519l, -5896l, - -6269l, -6638l, -7004l, -7365l, - -7722l, -8075l, -8422l, -8764l, - -9101l, -9433l, -9759l, -10079l, - -10393l, -10701l, -11002l, -11296l, - -11584l, -11865l, -12139l, -12405l, - -12664l, -12915l, -13159l, -13394l, - -13622l, -13841l, -14052l, -14255l, - -14448l, -14634l, -14810l, -14977l, - -15136l, -15285l, -15425l, -15556l, - -15678l, -15790l, -15892l, -15985l, - -16068l, -16142l, -16206l, -16260l, - -16304l, -16339l, -16363l, -16378l, - -16383l, -}; - -#endif - -#endif diff --git a/src/lib/vorbis/src/lpc.c b/src/lib/vorbis/src/lpc.c deleted file mode 100644 index 877da47f..00000000 --- a/src/lib/vorbis/src/lpc.c +++ /dev/null @@ -1,159 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: LPC low level routines - - ********************************************************************/ - -/* Some of these routines (autocorrelator, LPC coefficient estimator) - are derived from code written by Jutta Degener and Carsten Bormann; - thus we include their copyright below. The entirety of this file - is freely redistributable on the condition that both of these - copyright notices are preserved without modification. */ - -/* Preserved Copyright: *********************************************/ - -/* Copyright 1992, 1993, 1994 by Jutta Degener and Carsten Bormann, -Technische Universita"t Berlin - -Any use of this software is permitted provided that this notice is not -removed and that neither the authors nor the Technische Universita"t -Berlin are deemed to have made any representations as to the -suitability of this software for any purpose nor are held responsible -for any defects of this software. THERE IS ABSOLUTELY NO WARRANTY FOR -THIS SOFTWARE. - -As a matter of courtesy, the authors request to be informed about uses -this software has found, about bugs in this software, and about any -improvements that may be of general interest. - -Berlin, 28.11.1994 -Jutta Degener -Carsten Bormann - -*********************************************************************/ - -#include -#include -#include -#include "os.h" -#include "smallft.h" -#include "lpc.h" -#include "scales.h" -#include "misc.h" - -/* Autocorrelation LPC coeff generation algorithm invented by - N. Levinson in 1947, modified by J. Durbin in 1959. */ - -/* Input : n elements of time doamin data - Output: m lpc coefficients, excitation energy */ - -float vorbis_lpc_from_data(float *data,float *lpci,int n,int m){ - double *aut=alloca(sizeof(*aut)*(m+1)); - double *lpc=alloca(sizeof(*lpc)*(m)); - double error; - double epsilon; - int i,j; - - /* autocorrelation, p+1 lag coefficients */ - j=m+1; - while(j--){ - double d=0; /* double needed for accumulator depth */ - for(i=j;i -#include -#include -#include "lsp.h" -#include "os.h" -#include "misc.h" -#include "lookup.h" -#include "scales.h" - -/* three possible LSP to f curve functions; the exact computation - (float), a lookup based float implementation, and an integer - implementation. The float lookup is likely the optimal choice on - any machine with an FPU. The integer implementation is *not* fixed - point (due to the need for a large dynamic range and thus a - separately tracked exponent) and thus much more complex than the - relatively simple float implementations. It's mostly for future - work on a fully fixed point implementation for processors like the - ARM family. */ - -/* define either of these (preferably FLOAT_LOOKUP) to have faster - but less precise implementation. */ -#undef FLOAT_LOOKUP -#undef INT_LOOKUP - -#ifdef FLOAT_LOOKUP -#include "lookup.c" /* catch this in the build system; we #include for - compilers (like gcc) that can't inline across - modules */ - -/* side effect: changes *lsp to cosines of lsp */ -void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, - float amp,float ampoffset){ - int i; - float wdel=M_PI/ln; - vorbis_fpu_control fpu; - - vorbis_fpu_setround(&fpu); - for(i=0;i>1; - - while(c--){ - q*=ftmp[0]-w; - p*=ftmp[1]-w; - ftmp+=2; - } - - if(m&1){ - /* odd order filter; slightly assymetric */ - /* the last coefficient */ - q*=ftmp[0]-w; - q*=q; - p*=p*(1.f-w*w); - }else{ - /* even order filter; still symmetric */ - q*=q*(1.f+w); - p*=p*(1.f-w); - } - - q=frexp(p+q,&qexp); - q=vorbis_fromdBlook(amp* - vorbis_invsqlook(q)* - vorbis_invsq2explook(qexp+m)- - ampoffset); - - do{ - curve[i++]*=q; - }while(map[i]==k); - } - vorbis_fpu_restore(fpu); -} - -#else - -#ifdef INT_LOOKUP -#include "lookup.c" /* catch this in the build system; we #include for - compilers (like gcc) that can't inline across - modules */ - -static const int MLOOP_1[64]={ - 0,10,11,11, 12,12,12,12, 13,13,13,13, 13,13,13,13, - 14,14,14,14, 14,14,14,14, 14,14,14,14, 14,14,14,14, - 15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15, - 15,15,15,15, 15,15,15,15, 15,15,15,15, 15,15,15,15, -}; - -static const int MLOOP_2[64]={ - 0,4,5,5, 6,6,6,6, 7,7,7,7, 7,7,7,7, - 8,8,8,8, 8,8,8,8, 8,8,8,8, 8,8,8,8, - 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9, - 9,9,9,9, 9,9,9,9, 9,9,9,9, 9,9,9,9, -}; - -static const int MLOOP_3[8]={0,1,2,2,3,3,3,3}; - - -/* side effect: changes *lsp to cosines of lsp */ -void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, - float amp,float ampoffset){ - - /* 0 <= m < 256 */ - - /* set up for using all int later */ - int i; - int ampoffseti=rint(ampoffset*4096.f); - int ampi=rint(amp*16.f); - long *ilsp=alloca(m*sizeof(*ilsp)); - for(i=0;i>25])) - if(!(shift=MLOOP_2[(pi|qi)>>19])) - shift=MLOOP_3[(pi|qi)>>16]; - qi=(qi>>shift)*labs(ilsp[j-1]-wi); - pi=(pi>>shift)*labs(ilsp[j]-wi); - qexp+=shift; - } - if(!(shift=MLOOP_1[(pi|qi)>>25])) - if(!(shift=MLOOP_2[(pi|qi)>>19])) - shift=MLOOP_3[(pi|qi)>>16]; - - /* pi,qi normalized collectively, both tracked using qexp */ - - if(m&1){ - /* odd order filter; slightly assymetric */ - /* the last coefficient */ - qi=(qi>>shift)*labs(ilsp[j-1]-wi); - pi=(pi>>shift)<<14; - qexp+=shift; - - if(!(shift=MLOOP_1[(pi|qi)>>25])) - if(!(shift=MLOOP_2[(pi|qi)>>19])) - shift=MLOOP_3[(pi|qi)>>16]; - - pi>>=shift; - qi>>=shift; - qexp+=shift-14*((m+1)>>1); - - pi=((pi*pi)>>16); - qi=((qi*qi)>>16); - qexp=qexp*2+m; - - pi*=(1<<14)-((wi*wi)>>14); - qi+=pi>>14; - - }else{ - /* even order filter; still symmetric */ - - /* p*=p(1-w), q*=q(1+w), let normalization drift because it isn't - worth tracking step by step */ - - pi>>=shift; - qi>>=shift; - qexp+=shift-7*m; - - pi=((pi*pi)>>16); - qi=((qi*qi)>>16); - qexp=qexp*2+m; - - pi*=(1<<14)-wi; - qi*=(1<<14)+wi; - qi=(qi+pi)>>14; - - } - - - /* we've let the normalization drift because it wasn't important; - however, for the lookup, things must be normalized again. We - need at most one right shift or a number of left shifts */ - - if(qi&0xffff0000){ /* checks for 1.xxxxxxxxxxxxxxxx */ - qi>>=1; qexp++; - }else - while(qi && !(qi&0x8000)){ /* checks for 0.0xxxxxxxxxxxxxxx or less*/ - qi<<=1; qexp--; - } - - amp=vorbis_fromdBlook_i(ampi* /* n.4 */ - vorbis_invsqlook_i(qi,qexp)- - /* m.8, m+n<=8 */ - ampoffseti); /* 8.12[0] */ - - curve[i]*=amp; - while(map[++i]==k)curve[i]*=amp; - } -} - -#else - -/* old, nonoptimized but simple version for any poor sap who needs to - figure out what the hell this code does, or wants the other - fraction of a dB precision */ - -/* side effect: changes *lsp to cosines of lsp */ -void vorbis_lsp_to_curve(float *curve,int *map,int n,int ln,float *lsp,int m, - float amp,float ampoffset){ - int i; - float wdel=M_PI/ln; - for(i=0;i= i; j--) { - g[j-2] -= g[j]; - g[j] += g[j]; - } - } -} - -static int comp(const void *a,const void *b){ - return (*(float *)a<*(float *)b)-(*(float *)a>*(float *)b); -} - -/* Newton-Raphson-Maehly actually functioned as a decent root finder, - but there are root sets for which it gets into limit cycles - (exacerbated by zero suppression) and fails. We can't afford to - fail, even if the failure is 1 in 100,000,000, so we now use - Laguerre and later polish with Newton-Raphson (which can then - afford to fail) */ - -#define EPSILON 10e-7 -static int Laguerre_With_Deflation(float *a,int ord,float *r){ - int i,m; - double *defl=alloca(sizeof(*defl)*(ord+1)); - for(i=0;i<=ord;i++)defl[i]=a[i]; - - for(m=ord;m>0;m--){ - double new=0.f,delta; - - /* iterate a root */ - while(1){ - double p=defl[m],pp=0.f,ppp=0.f,denom; - - /* eval the polynomial and its first two derivatives */ - for(i=m;i>0;i--){ - ppp = new*ppp + pp; - pp = new*pp + p; - p = new*p + defl[i-1]; - } - - /* Laguerre's method */ - denom=(m-1) * ((m-1)*pp*pp - m*p*ppp); - if(denom<0) - return(-1); /* complex root! The LPC generator handed us a bad filter */ - - if(pp>0){ - denom = pp + sqrt(denom); - if(denom-(EPSILON))denom=-(EPSILON); - } - - delta = m*p/denom; - new -= delta; - - if(delta<0.f)delta*=-1; - - if(fabs(delta/new)<10e-12)break; - } - - r[m-1]=new; - - /* forward deflation */ - - for(i=m;i>0;i--) - defl[i-1]+=new*defl[i]; - defl++; - - } - return(0); -} - - -/* for spit-and-polish only */ -static int Newton_Raphson(float *a,int ord,float *r){ - int i, k, count=0; - double error=1.f; - double *root=alloca(ord*sizeof(*root)); - - for(i=0; i1e-20){ - error=0; - - for(i=0; i= 0; k--) { - - pp= pp* rooti + p; - p = p * rooti + a[k]; - } - - delta = p/pp; - root[i] -= delta; - error+= delta*delta; - } - - if(count>40)return(-1); - - count++; - } - - /* Replaced the original bubble sort with a real sort. With your - help, we can eliminate the bubble sort in our lifetime. --Monty */ - - for(i=0; i>1; - int g1_order,g2_order; - float *g1=alloca(sizeof(*g1)*(order2+1)); - float *g2=alloca(sizeof(*g2)*(order2+1)); - float *g1r=alloca(sizeof(*g1r)*(order2+1)); - float *g2r=alloca(sizeof(*g2r)*(order2+1)); - int i; - - /* even and odd are slightly different base cases */ - g1_order=(m+1)>>1; - g2_order=(m) >>1; - - /* Compute the lengths of the x polynomials. */ - /* Compute the first half of K & R F1 & F2 polynomials. */ - /* Compute half of the symmetric and antisymmetric polynomials. */ - /* Remove the roots at +1 and -1. */ - - g1[g1_order] = 1.f; - for(i=1;i<=g1_order;i++) g1[g1_order-i] = lpc[i-1]+lpc[m-i]; - g2[g2_order] = 1.f; - for(i=1;i<=g2_order;i++) g2[g2_order-i] = lpc[i-1]-lpc[m-i]; - - if(g1_order>g2_order){ - for(i=2; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+2]; - }else{ - for(i=1; i<=g1_order;i++) g1[g1_order-i] -= g1[g1_order-i+1]; - for(i=1; i<=g2_order;i++) g2[g2_order-i] += g2[g2_order-i+1]; - } - - /* Convert into polynomials in cos(alpha) */ - cheby(g1,g1_order); - cheby(g2,g2_order); - - /* Find the roots of the 2 even polynomials.*/ - if(Laguerre_With_Deflation(g1,g1_order,g1r) || - Laguerre_With_Deflation(g2,g2_order,g2r)) - return(-1); - - Newton_Raphson(g1,g1_order,g1r); /* if it fails, it leaves g1r alone */ - Newton_Raphson(g2,g2_order,g2r); /* if it fails, it leaves g2r alone */ - - qsort(g1r,g1_order,sizeof(*g1r),comp); - qsort(g2r,g2_order,sizeof(*g2r),comp); - - for(i=0;i -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "codebook.h" -#include "window.h" -#include "registry.h" -#include "psy.h" -#include "misc.h" - -/* simplistic, wasteful way of doing this (unique lookup for each - mode/submapping); there should be a central repository for - identical lookups. That will require minor work, so I'm putting it - off as low priority. - - Why a lookup for each backend in a given mode? Because the - blocksize is set by the mode, and low backend lookups may require - parameters from other areas of the mode/mapping */ - -static void mapping0_free_info(vorbis_info_mapping *i){ - vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)i; - if(info){ - memset(info,0,sizeof(*info)); - _ogg_free(info); - } -} - -static void mapping0_pack(vorbis_info *vi,vorbis_info_mapping *vm, - oggpack_buffer *opb){ - int i; - vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)vm; - - /* another 'we meant to do it this way' hack... up to beta 4, we - packed 4 binary zeros here to signify one submapping in use. We - now redefine that to mean four bitflags that indicate use of - deeper features; bit0:submappings, bit1:coupling, - bit2,3:reserved. This is backward compatable with all actual uses - of the beta code. */ - - if(info->submaps>1){ - oggpack_write(opb,1,1); - oggpack_write(opb,info->submaps-1,4); - }else - oggpack_write(opb,0,1); - - if(info->coupling_steps>0){ - oggpack_write(opb,1,1); - oggpack_write(opb,info->coupling_steps-1,8); - - for(i=0;icoupling_steps;i++){ - oggpack_write(opb,info->coupling_mag[i],ov_ilog(vi->channels-1)); - oggpack_write(opb,info->coupling_ang[i],ov_ilog(vi->channels-1)); - } - }else - oggpack_write(opb,0,1); - - oggpack_write(opb,0,2); /* 2,3:reserved */ - - /* we don't write the channel submappings if we only have one... */ - if(info->submaps>1){ - for(i=0;ichannels;i++) - oggpack_write(opb,info->chmuxlist[i],4); - } - for(i=0;isubmaps;i++){ - oggpack_write(opb,0,8); /* time submap unused */ - oggpack_write(opb,info->floorsubmap[i],8); - oggpack_write(opb,info->residuesubmap[i],8); - } -} - -/* also responsible for range checking */ -static vorbis_info_mapping *mapping0_unpack(vorbis_info *vi,oggpack_buffer *opb){ - int i,b; - vorbis_info_mapping0 *info=_ogg_calloc(1,sizeof(*info)); - codec_setup_info *ci=vi->codec_setup; - if(vi->channels<=0)goto err_out; - - b=oggpack_read(opb,1); - if(b<0)goto err_out; - if(b){ - info->submaps=oggpack_read(opb,4)+1; - if(info->submaps<=0)goto err_out; - }else - info->submaps=1; - - b=oggpack_read(opb,1); - if(b<0)goto err_out; - if(b){ - info->coupling_steps=oggpack_read(opb,8)+1; - if(info->coupling_steps<=0)goto err_out; - for(i=0;icoupling_steps;i++){ - /* vi->channels > 0 is enforced in the caller */ - int testM=info->coupling_mag[i]= - oggpack_read(opb,ov_ilog(vi->channels-1)); - int testA=info->coupling_ang[i]= - oggpack_read(opb,ov_ilog(vi->channels-1)); - - if(testM<0 || - testA<0 || - testM==testA || - testM>=vi->channels || - testA>=vi->channels) goto err_out; - } - - } - - if(oggpack_read(opb,2)!=0)goto err_out; /* 2,3:reserved */ - - if(info->submaps>1){ - for(i=0;ichannels;i++){ - info->chmuxlist[i]=oggpack_read(opb,4); - if(info->chmuxlist[i]>=info->submaps || info->chmuxlist[i]<0)goto err_out; - } - } - for(i=0;isubmaps;i++){ - oggpack_read(opb,8); /* time submap unused */ - info->floorsubmap[i]=oggpack_read(opb,8); - if(info->floorsubmap[i]>=ci->floors || info->floorsubmap[i]<0)goto err_out; - info->residuesubmap[i]=oggpack_read(opb,8); - if(info->residuesubmap[i]>=ci->residues || info->residuesubmap[i]<0)goto err_out; - } - - return info; - - err_out: - mapping0_free_info(info); - return(NULL); -} - -#include "os.h" -#include "lpc.h" -#include "lsp.h" -#include "envelope.h" -#include "mdct.h" -#include "psy.h" -#include "scales.h" - -#if 0 -static long seq=0; -static ogg_int64_t total=0; -static float FLOOR1_fromdB_LOOKUP[256]={ - 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, - 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, - 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, - 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, - 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, - 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, - 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, - 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, - 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, - 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, - 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, - 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, - 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, - 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, - 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, - 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, - 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, - 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, - 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, - 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, - 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, - 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, - 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, - 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, - 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, - 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, - 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, - 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, - 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, - 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, - 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, - 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, - 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, - 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, - 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, - 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, - 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, - 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, - 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, - 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, - 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, - 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, - 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, - 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, - 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, - 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, - 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, - 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, - 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, - 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, - 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, - 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, - 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, - 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, - 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, - 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, - 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, - 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, - 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, - 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, - 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, - 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, - 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, - 0.82788260F, 0.88168307F, 0.9389798F, 1.F, -}; - -#endif - - -static int mapping0_forward(vorbis_block *vb){ - vorbis_dsp_state *vd=vb->vd; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=vi->codec_setup; - private_state *b=vb->vd->backend_state; - vorbis_block_internal *vbi=(vorbis_block_internal *)vb->internal; - int n=vb->pcmend; - int i,j,k; - - int *nonzero = alloca(sizeof(*nonzero)*vi->channels); - float **gmdct = _vorbis_block_alloc(vb,vi->channels*sizeof(*gmdct)); - int **iwork = _vorbis_block_alloc(vb,vi->channels*sizeof(*iwork)); - int ***floor_posts = _vorbis_block_alloc(vb,vi->channels*sizeof(*floor_posts)); - - float global_ampmax=vbi->ampmax; - float *local_ampmax=alloca(sizeof(*local_ampmax)*vi->channels); - int blocktype=vbi->blocktype; - - int modenumber=vb->W; - vorbis_info_mapping0 *info=ci->map_param[modenumber]; - vorbis_look_psy *psy_look=b->psy+blocktype+(vb->W?2:0); - - vb->mode=modenumber; - - for(i=0;ichannels;i++){ - float scale=4.f/n; - float scale_dB; - - float *pcm =vb->pcm[i]; - float *logfft =pcm; - - iwork[i]=_vorbis_block_alloc(vb,n/2*sizeof(**iwork)); - gmdct[i]=_vorbis_block_alloc(vb,n/2*sizeof(**gmdct)); - - scale_dB=todB(&scale) + .345; /* + .345 is a hack; the original - todB estimation used on IEEE 754 - compliant machines had a bug that - returned dB values about a third - of a decibel too high. The bug - was harmless because tunings - implicitly took that into - account. However, fixing the bug - in the estimator requires - changing all the tunings as well. - For now, it's easier to sync - things back up here, and - recalibrate the tunings in the - next major model upgrade. */ - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("pcmL",seq,pcm,n,0,0,total-n/2); - else - _analysis_output("pcmR",seq,pcm,n,0,0,total-n/2); - }else{ - _analysis_output("pcm",seq,pcm,n,0,0,total-n/2); - } -#endif - - /* window the PCM data */ - _vorbis_apply_window(pcm,b->window,ci->blocksizes,vb->lW,vb->W,vb->nW); - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("windowedL",seq,pcm,n,0,0,total-n/2); - else - _analysis_output("windowedR",seq,pcm,n,0,0,total-n/2); - }else{ - _analysis_output("windowed",seq,pcm,n,0,0,total-n/2); - } -#endif - - /* transform the PCM data */ - /* only MDCT right now.... */ - mdct_forward(b->transform[vb->W][0],pcm,gmdct[i]); - - /* FFT yields more accurate tonal estimation (not phase sensitive) */ - drft_forward(&b->fft_look[vb->W],pcm); - logfft[0]=scale_dB+todB(pcm) + .345; /* + .345 is a hack; the - original todB estimation used on - IEEE 754 compliant machines had a - bug that returned dB values about - a third of a decibel too high. - The bug was harmless because - tunings implicitly took that into - account. However, fixing the bug - in the estimator requires - changing all the tunings as well. - For now, it's easier to sync - things back up here, and - recalibrate the tunings in the - next major model upgrade. */ - local_ampmax[i]=logfft[0]; - for(j=1;j>1]=scale_dB+.5f*todB(&temp) + .345; /* + - .345 is a hack; the original todB - estimation used on IEEE 754 - compliant machines had a bug that - returned dB values about a third - of a decibel too high. The bug - was harmless because tunings - implicitly took that into - account. However, fixing the bug - in the estimator requires - changing all the tunings as well. - For now, it's easier to sync - things back up here, and - recalibrate the tunings in the - next major model upgrade. */ - if(temp>local_ampmax[i])local_ampmax[i]=temp; - } - - if(local_ampmax[i]>0.f)local_ampmax[i]=0.f; - if(local_ampmax[i]>global_ampmax)global_ampmax=local_ampmax[i]; - -#if 0 - if(vi->channels==2){ - if(i==0){ - _analysis_output("fftL",seq,logfft,n/2,1,0,0); - }else{ - _analysis_output("fftR",seq,logfft,n/2,1,0,0); - } - }else{ - _analysis_output("fft",seq,logfft,n/2,1,0,0); - } -#endif - - } - - { - float *noise = _vorbis_block_alloc(vb,n/2*sizeof(*noise)); - float *tone = _vorbis_block_alloc(vb,n/2*sizeof(*tone)); - - for(i=0;ichannels;i++){ - /* the encoder setup assumes that all the modes used by any - specific bitrate tweaking use the same floor */ - - int submap=info->chmuxlist[i]; - - /* the following makes things clearer to *me* anyway */ - float *mdct =gmdct[i]; - float *logfft =vb->pcm[i]; - - float *logmdct =logfft+n/2; - float *logmask =logfft; - - vb->mode=modenumber; - - floor_posts[i]=_vorbis_block_alloc(vb,PACKETBLOBS*sizeof(**floor_posts)); - memset(floor_posts[i],0,sizeof(**floor_posts)*PACKETBLOBS); - - for(j=0;jchannels==2){ - if(i==0) - _analysis_output("mdctL",seq,logmdct,n/2,1,0,0); - else - _analysis_output("mdctR",seq,logmdct,n/2,1,0,0); - }else{ - _analysis_output("mdct",seq,logmdct,n/2,1,0,0); - } -#endif - - /* first step; noise masking. Not only does 'noise masking' - give us curves from which we can decide how much resolution - to give noise parts of the spectrum, it also implicitly hands - us a tonality estimate (the larger the value in the - 'noise_depth' vector, the more tonal that area is) */ - - _vp_noisemask(psy_look, - logmdct, - noise); /* noise does not have by-frequency offset - bias applied yet */ -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("noiseL",seq,noise,n/2,1,0,0); - else - _analysis_output("noiseR",seq,noise,n/2,1,0,0); - }else{ - _analysis_output("noise",seq,noise,n/2,1,0,0); - } -#endif - - /* second step: 'all the other crap'; all the stuff that isn't - computed/fit for bitrate management goes in the second psy - vector. This includes tone masking, peak limiting and ATH */ - - _vp_tonemask(psy_look, - logfft, - tone, - global_ampmax, - local_ampmax[i]); - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("toneL",seq,tone,n/2,1,0,0); - else - _analysis_output("toneR",seq,tone,n/2,1,0,0); - }else{ - _analysis_output("tone",seq,tone,n/2,1,0,0); - } -#endif - - /* third step; we offset the noise vectors, overlay tone - masking. We then do a floor1-specific line fit. If we're - performing bitrate management, the line fit is performed - multiple times for up/down tweakage on demand. */ - -#if 0 - { - float aotuv[psy_look->n]; -#endif - - _vp_offset_and_mix(psy_look, - noise, - tone, - 1, - logmask, - mdct, - logmdct); - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("aotuvM1_L",seq,aotuv,psy_look->n,1,1,0); - else - _analysis_output("aotuvM1_R",seq,aotuv,psy_look->n,1,1,0); - }else{ - _analysis_output("aotuvM1",seq,aotuv,psy_look->n,1,1,0); - } - } -#endif - - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("mask1L",seq,logmask,n/2,1,0,0); - else - _analysis_output("mask1R",seq,logmask,n/2,1,0,0); - }else{ - _analysis_output("mask1",seq,logmask,n/2,1,0,0); - } -#endif - - /* this algorithm is hardwired to floor 1 for now; abort out if - we're *not* floor1. This won't happen unless someone has - broken the encode setup lib. Guard it anyway. */ - if(ci->floor_type[info->floorsubmap[submap]]!=1)return(-1); - - floor_posts[i][PACKETBLOBS/2]= - floor1_fit(vb,b->flr[info->floorsubmap[submap]], - logmdct, - logmask); - - /* are we managing bitrate? If so, perform two more fits for - later rate tweaking (fits represent hi/lo) */ - if(vorbis_bitrate_managed(vb) && floor_posts[i][PACKETBLOBS/2]){ - /* higher rate by way of lower noise curve */ - - _vp_offset_and_mix(psy_look, - noise, - tone, - 2, - logmask, - mdct, - logmdct); - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("mask2L",seq,logmask,n/2,1,0,0); - else - _analysis_output("mask2R",seq,logmask,n/2,1,0,0); - }else{ - _analysis_output("mask2",seq,logmask,n/2,1,0,0); - } -#endif - - floor_posts[i][PACKETBLOBS-1]= - floor1_fit(vb,b->flr[info->floorsubmap[submap]], - logmdct, - logmask); - - /* lower rate by way of higher noise curve */ - _vp_offset_and_mix(psy_look, - noise, - tone, - 0, - logmask, - mdct, - logmdct); - -#if 0 - if(vi->channels==2){ - if(i==0) - _analysis_output("mask0L",seq,logmask,n/2,1,0,0); - else - _analysis_output("mask0R",seq,logmask,n/2,1,0,0); - }else{ - _analysis_output("mask0",seq,logmask,n/2,1,0,0); - } -#endif - - floor_posts[i][0]= - floor1_fit(vb,b->flr[info->floorsubmap[submap]], - logmdct, - logmask); - - /* we also interpolate a range of intermediate curves for - intermediate rates */ - for(k=1;kflr[info->floorsubmap[submap]], - floor_posts[i][0], - floor_posts[i][PACKETBLOBS/2], - k*65536/(PACKETBLOBS/2)); - for(k=PACKETBLOBS/2+1;kflr[info->floorsubmap[submap]], - floor_posts[i][PACKETBLOBS/2], - floor_posts[i][PACKETBLOBS-1], - (k-PACKETBLOBS/2)*65536/(PACKETBLOBS/2)); - } - } - } - vbi->ampmax=global_ampmax; - - /* - the next phases are performed once for vbr-only and PACKETBLOB - times for bitrate managed modes. - - 1) encode actual mode being used - 2) encode the floor for each channel, compute coded mask curve/res - 3) normalize and couple. - 4) encode residue - 5) save packet bytes to the packetblob vector - - */ - - /* iterate over the many masking curve fits we've created */ - - { - int **couple_bundle=alloca(sizeof(*couple_bundle)*vi->channels); - int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels); - - for(k=(vorbis_bitrate_managed(vb)?0:PACKETBLOBS/2); - k<=(vorbis_bitrate_managed(vb)?PACKETBLOBS-1:PACKETBLOBS/2); - k++){ - oggpack_buffer *opb=vbi->packetblob[k]; - - /* start out our new packet blob with packet type and mode */ - /* Encode the packet type */ - oggpack_write(opb,0,1); - /* Encode the modenumber */ - /* Encode frame mode, pre,post windowsize, then dispatch */ - oggpack_write(opb,modenumber,b->modebits); - if(vb->W){ - oggpack_write(opb,vb->lW,1); - oggpack_write(opb,vb->nW,1); - } - - /* encode floor, compute masking curve, sep out residue */ - for(i=0;ichannels;i++){ - int submap=info->chmuxlist[i]; - int *ilogmask=iwork[i]; - - nonzero[i]=floor1_encode(opb,vb,b->flr[info->floorsubmap[submap]], - floor_posts[i][k], - ilogmask); -#if 0 - { - char buf[80]; - sprintf(buf,"maskI%c%d",i?'R':'L',k); - float work[n/2]; - for(j=0;jpsy_g_param, - psy_look, - info, - gmdct, - iwork, - nonzero, - ci->psy_g_param.sliding_lowpass[vb->W][k], - vi->channels); - -#if 0 - for(i=0;ichannels;i++){ - char buf[80]; - sprintf(buf,"res%c%d",i?'R':'L',k); - float work[n/2]; - for(j=0;jsubmaps;i++){ - int ch_in_bundle=0; - long **classifications; - int resnum=info->residuesubmap[i]; - - for(j=0;jchannels;j++){ - if(info->chmuxlist[j]==i){ - zerobundle[ch_in_bundle]=0; - if(nonzero[j])zerobundle[ch_in_bundle]=1; - couple_bundle[ch_in_bundle++]=iwork[j]; - } - } - - classifications=_residue_P[ci->residue_type[resnum]]-> - class(vb,b->residue[resnum],couple_bundle,zerobundle,ch_in_bundle); - - ch_in_bundle=0; - for(j=0;jchannels;j++) - if(info->chmuxlist[j]==i) - couple_bundle[ch_in_bundle++]=iwork[j]; - - _residue_P[ci->residue_type[resnum]]-> - forward(opb,vb,b->residue[resnum], - couple_bundle,zerobundle,ch_in_bundle,classifications,i); - } - - /* ok, done encoding. Next protopacket. */ - } - - } - -#if 0 - seq++; - total+=ci->blocksizes[vb->W]/4+ci->blocksizes[vb->nW]/4; -#endif - return(0); -} - -static int mapping0_inverse(vorbis_block *vb,vorbis_info_mapping *l){ - vorbis_dsp_state *vd=vb->vd; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=vi->codec_setup; - private_state *b=vd->backend_state; - vorbis_info_mapping0 *info=(vorbis_info_mapping0 *)l; - - int i,j; - long n=vb->pcmend=ci->blocksizes[vb->W]; - - float **pcmbundle=alloca(sizeof(*pcmbundle)*vi->channels); - int *zerobundle=alloca(sizeof(*zerobundle)*vi->channels); - - int *nonzero =alloca(sizeof(*nonzero)*vi->channels); - void **floormemo=alloca(sizeof(*floormemo)*vi->channels); - - /* recover the spectral envelope; store it in the PCM vector for now */ - for(i=0;ichannels;i++){ - int submap=info->chmuxlist[i]; - floormemo[i]=_floor_P[ci->floor_type[info->floorsubmap[submap]]]-> - inverse1(vb,b->flr[info->floorsubmap[submap]]); - if(floormemo[i]) - nonzero[i]=1; - else - nonzero[i]=0; - memset(vb->pcm[i],0,sizeof(*vb->pcm[i])*n/2); - } - - /* channel coupling can 'dirty' the nonzero listing */ - for(i=0;icoupling_steps;i++){ - if(nonzero[info->coupling_mag[i]] || - nonzero[info->coupling_ang[i]]){ - nonzero[info->coupling_mag[i]]=1; - nonzero[info->coupling_ang[i]]=1; - } - } - - /* recover the residue into our working vectors */ - for(i=0;isubmaps;i++){ - int ch_in_bundle=0; - for(j=0;jchannels;j++){ - if(info->chmuxlist[j]==i){ - if(nonzero[j]) - zerobundle[ch_in_bundle]=1; - else - zerobundle[ch_in_bundle]=0; - pcmbundle[ch_in_bundle++]=vb->pcm[j]; - } - } - - _residue_P[ci->residue_type[info->residuesubmap[i]]]-> - inverse(vb,b->residue[info->residuesubmap[i]], - pcmbundle,zerobundle,ch_in_bundle); - } - - /* channel coupling */ - for(i=info->coupling_steps-1;i>=0;i--){ - float *pcmM=vb->pcm[info->coupling_mag[i]]; - float *pcmA=vb->pcm[info->coupling_ang[i]]; - - for(j=0;j0) - if(ang>0){ - pcmM[j]=mag; - pcmA[j]=mag-ang; - }else{ - pcmA[j]=mag; - pcmM[j]=mag+ang; - } - else - if(ang>0){ - pcmM[j]=mag; - pcmA[j]=mag+ang; - }else{ - pcmA[j]=mag; - pcmM[j]=mag-ang; - } - } - } - - /* compute and apply spectral envelope */ - for(i=0;ichannels;i++){ - float *pcm=vb->pcm[i]; - int submap=info->chmuxlist[i]; - _floor_P[ci->floor_type[info->floorsubmap[submap]]]-> - inverse2(vb,b->flr[info->floorsubmap[submap]], - floormemo[i],pcm); - } - - /* transform the PCM data; takes PCM vector, vb; modifies PCM vector */ - /* only MDCT right now.... */ - for(i=0;ichannels;i++){ - float *pcm=vb->pcm[i]; - mdct_backward(b->transform[vb->W][0],pcm,pcm); - } - - /* all done! */ - return(0); -} - -/* export hooks */ -const vorbis_func_mapping mapping0_exportbundle={ - &mapping0_pack, - &mapping0_unpack, - &mapping0_free_info, - &mapping0_forward, - &mapping0_inverse -}; diff --git a/src/lib/vorbis/src/masking.h b/src/lib/vorbis/src/masking.h deleted file mode 100644 index 7a196a37..00000000 --- a/src/lib/vorbis/src/masking.h +++ /dev/null @@ -1,784 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: masking curve data for psychoacoustics - - ********************************************************************/ - -#ifndef _V_MASKING_H_ -#define _V_MASKING_H_ - -/* more detailed ATH; the bass if flat to save stressing the floor - overly for only a bin or two of savings. */ - -#define MAX_ATH 88 -static const float ATH[]={ - /*15*/ -51, -52, -53, -54, -55, -56, -57, -58, - /*31*/ -59, -60, -61, -62, -63, -64, -65, -66, - /*63*/ -67, -68, -69, -70, -71, -72, -73, -74, - /*125*/ -75, -76, -77, -78, -80, -81, -82, -83, - /*250*/ -84, -85, -86, -87, -88, -88, -89, -89, - /*500*/ -90, -91, -91, -92, -93, -94, -95, -96, - /*1k*/ -96, -97, -98, -98, -99, -99,-100,-100, - /*2k*/ -101,-102,-103,-104,-106,-107,-107,-107, - /*4k*/ -107,-105,-103,-102,-101, -99, -98, -96, - /*8k*/ -95, -95, -96, -97, -96, -95, -93, -90, - /*16k*/ -80, -70, -50, -40, -30, -30, -30, -30 -}; - -/* The tone masking curves from Ehmer's and Fielder's papers have been - replaced by an empirically collected data set. The previously - published values were, far too often, simply on crack. */ - -#define EHMER_OFFSET 16 -#define EHMER_MAX 56 - -/* masking tones from -50 to 0dB, 62.5 through 16kHz at half octaves - test tones from -2 octaves to +5 octaves sampled at eighth octaves */ -/* (Vorbis 0dB, the loudest possible tone, is assumed to be ~100dB SPL - for collection of these curves) */ - -static const float tonemasks[P_BANDS][6][EHMER_MAX]={ - /* 62.5 Hz */ - {{ -60, -60, -60, -60, -60, -60, -60, -60, - -60, -60, -60, -60, -62, -62, -65, -73, - -69, -68, -68, -67, -70, -70, -72, -74, - -75, -79, -79, -80, -83, -88, -93, -100, - -110, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -48, -48, -48, -48, -48, -48, -48, -48, - -48, -48, -48, -48, -48, -53, -61, -66, - -66, -68, -67, -70, -76, -76, -72, -73, - -75, -76, -78, -79, -83, -88, -93, -100, - -110, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -37, -37, -37, -37, -37, -37, -37, -37, - -38, -40, -42, -46, -48, -53, -55, -62, - -65, -58, -56, -56, -61, -60, -65, -67, - -69, -71, -77, -77, -78, -80, -82, -84, - -88, -93, -98, -106, -112, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -25, -25, -25, -25, -25, -25, -25, -25, - -25, -26, -27, -29, -32, -38, -48, -52, - -52, -50, -48, -48, -51, -52, -54, -60, - -67, -67, -66, -68, -69, -73, -73, -76, - -80, -81, -81, -85, -85, -86, -88, -93, - -100, -110, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -16, -16, -16, -16, -16, -16, -16, -16, - -17, -19, -20, -22, -26, -28, -31, -40, - -47, -39, -39, -40, -42, -43, -47, -51, - -57, -52, -55, -55, -60, -58, -62, -63, - -70, -67, -69, -72, -73, -77, -80, -82, - -83, -87, -90, -94, -98, -104, -115, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -8, -8, -8, -8, -8, -8, -8, -8, - -8, -8, -10, -11, -15, -19, -25, -30, - -34, -31, -30, -31, -29, -32, -35, -42, - -48, -42, -44, -46, -50, -50, -51, -52, - -59, -54, -55, -55, -58, -62, -63, -66, - -72, -73, -76, -75, -78, -80, -80, -81, - -84, -88, -90, -94, -98, -101, -106, -110}}, - /* 88Hz */ - {{ -66, -66, -66, -66, -66, -66, -66, -66, - -66, -66, -66, -66, -66, -67, -67, -67, - -76, -72, -71, -74, -76, -76, -75, -78, - -79, -79, -81, -83, -86, -89, -93, -97, - -100, -105, -110, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -47, -47, -47, -47, -47, -47, -47, -47, - -47, -47, -47, -48, -51, -55, -59, -66, - -66, -66, -67, -66, -68, -69, -70, -74, - -79, -77, -77, -78, -80, -81, -82, -84, - -86, -88, -91, -95, -100, -108, -116, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -36, -36, -36, -36, -36, -36, -36, -36, - -36, -37, -37, -41, -44, -48, -51, -58, - -62, -60, -57, -59, -59, -60, -63, -65, - -72, -71, -70, -72, -74, -77, -76, -78, - -81, -81, -80, -83, -86, -91, -96, -100, - -105, -110, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -28, -28, -28, -28, -28, -28, -28, -28, - -28, -30, -32, -32, -33, -35, -41, -49, - -50, -49, -47, -48, -48, -52, -51, -57, - -65, -61, -59, -61, -64, -69, -70, -74, - -77, -77, -78, -81, -84, -85, -87, -90, - -92, -96, -100, -107, -112, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -19, -19, -19, -19, -19, -19, -19, -19, - -20, -21, -23, -27, -30, -35, -36, -41, - -46, -44, -42, -40, -41, -41, -43, -48, - -55, -53, -52, -53, -56, -59, -58, -60, - -67, -66, -69, -71, -72, -75, -79, -81, - -84, -87, -90, -93, -97, -101, -107, -114, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -9, -9, -9, -9, -9, -9, -9, -9, - -11, -12, -12, -15, -16, -20, -23, -30, - -37, -34, -33, -34, -31, -32, -32, -38, - -47, -44, -41, -40, -47, -49, -46, -46, - -58, -50, -50, -54, -58, -62, -64, -67, - -67, -70, -72, -76, -79, -83, -87, -91, - -96, -100, -104, -110, -999, -999, -999, -999}}, - /* 125 Hz */ - {{ -62, -62, -62, -62, -62, -62, -62, -62, - -62, -62, -63, -64, -66, -67, -66, -68, - -75, -72, -76, -75, -76, -78, -79, -82, - -84, -85, -90, -94, -101, -110, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -59, -59, -59, -59, -59, -59, -59, -59, - -59, -59, -59, -60, -60, -61, -63, -66, - -71, -68, -70, -70, -71, -72, -72, -75, - -81, -78, -79, -82, -83, -86, -90, -97, - -103, -113, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -53, -53, -53, -53, -53, -53, -53, -53, - -53, -54, -55, -57, -56, -57, -55, -61, - -65, -60, -60, -62, -63, -63, -66, -68, - -74, -73, -75, -75, -78, -80, -80, -82, - -85, -90, -96, -101, -108, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -46, -46, -46, -46, -46, -46, -46, -46, - -46, -46, -47, -47, -47, -47, -48, -51, - -57, -51, -49, -50, -51, -53, -54, -59, - -66, -60, -62, -67, -67, -70, -72, -75, - -76, -78, -81, -85, -88, -94, -97, -104, - -112, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -36, -36, -36, -36, -36, -36, -36, -36, - -39, -41, -42, -42, -39, -38, -41, -43, - -52, -44, -40, -39, -37, -37, -40, -47, - -54, -50, -48, -50, -55, -61, -59, -62, - -66, -66, -66, -69, -69, -73, -74, -74, - -75, -77, -79, -82, -87, -91, -95, -100, - -108, -115, -999, -999, -999, -999, -999, -999}, - { -28, -26, -24, -22, -20, -20, -23, -29, - -30, -31, -28, -27, -28, -28, -28, -35, - -40, -33, -32, -29, -30, -30, -30, -37, - -45, -41, -37, -38, -45, -47, -47, -48, - -53, -49, -48, -50, -49, -49, -51, -52, - -58, -56, -57, -56, -60, -61, -62, -70, - -72, -74, -78, -83, -88, -93, -100, -106}}, - /* 177 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -110, -105, -100, -95, -91, -87, -83, - -80, -78, -76, -78, -78, -81, -83, -85, - -86, -85, -86, -87, -90, -97, -107, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -110, -105, -100, -95, -90, - -85, -81, -77, -73, -70, -67, -67, -68, - -75, -73, -70, -69, -70, -72, -75, -79, - -84, -83, -84, -86, -88, -89, -89, -93, - -98, -105, -112, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-105, -100, -95, -90, -85, -80, -76, -71, - -68, -68, -65, -63, -63, -62, -62, -64, - -65, -64, -61, -62, -63, -64, -66, -68, - -73, -73, -74, -75, -76, -81, -83, -85, - -88, -89, -92, -95, -100, -108, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -80, -75, -71, -68, -65, -63, -62, -61, - -61, -61, -61, -59, -56, -57, -53, -50, - -58, -52, -50, -50, -52, -53, -54, -58, - -67, -63, -67, -68, -72, -75, -78, -80, - -81, -81, -82, -85, -89, -90, -93, -97, - -101, -107, -114, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - { -65, -61, -59, -57, -56, -55, -55, -56, - -56, -57, -55, -53, -52, -47, -44, -44, - -50, -44, -41, -39, -39, -42, -40, -46, - -51, -49, -50, -53, -54, -63, -60, -61, - -62, -66, -66, -66, -70, -73, -74, -75, - -76, -75, -79, -85, -89, -91, -96, -102, - -110, -999, -999, -999, -999, -999, -999, -999}, - { -52, -50, -49, -49, -48, -48, -48, -49, - -50, -50, -49, -46, -43, -39, -35, -33, - -38, -36, -32, -29, -32, -32, -32, -35, - -44, -39, -38, -38, -46, -50, -45, -46, - -53, -50, -50, -50, -54, -54, -53, -53, - -56, -57, -59, -66, -70, -72, -74, -79, - -83, -85, -90, -97, -114, -999, -999, -999}}, - /* 250 Hz */ - {{-999, -999, -999, -999, -999, -999, -110, -105, - -100, -95, -90, -86, -80, -75, -75, -79, - -80, -79, -80, -81, -82, -88, -95, -103, - -110, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -108, -103, -98, -93, - -88, -83, -79, -78, -75, -71, -67, -68, - -73, -73, -72, -73, -75, -77, -80, -82, - -88, -93, -100, -107, -114, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -110, -105, -101, -96, -90, - -86, -81, -77, -73, -69, -66, -61, -62, - -66, -64, -62, -65, -66, -70, -72, -76, - -81, -80, -84, -90, -95, -102, -110, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -107, -103, -97, -92, -88, - -83, -79, -74, -70, -66, -59, -53, -58, - -62, -55, -54, -54, -54, -58, -61, -62, - -72, -70, -72, -75, -78, -80, -81, -80, - -83, -83, -88, -93, -100, -107, -115, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -105, -100, -95, -90, -85, - -80, -75, -70, -66, -62, -56, -48, -44, - -48, -46, -46, -43, -46, -48, -48, -51, - -58, -58, -59, -60, -62, -62, -61, -61, - -65, -64, -65, -68, -70, -74, -75, -78, - -81, -86, -95, -110, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -105, -100, -95, -90, -85, -80, - -75, -70, -65, -61, -55, -49, -39, -33, - -40, -35, -32, -38, -40, -33, -35, -37, - -46, -41, -45, -44, -46, -42, -45, -46, - -52, -50, -50, -50, -54, -54, -55, -57, - -62, -64, -66, -68, -70, -76, -81, -90, - -100, -110, -999, -999, -999, -999, -999, -999}}, - /* 354 hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -105, -98, -90, -85, -82, -83, -80, -78, - -84, -79, -80, -83, -87, -89, -91, -93, - -99, -106, -117, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -105, -98, -90, -85, -80, -75, -70, -68, - -74, -72, -74, -77, -80, -82, -85, -87, - -92, -89, -91, -95, -100, -106, -112, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -105, -98, -90, -83, -75, -71, -63, -64, - -67, -62, -64, -67, -70, -73, -77, -81, - -84, -83, -85, -89, -90, -93, -98, -104, - -109, -114, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -103, -96, -88, -81, -75, -68, -58, -54, - -56, -54, -56, -56, -58, -60, -63, -66, - -74, -69, -72, -72, -75, -74, -77, -81, - -81, -82, -84, -87, -93, -96, -99, -104, - -110, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -108, -102, -96, - -91, -85, -80, -74, -68, -60, -51, -46, - -48, -46, -43, -45, -47, -47, -49, -48, - -56, -53, -55, -58, -57, -63, -58, -60, - -66, -64, -67, -70, -70, -74, -77, -84, - -86, -89, -91, -93, -94, -101, -109, -118, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -108, -103, -98, -93, -88, - -83, -78, -73, -68, -60, -53, -44, -35, - -38, -38, -34, -34, -36, -40, -41, -44, - -51, -45, -46, -47, -46, -54, -50, -49, - -50, -50, -50, -51, -54, -57, -58, -60, - -66, -66, -66, -64, -65, -68, -77, -82, - -87, -95, -110, -999, -999, -999, -999, -999}}, - /* 500 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -107, -102, -97, -92, -87, -83, -78, -75, - -82, -79, -83, -85, -89, -92, -95, -98, - -101, -105, -109, -113, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -106, - -100, -95, -90, -86, -81, -78, -74, -69, - -74, -74, -76, -79, -83, -84, -86, -89, - -92, -97, -93, -100, -103, -107, -110, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -106, -100, - -95, -90, -87, -83, -80, -75, -69, -60, - -66, -66, -68, -70, -74, -78, -79, -81, - -81, -83, -84, -87, -93, -96, -99, -103, - -107, -110, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -108, -103, -98, - -93, -89, -85, -82, -78, -71, -62, -55, - -58, -58, -54, -54, -55, -59, -61, -62, - -70, -66, -66, -67, -70, -72, -75, -78, - -84, -84, -84, -88, -91, -90, -95, -98, - -102, -103, -106, -110, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -108, -103, -98, -94, - -90, -87, -82, -79, -73, -67, -58, -47, - -50, -45, -41, -45, -48, -44, -44, -49, - -54, -51, -48, -47, -49, -50, -51, -57, - -58, -60, -63, -69, -70, -69, -71, -74, - -78, -82, -90, -95, -101, -105, -110, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -105, -101, -97, -93, -90, - -85, -80, -77, -72, -65, -56, -48, -37, - -40, -36, -34, -40, -50, -47, -38, -41, - -47, -38, -35, -39, -38, -43, -40, -45, - -50, -45, -44, -47, -50, -55, -48, -48, - -52, -66, -70, -76, -82, -90, -97, -105, - -110, -999, -999, -999, -999, -999, -999, -999}}, - /* 707 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -108, -103, -98, -93, -86, -79, -76, - -83, -81, -85, -87, -89, -93, -98, -102, - -107, -112, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -108, -103, -98, -93, -86, -79, -71, - -77, -74, -77, -79, -81, -84, -85, -90, - -92, -93, -92, -98, -101, -108, -112, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -108, -103, -98, -93, -87, -78, -68, -65, - -66, -62, -65, -67, -70, -73, -75, -78, - -82, -82, -83, -84, -91, -93, -98, -102, - -106, -110, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -105, -100, -95, -90, -82, -74, -62, -57, - -58, -56, -51, -52, -52, -54, -54, -58, - -66, -59, -60, -63, -66, -69, -73, -79, - -83, -84, -80, -81, -81, -82, -88, -92, - -98, -105, -113, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -107, - -102, -97, -92, -84, -79, -69, -57, -47, - -52, -47, -44, -45, -50, -52, -42, -42, - -53, -43, -43, -48, -51, -56, -55, -52, - -57, -59, -61, -62, -67, -71, -78, -83, - -86, -94, -98, -103, -110, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -105, -100, - -95, -90, -84, -78, -70, -61, -51, -41, - -40, -38, -40, -46, -52, -51, -41, -40, - -46, -40, -38, -38, -41, -46, -41, -46, - -47, -43, -43, -45, -41, -45, -56, -67, - -68, -83, -87, -90, -95, -102, -107, -113, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 1000 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -109, -105, -101, -96, -91, -84, -77, - -82, -82, -85, -89, -94, -100, -106, -110, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -106, -103, -98, -92, -85, -80, -71, - -75, -72, -76, -80, -84, -86, -89, -93, - -100, -107, -113, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -107, - -104, -101, -97, -92, -88, -84, -80, -64, - -66, -63, -64, -66, -69, -73, -77, -83, - -83, -86, -91, -98, -104, -111, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -107, - -104, -101, -97, -92, -90, -84, -74, -57, - -58, -52, -55, -54, -50, -52, -50, -52, - -63, -62, -69, -76, -77, -78, -78, -79, - -82, -88, -94, -100, -106, -111, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -106, -102, - -98, -95, -90, -85, -83, -78, -70, -50, - -50, -41, -44, -49, -47, -50, -50, -44, - -55, -46, -47, -48, -48, -54, -49, -49, - -58, -62, -71, -81, -87, -92, -97, -102, - -108, -114, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -106, -102, - -98, -95, -90, -85, -83, -78, -70, -45, - -43, -41, -47, -50, -51, -50, -49, -45, - -47, -41, -44, -41, -39, -43, -38, -37, - -40, -41, -44, -50, -58, -65, -73, -79, - -85, -92, -97, -101, -105, -109, -113, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 1414 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -107, -100, -95, -87, -81, - -85, -83, -88, -93, -100, -107, -114, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -107, -101, -95, -88, -83, -76, - -73, -72, -79, -84, -90, -95, -100, -105, - -110, -115, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -104, -98, -92, -87, -81, -70, - -65, -62, -67, -71, -74, -80, -85, -91, - -95, -99, -103, -108, -111, -114, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -103, -97, -90, -85, -76, -60, - -56, -54, -60, -62, -61, -56, -63, -65, - -73, -74, -77, -75, -78, -81, -86, -87, - -88, -91, -94, -98, -103, -110, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -105, - -100, -97, -92, -86, -81, -79, -70, -57, - -51, -47, -51, -58, -60, -56, -53, -50, - -58, -52, -50, -50, -53, -55, -64, -69, - -71, -85, -82, -78, -81, -85, -95, -102, - -112, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -105, - -100, -97, -92, -85, -83, -79, -72, -49, - -40, -43, -43, -54, -56, -51, -50, -40, - -43, -38, -36, -35, -37, -38, -37, -44, - -54, -60, -57, -60, -70, -75, -84, -92, - -103, -112, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 2000 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -102, -95, -89, -82, - -83, -84, -90, -92, -99, -107, -113, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -107, -101, -95, -89, -83, -72, - -74, -78, -85, -88, -88, -90, -92, -98, - -105, -111, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -109, -103, -97, -93, -87, -81, -70, - -70, -67, -75, -73, -76, -79, -81, -83, - -88, -89, -97, -103, -110, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -107, -100, -94, -88, -83, -75, -63, - -59, -59, -63, -66, -60, -62, -67, -67, - -77, -76, -81, -88, -86, -92, -96, -102, - -109, -116, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -105, -98, -92, -86, -81, -73, -56, - -52, -47, -55, -60, -58, -52, -51, -45, - -49, -50, -53, -54, -61, -71, -70, -69, - -78, -79, -87, -90, -96, -104, -112, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -103, -96, -90, -86, -78, -70, -51, - -42, -47, -48, -55, -54, -54, -53, -42, - -35, -28, -33, -38, -37, -44, -47, -49, - -54, -63, -68, -78, -82, -89, -94, -99, - -104, -109, -114, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 2828 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -110, -100, -90, -79, - -85, -81, -82, -82, -89, -94, -99, -103, - -109, -115, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -105, -97, -85, -72, - -74, -70, -70, -70, -76, -85, -91, -93, - -97, -103, -109, -115, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -112, -93, -81, -68, - -62, -60, -60, -57, -63, -70, -77, -82, - -90, -93, -98, -104, -109, -113, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -113, -100, -93, -84, -63, - -58, -48, -53, -54, -52, -52, -57, -64, - -66, -76, -83, -81, -85, -85, -90, -95, - -98, -101, -103, -106, -108, -111, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -105, -95, -86, -74, -53, - -50, -38, -43, -49, -43, -42, -39, -39, - -46, -52, -57, -56, -72, -69, -74, -81, - -87, -92, -94, -97, -99, -102, -105, -108, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -108, -99, -90, -76, -66, -45, - -43, -41, -44, -47, -43, -47, -40, -30, - -31, -31, -39, -33, -40, -41, -43, -53, - -59, -70, -73, -77, -79, -82, -84, -87, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 4000 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -110, -91, -76, - -75, -85, -93, -98, -104, -110, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -110, -91, -70, - -70, -75, -86, -89, -94, -98, -101, -106, - -110, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -110, -95, -80, -60, - -65, -64, -74, -83, -88, -91, -95, -99, - -103, -107, -110, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -110, -95, -80, -58, - -55, -49, -66, -68, -71, -78, -78, -80, - -88, -85, -89, -97, -100, -105, -110, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -110, -95, -80, -53, - -52, -41, -59, -59, -49, -58, -56, -63, - -86, -79, -90, -93, -98, -103, -107, -112, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -97, -91, -73, -45, - -40, -33, -53, -61, -49, -54, -50, -50, - -60, -52, -67, -74, -81, -92, -96, -100, - -105, -110, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 5657 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -113, -106, -99, -92, -77, - -80, -88, -97, -106, -115, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -116, -109, -102, -95, -89, -74, - -72, -88, -87, -95, -102, -109, -116, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -116, -109, -102, -95, -89, -75, - -66, -74, -77, -78, -86, -87, -90, -96, - -105, -115, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -115, -108, -101, -94, -88, -66, - -56, -61, -70, -65, -78, -72, -83, -84, - -93, -98, -105, -110, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -110, -105, -95, -89, -82, -57, - -52, -52, -59, -56, -59, -58, -69, -67, - -88, -82, -82, -89, -94, -100, -108, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -110, -101, -96, -90, -83, -77, -54, - -43, -38, -50, -48, -52, -48, -42, -42, - -51, -52, -53, -59, -65, -71, -78, -85, - -95, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 8000 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -120, -105, -86, -68, - -78, -79, -90, -100, -110, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -120, -105, -86, -66, - -73, -77, -88, -96, -105, -115, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -120, -105, -92, -80, -61, - -64, -68, -80, -87, -92, -100, -110, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -120, -104, -91, -79, -52, - -60, -54, -64, -69, -77, -80, -82, -84, - -85, -87, -88, -90, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -118, -100, -87, -77, -49, - -50, -44, -58, -61, -61, -67, -65, -62, - -62, -62, -65, -68, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -115, -98, -84, -62, -49, - -44, -38, -46, -49, -49, -46, -39, -37, - -39, -40, -42, -43, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 11314 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -110, -88, -74, - -77, -82, -82, -85, -90, -94, -99, -104, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -110, -88, -66, - -70, -81, -80, -81, -84, -88, -91, -93, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -110, -88, -61, - -63, -70, -71, -74, -77, -80, -83, -85, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -110, -86, -62, - -63, -62, -62, -58, -52, -50, -50, -52, - -54, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -118, -108, -84, -53, - -50, -50, -50, -55, -47, -45, -40, -40, - -40, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -118, -100, -73, -43, - -37, -42, -43, -53, -38, -37, -35, -35, - -38, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}}, - /* 16000 Hz */ - {{-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -100, -91, -84, -74, - -80, -80, -80, -80, -80, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -100, -91, -84, -74, - -68, -68, -68, -68, -68, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -100, -86, -78, -70, - -60, -45, -30, -21, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -100, -87, -78, -67, - -48, -38, -29, -21, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -100, -86, -69, -56, - -45, -35, -33, -29, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}, - {-999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -110, -100, -83, -71, -48, - -27, -38, -37, -34, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999, - -999, -999, -999, -999, -999, -999, -999, -999}} -}; - -#endif diff --git a/src/lib/vorbis/src/mdct.c b/src/lib/vorbis/src/mdct.c deleted file mode 100644 index 2a0ff8d0..00000000 --- a/src/lib/vorbis/src/mdct.c +++ /dev/null @@ -1,562 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: normalized modified discrete cosine transform - power of two length transform only [64 <= n ] - - Original algorithm adapted long ago from _The use of multirate filter - banks for coding of high quality digital audio_, by T. Sporer, - K. Brandenburg and B. Edler, collection of the European Signal - Processing Conference (EUSIPCO), Amsterdam, June 1992, Vol.1, pp - 211-214 - - The below code implements an algorithm that no longer looks much like - that presented in the paper, but the basic structure remains if you - dig deep enough to see it. - - This module DOES NOT INCLUDE code to generate/apply the window - function. Everybody has their own weird favorite including me... I - happen to like the properties of y=sin(.5PI*sin^2(x)), but others may - vehemently disagree. - - ********************************************************************/ - -/* this can also be run as an integer transform by uncommenting a - define in mdct.h; the integerization is a first pass and although - it's likely stable for Vorbis, the dynamic range is constrained and - roundoff isn't done (so it's noisy). Consider it functional, but - only a starting point. There's no point on a machine with an FPU */ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "mdct.h" -#include "os.h" -#include "misc.h" - -/* build lookups for trig functions; also pre-figure scaling and - some window function algebra. */ - -void mdct_init(mdct_lookup *lookup,int n){ - int *bitrev=_ogg_malloc(sizeof(*bitrev)*(n/4)); - DATA_TYPE *T=_ogg_malloc(sizeof(*T)*(n+n/4)); - - int i; - int n2=n>>1; - int log2n=lookup->log2n=rint(log((float)n)/log(2.f)); - lookup->n=n; - lookup->trig=T; - lookup->bitrev=bitrev; - -/* trig lookups... */ - - for(i=0;i>j;j++) - if((msb>>j)&i)acc|=1<scale=FLOAT_CONV(4.f/n); -} - -/* 8 point butterfly (in place, 4 register) */ -STIN void mdct_butterfly_8(DATA_TYPE *x){ - REG_TYPE r0 = x[6] + x[2]; - REG_TYPE r1 = x[6] - x[2]; - REG_TYPE r2 = x[4] + x[0]; - REG_TYPE r3 = x[4] - x[0]; - - x[6] = r0 + r2; - x[4] = r0 - r2; - - r0 = x[5] - x[1]; - r2 = x[7] - x[3]; - x[0] = r1 + r0; - x[2] = r1 - r0; - - r0 = x[5] + x[1]; - r1 = x[7] + x[3]; - x[3] = r2 + r3; - x[1] = r2 - r3; - x[7] = r1 + r0; - x[5] = r1 - r0; - -} - -/* 16 point butterfly (in place, 4 register) */ -STIN void mdct_butterfly_16(DATA_TYPE *x){ - REG_TYPE r0 = x[1] - x[9]; - REG_TYPE r1 = x[0] - x[8]; - - x[8] += x[0]; - x[9] += x[1]; - x[0] = MULT_NORM((r0 + r1) * cPI2_8); - x[1] = MULT_NORM((r0 - r1) * cPI2_8); - - r0 = x[3] - x[11]; - r1 = x[10] - x[2]; - x[10] += x[2]; - x[11] += x[3]; - x[2] = r0; - x[3] = r1; - - r0 = x[12] - x[4]; - r1 = x[13] - x[5]; - x[12] += x[4]; - x[13] += x[5]; - x[4] = MULT_NORM((r0 - r1) * cPI2_8); - x[5] = MULT_NORM((r0 + r1) * cPI2_8); - - r0 = x[14] - x[6]; - r1 = x[15] - x[7]; - x[14] += x[6]; - x[15] += x[7]; - x[6] = r0; - x[7] = r1; - - mdct_butterfly_8(x); - mdct_butterfly_8(x+8); -} - -/* 32 point butterfly (in place, 4 register) */ -STIN void mdct_butterfly_32(DATA_TYPE *x){ - REG_TYPE r0 = x[30] - x[14]; - REG_TYPE r1 = x[31] - x[15]; - - x[30] += x[14]; - x[31] += x[15]; - x[14] = r0; - x[15] = r1; - - r0 = x[28] - x[12]; - r1 = x[29] - x[13]; - x[28] += x[12]; - x[29] += x[13]; - x[12] = MULT_NORM( r0 * cPI1_8 - r1 * cPI3_8 ); - x[13] = MULT_NORM( r0 * cPI3_8 + r1 * cPI1_8 ); - - r0 = x[26] - x[10]; - r1 = x[27] - x[11]; - x[26] += x[10]; - x[27] += x[11]; - x[10] = MULT_NORM(( r0 - r1 ) * cPI2_8); - x[11] = MULT_NORM(( r0 + r1 ) * cPI2_8); - - r0 = x[24] - x[8]; - r1 = x[25] - x[9]; - x[24] += x[8]; - x[25] += x[9]; - x[8] = MULT_NORM( r0 * cPI3_8 - r1 * cPI1_8 ); - x[9] = MULT_NORM( r1 * cPI3_8 + r0 * cPI1_8 ); - - r0 = x[22] - x[6]; - r1 = x[7] - x[23]; - x[22] += x[6]; - x[23] += x[7]; - x[6] = r1; - x[7] = r0; - - r0 = x[4] - x[20]; - r1 = x[5] - x[21]; - x[20] += x[4]; - x[21] += x[5]; - x[4] = MULT_NORM( r1 * cPI1_8 + r0 * cPI3_8 ); - x[5] = MULT_NORM( r1 * cPI3_8 - r0 * cPI1_8 ); - - r0 = x[2] - x[18]; - r1 = x[3] - x[19]; - x[18] += x[2]; - x[19] += x[3]; - x[2] = MULT_NORM(( r1 + r0 ) * cPI2_8); - x[3] = MULT_NORM(( r1 - r0 ) * cPI2_8); - - r0 = x[0] - x[16]; - r1 = x[1] - x[17]; - x[16] += x[0]; - x[17] += x[1]; - x[0] = MULT_NORM( r1 * cPI3_8 + r0 * cPI1_8 ); - x[1] = MULT_NORM( r1 * cPI1_8 - r0 * cPI3_8 ); - - mdct_butterfly_16(x); - mdct_butterfly_16(x+16); - -} - -/* N point first stage butterfly (in place, 2 register) */ -STIN void mdct_butterfly_first(DATA_TYPE *T, - DATA_TYPE *x, - int points){ - - DATA_TYPE *x1 = x + points - 8; - DATA_TYPE *x2 = x + (points>>1) - 8; - REG_TYPE r0; - REG_TYPE r1; - - do{ - - r0 = x1[6] - x2[6]; - r1 = x1[7] - x2[7]; - x1[6] += x2[6]; - x1[7] += x2[7]; - x2[6] = MULT_NORM(r1 * T[1] + r0 * T[0]); - x2[7] = MULT_NORM(r1 * T[0] - r0 * T[1]); - - r0 = x1[4] - x2[4]; - r1 = x1[5] - x2[5]; - x1[4] += x2[4]; - x1[5] += x2[5]; - x2[4] = MULT_NORM(r1 * T[5] + r0 * T[4]); - x2[5] = MULT_NORM(r1 * T[4] - r0 * T[5]); - - r0 = x1[2] - x2[2]; - r1 = x1[3] - x2[3]; - x1[2] += x2[2]; - x1[3] += x2[3]; - x2[2] = MULT_NORM(r1 * T[9] + r0 * T[8]); - x2[3] = MULT_NORM(r1 * T[8] - r0 * T[9]); - - r0 = x1[0] - x2[0]; - r1 = x1[1] - x2[1]; - x1[0] += x2[0]; - x1[1] += x2[1]; - x2[0] = MULT_NORM(r1 * T[13] + r0 * T[12]); - x2[1] = MULT_NORM(r1 * T[12] - r0 * T[13]); - - x1-=8; - x2-=8; - T+=16; - - }while(x2>=x); -} - -/* N/stage point generic N stage butterfly (in place, 2 register) */ -STIN void mdct_butterfly_generic(DATA_TYPE *T, - DATA_TYPE *x, - int points, - int trigint){ - - DATA_TYPE *x1 = x + points - 8; - DATA_TYPE *x2 = x + (points>>1) - 8; - REG_TYPE r0; - REG_TYPE r1; - - do{ - - r0 = x1[6] - x2[6]; - r1 = x1[7] - x2[7]; - x1[6] += x2[6]; - x1[7] += x2[7]; - x2[6] = MULT_NORM(r1 * T[1] + r0 * T[0]); - x2[7] = MULT_NORM(r1 * T[0] - r0 * T[1]); - - T+=trigint; - - r0 = x1[4] - x2[4]; - r1 = x1[5] - x2[5]; - x1[4] += x2[4]; - x1[5] += x2[5]; - x2[4] = MULT_NORM(r1 * T[1] + r0 * T[0]); - x2[5] = MULT_NORM(r1 * T[0] - r0 * T[1]); - - T+=trigint; - - r0 = x1[2] - x2[2]; - r1 = x1[3] - x2[3]; - x1[2] += x2[2]; - x1[3] += x2[3]; - x2[2] = MULT_NORM(r1 * T[1] + r0 * T[0]); - x2[3] = MULT_NORM(r1 * T[0] - r0 * T[1]); - - T+=trigint; - - r0 = x1[0] - x2[0]; - r1 = x1[1] - x2[1]; - x1[0] += x2[0]; - x1[1] += x2[1]; - x2[0] = MULT_NORM(r1 * T[1] + r0 * T[0]); - x2[1] = MULT_NORM(r1 * T[0] - r0 * T[1]); - - T+=trigint; - x1-=8; - x2-=8; - - }while(x2>=x); -} - -STIN void mdct_butterflies(mdct_lookup *init, - DATA_TYPE *x, - int points){ - - DATA_TYPE *T=init->trig; - int stages=init->log2n-5; - int i,j; - - if(--stages>0){ - mdct_butterfly_first(T,x,points); - } - - for(i=1;--stages>0;i++){ - for(j=0;j<(1<>i)*j,points>>i,4<trig)_ogg_free(l->trig); - if(l->bitrev)_ogg_free(l->bitrev); - memset(l,0,sizeof(*l)); - } -} - -STIN void mdct_bitreverse(mdct_lookup *init, - DATA_TYPE *x){ - int n = init->n; - int *bit = init->bitrev; - DATA_TYPE *w0 = x; - DATA_TYPE *w1 = x = w0+(n>>1); - DATA_TYPE *T = init->trig+n; - - do{ - DATA_TYPE *x0 = x+bit[0]; - DATA_TYPE *x1 = x+bit[1]; - - REG_TYPE r0 = x0[1] - x1[1]; - REG_TYPE r1 = x0[0] + x1[0]; - REG_TYPE r2 = MULT_NORM(r1 * T[0] + r0 * T[1]); - REG_TYPE r3 = MULT_NORM(r1 * T[1] - r0 * T[0]); - - w1 -= 4; - - r0 = HALVE(x0[1] + x1[1]); - r1 = HALVE(x0[0] - x1[0]); - - w0[0] = r0 + r2; - w1[2] = r0 - r2; - w0[1] = r1 + r3; - w1[3] = r3 - r1; - - x0 = x+bit[2]; - x1 = x+bit[3]; - - r0 = x0[1] - x1[1]; - r1 = x0[0] + x1[0]; - r2 = MULT_NORM(r1 * T[2] + r0 * T[3]); - r3 = MULT_NORM(r1 * T[3] - r0 * T[2]); - - r0 = HALVE(x0[1] + x1[1]); - r1 = HALVE(x0[0] - x1[0]); - - w0[2] = r0 + r2; - w1[0] = r0 - r2; - w0[3] = r1 + r3; - w1[1] = r3 - r1; - - T += 4; - bit += 4; - w0 += 4; - - }while(w0n; - int n2=n>>1; - int n4=n>>2; - - /* rotate */ - - DATA_TYPE *iX = in+n2-7; - DATA_TYPE *oX = out+n2+n4; - DATA_TYPE *T = init->trig+n4; - - do{ - oX -= 4; - oX[0] = MULT_NORM(-iX[2] * T[3] - iX[0] * T[2]); - oX[1] = MULT_NORM (iX[0] * T[3] - iX[2] * T[2]); - oX[2] = MULT_NORM(-iX[6] * T[1] - iX[4] * T[0]); - oX[3] = MULT_NORM (iX[4] * T[1] - iX[6] * T[0]); - iX -= 8; - T += 4; - }while(iX>=in); - - iX = in+n2-8; - oX = out+n2+n4; - T = init->trig+n4; - - do{ - T -= 4; - oX[0] = MULT_NORM (iX[4] * T[3] + iX[6] * T[2]); - oX[1] = MULT_NORM (iX[4] * T[2] - iX[6] * T[3]); - oX[2] = MULT_NORM (iX[0] * T[1] + iX[2] * T[0]); - oX[3] = MULT_NORM (iX[0] * T[0] - iX[2] * T[1]); - iX -= 8; - oX += 4; - }while(iX>=in); - - mdct_butterflies(init,out+n2,n2); - mdct_bitreverse(init,out); - - /* roatate + window */ - - { - DATA_TYPE *oX1=out+n2+n4; - DATA_TYPE *oX2=out+n2+n4; - DATA_TYPE *iX =out; - T =init->trig+n2; - - do{ - oX1-=4; - - oX1[3] = MULT_NORM (iX[0] * T[1] - iX[1] * T[0]); - oX2[0] = -MULT_NORM (iX[0] * T[0] + iX[1] * T[1]); - - oX1[2] = MULT_NORM (iX[2] * T[3] - iX[3] * T[2]); - oX2[1] = -MULT_NORM (iX[2] * T[2] + iX[3] * T[3]); - - oX1[1] = MULT_NORM (iX[4] * T[5] - iX[5] * T[4]); - oX2[2] = -MULT_NORM (iX[4] * T[4] + iX[5] * T[5]); - - oX1[0] = MULT_NORM (iX[6] * T[7] - iX[7] * T[6]); - oX2[3] = -MULT_NORM (iX[6] * T[6] + iX[7] * T[7]); - - oX2+=4; - iX += 8; - T += 8; - }while(iXoX2); - } -} - -void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out){ - int n=init->n; - int n2=n>>1; - int n4=n>>2; - int n8=n>>3; - DATA_TYPE *w=alloca(n*sizeof(*w)); /* forward needs working space */ - DATA_TYPE *w2=w+n2; - - /* rotate */ - - /* window + rotate + step 1 */ - - REG_TYPE r0; - REG_TYPE r1; - DATA_TYPE *x0=in+n2+n4; - DATA_TYPE *x1=x0+1; - DATA_TYPE *T=init->trig+n2; - - int i=0; - - for(i=0;itrig+n2; - x0=out+n2; - - for(i=0;iscale); - x0[0] =MULT_NORM((w[0]*T[1]-w[1]*T[0])*init->scale); - w+=2; - T+=2; - } -} diff --git a/src/lib/vorbis/src/mdct.h b/src/lib/vorbis/src/mdct.h deleted file mode 100644 index ceaea617..00000000 --- a/src/lib/vorbis/src/mdct.h +++ /dev/null @@ -1,70 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: modified discrete cosine transform prototypes - - ********************************************************************/ - -#ifndef _OGG_mdct_H_ -#define _OGG_mdct_H_ - -#include "vorbis/codec.h" - - - - - -/*#define MDCT_INTEGERIZED <- be warned there could be some hurt left here*/ -#ifdef MDCT_INTEGERIZED - -#define DATA_TYPE int -#define REG_TYPE register int -#define TRIGBITS 14 -#define cPI3_8 6270 -#define cPI2_8 11585 -#define cPI1_8 15137 - -#define FLOAT_CONV(x) ((int)((x)*(1<>TRIGBITS) -#define HALVE(x) ((x)>>1) - -#else - -#define DATA_TYPE float -#define REG_TYPE float -#define cPI3_8 .38268343236508977175F -#define cPI2_8 .70710678118654752441F -#define cPI1_8 .92387953251128675613F - -#define FLOAT_CONV(x) (x) -#define MULT_NORM(x) (x) -#define HALVE(x) ((x)*.5f) - -#endif - - -typedef struct { - int n; - int log2n; - - DATA_TYPE *trig; - int *bitrev; - - DATA_TYPE scale; -} mdct_lookup; - -extern void mdct_init(mdct_lookup *lookup,int n); -extern void mdct_clear(mdct_lookup *l); -extern void mdct_forward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out); -extern void mdct_backward(mdct_lookup *init, DATA_TYPE *in, DATA_TYPE *out); - -#endif diff --git a/src/lib/vorbis/src/misc.h b/src/lib/vorbis/src/misc.h deleted file mode 100644 index eac5160e..00000000 --- a/src/lib/vorbis/src/misc.h +++ /dev/null @@ -1,57 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: miscellaneous prototypes - - ********************************************************************/ - -#ifndef _V_RANDOM_H_ -#define _V_RANDOM_H_ -#include "vorbis/codec.h" - -extern void *_vorbis_block_alloc(vorbis_block *vb,long bytes); -extern void _vorbis_block_ripcord(vorbis_block *vb); -extern int ov_ilog(ogg_uint32_t v); - -#ifdef ANALYSIS -extern int analysis_noisy; -extern void _analysis_output(char *base,int i,float *v,int n,int bark,int dB, - ogg_int64_t off); -extern void _analysis_output_always(char *base,int i,float *v,int n,int bark,int dB, - ogg_int64_t off); -#endif - -#ifdef DEBUG_MALLOC - -#define _VDBG_GRAPHFILE "malloc.m" -#undef _VDBG_GRAPHFILE -extern void *_VDBG_malloc(void *ptr,long bytes,char *file,long line); -extern void _VDBG_free(void *ptr,char *file,long line); - -#ifndef MISC_C -#undef _ogg_malloc -#undef _ogg_calloc -#undef _ogg_realloc -#undef _ogg_free - -#define _ogg_malloc(x) _VDBG_malloc(NULL,(x),__FILE__,__LINE__) -#define _ogg_calloc(x,y) _VDBG_malloc(NULL,(x)*(y),__FILE__,__LINE__) -#define _ogg_realloc(x,y) _VDBG_malloc((x),(y),__FILE__,__LINE__) -#define _ogg_free(x) _VDBG_free((x),__FILE__,__LINE__) -#endif -#endif - -#endif - - - - diff --git a/src/lib/vorbis/src/os.h b/src/lib/vorbis/src/os.h deleted file mode 100644 index 9ded7358..00000000 --- a/src/lib/vorbis/src/os.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef _OS_H -#define _OS_H -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: #ifdef jail to whip a few platforms into the UNIX ideal. - - ********************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include - -#include "misc.h" - -#ifndef _V_IFDEFJAIL_H_ -# define _V_IFDEFJAIL_H_ - -# ifdef __GNUC__ -# define STIN static __inline__ -# elif defined(_WIN32) -# define STIN static __inline -# else -# define STIN static -# endif - -#ifdef DJGPP -# define rint(x) (floor((x)+0.5f)) -#endif - -#ifndef M_PI -# define M_PI (3.1415926536f) -#endif - -#if defined(_WIN32) && !defined(__SYMBIAN32__) -# include -# define rint(x) (floor((x)+0.5f)) -# define NO_FLOAT_MATH_LIB -# define FAST_HYPOT(a, b) sqrt((a)*(a) + (b)*(b)) -#endif - -#if defined(__SYMBIAN32__) && defined(__WINS__) -void *_alloca(size_t size); -# define alloca _alloca -#endif - -#ifndef FAST_HYPOT -# define FAST_HYPOT hypot -#endif - -#endif /* _V_IFDEFJAIL_H_ */ - -#ifdef HAVE_ALLOCA_H -# include -#endif - -#ifdef USE_MEMORY_H -# include -#endif - -#ifndef min -# define min(x,y) ((x)>(y)?(y):(x)) -#endif - -#ifndef max -# define max(x,y) ((x)<(y)?(y):(x)) -#endif - - -/* Special i386 GCC implementation */ -#if defined(__i386__) && defined(__GNUC__) && !defined(__BEOS__) && !defined(__SSE2_MATH__) -# define VORBIS_FPU_CONTROL -/* both GCC and MSVC are kinda stupid about rounding/casting to int. - Because of encapsulation constraints (GCC can't see inside the asm - block and so we end up doing stupid things like a store/load that - is collectively a noop), we do it this way */ - -/* we must set up the fpu before this works!! */ - -typedef ogg_int16_t vorbis_fpu_control; - -static inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ - ogg_int16_t ret; - ogg_int16_t temp; - __asm__ __volatile__("fnstcw %0\n\t" - "movw %0,%%dx\n\t" - "andw $62463,%%dx\n\t" - "movw %%dx,%1\n\t" - "fldcw %1\n\t":"=m"(ret):"m"(temp): "dx"); - *fpu=ret; -} - -static inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ - __asm__ __volatile__("fldcw %0":: "m"(fpu)); -} - -/* assumes the FPU is in round mode! */ -static inline int vorbis_ftoi(double f){ /* yes, double! Otherwise, - we get extra fst/fld to - truncate precision */ - int i; - __asm__("fistl %0": "=m"(i) : "t"(f)); - return(i); -} -#endif /* Special i386 GCC implementation */ - - -/* MSVC inline assembly. 32 bit only; inline ASM isn't implemented in the - * 64 bit compiler and doesn't work on arm. */ -#if defined(_MSC_VER) && defined(_M_IX86) && !defined(_WIN32_WCE) -# define VORBIS_FPU_CONTROL - -typedef ogg_int16_t vorbis_fpu_control; - -static __inline int vorbis_ftoi(double f){ - int i; - __asm{ - fld f - fistp i - } - return i; -} - -static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ - (void)fpu; -} - -static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ - (void)fpu; -} - -#endif /* Special MSVC 32 bit implementation */ - - -/* Optimized code path for x86_64 builds. Uses SSE2 intrinsics. This can be - done safely because all x86_64 CPUs supports SSE2. */ -#if (defined(_MSC_VER) && defined(_M_X64)) || (defined(__GNUC__) && defined (__SSE2_MATH__)) -# define VORBIS_FPU_CONTROL - -typedef ogg_int16_t vorbis_fpu_control; - -#include -static __inline int vorbis_ftoi(double f){ - return _mm_cvtsd_si32(_mm_load_sd(&f)); -} - -static __inline void vorbis_fpu_setround(vorbis_fpu_control *fpu){ - (void)fpu; -} - -static __inline void vorbis_fpu_restore(vorbis_fpu_control fpu){ - (void)fpu; -} - -#endif /* Special MSVC x64 implementation */ - - -/* If no special implementation was found for the current compiler / platform, - use the default implementation here: */ -#ifndef VORBIS_FPU_CONTROL - -typedef int vorbis_fpu_control; - -STIN int vorbis_ftoi(double f){ - /* Note: MSVC and GCC (at least on some systems) round towards zero, thus, - the floor() call is required to ensure correct roudning of - negative numbers */ - return (int)floor(f+.5); -} - -/* We don't have special code for this compiler/arch, so do it the slow way */ -# define vorbis_fpu_setround(vorbis_fpu_control) {} -# define vorbis_fpu_restore(vorbis_fpu_control) {} - -#endif /* default implementation */ - -#endif /* _OS_H */ diff --git a/src/lib/vorbis/src/psy.c b/src/lib/vorbis/src/psy.c deleted file mode 100644 index 036b094a..00000000 --- a/src/lib/vorbis/src/psy.c +++ /dev/null @@ -1,1209 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: psychoacoustics not including preecho - - ********************************************************************/ - -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" - -#include "masking.h" -#include "psy.h" -#include "os.h" -#include "lpc.h" -#include "smallft.h" -#include "scales.h" -#include "misc.h" - -#define NEGINF -9999.f -static const double stereo_threshholds[]={0.0, .5, 1.0, 1.5, 2.5, 4.5, 8.5, 16.5, 9e10}; -static const double stereo_threshholds_limited[]={0.0, .5, 1.0, 1.5, 2.0, 2.5, 4.5, 8.5, 9e10}; - -vorbis_look_psy_global *_vp_global_look(vorbis_info *vi){ - codec_setup_info *ci=vi->codec_setup; - vorbis_info_psy_global *gi=&ci->psy_g_param; - vorbis_look_psy_global *look=_ogg_calloc(1,sizeof(*look)); - - look->channels=vi->channels; - - look->ampmax=-9999.; - look->gi=gi; - return(look); -} - -void _vp_global_free(vorbis_look_psy_global *look){ - if(look){ - memset(look,0,sizeof(*look)); - _ogg_free(look); - } -} - -void _vi_gpsy_free(vorbis_info_psy_global *i){ - if(i){ - memset(i,0,sizeof(*i)); - _ogg_free(i); - } -} - -void _vi_psy_free(vorbis_info_psy *i){ - if(i){ - memset(i,0,sizeof(*i)); - _ogg_free(i); - } -} - -static void min_curve(float *c, - float *c2){ - int i; - for(i=0;ic[i])c[i]=c2[i]; -} - -static void attenuate_curve(float *c,float att){ - int i; - for(i=0;iATH[j+k+ath_offset])min=ATH[j+k+ath_offset]; - }else{ - if(min>ATH[MAX_ATH-1])min=ATH[MAX_ATH-1]; - } - ath[j]=min; - } - - /* copy curves into working space, replicate the 50dB curve to 30 - and 40, replicate the 100dB curve to 110 */ - for(j=0;j<6;j++) - memcpy(workc[i][j+2],tonemasks[i][j],EHMER_MAX*sizeof(*tonemasks[i][j])); - memcpy(workc[i][0],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0])); - memcpy(workc[i][1],tonemasks[i][0],EHMER_MAX*sizeof(*tonemasks[i][0])); - - /* apply centered curve boost/decay */ - for(j=0;j0)adj=0.; - if(adj>0. && center_boost<0)adj=0.; - workc[i][j][k]+=adj; - } - } - - /* normalize curves so the driving amplitude is 0dB */ - /* make temp curves with the ATH overlayed */ - for(j=0;j an eighth of an octave and that the eighth - octave values may also be composited. */ - - /* which octave curves will we be compositing? */ - bin=floor(fromOC(i*.5)/binHz); - lo_curve= ceil(toOC(bin*binHz+1)*2); - hi_curve= floor(toOC((bin+1)*binHz)*2); - if(lo_curve>i)lo_curve=i; - if(lo_curve<0)lo_curve=0; - if(hi_curve>=P_BANDS)hi_curve=P_BANDS-1; - - for(m=0;mn)lo_bin=n; - if(lo_binn)hi_bin=n; - - for(;lworkc[k][m][j]) - brute_buffer[l]=workc[k][m][j]; - } - - for(;lworkc[k][m][EHMER_MAX-1]) - brute_buffer[l]=workc[k][m][EHMER_MAX-1]; - - } - - /* be equally paranoid about being valid up to next half ocatve */ - if(i+1n)lo_bin=n; - if(lo_binn)hi_bin=n; - - for(;lworkc[k][m][j]) - brute_buffer[l]=workc[k][m][j]; - } - - for(;lworkc[k][m][EHMER_MAX-1]) - brute_buffer[l]=workc[k][m][EHMER_MAX-1]; - - } - - - for(j=0;j=n){ - ret[i][m][j+2]=-999.; - }else{ - ret[i][m][j+2]=brute_buffer[bin]; - } - } - } - - /* add fenceposts */ - for(j=0;j-200.f)break; - ret[i][m][0]=j; - - for(j=EHMER_MAX-1;j>EHMER_OFFSET+1;j--) - if(ret[i][m][j+2]>-200.f) - break; - ret[i][m][1]=j; - - } - } - - return(ret); -} - -void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, - vorbis_info_psy_global *gi,int n,long rate){ - long i,j,lo=-99,hi=1; - long maxoc; - memset(p,0,sizeof(*p)); - - p->eighth_octave_lines=gi->eighth_octave_lines; - p->shiftoc=rint(log(gi->eighth_octave_lines*8.f)/log(2.f))-1; - - p->firstoc=toOC(.25f*rate*.5/n)*(1<<(p->shiftoc+1))-gi->eighth_octave_lines; - maxoc=toOC((n+.25f)*rate*.5/n)*(1<<(p->shiftoc+1))+.5f; - p->total_octave_lines=maxoc-p->firstoc+1; - p->ath=_ogg_malloc(n*sizeof(*p->ath)); - - p->octave=_ogg_malloc(n*sizeof(*p->octave)); - p->bark=_ogg_malloc(n*sizeof(*p->bark)); - p->vi=vi; - p->n=n; - p->rate=rate; - - /* AoTuV HF weighting */ - p->m_val = 1.; - if(rate < 26000) p->m_val = 0; - else if(rate < 38000) p->m_val = .94; /* 32kHz */ - else if(rate > 46000) p->m_val = 1.275; /* 48kHz */ - - /* set up the lookups for a given blocksize and sample rate */ - - for(i=0,j=0;iath[j]=base+100.; - base+=delta; - } - } - } - - for(;jath[j]=p->ath[j-1]; - } - - for(i=0;inoisewindowlominnoisewindowlo);lo++); - - for(;hi<=n && (hinoisewindowhimin || - toBARK(rate/(2*n)*hi)<(bark+vi->noisewindowhi));hi++); - - p->bark[i]=((lo-1)<<16)+(hi-1); - - } - - for(i=0;ioctave[i]=toOC((i+.25f)*.5*rate/n)*(1<<(p->shiftoc+1))+.5f; - - p->tonecurves=setup_tone_curves(vi->toneatt,rate*.5/n,n, - vi->tone_centerboost,vi->tone_decay); - - /* set up rolling noise median */ - p->noiseoffset=_ogg_malloc(P_NOISECURVES*sizeof(*p->noiseoffset)); - for(i=0;inoiseoffset[i]=_ogg_malloc(n*sizeof(**p->noiseoffset)); - - for(i=0;i=P_BANDS-1)halfoc=P_BANDS-1; - inthalfoc=(int)halfoc; - del=halfoc-inthalfoc; - - for(j=0;jnoiseoffset[j][i]= - p->vi->noiseoff[j][inthalfoc]*(1.-del) + - p->vi->noiseoff[j][inthalfoc+1]*del; - - } -#if 0 - { - static int ls=0; - _analysis_output_always("noiseoff0",ls,p->noiseoffset[0],n,1,0,0); - _analysis_output_always("noiseoff1",ls,p->noiseoffset[1],n,1,0,0); - _analysis_output_always("noiseoff2",ls++,p->noiseoffset[2],n,1,0,0); - } -#endif -} - -void _vp_psy_clear(vorbis_look_psy *p){ - int i,j; - if(p){ - if(p->ath)_ogg_free(p->ath); - if(p->octave)_ogg_free(p->octave); - if(p->bark)_ogg_free(p->bark); - if(p->tonecurves){ - for(i=0;itonecurves[i][j]); - } - _ogg_free(p->tonecurves[i]); - } - _ogg_free(p->tonecurves); - } - if(p->noiseoffset){ - for(i=0;inoiseoffset[i]); - } - _ogg_free(p->noiseoffset); - } - memset(p,0,sizeof(*p)); - } -} - -/* octave/(8*eighth_octave_lines) x scale and dB y scale */ -static void seed_curve(float *seed, - const float **curves, - float amp, - int oc, int n, - int linesper,float dBoffset){ - int i,post1; - int seedptr; - const float *posts,*curve; - - int choice=(int)((amp+dBoffset-P_LEVEL_0)*.1f); - choice=max(choice,0); - choice=min(choice,P_LEVELS-1); - posts=curves[choice]; - curve=posts+2; - post1=(int)posts[1]; - seedptr=oc+(posts[0]-EHMER_OFFSET)*linesper-(linesper>>1); - - for(i=posts[0];i0){ - float lin=amp+curve[i]; - if(seed[seedptr]=n)break; - } -} - -static void seed_loop(vorbis_look_psy *p, - const float ***curves, - const float *f, - const float *flr, - float *seed, - float specmax){ - vorbis_info_psy *vi=p->vi; - long n=p->n,i; - float dBoffset=vi->max_curve_dB-specmax; - - /* prime the working vector with peak values */ - - for(i=0;ioctave[i]; - while(i+1octave[i+1]==oc){ - i++; - if(f[i]>max)max=f[i]; - } - - if(max+6.f>flr[i]){ - oc=oc>>p->shiftoc; - - if(oc>=P_BANDS)oc=P_BANDS-1; - if(oc<0)oc=0; - - seed_curve(seed, - curves[oc], - max, - p->octave[i]-p->firstoc, - p->total_octave_lines, - p->eighth_octave_lines, - dBoffset); - } - } -} - -static void seed_chase(float *seeds, int linesper, long n){ - long *posstack=alloca(n*sizeof(*posstack)); - float *ampstack=alloca(n*sizeof(*ampstack)); - long stack=0; - long pos=0; - long i; - - for(i=0;i1 && ampstack[stack-1]<=ampstack[stack-2] && - iampstack[i]){ - endpos=posstack[i+1]; - }else{ - endpos=posstack[i]+linesper+1; /* +1 is important, else bin 0 is - discarded in short frames */ - } - if(endpos>n)endpos=n; - for(;pos -static void max_seeds(vorbis_look_psy *p, - float *seed, - float *flr){ - long n=p->total_octave_lines; - int linesper=p->eighth_octave_lines; - long linpos=0; - long pos; - - seed_chase(seed,linesper,n); /* for masking */ - - pos=p->octave[0]-p->firstoc-(linesper>>1); - - while(linpos+1n){ - float minV=seed[pos]; - long end=((p->octave[linpos]+p->octave[linpos+1])>>1)-p->firstoc; - if(minV>p->vi->tone_abs_limit)minV=p->vi->tone_abs_limit; - while(pos+1<=end){ - pos++; - if((seed[pos]>NEGINF && seed[pos]firstoc; - for(;linposn && p->octave[linpos]<=end;linpos++) - if(flr[linpos]total_octave_lines-1]; - for(;linposn;linpos++) - if(flr[linpos]> 16; - hi = b[i] & 0xffff; - if( lo>=0 || -lo>=n ) break; - if( hi>=n ) break; - - tN = N[hi] + N[-lo]; - tX = X[hi] - X[-lo]; - tXX = XX[hi] + XX[-lo]; - tY = Y[hi] + Y[-lo]; - tXY = XY[hi] - XY[-lo]; - - A = tY * tXX - tX * tXY; - B = tN * tXY - tX * tY; - D = tN * tXX - tX * tX; - R = (A + x * B) / D; - if (R < 0.f) R = 0.f; - - noise[i] = R - offset; - } - - for ( ; i < n; i++, x += 1.f) { - - lo = b[i] >> 16; - hi = b[i] & 0xffff; - if( lo<0 || lo>=n ) break; - if( hi>=n ) break; - - tN = N[hi] - N[lo]; - tX = X[hi] - X[lo]; - tXX = XX[hi] - XX[lo]; - tY = Y[hi] - Y[lo]; - tXY = XY[hi] - XY[lo]; - - A = tY * tXX - tX * tXY; - B = tN * tXY - tX * tY; - D = tN * tXX - tX * tX; - R = (A + x * B) / D; - if (R < 0.f) R = 0.f; - - noise[i] = R - offset; - } - - for ( ; i < n; i++, x += 1.f) { - - R = (A + x * B) / D; - if (R < 0.f) R = 0.f; - - noise[i] = R - offset; - } - - if (fixed <= 0) return; - - for (i = 0, x = 0.f; i < n; i++, x += 1.f) { - hi = i + fixed / 2; - lo = hi - fixed; - if ( hi>=n ) break; - if ( lo>=0 ) break; - - tN = N[hi] + N[-lo]; - tX = X[hi] - X[-lo]; - tXX = XX[hi] + XX[-lo]; - tY = Y[hi] + Y[-lo]; - tXY = XY[hi] - XY[-lo]; - - - A = tY * tXX - tX * tXY; - B = tN * tXY - tX * tY; - D = tN * tXX - tX * tX; - R = (A + x * B) / D; - - if (R - offset < noise[i]) noise[i] = R - offset; - } - for ( ; i < n; i++, x += 1.f) { - - hi = i + fixed / 2; - lo = hi - fixed; - if ( hi>=n ) break; - if ( lo<0 ) break; - - tN = N[hi] - N[lo]; - tX = X[hi] - X[lo]; - tXX = XX[hi] - XX[lo]; - tY = Y[hi] - Y[lo]; - tXY = XY[hi] - XY[lo]; - - A = tY * tXX - tX * tXY; - B = tN * tXY - tX * tY; - D = tN * tXX - tX * tX; - R = (A + x * B) / D; - - if (R - offset < noise[i]) noise[i] = R - offset; - } - for ( ; i < n; i++, x += 1.f) { - R = (A + x * B) / D; - if (R - offset < noise[i]) noise[i] = R - offset; - } -} - -void _vp_noisemask(vorbis_look_psy *p, - float *logmdct, - float *logmask){ - - int i,n=p->n; - float *work=alloca(n*sizeof(*work)); - - bark_noise_hybridmp(n,p->bark,logmdct,logmask, - 140.,-1); - - for(i=0;ibark,work,logmask,0., - p->vi->noisewindowfixed); - - for(i=0;i=NOISE_COMPAND_LEVELS)dB=NOISE_COMPAND_LEVELS-1; - if(dB<0)dB=0; - logmask[i]= work[i]+p->vi->noisecompand[dB]; - } - -} - -void _vp_tonemask(vorbis_look_psy *p, - float *logfft, - float *logmask, - float global_specmax, - float local_specmax){ - - int i,n=p->n; - - float *seed=alloca(sizeof(*seed)*p->total_octave_lines); - float att=local_specmax+p->vi->ath_adjatt; - for(i=0;itotal_octave_lines;i++)seed[i]=NEGINF; - - /* set the ATH (floating below localmax, not global max by a - specified att) */ - if(attvi->ath_maxatt)att=p->vi->ath_maxatt; - - for(i=0;iath[i]+att; - - /* tone masking */ - seed_loop(p,(const float ***)p->tonecurves,logfft,logmask,seed,global_specmax); - max_seeds(p,seed,logmask); - -} - -void _vp_offset_and_mix(vorbis_look_psy *p, - float *noise, - float *tone, - int offset_select, - float *logmask, - float *mdct, - float *logmdct){ - int i,n=p->n; - float de, coeffi, cx;/* AoTuV */ - float toneatt=p->vi->tone_masteratt[offset_select]; - - cx = p->m_val; - - for(i=0;inoiseoffset[offset_select][i]; - if(val>p->vi->noisemaxsupp)val=p->vi->noisemaxsupp; - logmask[i]=max(val,tone[i]+toneatt); - - - /* AoTuV */ - /** @ M1 ** - The following codes improve a noise problem. - A fundamental idea uses the value of masking and carries out - the relative compensation of the MDCT. - However, this code is not perfect and all noise problems cannot be solved. - by Aoyumi @ 2004/04/18 - */ - - if(offset_select == 1) { - coeffi = -17.2; /* coeffi is a -17.2dB threshold */ - val = val - logmdct[i]; /* val == mdct line value relative to floor in dB */ - - if(val > coeffi){ - /* mdct value is > -17.2 dB below floor */ - - de = 1.0-((val-coeffi)*0.005*cx); - /* pro-rated attenuation: - -0.00 dB boost if mdct value is -17.2dB (relative to floor) - -0.77 dB boost if mdct value is 0dB (relative to floor) - -1.64 dB boost if mdct value is +17.2dB (relative to floor) - etc... */ - - if(de < 0) de = 0.0001; - }else - /* mdct value is <= -17.2 dB below floor */ - - de = 1.0-((val-coeffi)*0.0003*cx); - /* pro-rated attenuation: - +0.00 dB atten if mdct value is -17.2dB (relative to floor) - +0.45 dB atten if mdct value is -34.4dB (relative to floor) - etc... */ - - mdct[i] *= de; - - } - } -} - -float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd){ - vorbis_info *vi=vd->vi; - codec_setup_info *ci=vi->codec_setup; - vorbis_info_psy_global *gi=&ci->psy_g_param; - - int n=ci->blocksizes[vd->W]/2; - float secs=(float)n/vi->rate; - - amp+=secs*gi->ampmax_att_per_sec; - if(amp<-9999)amp=-9999; - return(amp); -} - -static float FLOOR1_fromdB_LOOKUP[256]={ - 1.0649863e-07F, 1.1341951e-07F, 1.2079015e-07F, 1.2863978e-07F, - 1.3699951e-07F, 1.4590251e-07F, 1.5538408e-07F, 1.6548181e-07F, - 1.7623575e-07F, 1.8768855e-07F, 1.9988561e-07F, 2.128753e-07F, - 2.2670913e-07F, 2.4144197e-07F, 2.5713223e-07F, 2.7384213e-07F, - 2.9163793e-07F, 3.1059021e-07F, 3.3077411e-07F, 3.5226968e-07F, - 3.7516214e-07F, 3.9954229e-07F, 4.2550680e-07F, 4.5315863e-07F, - 4.8260743e-07F, 5.1396998e-07F, 5.4737065e-07F, 5.8294187e-07F, - 6.2082472e-07F, 6.6116941e-07F, 7.0413592e-07F, 7.4989464e-07F, - 7.9862701e-07F, 8.5052630e-07F, 9.0579828e-07F, 9.6466216e-07F, - 1.0273513e-06F, 1.0941144e-06F, 1.1652161e-06F, 1.2409384e-06F, - 1.3215816e-06F, 1.4074654e-06F, 1.4989305e-06F, 1.5963394e-06F, - 1.7000785e-06F, 1.8105592e-06F, 1.9282195e-06F, 2.0535261e-06F, - 2.1869758e-06F, 2.3290978e-06F, 2.4804557e-06F, 2.6416497e-06F, - 2.8133190e-06F, 2.9961443e-06F, 3.1908506e-06F, 3.3982101e-06F, - 3.6190449e-06F, 3.8542308e-06F, 4.1047004e-06F, 4.3714470e-06F, - 4.6555282e-06F, 4.9580707e-06F, 5.2802740e-06F, 5.6234160e-06F, - 5.9888572e-06F, 6.3780469e-06F, 6.7925283e-06F, 7.2339451e-06F, - 7.7040476e-06F, 8.2047000e-06F, 8.7378876e-06F, 9.3057248e-06F, - 9.9104632e-06F, 1.0554501e-05F, 1.1240392e-05F, 1.1970856e-05F, - 1.2748789e-05F, 1.3577278e-05F, 1.4459606e-05F, 1.5399272e-05F, - 1.6400004e-05F, 1.7465768e-05F, 1.8600792e-05F, 1.9809576e-05F, - 2.1096914e-05F, 2.2467911e-05F, 2.3928002e-05F, 2.5482978e-05F, - 2.7139006e-05F, 2.8902651e-05F, 3.0780908e-05F, 3.2781225e-05F, - 3.4911534e-05F, 3.7180282e-05F, 3.9596466e-05F, 4.2169667e-05F, - 4.4910090e-05F, 4.7828601e-05F, 5.0936773e-05F, 5.4246931e-05F, - 5.7772202e-05F, 6.1526565e-05F, 6.5524908e-05F, 6.9783085e-05F, - 7.4317983e-05F, 7.9147585e-05F, 8.4291040e-05F, 8.9768747e-05F, - 9.5602426e-05F, 0.00010181521F, 0.00010843174F, 0.00011547824F, - 0.00012298267F, 0.00013097477F, 0.00013948625F, 0.00014855085F, - 0.00015820453F, 0.00016848555F, 0.00017943469F, 0.00019109536F, - 0.00020351382F, 0.00021673929F, 0.00023082423F, 0.00024582449F, - 0.00026179955F, 0.00027881276F, 0.00029693158F, 0.00031622787F, - 0.00033677814F, 0.00035866388F, 0.00038197188F, 0.00040679456F, - 0.00043323036F, 0.00046138411F, 0.00049136745F, 0.00052329927F, - 0.00055730621F, 0.00059352311F, 0.00063209358F, 0.00067317058F, - 0.00071691700F, 0.00076350630F, 0.00081312324F, 0.00086596457F, - 0.00092223983F, 0.00098217216F, 0.0010459992F, 0.0011139742F, - 0.0011863665F, 0.0012634633F, 0.0013455702F, 0.0014330129F, - 0.0015261382F, 0.0016253153F, 0.0017309374F, 0.0018434235F, - 0.0019632195F, 0.0020908006F, 0.0022266726F, 0.0023713743F, - 0.0025254795F, 0.0026895994F, 0.0028643847F, 0.0030505286F, - 0.0032487691F, 0.0034598925F, 0.0036847358F, 0.0039241906F, - 0.0041792066F, 0.0044507950F, 0.0047400328F, 0.0050480668F, - 0.0053761186F, 0.0057254891F, 0.0060975636F, 0.0064938176F, - 0.0069158225F, 0.0073652516F, 0.0078438871F, 0.0083536271F, - 0.0088964928F, 0.009474637F, 0.010090352F, 0.010746080F, - 0.011444421F, 0.012188144F, 0.012980198F, 0.013823725F, - 0.014722068F, 0.015678791F, 0.016697687F, 0.017782797F, - 0.018938423F, 0.020169149F, 0.021479854F, 0.022875735F, - 0.024362330F, 0.025945531F, 0.027631618F, 0.029427276F, - 0.031339626F, 0.033376252F, 0.035545228F, 0.037855157F, - 0.040315199F, 0.042935108F, 0.045725273F, 0.048696758F, - 0.051861348F, 0.055231591F, 0.058820850F, 0.062643361F, - 0.066714279F, 0.071049749F, 0.075666962F, 0.080584227F, - 0.085821044F, 0.091398179F, 0.097337747F, 0.10366330F, - 0.11039993F, 0.11757434F, 0.12521498F, 0.13335215F, - 0.14201813F, 0.15124727F, 0.16107617F, 0.17154380F, - 0.18269168F, 0.19456402F, 0.20720788F, 0.22067342F, - 0.23501402F, 0.25028656F, 0.26655159F, 0.28387361F, - 0.30232132F, 0.32196786F, 0.34289114F, 0.36517414F, - 0.38890521F, 0.41417847F, 0.44109412F, 0.46975890F, - 0.50028648F, 0.53279791F, 0.56742212F, 0.60429640F, - 0.64356699F, 0.68538959F, 0.72993007F, 0.77736504F, - 0.82788260F, 0.88168307F, 0.9389798F, 1.F, -}; - -/* this is for per-channel noise normalization */ -static int apsort(const void *a, const void *b){ - float f1=**(float**)a; - float f2=**(float**)b; - return (f1f2); -} - -static void flag_lossless(int limit, float prepoint, float postpoint, float *mdct, - float *floor, int *flag, int i, int jn){ - int j; - for(j=0;j=limit-i ? postpoint : prepoint; - float r = fabs(mdct[j])/floor[j]; - if(rvi; - float **sort = alloca(n*sizeof(*sort)); - int j,count=0; - int start = (vi->normal_p ? vi->normal_start-i : n); - if(start>n)start=n; - - /* force classic behavior where only energy in the current band is considered */ - acc=0.f; - - /* still responsible for populating *out where noise norm not in - effect. There's no need to [re]populate *q in these areas */ - for(j=0;j pointlimit */ - if(ve<.25f && (!flags || j>=limit-i)){ - acc += ve; - sort[count++]=q+j; /* q is fabs(r) for unflagged element */ - }else{ - /* For now: no acc adjustment for nonzero quantization. populate *out and q as this value is final. */ - if(r[j]<0) - out[j] = -rint(sqrt(ve)); - else - out[j] = rint(sqrt(ve)); - q[j] = out[j]*out[j]*f[j]; - } - }/* else{ - again, no energy adjustment for error in nonzero quant-- for now - }*/ - } - - if(count){ - /* noise norm to do */ - qsort(sort,count,sizeof(*sort),apsort); - for(j=0;j=vi->normal_thresh){ - out[k]=unitnorm(r[k]); - acc-=1.f; - q[k]=f[k]; - }else{ - out[k]=0; - q[k]=0.f; - } - } - } - - return acc; -} - -/* Noise normalization, quantization and coupling are not wholly - seperable processes in depth>1 coupling. */ -void _vp_couple_quantize_normalize(int blobno, - vorbis_info_psy_global *g, - vorbis_look_psy *p, - vorbis_info_mapping0 *vi, - float **mdct, - int **iwork, - int *nonzero, - int sliding_lowpass, - int ch){ - - int i; - int n = p->n; - int partition=(p->vi->normal_p ? p->vi->normal_partition : 16); - int limit = g->coupling_pointlimit[p->vi->blockflag][blobno]; - float prepoint=stereo_threshholds[g->coupling_prepointamp[blobno]]; - float postpoint=stereo_threshholds[g->coupling_postpointamp[blobno]]; -#if 0 - float de=0.1*p->m_val; /* a blend of the AoTuV M2 and M3 code here and below */ -#endif - - /* mdct is our raw mdct output, floor not removed. */ - /* inout passes in the ifloor, passes back quantized result */ - - /* unquantized energy (negative indicates amplitude has negative sign) */ - float **raw = alloca(ch*sizeof(*raw)); - - /* dual pupose; quantized energy (if flag set), othersize fabs(raw) */ - float **quant = alloca(ch*sizeof(*quant)); - - /* floor energy */ - float **floor = alloca(ch*sizeof(*floor)); - - /* flags indicating raw/quantized status of elements in raw vector */ - int **flag = alloca(ch*sizeof(*flag)); - - /* non-zero flag working vector */ - int *nz = alloca(ch*sizeof(*nz)); - - /* energy surplus/defecit tracking */ - float *acc = alloca((ch+vi->coupling_steps)*sizeof(*acc)); - - /* The threshold of a stereo is changed with the size of n */ - if(n > 1000) - postpoint=stereo_threshholds_limited[g->coupling_postpointamp[blobno]]; - - raw[0] = alloca(ch*partition*sizeof(**raw)); - quant[0] = alloca(ch*partition*sizeof(**quant)); - floor[0] = alloca(ch*partition*sizeof(**floor)); - flag[0] = alloca(ch*partition*sizeof(**flag)); - - for(i=1;icoupling_steps;i++) - acc[i]=0.f; - - for(i=0;i n-i ? n-i : partition; - int step,track = 0; - - memcpy(nz,nonzero,sizeof(*nz)*ch); - - /* prefill */ - memset(flag[0],0,ch*partition*sizeof(**flag)); - for(k=0;kcoupling_steps;step++){ - int Mi = vi->coupling_mag[step]; - int Ai = vi->coupling_ang[step]; - int *iM = &iwork[Mi][i]; - int *iA = &iwork[Ai][i]; - float *reM = raw[Mi]; - float *reA = raw[Ai]; - float *qeM = quant[Mi]; - float *qeA = quant[Ai]; - float *floorM = floor[Mi]; - float *floorA = floor[Ai]; - int *fM = flag[Mi]; - int *fA = flag[Ai]; - - if(nz[Mi] || nz[Ai]){ - nz[Mi] = nz[Ai] = 1; - - for(j=0;jabs(B)){ - iA[j]=(A>0?A-B:B-A); - }else{ - iA[j]=(B>0?A-B:B-A); - iM[j]=B; - } - - /* collapse two equivalent tuples to one */ - if(iA[j]>=abs(iM[j])*2){ - iA[j]= -iA[j]; - iM[j]= -iM[j]; - } - - } - - }else{ - /* lossy (point) coupling */ - if(jcoupling_steps;i++){ - /* make sure coupling a zero and a nonzero channel results in two - nonzero channels. */ - if(nonzero[vi->coupling_mag[i]] || - nonzero[vi->coupling_ang[i]]){ - nonzero[vi->coupling_mag[i]]=1; - nonzero[vi->coupling_ang[i]]=1; - } - } -} diff --git a/src/lib/vorbis/src/psy.h b/src/lib/vorbis/src/psy.h deleted file mode 100644 index d9a04e8b..00000000 --- a/src/lib/vorbis/src/psy.h +++ /dev/null @@ -1,153 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: random psychoacoustics (not including preecho) - - ********************************************************************/ - -#ifndef _V_PSY_H_ -#define _V_PSY_H_ -#include "smallft.h" - -#include "backends.h" -#include "envelope.h" - -#ifndef EHMER_MAX -#define EHMER_MAX 56 -#endif - -/* psychoacoustic setup ********************************************/ -#define P_BANDS 17 /* 62Hz to 16kHz */ -#define P_LEVELS 8 /* 30dB to 100dB */ -#define P_LEVEL_0 30. /* 30 dB */ -#define P_NOISECURVES 3 - -#define NOISE_COMPAND_LEVELS 40 -typedef struct vorbis_info_psy{ - int blockflag; - - float ath_adjatt; - float ath_maxatt; - - float tone_masteratt[P_NOISECURVES]; - float tone_centerboost; - float tone_decay; - float tone_abs_limit; - float toneatt[P_BANDS]; - - int noisemaskp; - float noisemaxsupp; - float noisewindowlo; - float noisewindowhi; - int noisewindowlomin; - int noisewindowhimin; - int noisewindowfixed; - float noiseoff[P_NOISECURVES][P_BANDS]; - float noisecompand[NOISE_COMPAND_LEVELS]; - - float max_curve_dB; - - int normal_p; - int normal_start; - int normal_partition; - double normal_thresh; -} vorbis_info_psy; - -typedef struct{ - int eighth_octave_lines; - - /* for block long/short tuning; encode only */ - float preecho_thresh[VE_BANDS]; - float postecho_thresh[VE_BANDS]; - float stretch_penalty; - float preecho_minenergy; - - float ampmax_att_per_sec; - - /* channel coupling config */ - int coupling_pkHz[PACKETBLOBS]; - int coupling_pointlimit[2][PACKETBLOBS]; - int coupling_prepointamp[PACKETBLOBS]; - int coupling_postpointamp[PACKETBLOBS]; - int sliding_lowpass[2][PACKETBLOBS]; - -} vorbis_info_psy_global; - -typedef struct { - float ampmax; - int channels; - - vorbis_info_psy_global *gi; - int coupling_pointlimit[2][P_NOISECURVES]; -} vorbis_look_psy_global; - - -typedef struct { - int n; - struct vorbis_info_psy *vi; - - float ***tonecurves; - float **noiseoffset; - - float *ath; - long *octave; /* in n.ocshift format */ - long *bark; - - long firstoc; - long shiftoc; - int eighth_octave_lines; /* power of two, please */ - int total_octave_lines; - long rate; /* cache it */ - - float m_val; /* Masking compensation value */ - -} vorbis_look_psy; - -extern void _vp_psy_init(vorbis_look_psy *p,vorbis_info_psy *vi, - vorbis_info_psy_global *gi,int n,long rate); -extern void _vp_psy_clear(vorbis_look_psy *p); -extern void *_vi_psy_dup(void *source); - -extern void _vi_psy_free(vorbis_info_psy *i); -extern vorbis_info_psy *_vi_psy_copy(vorbis_info_psy *i); - -extern void _vp_noisemask(vorbis_look_psy *p, - float *logmdct, - float *logmask); - -extern void _vp_tonemask(vorbis_look_psy *p, - float *logfft, - float *logmask, - float global_specmax, - float local_specmax); - -extern void _vp_offset_and_mix(vorbis_look_psy *p, - float *noise, - float *tone, - int offset_select, - float *logmask, - float *mdct, - float *logmdct); - -extern float _vp_ampmax_decay(float amp,vorbis_dsp_state *vd); - -extern void _vp_couple_quantize_normalize(int blobno, - vorbis_info_psy_global *g, - vorbis_look_psy *p, - vorbis_info_mapping0 *vi, - float **mdct, - int **iwork, - int *nonzero, - int sliding_lowpass, - int ch); - -#endif diff --git a/src/lib/vorbis/src/registry.c b/src/lib/vorbis/src/registry.c deleted file mode 100644 index db0f67b2..00000000 --- a/src/lib/vorbis/src/registry.c +++ /dev/null @@ -1,44 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: registry for time, floor, res backends and channel mappings - - ********************************************************************/ - -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "registry.h" -#include "misc.h" -/* seems like major overkill now; the backend numbers will grow into - the infrastructure soon enough */ - -extern const vorbis_func_floor floor0_exportbundle; -extern const vorbis_func_floor floor1_exportbundle; -extern const vorbis_func_residue residue0_exportbundle; -extern const vorbis_func_residue residue1_exportbundle; -extern const vorbis_func_residue residue2_exportbundle; -extern const vorbis_func_mapping mapping0_exportbundle; - -const vorbis_func_floor *const _floor_P[]={ - &floor0_exportbundle, - &floor1_exportbundle, -}; - -const vorbis_func_residue *const _residue_P[]={ - &residue0_exportbundle, - &residue1_exportbundle, - &residue2_exportbundle, -}; - -const vorbis_func_mapping *const _mapping_P[]={ - &mapping0_exportbundle, -}; diff --git a/src/lib/vorbis/src/registry.h b/src/lib/vorbis/src/registry.h deleted file mode 100644 index b823aa60..00000000 --- a/src/lib/vorbis/src/registry.h +++ /dev/null @@ -1,31 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: registry for time, floor, res backends and channel mappings - - ********************************************************************/ - -#ifndef _V_REG_H_ -#define _V_REG_H_ - -#define VI_TRANSFORMB 1 -#define VI_WINDOWB 1 -#define VI_TIMEB 1 -#define VI_FLOORB 2 -#define VI_RESB 3 -#define VI_MAPB 1 - -extern const vorbis_func_floor *const _floor_P[]; -extern const vorbis_func_residue *const _residue_P[]; -extern const vorbis_func_mapping *const _mapping_P[]; - -#endif diff --git a/src/lib/vorbis/src/res0.c b/src/lib/vorbis/src/res0.c deleted file mode 100644 index c931aded..00000000 --- a/src/lib/vorbis/src/res0.c +++ /dev/null @@ -1,886 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2010 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: residue backend 0, 1 and 2 implementation - - ********************************************************************/ - -/* Slow, slow, slow, simpleminded and did I mention it was slow? The - encode/decode loops are coded for clarity and performance is not - yet even a nagging little idea lurking in the shadows. Oh and BTW, - it's slow. */ - -#include -#include -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "registry.h" -#include "codebook.h" -#include "misc.h" -#include "os.h" - -#if defined(TRAIN_RES) || defined (TRAIN_RESAUX) -#include -#endif - -typedef struct { - vorbis_info_residue0 *info; - - int parts; - int stages; - codebook *fullbooks; - codebook *phrasebook; - codebook ***partbooks; - - int partvals; - int **decodemap; - - long postbits; - long phrasebits; - long frames; - -#if defined(TRAIN_RES) || defined(TRAIN_RESAUX) - int train_seq; - long *training_data[8][64]; - float training_max[8][64]; - float training_min[8][64]; - float tmin; - float tmax; - int submap; -#endif - -} vorbis_look_residue0; - -void res0_free_info(vorbis_info_residue *i){ - vorbis_info_residue0 *info=(vorbis_info_residue0 *)i; - if(info){ - memset(info,0,sizeof(*info)); - _ogg_free(info); - } -} - -void res0_free_look(vorbis_look_residue *i){ - int j; - if(i){ - - vorbis_look_residue0 *look=(vorbis_look_residue0 *)i; - -#ifdef TRAIN_RES - { - int j,k,l; - for(j=0;jparts;j++){ - /*fprintf(stderr,"partition %d: ",j);*/ - for(k=0;k<8;k++) - if(look->training_data[k][j]){ - char buffer[80]; - FILE *of; - codebook *statebook=look->partbooks[j][k]; - - /* long and short into the same bucket by current convention */ - sprintf(buffer,"res_sub%d_part%d_pass%d.vqd",look->submap,j,k); - of=fopen(buffer,"a"); - - for(l=0;lentries;l++) - fprintf(of,"%d:%ld\n",l,look->training_data[k][j][l]); - - fclose(of); - - /*fprintf(stderr,"%d(%.2f|%.2f) ",k, - look->training_min[k][j],look->training_max[k][j]);*/ - - _ogg_free(look->training_data[k][j]); - look->training_data[k][j]=NULL; - } - /*fprintf(stderr,"\n");*/ - } - } - fprintf(stderr,"min/max residue: %g::%g\n",look->tmin,look->tmax); - - /*fprintf(stderr,"residue bit usage %f:%f (%f total)\n", - (float)look->phrasebits/look->frames, - (float)look->postbits/look->frames, - (float)(look->postbits+look->phrasebits)/look->frames);*/ -#endif - - - /*vorbis_info_residue0 *info=look->info; - - fprintf(stderr, - "%ld frames encoded in %ld phrasebits and %ld residue bits " - "(%g/frame) \n",look->frames,look->phrasebits, - look->resbitsflat, - (look->phrasebits+look->resbitsflat)/(float)look->frames); - - for(j=0;jparts;j++){ - long acc=0; - fprintf(stderr,"\t[%d] == ",j); - for(k=0;kstages;k++) - if((info->secondstages[j]>>k)&1){ - fprintf(stderr,"%ld,",look->resbits[j][k]); - acc+=look->resbits[j][k]; - } - - fprintf(stderr,":: (%ld vals) %1.2fbits/sample\n",look->resvals[j], - acc?(float)acc/(look->resvals[j]*info->grouping):0); - } - fprintf(stderr,"\n");*/ - - for(j=0;jparts;j++) - if(look->partbooks[j])_ogg_free(look->partbooks[j]); - _ogg_free(look->partbooks); - for(j=0;jpartvals;j++) - _ogg_free(look->decodemap[j]); - _ogg_free(look->decodemap); - - memset(look,0,sizeof(*look)); - _ogg_free(look); - } -} - -static int icount(unsigned int v){ - int ret=0; - while(v){ - ret+=v&1; - v>>=1; - } - return(ret); -} - - -void res0_pack(vorbis_info_residue *vr,oggpack_buffer *opb){ - vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr; - int j,acc=0; - oggpack_write(opb,info->begin,24); - oggpack_write(opb,info->end,24); - - oggpack_write(opb,info->grouping-1,24); /* residue vectors to group and - code with a partitioned book */ - oggpack_write(opb,info->partitions-1,6); /* possible partition choices */ - oggpack_write(opb,info->groupbook,8); /* group huffman book */ - - /* secondstages is a bitmask; as encoding progresses pass by pass, a - bitmask of one indicates this partition class has bits to write - this pass */ - for(j=0;jpartitions;j++){ - if(ov_ilog(info->secondstages[j])>3){ - /* yes, this is a minor hack due to not thinking ahead */ - oggpack_write(opb,info->secondstages[j],3); - oggpack_write(opb,1,1); - oggpack_write(opb,info->secondstages[j]>>3,5); - }else - oggpack_write(opb,info->secondstages[j],4); /* trailing zero */ - acc+=icount(info->secondstages[j]); - } - for(j=0;jbooklist[j],8); - -} - -/* vorbis_info is for range checking */ -vorbis_info_residue *res0_unpack(vorbis_info *vi,oggpack_buffer *opb){ - int j,acc=0; - vorbis_info_residue0 *info=_ogg_calloc(1,sizeof(*info)); - codec_setup_info *ci=vi->codec_setup; - - info->begin=oggpack_read(opb,24); - info->end=oggpack_read(opb,24); - info->grouping=oggpack_read(opb,24)+1; - info->partitions=oggpack_read(opb,6)+1; - info->groupbook=oggpack_read(opb,8); - - /* check for premature EOP */ - if(info->groupbook<0)goto errout; - - for(j=0;jpartitions;j++){ - int cascade=oggpack_read(opb,3); - int cflag=oggpack_read(opb,1); - if(cflag<0) goto errout; - if(cflag){ - int c=oggpack_read(opb,5); - if(c<0) goto errout; - cascade|=(c<<3); - } - info->secondstages[j]=cascade; - - acc+=icount(cascade); - } - for(j=0;jbooklist[j]=book; - } - - if(info->groupbook>=ci->books)goto errout; - for(j=0;jbooklist[j]>=ci->books)goto errout; - if(ci->book_param[info->booklist[j]]->maptype==0)goto errout; - } - - /* verify the phrasebook is not specifying an impossible or - inconsistent partitioning scheme. */ - /* modify the phrasebook ranging check from r16327; an early beta - encoder had a bug where it used an oversized phrasebook by - accident. These files should continue to be playable, but don't - allow an exploit */ - { - int entries = ci->book_param[info->groupbook]->entries; - int dim = ci->book_param[info->groupbook]->dim; - int partvals = 1; - if (dim<1) goto errout; - while(dim>0){ - partvals *= info->partitions; - if(partvals > entries) goto errout; - dim--; - } - info->partvals = partvals; - } - - return(info); - errout: - res0_free_info(info); - return(NULL); -} - -vorbis_look_residue *res0_look(vorbis_dsp_state *vd, - vorbis_info_residue *vr){ - vorbis_info_residue0 *info=(vorbis_info_residue0 *)vr; - vorbis_look_residue0 *look=_ogg_calloc(1,sizeof(*look)); - codec_setup_info *ci=vd->vi->codec_setup; - - int j,k,acc=0; - int dim; - int maxstage=0; - look->info=info; - - look->parts=info->partitions; - look->fullbooks=ci->fullbooks; - look->phrasebook=ci->fullbooks+info->groupbook; - dim=look->phrasebook->dim; - - look->partbooks=_ogg_calloc(look->parts,sizeof(*look->partbooks)); - - for(j=0;jparts;j++){ - int stages=ov_ilog(info->secondstages[j]); - if(stages){ - if(stages>maxstage)maxstage=stages; - look->partbooks[j]=_ogg_calloc(stages,sizeof(*look->partbooks[j])); - for(k=0;ksecondstages[j]&(1<partbooks[j][k]=ci->fullbooks+info->booklist[acc++]; -#ifdef TRAIN_RES - look->training_data[k][j]=_ogg_calloc(look->partbooks[j][k]->entries, - sizeof(***look->training_data)); -#endif - } - } - } - - look->partvals=1; - for(j=0;jpartvals*=look->parts; - - look->stages=maxstage; - look->decodemap=_ogg_malloc(look->partvals*sizeof(*look->decodemap)); - for(j=0;jpartvals;j++){ - long val=j; - long mult=look->partvals/look->parts; - look->decodemap[j]=_ogg_malloc(dim*sizeof(*look->decodemap[j])); - for(k=0;kparts; - look->decodemap[j][k]=deco; - } - } -#if defined(TRAIN_RES) || defined (TRAIN_RESAUX) - { - static int train_seq=0; - look->train_seq=train_seq++; - } -#endif - return(look); -} - -/* break an abstraction and copy some code for performance purposes */ -static int local_book_besterror(codebook *book,int *a){ - int dim=book->dim; - int i,j,o; - int minval=book->minval; - int del=book->delta; - int qv=book->quantvals; - int ze=(qv>>1); - int index=0; - /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ - int p[8]={0,0,0,0,0,0,0,0}; - - if(del!=1){ - for(i=0,o=dim;i>1))/del; - int m = (v=qv?qv-1:m)); - p[o]=v*del+minval; - } - }else{ - for(i=0,o=dim;i=qv?qv-1:m)); - p[o]=v*del+minval; - } - } - - if(book->c->lengthlist[index]<=0){ - const static_codebook *c=book->c; - int best=-1; - /* assumes integer/centered encoder codebook maptype 1 no more than dim 8 */ - int e[8]={0,0,0,0,0,0,0,0}; - int maxval = book->minval + book->delta*(book->quantvals-1); - for(i=0;ientries;i++){ - if(c->lengthlist[i]>0){ - int this=0; - for(j=0;j=maxval) - e[j++]=0; - if(e[j]>=0) - e[j]+=book->delta; - e[j]= -e[j]; - } - } - - if(index>-1){ - for(i=0;idim; - int step=n/dim; - - for(i=0;i=0) - acc[entry]++; -#endif - - bits+=vorbis_book_encode(book,entry,opb); - - } - - return(bits); -} - -static long **_01class(vorbis_block *vb,vorbis_look_residue *vl, - int **in,int ch){ - long i,j,k; - vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; - vorbis_info_residue0 *info=look->info; - - /* move all this setup out later */ - int samples_per_partition=info->grouping; - int possible_partitions=info->partitions; - int n=info->end-info->begin; - - int partvals=n/samples_per_partition; - long **partword=_vorbis_block_alloc(vb,ch*sizeof(*partword)); - float scale=100./samples_per_partition; - - /* we find the partition type for each partition of each - channel. We'll go back and do the interleaved encoding in a - bit. For now, clarity */ - - for(i=0;ibegin; - for(j=0;jmax)max=abs(in[j][offset+k]); - ent+=abs(in[j][offset+k]); - } - ent*=scale; - - for(k=0;kclassmetric1[k] && - (info->classmetric2[k]<0 || entclassmetric2[k])) - break; - - partword[j][i]=k; - } - } - -#ifdef TRAIN_RESAUX - { - FILE *of; - char buffer[80]; - - for(i=0;itrain_seq); - of=fopen(buffer,"a"); - for(j=0;jframes++; - - return(partword); -} - -/* designed for stereo or other modes where the partition size is an - integer multiple of the number of channels encoded in the current - submap */ -static long **_2class(vorbis_block *vb,vorbis_look_residue *vl,int **in, - int ch){ - long i,j,k,l; - vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; - vorbis_info_residue0 *info=look->info; - - /* move all this setup out later */ - int samples_per_partition=info->grouping; - int possible_partitions=info->partitions; - int n=info->end-info->begin; - - int partvals=n/samples_per_partition; - long **partword=_vorbis_block_alloc(vb,sizeof(*partword)); - -#if defined(TRAIN_RES) || defined (TRAIN_RESAUX) - FILE *of; - char buffer[80]; -#endif - - partword[0]=_vorbis_block_alloc(vb,partvals*sizeof(*partword[0])); - memset(partword[0],0,partvals*sizeof(*partword[0])); - - for(i=0,l=info->begin/ch;imagmax)magmax=abs(in[0][l]); - for(k=1;kangmax)angmax=abs(in[k][l]); - l++; - } - - for(j=0;jclassmetric1[j] && - angmax<=info->classmetric2[j]) - break; - - partword[0][i]=j; - - } - -#ifdef TRAIN_RESAUX - sprintf(buffer,"resaux_%d.vqd",look->train_seq); - of=fopen(buffer,"a"); - for(i=0;iframes++; - - return(partword); -} - -static int _01forward(oggpack_buffer *opb, - vorbis_look_residue *vl, - int **in,int ch, - long **partword, -#ifdef TRAIN_RES - int (*encode)(oggpack_buffer *,int *,int, - codebook *,long *), - int submap -#else - int (*encode)(oggpack_buffer *,int *,int, - codebook *) -#endif -){ - long i,j,k,s; - vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; - vorbis_info_residue0 *info=look->info; - -#ifdef TRAIN_RES - look->submap=submap; -#endif - - /* move all this setup out later */ - int samples_per_partition=info->grouping; - int possible_partitions=info->partitions; - int partitions_per_word=look->phrasebook->dim; - int n=info->end-info->begin; - - int partvals=n/samples_per_partition; - long resbits[128]; - long resvals[128]; - -#ifdef TRAIN_RES - for(i=0;ibegin;jend;j++){ - if(in[i][j]>look->tmax)look->tmax=in[i][j]; - if(in[i][j]tmin)look->tmin=in[i][j]; - } -#endif - - memset(resbits,0,sizeof(resbits)); - memset(resvals,0,sizeof(resvals)); - - /* we code the partition words for each channel, then the residual - words for a partition per channel until we've written all the - residual words for that partition word. Then write the next - partition channel words... */ - - for(s=0;sstages;s++){ - - for(i=0;iphrasebook->entries) - look->phrasebits+=vorbis_book_encode(look->phrasebook,val,opb); -#if 0 /*def TRAIN_RES*/ - else - fprintf(stderr,"!"); -#endif - - } - } - - /* now we encode interleaved residual values for the partitions */ - for(k=0;kbegin; - - for(j=0;jsecondstages[partword[j][i]]&(1<partbooks[partword[j][i]][s]; - if(statebook){ - int ret; -#ifdef TRAIN_RES - long *accumulator=NULL; - accumulator=look->training_data[s][partword[j][i]]; - { - int l; - int *samples=in[j]+offset; - for(l=0;ltraining_min[s][partword[j][i]]) - look->training_min[s][partword[j][i]]=samples[l]; - if(samples[l]>look->training_max[s][partword[j][i]]) - look->training_max[s][partword[j][i]]=samples[l]; - } - } - ret=encode(opb,in[j]+offset,samples_per_partition, - statebook,accumulator); -#else - ret=encode(opb,in[j]+offset,samples_per_partition, - statebook); -#endif - - look->postbits+=ret; - resbits[partword[j][i]]+=ret; - } - } - } - } - } - } - - return(0); -} - -/* a truncated packet here just means 'stop working'; it's not an error */ -static int _01inverse(vorbis_block *vb,vorbis_look_residue *vl, - float **in,int ch, - long (*decodepart)(codebook *, float *, - oggpack_buffer *,int)){ - - long i,j,k,l,s; - vorbis_look_residue0 *look=(vorbis_look_residue0 *)vl; - vorbis_info_residue0 *info=look->info; - - /* move all this setup out later */ - int samples_per_partition=info->grouping; - int partitions_per_word=look->phrasebook->dim; - int max=vb->pcmend>>1; - int end=(info->endend:max); - int n=end-info->begin; - - if(n>0){ - int partvals=n/samples_per_partition; - int partwords=(partvals+partitions_per_word-1)/partitions_per_word; - int ***partword=alloca(ch*sizeof(*partword)); - - for(j=0;jstages;s++){ - - /* each loop decodes on partition codeword containing - partitions_per_word partitions */ - for(i=0,l=0;iphrasebook,&vb->opb); - - if(temp==-1 || temp>=info->partvals)goto eopbreak; - partword[j][l]=look->decodemap[temp]; - if(partword[j][l]==NULL)goto errout; - } - } - - /* now we decode residual values for the partitions */ - for(k=0;kbegin+i*samples_per_partition; - if(info->secondstages[partword[j][l][k]]&(1<partbooks[partword[j][l][k]][s]; - if(stagebook){ - if(decodepart(stagebook,in[j]+offset,&vb->opb, - samples_per_partition)==-1)goto eopbreak; - } - } - } - } - } - } - errout: - eopbreak: - return(0); -} - -int res0_inverse(vorbis_block *vb,vorbis_look_residue *vl, - float **in,int *nonzero,int ch){ - int i,used=0; - for(i=0;ipcmend/2,used=0; - - /* don't duplicate the code; use a working vector hack for now and - reshape ourselves into a single channel res1 */ - /* ugly; reallocs for each coupling pass :-( */ - int *work=_vorbis_block_alloc(vb,ch*n*sizeof(*work)); - for(i=0;iinfo; - - /* move all this setup out later */ - int samples_per_partition=info->grouping; - int partitions_per_word=look->phrasebook->dim; - int max=(vb->pcmend*ch)>>1; - int end=(info->endend:max); - int n=end-info->begin; - - if(n>0){ - int partvals=n/samples_per_partition; - int partwords=(partvals+partitions_per_word-1)/partitions_per_word; - int **partword=_vorbis_block_alloc(vb,partwords*sizeof(*partword)); - - for(i=0;istages;s++){ - for(i=0,l=0;iphrasebook,&vb->opb); - if(temp==-1 || temp>=info->partvals)goto eopbreak; - partword[l]=look->decodemap[temp]; - if(partword[l]==NULL)goto errout; - } - - /* now we decode residual values for the partitions */ - for(k=0;ksecondstages[partword[l][k]]&(1<partbooks[partword[l][k]][s]; - - if(stagebook){ - if(vorbis_book_decodevv_add(stagebook,in, - i*samples_per_partition+info->begin,ch, - &vb->opb,samples_per_partition)==-1) - goto eopbreak; - } - } - } - } - } - errout: - eopbreak: - return(0); -} - - -const vorbis_func_residue residue0_exportbundle={ - NULL, - &res0_unpack, - &res0_look, - &res0_free_info, - &res0_free_look, - NULL, - NULL, - &res0_inverse -}; - -const vorbis_func_residue residue1_exportbundle={ - &res0_pack, - &res0_unpack, - &res0_look, - &res0_free_info, - &res0_free_look, - &res1_class, - &res1_forward, - &res1_inverse -}; - -const vorbis_func_residue residue2_exportbundle={ - &res0_pack, - &res0_unpack, - &res0_look, - &res0_free_info, - &res0_free_look, - &res2_class, - &res2_forward, - &res2_inverse -}; diff --git a/src/lib/vorbis/src/scales.h b/src/lib/vorbis/src/scales.h deleted file mode 100644 index 3c2ae48d..00000000 --- a/src/lib/vorbis/src/scales.h +++ /dev/null @@ -1,89 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: linear scale -> dB, Bark and Mel scales - - ********************************************************************/ - -#ifndef _V_SCALES_H_ -#define _V_SCALES_H_ - -#include -#include "os.h" - -#ifdef _MSC_VER -/* MS Visual Studio doesn't have C99 inline keyword. */ -#define inline __inline -#endif - -/* 20log10(x) */ -#define VORBIS_IEEE_FLOAT32 1 -#ifdef VORBIS_IEEE_FLOAT32 - -static inline float unitnorm(float x){ - union { - ogg_uint32_t i; - float f; - } ix; - ix.f = x; - ix.i = (ix.i & 0x80000000U) | (0x3f800000U); - return ix.f; -} - -/* Segher was off (too high) by ~ .3 decibel. Center the conversion correctly. */ -static inline float todB(const float *x){ - union { - ogg_uint32_t i; - float f; - } ix; - ix.f = *x; - ix.i = ix.i&0x7fffffff; - return (float)(ix.i * 7.17711438e-7f -764.6161886f); -} - -#define todB_nn(x) todB(x) - -#else - -static float unitnorm(float x){ - if(x<0)return(-1.f); - return(1.f); -} - -#define todB(x) (*(x)==0?-400.f:log(*(x)**(x))*4.34294480f) -#define todB_nn(x) (*(x)==0.f?-400.f:log(*(x))*8.6858896f) - -#endif - -#define fromdB(x) (exp((x)*.11512925f)) - -/* The bark scale equations are approximations, since the original - table was somewhat hand rolled. The below are chosen to have the - best possible fit to the rolled tables, thus their somewhat odd - appearance (these are more accurate and over a longer range than - the oft-quoted bark equations found in the texts I have). The - approximations are valid from 0 - 30kHz (nyquist) or so. - - all f in Hz, z in Bark */ - -#define toBARK(n) (13.1f*atan(.00074f*(n))+2.24f*atan((n)*(n)*1.85e-8f)+1e-4f*(n)) -#define fromBARK(z) (102.f*(z)-2.f*pow(z,2.f)+.4f*pow(z,3.f)+pow(1.46f,z)-1.f) -#define toMEL(n) (log(1.f+(n)*.001f)*1442.695f) -#define fromMEL(m) (1000.f*exp((m)/1442.695f)-1000.f) - -/* Frequency to octave. We arbitrarily declare 63.5 Hz to be octave - 0.0 */ - -#define toOC(n) (log(n)*1.442695f-5.965784f) -#define fromOC(o) (exp(((o)+5.965784f)*.693147f)) - -#endif diff --git a/src/lib/vorbis/src/sharedbook.c b/src/lib/vorbis/src/sharedbook.c deleted file mode 100644 index 62a9a00a..00000000 --- a/src/lib/vorbis/src/sharedbook.c +++ /dev/null @@ -1,604 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: basic shared codebook operations - - ********************************************************************/ - -#include -#include -#include -#include -#include -#include "os.h" -#include "misc.h" -#include "vorbis/codec.h" -#include "codebook.h" -#include "scales.h" - -/**** pack/unpack helpers ******************************************/ - -int ov_ilog(ogg_uint32_t v){ - int ret; - for(ret=0;v;ret++)v>>=1; - return ret; -} - -/* 32 bit float (not IEEE; nonnormalized mantissa + - biased exponent) : neeeeeee eeemmmmm mmmmmmmm mmmmmmmm - Why not IEEE? It's just not that important here. */ - -#define VQ_FEXP 10 -#define VQ_FMAN 21 -#define VQ_FEXP_BIAS 768 /* bias toward values smaller than 1. */ - -/* doesn't currently guard under/overflow */ -long _float32_pack(float val){ - int sign=0; - long exp; - long mant; - if(val<0){ - sign=0x80000000; - val= -val; - } - exp= floor(log(val)/log(2.f)+.001); /* +epsilon */ - mant=rint(ldexp(val,(VQ_FMAN-1)-exp)); - exp=(exp+VQ_FEXP_BIAS)<>VQ_FMAN; - if(sign)mant= -mant; - exp=exp-(VQ_FMAN-1)-VQ_FEXP_BIAS; - /* clamp excessive exponent values */ - if (exp>63){ - exp=63; - } - if (exp<-63){ - exp=-63; - } - return(ldexp(mant,exp)); -} - -/* given a list of word lengths, generate a list of codewords. Works - for length ordered or unordered, always assigns the lowest valued - codewords first. Extended to handle unused entries (length 0) */ -ogg_uint32_t *_make_words(char *l,long n,long sparsecount){ - long i,j,count=0; - ogg_uint32_t marker[33]; - ogg_uint32_t *r=_ogg_malloc((sparsecount?sparsecount:n)*sizeof(*r)); - memset(marker,0,sizeof(marker)); - - for(i=0;i0){ - ogg_uint32_t entry=marker[length]; - - /* when we claim a node for an entry, we also claim the nodes - below it (pruning off the imagined tree that may have dangled - from it) as well as blocking the use of any nodes directly - above for leaves */ - - /* update ourself */ - if(length<32 && (entry>>length)){ - /* error condition; the lengths must specify an overpopulated tree */ - _ogg_free(r); - return(NULL); - } - r[count++]=entry; - - /* Look to see if the next shorter marker points to the node - above. if so, update it and repeat. */ - { - for(j=length;j>0;j--){ - - if(marker[j]&1){ - /* have to jump branches */ - if(j==1) - marker[1]++; - else - marker[j]=marker[j-1]<<1; - break; /* invariant says next upper marker would already - have been moved if it was on the same path */ - } - marker[j]++; - } - } - - /* prune the tree; the implicit invariant says all the longer - markers were dangling from our just-taken node. Dangle them - from our *new* node. */ - for(j=length+1;j<33;j++) - if((marker[j]>>1) == entry){ - entry=marker[j]; - marker[j]=marker[j-1]<<1; - }else - break; - }else - if(sparsecount==0)count++; - } - - /* any underpopulated tree must be rejected. */ - /* Single-entry codebooks are a retconned extension to the spec. - They have a single codeword '0' of length 1 that results in an - underpopulated tree. Shield that case from the underformed tree check. */ - if(!(count==1 && marker[2]==2)){ - for(i=1;i<33;i++) - if(marker[i] & (0xffffffffUL>>(32-i))){ - _ogg_free(r); - return(NULL); - } - } - - /* bitreverse the words because our bitwise packer/unpacker is LSb - endian */ - for(i=0,count=0;i>j)&1; - } - - if(sparsecount){ - if(l[i]) - r[count++]=temp; - }else - r[count++]=temp; - } - - return(r); -} - -/* there might be a straightforward one-line way to do the below - that's portable and totally safe against roundoff, but I haven't - thought of it. Therefore, we opt on the side of caution */ -long _book_maptype1_quantvals(const static_codebook *b){ - long vals; - if(b->entries<1){ - return(0); - } - vals=floor(pow((float)b->entries,1.f/b->dim)); - - /* the above *should* be reliable, but we'll not assume that FP is - ever reliable when bitstream sync is at stake; verify via integer - means that vals really is the greatest value of dim for which - vals^b->bim <= b->entries */ - /* treat the above as an initial guess */ - if(vals<1){ - vals=1; - } - while(1){ - long acc=1; - long acc1=1; - int i; - for(i=0;idim;i++){ - if(b->entries/vals=b->dim && acc<=b->entries && acc1>b->entries){ - return(vals); - }else{ - if(idim || acc>b->entries){ - vals--; - }else{ - vals++; - } - } - } -} - -/* unpack the quantized list of values for encode/decode ***********/ -/* we need to deal with two map types: in map type 1, the values are - generated algorithmically (each column of the vector counts through - the values in the quant vector). in map type 2, all the values came - in in an explicit list. Both value lists must be unpacked */ -float *_book_unquantize(const static_codebook *b,int n,int *sparsemap){ - long j,k,count=0; - if(b->maptype==1 || b->maptype==2){ - int quantvals; - float mindel=_float32_unpack(b->q_min); - float delta=_float32_unpack(b->q_delta); - float *r=_ogg_calloc(n*b->dim,sizeof(*r)); - - /* maptype 1 and 2 both use a quantized value vector, but - different sizes */ - switch(b->maptype){ - case 1: - /* most of the time, entries%dimensions == 0, but we need to be - well defined. We define that the possible vales at each - scalar is values == entries/dim. If entries%dim != 0, we'll - have 'too few' values (values*dimentries;j++){ - if((sparsemap && b->lengthlist[j]) || !sparsemap){ - float last=0.f; - int indexdiv=1; - for(k=0;kdim;k++){ - int index= (j/indexdiv)%quantvals; - float val=b->quantlist[index]; - val=fabs(val)*delta+mindel+last; - if(b->q_sequencep)last=val; - if(sparsemap) - r[sparsemap[count]*b->dim+k]=val; - else - r[count*b->dim+k]=val; - indexdiv*=quantvals; - } - count++; - } - - } - break; - case 2: - for(j=0;jentries;j++){ - if((sparsemap && b->lengthlist[j]) || !sparsemap){ - float last=0.f; - - for(k=0;kdim;k++){ - float val=b->quantlist[j*b->dim+k]; - val=fabs(val)*delta+mindel+last; - if(b->q_sequencep)last=val; - if(sparsemap) - r[sparsemap[count]*b->dim+k]=val; - else - r[count*b->dim+k]=val; - } - count++; - } - } - break; - } - - return(r); - } - return(NULL); -} - -void vorbis_staticbook_destroy(static_codebook *b){ - if(b->allocedp){ - if(b->quantlist)_ogg_free(b->quantlist); - if(b->lengthlist)_ogg_free(b->lengthlist); - memset(b,0,sizeof(*b)); - _ogg_free(b); - } /* otherwise, it is in static memory */ -} - -void vorbis_book_clear(codebook *b){ - /* static book is not cleared; we're likely called on the lookup and - the static codebook belongs to the info struct */ - if(b->valuelist)_ogg_free(b->valuelist); - if(b->codelist)_ogg_free(b->codelist); - - if(b->dec_index)_ogg_free(b->dec_index); - if(b->dec_codelengths)_ogg_free(b->dec_codelengths); - if(b->dec_firsttable)_ogg_free(b->dec_firsttable); - - memset(b,0,sizeof(*b)); -} - -int vorbis_book_init_encode(codebook *c,const static_codebook *s){ - - memset(c,0,sizeof(*c)); - c->c=s; - c->entries=s->entries; - c->used_entries=s->entries; - c->dim=s->dim; - c->codelist=_make_words(s->lengthlist,s->entries,0); - /* c->valuelist=_book_unquantize(s,s->entries,NULL); */ - c->quantvals=_book_maptype1_quantvals(s); - c->minval=(int)rint(_float32_unpack(s->q_min)); - c->delta=(int)rint(_float32_unpack(s->q_delta)); - - return(0); -} - -static ogg_uint32_t bitreverse(ogg_uint32_t x){ - x= ((x>>16)&0x0000ffffUL) | ((x<<16)&0xffff0000UL); - x= ((x>> 8)&0x00ff00ffUL) | ((x<< 8)&0xff00ff00UL); - x= ((x>> 4)&0x0f0f0f0fUL) | ((x<< 4)&0xf0f0f0f0UL); - x= ((x>> 2)&0x33333333UL) | ((x<< 2)&0xccccccccUL); - return((x>> 1)&0x55555555UL) | ((x<< 1)&0xaaaaaaaaUL); -} - -static int sort32a(const void *a,const void *b){ - return ( **(ogg_uint32_t **)a>**(ogg_uint32_t **)b)- - ( **(ogg_uint32_t **)a<**(ogg_uint32_t **)b); -} - -/* decode codebook arrangement is more heavily optimized than encode */ -int vorbis_book_init_decode(codebook *c,const static_codebook *s){ - int i,j,n=0,tabn; - int *sortindex; - - memset(c,0,sizeof(*c)); - - /* count actually used entries and find max length */ - for(i=0;ientries;i++) - if(s->lengthlist[i]>0) - n++; - - c->entries=s->entries; - c->used_entries=n; - c->dim=s->dim; - - if(n>0){ - /* two different remappings go on here. - - First, we collapse the likely sparse codebook down only to - actually represented values/words. This collapsing needs to be - indexed as map-valueless books are used to encode original entry - positions as integers. - - Second, we reorder all vectors, including the entry index above, - by sorted bitreversed codeword to allow treeless decode. */ - - /* perform sort */ - ogg_uint32_t *codes=_make_words(s->lengthlist,s->entries,c->used_entries); - ogg_uint32_t **codep=alloca(sizeof(*codep)*n); - - if(codes==NULL)goto err_out; - - for(i=0;icodelist=_ogg_malloc(n*sizeof(*c->codelist)); - /* the index is a reverse index */ - for(i=0;icodelist[sortindex[i]]=codes[i]; - _ogg_free(codes); - - c->valuelist=_book_unquantize(s,n,sortindex); - c->dec_index=_ogg_malloc(n*sizeof(*c->dec_index)); - - for(n=0,i=0;ientries;i++) - if(s->lengthlist[i]>0) - c->dec_index[sortindex[n++]]=i; - - c->dec_codelengths=_ogg_malloc(n*sizeof(*c->dec_codelengths)); - c->dec_maxlength=0; - for(n=0,i=0;ientries;i++) - if(s->lengthlist[i]>0){ - c->dec_codelengths[sortindex[n++]]=s->lengthlist[i]; - if(s->lengthlist[i]>c->dec_maxlength) - c->dec_maxlength=s->lengthlist[i]; - } - - if(n==1 && c->dec_maxlength==1){ - /* special case the 'single entry codebook' with a single bit - fastpath table (that always returns entry 0 )in order to use - unmodified decode paths. */ - c->dec_firsttablen=1; - c->dec_firsttable=_ogg_calloc(2,sizeof(*c->dec_firsttable)); - c->dec_firsttable[0]=c->dec_firsttable[1]=1; - - }else{ - c->dec_firsttablen=ov_ilog(c->used_entries)-4; /* this is magic */ - if(c->dec_firsttablen<5)c->dec_firsttablen=5; - if(c->dec_firsttablen>8)c->dec_firsttablen=8; - - tabn=1<dec_firsttablen; - c->dec_firsttable=_ogg_calloc(tabn,sizeof(*c->dec_firsttable)); - - for(i=0;idec_codelengths[i]<=c->dec_firsttablen){ - ogg_uint32_t orig=bitreverse(c->codelist[i]); - for(j=0;j<(1<<(c->dec_firsttablen-c->dec_codelengths[i]));j++) - c->dec_firsttable[orig|(j<dec_codelengths[i])]=i+1; - } - } - - /* now fill in 'unused' entries in the firsttable with hi/lo search - hints for the non-direct-hits */ - { - ogg_uint32_t mask=0xfffffffeUL<<(31-c->dec_firsttablen); - long lo=0,hi=0; - - for(i=0;idec_firsttablen); - if(c->dec_firsttable[bitreverse(word)]==0){ - while((lo+1)codelist[lo+1]<=word)lo++; - while( hi=(c->codelist[hi]&mask))hi++; - - /* we only actually have 15 bits per hint to play with here. - In order to overflow gracefully (nothing breaks, efficiency - just drops), encode as the difference from the extremes. */ - { - unsigned long loval=lo; - unsigned long hival=n-hi; - - if(loval>0x7fff)loval=0x7fff; - if(hival>0x7fff)hival=0x7fff; - c->dec_firsttable[bitreverse(word)]= - 0x80000000UL | (loval<<15) | hival; - } - } - } - } - } - } - - return(0); - err_out: - vorbis_book_clear(c); - return(-1); -} - -long vorbis_book_codeword(codebook *book,int entry){ - if(book->c) /* only use with encode; decode optimizations are - allowed to break this */ - return book->codelist[entry]; - return -1; -} - -long vorbis_book_codelen(codebook *book,int entry){ - if(book->c) /* only use with encode; decode optimizations are - allowed to break this */ - return book->c->lengthlist[entry]; - return -1; -} - -#ifdef _V_SELFTEST - -/* Unit tests of the dequantizer; this stuff will be OK - cross-platform, I simply want to be sure that special mapping cases - actually work properly; a bug could go unnoticed for a while */ - -#include - -/* cases: - - no mapping - full, explicit mapping - algorithmic mapping - - nonsequential - sequential -*/ - -static long full_quantlist1[]={0,1,2,3, 4,5,6,7, 8,3,6,1}; -static long partial_quantlist1[]={0,7,2}; - -/* no mapping */ -static_codebook test1={ - 4,16, - NULL, - 0, - 0,0,0,0, - NULL, - 0 -}; -static float *test1_result=NULL; - -/* linear, full mapping, nonsequential */ -static_codebook test2={ - 4,3, - NULL, - 2, - -533200896,1611661312,4,0, - full_quantlist1, - 0 -}; -static float test2_result[]={-3,-2,-1,0, 1,2,3,4, 5,0,3,-2}; - -/* linear, full mapping, sequential */ -static_codebook test3={ - 4,3, - NULL, - 2, - -533200896,1611661312,4,1, - full_quantlist1, - 0 -}; -static float test3_result[]={-3,-5,-6,-6, 1,3,6,10, 5,5,8,6}; - -/* linear, algorithmic mapping, nonsequential */ -static_codebook test4={ - 3,27, - NULL, - 1, - -533200896,1611661312,4,0, - partial_quantlist1, - 0 -}; -static float test4_result[]={-3,-3,-3, 4,-3,-3, -1,-3,-3, - -3, 4,-3, 4, 4,-3, -1, 4,-3, - -3,-1,-3, 4,-1,-3, -1,-1,-3, - -3,-3, 4, 4,-3, 4, -1,-3, 4, - -3, 4, 4, 4, 4, 4, -1, 4, 4, - -3,-1, 4, 4,-1, 4, -1,-1, 4, - -3,-3,-1, 4,-3,-1, -1,-3,-1, - -3, 4,-1, 4, 4,-1, -1, 4,-1, - -3,-1,-1, 4,-1,-1, -1,-1,-1}; - -/* linear, algorithmic mapping, sequential */ -static_codebook test5={ - 3,27, - NULL, - 1, - -533200896,1611661312,4,1, - partial_quantlist1, - 0 -}; -static float test5_result[]={-3,-6,-9, 4, 1,-2, -1,-4,-7, - -3, 1,-2, 4, 8, 5, -1, 3, 0, - -3,-4,-7, 4, 3, 0, -1,-2,-5, - -3,-6,-2, 4, 1, 5, -1,-4, 0, - -3, 1, 5, 4, 8,12, -1, 3, 7, - -3,-4, 0, 4, 3, 7, -1,-2, 2, - -3,-6,-7, 4, 1, 0, -1,-4,-5, - -3, 1, 0, 4, 8, 7, -1, 3, 2, - -3,-4,-5, 4, 3, 2, -1,-2,-3}; - -void run_test(static_codebook *b,float *comp){ - float *out=_book_unquantize(b,b->entries,NULL); - int i; - - if(comp){ - if(!out){ - fprintf(stderr,"_book_unquantize incorrectly returned NULL\n"); - exit(1); - } - - for(i=0;ientries*b->dim;i++) - if(fabs(out[i]-comp[i])>.0001){ - fprintf(stderr,"disagreement in unquantized and reference data:\n" - "position %d, %g != %g\n",i,out[i],comp[i]); - exit(1); - } - - }else{ - if(out){ - fprintf(stderr,"_book_unquantize returned a value array: \n" - " correct result should have been NULL\n"); - exit(1); - } - } - free(out); -} - -int main(){ - /* run the nine dequant tests, and compare to the hand-rolled results */ - fprintf(stderr,"Dequant test 1... "); - run_test(&test1,test1_result); - fprintf(stderr,"OK\nDequant test 2... "); - run_test(&test2,test2_result); - fprintf(stderr,"OK\nDequant test 3... "); - run_test(&test3,test3_result); - fprintf(stderr,"OK\nDequant test 4... "); - run_test(&test4,test4_result); - fprintf(stderr,"OK\nDequant test 5... "); - run_test(&test5,test5_result); - fprintf(stderr,"OK\n\n"); - - return(0); -} - -#endif diff --git a/src/lib/vorbis/src/smallft.c b/src/lib/vorbis/src/smallft.c deleted file mode 100644 index 4ffabab4..00000000 --- a/src/lib/vorbis/src/smallft.c +++ /dev/null @@ -1,1254 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: *unnormalized* fft transform - - ********************************************************************/ - -/* FFT implementation from OggSquish, minus cosine transforms, - * minus all but radix 2/4 case. In Vorbis we only need this - * cut-down version. - * - * To do more than just power-of-two sized vectors, see the full - * version I wrote for NetLib. - * - * Note that the packing is a little strange; rather than the FFT r/i - * packing following R_0, I_n, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, - * it follows R_0, R_1, I_1, R_2, I_2 ... R_n-1, I_n-1, I_n like the - * FORTRAN version - */ - -#include -#include -#include -#include "smallft.h" -#include "os.h" -#include "misc.h" - -static void drfti1(int n, float *wa, int *ifac){ - static int ntryh[4] = { 4,2,3,5 }; - static float tpi = 6.28318530717958648f; - float arg,argh,argld,fi; - int ntry=0,i,j=-1; - int k1, l1, l2, ib; - int ld, ii, ip, is, nq, nr; - int ido, ipm, nfm1; - int nl=n; - int nf=0; - - L101: - j++; - if (j < 4) - ntry=ntryh[j]; - else - ntry+=2; - - L104: - nq=nl/ntry; - nr=nl-ntry*nq; - if (nr!=0) goto L101; - - nf++; - ifac[nf+1]=ntry; - nl=nq; - if(ntry!=2)goto L107; - if(nf==1)goto L107; - - for (i=1;i>1; - ipp2=ip; - idp2=ido; - nbd=(ido-1)>>1; - t0=l1*ido; - t10=ip*ido; - - if(ido==1)goto L119; - for(ik=0;ikl1){ - for(j=1;j>1; - ipp2=ip; - ipph=(ip+1)>>1; - if(idol1)goto L139; - - is= -ido-1; - t1=0; - for(j=1;jn==1)return; - drftf1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); -} - -void drft_backward(drft_lookup *l,float *data){ - if (l->n==1)return; - drftb1(l->n,data,l->trigcache,l->trigcache+l->n,l->splitcache); -} - -void drft_init(drft_lookup *l,int n){ - l->n=n; - l->trigcache=_ogg_calloc(3*n,sizeof(*l->trigcache)); - l->splitcache=_ogg_calloc(32,sizeof(*l->splitcache)); - fdrffti(n, l->trigcache, l->splitcache); -} - -void drft_clear(drft_lookup *l){ - if(l){ - if(l->trigcache)_ogg_free(l->trigcache); - if(l->splitcache)_ogg_free(l->splitcache); - memset(l,0,sizeof(*l)); - } -} diff --git a/src/lib/vorbis/src/smallft.h b/src/lib/vorbis/src/smallft.h deleted file mode 100644 index 02fe8f9c..00000000 --- a/src/lib/vorbis/src/smallft.h +++ /dev/null @@ -1,33 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2007 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: fft transform - - ********************************************************************/ - -#ifndef _V_SMFT_H_ -#define _V_SMFT_H_ - -#include "vorbis/codec.h" - -typedef struct { - int n; - float *trigcache; - int *splitcache; -} drft_lookup; - -extern void drft_forward(drft_lookup *l,float *data); -extern void drft_backward(drft_lookup *l,float *data); -extern void drft_init(drft_lookup *l,int n); -extern void drft_clear(drft_lookup *l); - -#endif diff --git a/src/lib/vorbis/src/synthesis.c b/src/lib/vorbis/src/synthesis.c deleted file mode 100644 index 3e2d6812..00000000 --- a/src/lib/vorbis/src/synthesis.c +++ /dev/null @@ -1,179 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: single-block PCM synthesis - - ********************************************************************/ - -#include -#include -#include "vorbis/codec.h" -#include "codec_internal.h" -#include "registry.h" -#include "misc.h" -#include "os.h" - -int vorbis_synthesis(vorbis_block *vb,ogg_packet *op){ - vorbis_dsp_state *vd= vb ? vb->vd : 0; - private_state *b= vd ? vd->backend_state : 0; - vorbis_info *vi= vd ? vd->vi : 0; - codec_setup_info *ci= vi ? vi->codec_setup : 0; - oggpack_buffer *opb=vb ? &vb->opb : 0; - int type,mode,i; - - if (!vd || !b || !vi || !ci || !opb) { - return OV_EBADPACKET; - } - - /* first things first. Make sure decode is ready */ - _vorbis_block_ripcord(vb); - oggpack_readinit(opb,op->packet,op->bytes); - - /* Check the packet type */ - if(oggpack_read(opb,1)!=0){ - /* Oops. This is not an audio data packet */ - return(OV_ENOTAUDIO); - } - - /* read our mode and pre/post windowsize */ - mode=oggpack_read(opb,b->modebits); - if(mode==-1){ - return(OV_EBADPACKET); - } - - vb->mode=mode; - if(!ci->mode_param[mode]){ - return(OV_EBADPACKET); - } - - vb->W=ci->mode_param[mode]->blockflag; - if(vb->W){ - - /* this doesn;t get mapped through mode selection as it's used - only for window selection */ - vb->lW=oggpack_read(opb,1); - vb->nW=oggpack_read(opb,1); - if(vb->nW==-1){ - return(OV_EBADPACKET); - } - }else{ - vb->lW=0; - vb->nW=0; - } - - /* more setup */ - vb->granulepos=op->granulepos; - vb->sequence=op->packetno; - vb->eofflag=op->e_o_s; - - /* alloc pcm passback storage */ - vb->pcmend=ci->blocksizes[vb->W]; - vb->pcm=_vorbis_block_alloc(vb,sizeof(*vb->pcm)*vi->channels); - for(i=0;ichannels;i++) - vb->pcm[i]=_vorbis_block_alloc(vb,vb->pcmend*sizeof(*vb->pcm[i])); - - /* unpack_header enforces range checking */ - type=ci->map_type[ci->mode_param[mode]->mapping]; - - return(_mapping_P[type]->inverse(vb,ci->map_param[ci->mode_param[mode]-> - mapping])); -} - -/* used to track pcm position without actually performing decode. - Useful for sequential 'fast forward' */ -int vorbis_synthesis_trackonly(vorbis_block *vb,ogg_packet *op){ - vorbis_dsp_state *vd=vb->vd; - private_state *b=vd->backend_state; - vorbis_info *vi=vd->vi; - codec_setup_info *ci=vi->codec_setup; - oggpack_buffer *opb=&vb->opb; - int mode; - - /* first things first. Make sure decode is ready */ - _vorbis_block_ripcord(vb); - oggpack_readinit(opb,op->packet,op->bytes); - - /* Check the packet type */ - if(oggpack_read(opb,1)!=0){ - /* Oops. This is not an audio data packet */ - return(OV_ENOTAUDIO); - } - - /* read our mode and pre/post windowsize */ - mode=oggpack_read(opb,b->modebits); - if(mode==-1)return(OV_EBADPACKET); - - vb->mode=mode; - if(!ci->mode_param[mode]){ - return(OV_EBADPACKET); - } - - vb->W=ci->mode_param[mode]->blockflag; - if(vb->W){ - vb->lW=oggpack_read(opb,1); - vb->nW=oggpack_read(opb,1); - if(vb->nW==-1) return(OV_EBADPACKET); - }else{ - vb->lW=0; - vb->nW=0; - } - - /* more setup */ - vb->granulepos=op->granulepos; - vb->sequence=op->packetno; - vb->eofflag=op->e_o_s; - - /* no pcm */ - vb->pcmend=0; - vb->pcm=NULL; - - return(0); -} - -long vorbis_packet_blocksize(vorbis_info *vi,ogg_packet *op){ - codec_setup_info *ci=vi->codec_setup; - oggpack_buffer opb; - int mode; - - if(ci==NULL || ci->modes<=0){ - /* codec setup not properly intialized */ - return(OV_EFAULT); - } - - oggpack_readinit(&opb,op->packet,op->bytes); - - /* Check the packet type */ - if(oggpack_read(&opb,1)!=0){ - /* Oops. This is not an audio data packet */ - return(OV_ENOTAUDIO); - } - - /* read our mode and pre/post windowsize */ - mode=oggpack_read(&opb,ov_ilog(ci->modes-1)); - if(mode==-1 || !ci->mode_param[mode])return(OV_EBADPACKET); - return(ci->blocksizes[ci->mode_param[mode]->blockflag]); -} - -int vorbis_synthesis_halfrate(vorbis_info *vi,int flag){ - /* set / clear half-sample-rate mode */ - codec_setup_info *ci=vi->codec_setup; - - /* right now, our MDCT can't handle < 64 sample windows. */ - if(ci->blocksizes[0]<=64 && flag)return -1; - ci->halfrate_flag=(flag?1:0); - return 0; -} - -int vorbis_synthesis_halfrate_p(vorbis_info *vi){ - codec_setup_info *ci=vi->codec_setup; - return ci->halfrate_flag; -} diff --git a/src/lib/vorbis/src/vorbisfile.c b/src/lib/vorbis/src/vorbisfile.c deleted file mode 100644 index 9219c2f2..00000000 --- a/src/lib/vorbis/src/vorbisfile.c +++ /dev/null @@ -1,2427 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2015 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: stdio-based convenience library for opening/seeking/decoding - - ********************************************************************/ - -#include -#include -#include -#include -#include - -#include "vorbis/codec.h" - -/* we don't need or want the static callback symbols here */ -#define OV_EXCLUDE_STATIC_CALLBACKS -#include "vorbis/vorbisfile.h" - -#include "os.h" -#include "misc.h" - -/* A 'chained bitstream' is a Vorbis bitstream that contains more than - one logical bitstream arranged end to end (the only form of Ogg - multiplexing allowed in a Vorbis bitstream; grouping [parallel - multiplexing] is not allowed in Vorbis) */ - -/* A Vorbis file can be played beginning to end (streamed) without - worrying ahead of time about chaining (see decoder_example.c). If - we have the whole file, however, and want random access - (seeking/scrubbing) or desire to know the total length/time of a - file, we need to account for the possibility of chaining. */ - -/* We can handle things a number of ways; we can determine the entire - bitstream structure right off the bat, or find pieces on demand. - This example determines and caches structure for the entire - bitstream, but builds a virtual decoder on the fly when moving - between links in the chain. */ - -/* There are also different ways to implement seeking. Enough - information exists in an Ogg bitstream to seek to - sample-granularity positions in the output. Or, one can seek by - picking some portion of the stream roughly in the desired area if - we only want coarse navigation through the stream. */ - -/************************************************************************* - * Many, many internal helpers. The intention is not to be confusing; - * rampant duplication and monolithic function implementation would be - * harder to understand anyway. The high level functions are last. Begin - * grokking near the end of the file */ - -/* read a little more data from the file/pipe into the ogg_sync framer -*/ -#define CHUNKSIZE 65536 /* greater-than-page-size granularity seeking */ -#define READSIZE 2048 /* a smaller read size is needed for low-rate streaming. */ - -static long _get_data(OggVorbis_File *vf){ - errno=0; - if(!(vf->callbacks.read_func))return(-1); - if(vf->datasource){ - char *buffer=ogg_sync_buffer(&vf->oy,READSIZE); - long bytes=(vf->callbacks.read_func)(buffer,1,READSIZE,vf->datasource); - if(bytes>0)ogg_sync_wrote(&vf->oy,bytes); - if(bytes==0 && errno)return(-1); - return(bytes); - }else - return(0); -} - -/* save a tiny smidge of verbosity to make the code more readable */ -static int _seek_helper(OggVorbis_File *vf,ogg_int64_t offset){ - if(vf->datasource){ - /* only seek if the file position isn't already there */ - if(vf->offset != offset){ - if(!(vf->callbacks.seek_func)|| - (vf->callbacks.seek_func)(vf->datasource, offset, SEEK_SET) == -1) - return OV_EREAD; - vf->offset=offset; - ogg_sync_reset(&vf->oy); - } - }else{ - /* shouldn't happen unless someone writes a broken callback */ - return OV_EFAULT; - } - return 0; -} - -/* The read/seek functions track absolute position within the stream */ - -/* from the head of the stream, get the next page. boundary specifies - if the function is allowed to fetch more data from the stream (and - how much) or only use internally buffered data. - - boundary: -1) unbounded search - 0) read no additional data; use cached only - n) search for a new page beginning for n bytes - - return: <0) did not find a page (OV_FALSE, OV_EOF, OV_EREAD) - n) found a page at absolute offset n */ - -static ogg_int64_t _get_next_page(OggVorbis_File *vf,ogg_page *og, - ogg_int64_t boundary){ - if(boundary>0)boundary+=vf->offset; - while(1){ - long more; - - if(boundary>0 && vf->offset>=boundary)return(OV_FALSE); - more=ogg_sync_pageseek(&vf->oy,og); - - if(more<0){ - /* skipped n bytes */ - vf->offset-=more; - }else{ - if(more==0){ - /* send more paramedics */ - if(!boundary)return(OV_FALSE); - { - long ret=_get_data(vf); - if(ret==0)return(OV_EOF); - if(ret<0)return(OV_EREAD); - } - }else{ - /* got a page. Return the offset at the page beginning, - advance the internal offset past the page end */ - ogg_int64_t ret=vf->offset; - vf->offset+=more; - return(ret); - - } - } - } -} - -/* find the latest page beginning before the passed in position. Much - dirtier than the above as Ogg doesn't have any backward search - linkage. no 'readp' as it will certainly have to read. */ -/* returns offset or OV_EREAD, OV_FAULT */ -static ogg_int64_t _get_prev_page(OggVorbis_File *vf,ogg_int64_t begin,ogg_page *og){ - ogg_int64_t end = begin; - ogg_int64_t ret; - ogg_int64_t offset=-1; - - while(offset==-1){ - begin-=CHUNKSIZE; - if(begin<0) - begin=0; - - ret=_seek_helper(vf,begin); - if(ret)return(ret); - - while(vf->offsetoffset); - if(ret==OV_EREAD)return(OV_EREAD); - if(ret<0){ - break; - }else{ - offset=ret; - } - } - } - - /* In a fully compliant, non-multiplexed stream, we'll still be - holding the last page. In multiplexed (or noncompliant streams), - we will probably have to re-read the last page we saw */ - if(og->header_len==0){ - ret=_seek_helper(vf,offset); - if(ret)return(ret); - - ret=_get_next_page(vf,og,CHUNKSIZE); - if(ret<0) - /* this shouldn't be possible */ - return(OV_EFAULT); - } - - return(offset); -} - -static void _add_serialno(ogg_page *og,long **serialno_list, int *n){ - long s = ogg_page_serialno(og); - (*n)++; - - if(*serialno_list){ - *serialno_list = _ogg_realloc(*serialno_list, sizeof(**serialno_list)*(*n)); - }else{ - *serialno_list = _ogg_malloc(sizeof(**serialno_list)); - } - - (*serialno_list)[(*n)-1] = s; -} - -/* returns nonzero if found */ -static int _lookup_serialno(long s, long *serialno_list, int n){ - if(serialno_list){ - while(n--){ - if(*serialno_list == s) return 1; - serialno_list++; - } - } - return 0; -} - -static int _lookup_page_serialno(ogg_page *og, long *serialno_list, int n){ - long s = ogg_page_serialno(og); - return _lookup_serialno(s,serialno_list,n); -} - -/* performs the same search as _get_prev_page, but prefers pages of - the specified serial number. If a page of the specified serialno is - spotted during the seek-back-and-read-forward, it will return the - info of last page of the matching serial number instead of the very - last page. If no page of the specified serialno is seen, it will - return the info of last page and alter *serialno. */ -static ogg_int64_t _get_prev_page_serial(OggVorbis_File *vf, ogg_int64_t begin, - long *serial_list, int serial_n, - int *serialno, ogg_int64_t *granpos){ - ogg_page og; - ogg_int64_t end=begin; - ogg_int64_t ret; - - ogg_int64_t prefoffset=-1; - ogg_int64_t offset=-1; - ogg_int64_t ret_serialno=-1; - ogg_int64_t ret_gran=-1; - - while(offset==-1){ - begin-=CHUNKSIZE; - if(begin<0) - begin=0; - - ret=_seek_helper(vf,begin); - if(ret)return(ret); - - while(vf->offsetoffset); - if(ret==OV_EREAD)return(OV_EREAD); - if(ret<0){ - break; - }else{ - ret_serialno=ogg_page_serialno(&og); - ret_gran=ogg_page_granulepos(&og); - offset=ret; - - if(ret_serialno == *serialno){ - prefoffset=ret; - *granpos=ret_gran; - } - - if(!_lookup_serialno(ret_serialno,serial_list,serial_n)){ - /* we fell off the end of the link, which means we seeked - back too far and shouldn't have been looking in that link - to begin with. If we found the preferred serial number, - forget that we saw it. */ - prefoffset=-1; - } - } - } - /*We started from the beginning of the stream and found nothing. - This should be impossible unless the contents of the stream changed out - from under us after we read from it.*/ - if(!begin&&vf->offset<0)return OV_EBADLINK; - } - - /* we're not interested in the page... just the serialno and granpos. */ - if(prefoffset>=0)return(prefoffset); - - *serialno = ret_serialno; - *granpos = ret_gran; - return(offset); - -} - -/* uses the local ogg_stream storage in vf; this is important for - non-streaming input sources */ -static int _fetch_headers(OggVorbis_File *vf,vorbis_info *vi,vorbis_comment *vc, - long **serialno_list, int *serialno_n, - ogg_page *og_ptr){ - ogg_page og; - ogg_packet op; - int i,ret; - int allbos=0; - - if(!og_ptr){ - ogg_int64_t llret=_get_next_page(vf,&og,CHUNKSIZE); - if(llret==OV_EREAD)return(OV_EREAD); - if(llret<0)return(OV_ENOTVORBIS); - og_ptr=&og; - } - - vorbis_info_init(vi); - vorbis_comment_init(vc); - vf->ready_state=OPENED; - - /* extract the serialnos of all BOS pages + the first set of vorbis - headers we see in the link */ - - while(ogg_page_bos(og_ptr)){ - if(serialno_list){ - if(_lookup_page_serialno(og_ptr,*serialno_list,*serialno_n)){ - /* a dupe serialnumber in an initial header packet set == invalid stream */ - if(*serialno_list)_ogg_free(*serialno_list); - *serialno_list=0; - *serialno_n=0; - ret=OV_EBADHEADER; - goto bail_header; - } - - _add_serialno(og_ptr,serialno_list,serialno_n); - } - - if(vf->ready_stateos,ogg_page_serialno(og_ptr)); - ogg_stream_pagein(&vf->os,og_ptr); - - if(ogg_stream_packetout(&vf->os,&op) > 0 && - vorbis_synthesis_idheader(&op)){ - /* vorbis header; continue setup */ - vf->ready_state=STREAMSET; - if((ret=vorbis_synthesis_headerin(vi,vc,&op))){ - ret=OV_EBADHEADER; - goto bail_header; - } - } - } - - /* get next page */ - { - ogg_int64_t llret=_get_next_page(vf,og_ptr,CHUNKSIZE); - if(llret==OV_EREAD){ - ret=OV_EREAD; - goto bail_header; - } - if(llret<0){ - ret=OV_ENOTVORBIS; - goto bail_header; - } - - /* if this page also belongs to our vorbis stream, submit it and break */ - if(vf->ready_state==STREAMSET && - vf->os.serialno == ogg_page_serialno(og_ptr)){ - ogg_stream_pagein(&vf->os,og_ptr); - break; - } - } - } - - if(vf->ready_state!=STREAMSET){ - ret = OV_ENOTVORBIS; - goto bail_header; - } - - while(1){ - - i=0; - while(i<2){ /* get a page loop */ - - while(i<2){ /* get a packet loop */ - - int result=ogg_stream_packetout(&vf->os,&op); - if(result==0)break; - if(result==-1){ - ret=OV_EBADHEADER; - goto bail_header; - } - - if((ret=vorbis_synthesis_headerin(vi,vc,&op))) - goto bail_header; - - i++; - } - - while(i<2){ - if(_get_next_page(vf,og_ptr,CHUNKSIZE)<0){ - ret=OV_EBADHEADER; - goto bail_header; - } - - /* if this page belongs to the correct stream, go parse it */ - if(vf->os.serialno == ogg_page_serialno(og_ptr)){ - ogg_stream_pagein(&vf->os,og_ptr); - break; - } - - /* if we never see the final vorbis headers before the link - ends, abort */ - if(ogg_page_bos(og_ptr)){ - if(allbos){ - ret = OV_EBADHEADER; - goto bail_header; - }else - allbos=1; - } - - /* otherwise, keep looking */ - } - } - - return 0; - } - - bail_header: - vorbis_info_clear(vi); - vorbis_comment_clear(vc); - vf->ready_state=OPENED; - - return ret; -} - -/* Starting from current cursor position, get initial PCM offset of - next page. Consumes the page in the process without decoding - audio, however this is only called during stream parsing upon - seekable open. */ -static ogg_int64_t _initial_pcmoffset(OggVorbis_File *vf, vorbis_info *vi){ - ogg_page og; - ogg_int64_t accumulated=0; - long lastblock=-1; - int result; - int serialno = vf->os.serialno; - - while(1){ - ogg_packet op; - if(_get_next_page(vf,&og,-1)<0) - break; /* should not be possible unless the file is truncated/mangled */ - - if(ogg_page_bos(&og)) break; - if(ogg_page_serialno(&og)!=serialno) continue; - - /* count blocksizes of all frames in the page */ - ogg_stream_pagein(&vf->os,&og); - while((result=ogg_stream_packetout(&vf->os,&op))){ - if(result>0){ /* ignore holes */ - long thisblock=vorbis_packet_blocksize(vi,&op); - if(thisblock>=0){ - if(lastblock!=-1) - accumulated+=(lastblock+thisblock)>>2; - lastblock=thisblock; - } - } - } - - if(ogg_page_granulepos(&og)!=-1){ - /* pcm offset of last packet on the first audio page */ - accumulated= ogg_page_granulepos(&og)-accumulated; - break; - } - } - - /* less than zero? Either a corrupt file or a stream with samples - trimmed off the beginning, a normal occurrence; in both cases set - the offset to zero */ - if(accumulated<0)accumulated=0; - - return accumulated; -} - -/* finds each bitstream link one at a time using a bisection search - (has to begin by knowing the offset of the lb's initial page). - Recurses for each link so it can alloc the link storage after - finding them all, then unroll and fill the cache at the same time */ -static int _bisect_forward_serialno(OggVorbis_File *vf, - ogg_int64_t begin, - ogg_int64_t searched, - ogg_int64_t end, - ogg_int64_t endgran, - int endserial, - long *currentno_list, - int currentnos, - long m){ - ogg_int64_t pcmoffset; - ogg_int64_t dataoffset=searched; - ogg_int64_t endsearched=end; - ogg_int64_t next=end; - ogg_int64_t searchgran=-1; - ogg_page og; - ogg_int64_t ret,last; - int serialno = vf->os.serialno; - - /* invariants: - we have the headers and serialnos for the link beginning at 'begin' - we have the offset and granpos of the last page in the file (potentially - not a page we care about) - */ - - /* Is the last page in our list of current serialnumbers? */ - if(_lookup_serialno(endserial,currentno_list,currentnos)){ - - /* last page is in the starting serialno list, so we've bisected - down to (or just started with) a single link. Now we need to - find the last vorbis page belonging to the first vorbis stream - for this link. */ - searched = end; - while(endserial != serialno){ - endserial = serialno; - searched=_get_prev_page_serial(vf,searched,currentno_list,currentnos,&endserial,&endgran); - } - - vf->links=m+1; - if(vf->offsets)_ogg_free(vf->offsets); - if(vf->serialnos)_ogg_free(vf->serialnos); - if(vf->dataoffsets)_ogg_free(vf->dataoffsets); - - vf->offsets=_ogg_malloc((vf->links+1)*sizeof(*vf->offsets)); - vf->vi=_ogg_realloc(vf->vi,vf->links*sizeof(*vf->vi)); - vf->vc=_ogg_realloc(vf->vc,vf->links*sizeof(*vf->vc)); - vf->serialnos=_ogg_malloc(vf->links*sizeof(*vf->serialnos)); - vf->dataoffsets=_ogg_malloc(vf->links*sizeof(*vf->dataoffsets)); - vf->pcmlengths=_ogg_malloc(vf->links*2*sizeof(*vf->pcmlengths)); - - vf->offsets[m+1]=end; - vf->offsets[m]=begin; - vf->pcmlengths[m*2+1]=(endgran<0?0:endgran); - - }else{ - - /* last page is not in the starting stream's serial number list, - so we have multiple links. Find where the stream that begins - our bisection ends. */ - - long *next_serialno_list=NULL; - int next_serialnos=0; - vorbis_info vi; - vorbis_comment vc; - int testserial = serialno+1; - - /* the below guards against garbage seperating the last and - first pages of two links. */ - while(searched=0)next=last; - }else{ - searched=vf->offset; - } - } - - /* Bisection point found */ - /* for the time being, fetch end PCM offset the simple way */ - searched = next; - while(testserial != serialno){ - testserial = serialno; - searched = _get_prev_page_serial(vf,searched,currentno_list,currentnos,&testserial,&searchgran); - } - - ret=_seek_helper(vf,next); - if(ret)return(ret); - - ret=_fetch_headers(vf,&vi,&vc,&next_serialno_list,&next_serialnos,NULL); - if(ret)return(ret); - serialno = vf->os.serialno; - dataoffset = vf->offset; - - /* this will consume a page, however the next bisection always - starts with a raw seek */ - pcmoffset = _initial_pcmoffset(vf,&vi); - - ret=_bisect_forward_serialno(vf,next,vf->offset,end,endgran,endserial, - next_serialno_list,next_serialnos,m+1); - if(ret)return(ret); - - if(next_serialno_list)_ogg_free(next_serialno_list); - - vf->offsets[m+1]=next; - vf->serialnos[m+1]=serialno; - vf->dataoffsets[m+1]=dataoffset; - - vf->vi[m+1]=vi; - vf->vc[m+1]=vc; - - vf->pcmlengths[m*2+1]=searchgran; - vf->pcmlengths[m*2+2]=pcmoffset; - vf->pcmlengths[m*2+3]-=pcmoffset; - if(vf->pcmlengths[m*2+3]<0)vf->pcmlengths[m*2+3]=0; - } - return(0); -} - -static int _make_decode_ready(OggVorbis_File *vf){ - if(vf->ready_state>STREAMSET)return 0; - if(vf->ready_stateseekable){ - if(vorbis_synthesis_init(&vf->vd,vf->vi+vf->current_link)) - return OV_EBADLINK; - }else{ - if(vorbis_synthesis_init(&vf->vd,vf->vi)) - return OV_EBADLINK; - } - vorbis_block_init(&vf->vd,&vf->vb); - vf->ready_state=INITSET; - vf->bittrack=0.f; - vf->samptrack=0.f; - return 0; -} - -static int _open_seekable2(OggVorbis_File *vf){ - ogg_int64_t dataoffset=vf->dataoffsets[0],end,endgran=-1; - int endserial=vf->os.serialno; - int serialno=vf->os.serialno; - - /* we're partially open and have a first link header state in - storage in vf */ - - /* fetch initial PCM offset */ - ogg_int64_t pcmoffset = _initial_pcmoffset(vf,vf->vi); - - /* we can seek, so set out learning all about this file */ - if(vf->callbacks.seek_func && vf->callbacks.tell_func){ - (vf->callbacks.seek_func)(vf->datasource,0,SEEK_END); - vf->offset=vf->end=(vf->callbacks.tell_func)(vf->datasource); - }else{ - vf->offset=vf->end=-1; - } - - /* If seek_func is implemented, tell_func must also be implemented */ - if(vf->end==-1) return(OV_EINVAL); - - /* Get the offset of the last page of the physical bitstream, or, if - we're lucky the last vorbis page of this link as most OggVorbis - files will contain a single logical bitstream */ - end=_get_prev_page_serial(vf,vf->end,vf->serialnos+2,vf->serialnos[1],&endserial,&endgran); - if(end<0)return(end); - - /* now determine bitstream structure recursively */ - if(_bisect_forward_serialno(vf,0,dataoffset,end,endgran,endserial, - vf->serialnos+2,vf->serialnos[1],0)<0)return(OV_EREAD); - - vf->offsets[0]=0; - vf->serialnos[0]=serialno; - vf->dataoffsets[0]=dataoffset; - vf->pcmlengths[0]=pcmoffset; - vf->pcmlengths[1]-=pcmoffset; - if(vf->pcmlengths[1]<0)vf->pcmlengths[1]=0; - - return(ov_raw_seek(vf,dataoffset)); -} - -/* clear out the current logical bitstream decoder */ -static void _decode_clear(OggVorbis_File *vf){ - vorbis_dsp_clear(&vf->vd); - vorbis_block_clear(&vf->vb); - vf->ready_state=OPENED; -} - -/* fetch and process a packet. Handles the case where we're at a - bitstream boundary and dumps the decoding machine. If the decoding - machine is unloaded, it loads it. It also keeps pcm_offset up to - date (seek and read both use this. seek uses a special hack with - readp). - - return: <0) error, OV_HOLE (lost packet) or OV_EOF - 0) need more data (only if readp==0) - 1) got a packet -*/ - -static int _fetch_and_process_packet(OggVorbis_File *vf, - ogg_packet *op_in, - int readp, - int spanp){ - ogg_page og; - - /* handle one packet. Try to fetch it from current stream state */ - /* extract packets from page */ - while(1){ - - if(vf->ready_state==STREAMSET){ - int ret=_make_decode_ready(vf); - if(ret<0)return ret; - } - - /* process a packet if we can. */ - - if(vf->ready_state==INITSET){ - int hs=vorbis_synthesis_halfrate_p(vf->vi); - - while(1) { - ogg_packet op; - ogg_packet *op_ptr=(op_in?op_in:&op); - int result=ogg_stream_packetout(&vf->os,op_ptr); - ogg_int64_t granulepos; - - op_in=NULL; - if(result==-1)return(OV_HOLE); /* hole in the data. */ - if(result>0){ - /* got a packet. process it */ - granulepos=op_ptr->granulepos; - if(!vorbis_synthesis(&vf->vb,op_ptr)){ /* lazy check for lazy - header handling. The - header packets aren't - audio, so if/when we - submit them, - vorbis_synthesis will - reject them */ - - /* suck in the synthesis data and track bitrate */ - { - int oldsamples=vorbis_synthesis_pcmout(&vf->vd,NULL); - /* for proper use of libvorbis within libvorbisfile, - oldsamples will always be zero. */ - if(oldsamples)return(OV_EFAULT); - - vorbis_synthesis_blockin(&vf->vd,&vf->vb); - vf->samptrack+=(vorbis_synthesis_pcmout(&vf->vd,NULL)<bittrack+=op_ptr->bytes*8; - } - - /* update the pcm offset. */ - if(granulepos!=-1 && !op_ptr->e_o_s){ - int link=(vf->seekable?vf->current_link:0); - int i,samples; - - /* this packet has a pcm_offset on it (the last packet - completed on a page carries the offset) After processing - (above), we know the pcm position of the *last* sample - ready to be returned. Find the offset of the *first* - - As an aside, this trick is inaccurate if we begin - reading anew right at the last page; the end-of-stream - granulepos declares the last frame in the stream, and the - last packet of the last page may be a partial frame. - So, we need a previous granulepos from an in-sequence page - to have a reference point. Thus the !op_ptr->e_o_s clause - above */ - - if(vf->seekable && link>0) - granulepos-=vf->pcmlengths[link*2]; - if(granulepos<0)granulepos=0; /* actually, this - shouldn't be possible - here unless the stream - is very broken */ - - samples=(vorbis_synthesis_pcmout(&vf->vd,NULL)<pcmlengths[i*2+1]; - vf->pcm_offset=granulepos; - } - return(1); - } - } - else - break; - } - } - - if(vf->ready_state>=OPENED){ - ogg_int64_t ret; - - while(1){ - /* the loop is not strictly necessary, but there's no sense in - doing the extra checks of the larger loop for the common - case in a multiplexed bistream where the page is simply - part of a different logical bitstream; keep reading until - we get one with the correct serialno */ - - if(!readp)return(0); - if((ret=_get_next_page(vf,&og,-1))<0){ - return(OV_EOF); /* eof. leave unitialized */ - } - - /* bitrate tracking; add the header's bytes here, the body bytes - are done by packet above */ - vf->bittrack+=og.header_len*8; - - if(vf->ready_state==INITSET){ - if(vf->current_serialno!=ogg_page_serialno(&og)){ - - /* two possibilities: - 1) our decoding just traversed a bitstream boundary - 2) another stream is multiplexed into this logical section */ - - if(ogg_page_bos(&og)){ - /* boundary case */ - if(!spanp) - return(OV_EOF); - - _decode_clear(vf); - - if(!vf->seekable){ - vorbis_info_clear(vf->vi); - vorbis_comment_clear(vf->vc); - } - break; - - }else - continue; /* possibility #2 */ - } - } - - break; - } - } - - /* Do we need to load a new machine before submitting the page? */ - /* This is different in the seekable and non-seekable cases. - - In the seekable case, we already have all the header - information loaded and cached; we just initialize the machine - with it and continue on our merry way. - - In the non-seekable (streaming) case, we'll only be at a - boundary if we just left the previous logical bitstream and - we're now nominally at the header of the next bitstream - */ - - if(vf->ready_state!=INITSET){ - int link; - - if(vf->ready_stateseekable){ - long serialno = ogg_page_serialno(&og); - - /* match the serialno to bitstream section. We use this rather than - offset positions to avoid problems near logical bitstream - boundaries */ - - for(link=0;linklinks;link++) - if(vf->serialnos[link]==serialno)break; - - if(link==vf->links) continue; /* not the desired Vorbis - bitstream section; keep - trying */ - - vf->current_serialno=serialno; - vf->current_link=link; - - ogg_stream_reset_serialno(&vf->os,vf->current_serialno); - vf->ready_state=STREAMSET; - - }else{ - /* we're streaming */ - /* fetch the three header packets, build the info struct */ - - int ret=_fetch_headers(vf,vf->vi,vf->vc,NULL,NULL,&og); - if(ret)return(ret); - vf->current_serialno=vf->os.serialno; - vf->current_link++; - link=0; - } - } - } - - /* the buffered page is the data we want, and we're ready for it; - add it to the stream state */ - ogg_stream_pagein(&vf->os,&og); - - } -} - -/* if, eg, 64 bit stdio is configured by default, this will build with - fseek64 */ -static int _fseek64_wrap(FILE *f,ogg_int64_t off,int whence){ - if(f==NULL)return(-1); - return fseek(f,off,whence); -} - -static int _ov_open1(void *f,OggVorbis_File *vf,const char *initial, - long ibytes, ov_callbacks callbacks){ - int offsettest=((f && callbacks.seek_func)?callbacks.seek_func(f,0,SEEK_CUR):-1); - long *serialno_list=NULL; - int serialno_list_size=0; - int ret; - - memset(vf,0,sizeof(*vf)); - vf->datasource=f; - vf->callbacks = callbacks; - - /* init the framing state */ - ogg_sync_init(&vf->oy); - - /* perhaps some data was previously read into a buffer for testing - against other stream types. Allow initialization from this - previously read data (especially as we may be reading from a - non-seekable stream) */ - if(initial){ - char *buffer=ogg_sync_buffer(&vf->oy,ibytes); - memcpy(buffer,initial,ibytes); - ogg_sync_wrote(&vf->oy,ibytes); - } - - /* can we seek? Stevens suggests the seek test was portable */ - if(offsettest!=-1)vf->seekable=1; - - /* No seeking yet; Set up a 'single' (current) logical bitstream - entry for partial open */ - vf->links=1; - vf->vi=_ogg_calloc(vf->links,sizeof(*vf->vi)); - vf->vc=_ogg_calloc(vf->links,sizeof(*vf->vc)); - ogg_stream_init(&vf->os,-1); /* fill in the serialno later */ - - /* Fetch all BOS pages, store the vorbis header and all seen serial - numbers, load subsequent vorbis setup headers */ - if((ret=_fetch_headers(vf,vf->vi,vf->vc,&serialno_list,&serialno_list_size,NULL))<0){ - vf->datasource=NULL; - ov_clear(vf); - }else{ - /* serial number list for first link needs to be held somewhere - for second stage of seekable stream open; this saves having to - seek/reread first link's serialnumber data then. */ - vf->serialnos=_ogg_calloc(serialno_list_size+2,sizeof(*vf->serialnos)); - vf->serialnos[0]=vf->current_serialno=vf->os.serialno; - vf->serialnos[1]=serialno_list_size; - memcpy(vf->serialnos+2,serialno_list,serialno_list_size*sizeof(*vf->serialnos)); - - vf->offsets=_ogg_calloc(1,sizeof(*vf->offsets)); - vf->dataoffsets=_ogg_calloc(1,sizeof(*vf->dataoffsets)); - vf->offsets[0]=0; - vf->dataoffsets[0]=vf->offset; - - vf->ready_state=PARTOPEN; - } - if(serialno_list)_ogg_free(serialno_list); - return(ret); -} - -static int _ov_open2(OggVorbis_File *vf){ - if(vf->ready_state != PARTOPEN) return OV_EINVAL; - vf->ready_state=OPENED; - if(vf->seekable){ - int ret=_open_seekable2(vf); - if(ret){ - vf->datasource=NULL; - ov_clear(vf); - } - return(ret); - }else - vf->ready_state=STREAMSET; - - return 0; -} - - -/* clear out the OggVorbis_File struct */ -int ov_clear(OggVorbis_File *vf){ - if(vf){ - vorbis_block_clear(&vf->vb); - vorbis_dsp_clear(&vf->vd); - ogg_stream_clear(&vf->os); - - if(vf->vi && vf->links){ - int i; - for(i=0;ilinks;i++){ - vorbis_info_clear(vf->vi+i); - vorbis_comment_clear(vf->vc+i); - } - _ogg_free(vf->vi); - _ogg_free(vf->vc); - } - if(vf->dataoffsets)_ogg_free(vf->dataoffsets); - if(vf->pcmlengths)_ogg_free(vf->pcmlengths); - if(vf->serialnos)_ogg_free(vf->serialnos); - if(vf->offsets)_ogg_free(vf->offsets); - ogg_sync_clear(&vf->oy); - if(vf->datasource && vf->callbacks.close_func) - (vf->callbacks.close_func)(vf->datasource); - memset(vf,0,sizeof(*vf)); - } -#ifdef DEBUG_LEAKS - _VDBG_dump(); -#endif - return(0); -} - -/* inspects the OggVorbis file and finds/documents all the logical - bitstreams contained in it. Tries to be tolerant of logical - bitstream sections that are truncated/woogie. - - return: -1) error - 0) OK -*/ - -int ov_open_callbacks(void *f,OggVorbis_File *vf, - const char *initial,long ibytes,ov_callbacks callbacks){ - int ret=_ov_open1(f,vf,initial,ibytes,callbacks); - if(ret)return ret; - return _ov_open2(vf); -} - -int ov_open(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ - ov_callbacks callbacks = { - (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, - (int (*)(void *)) fclose, - (long (*)(void *)) ftell - }; - - return ov_open_callbacks((void *)f, vf, initial, ibytes, callbacks); -} - -int ov_fopen(const char *path,OggVorbis_File *vf){ - int ret; - FILE *f = fopen(path,"rb"); - if(!f) return -1; - - ret = ov_open(f,vf,NULL,0); - if(ret) fclose(f); - return ret; -} - - -/* cheap hack for game usage where downsampling is desirable; there's - no need for SRC as we can just do it cheaply in libvorbis. */ - -int ov_halfrate(OggVorbis_File *vf,int flag){ - int i; - if(vf->vi==NULL)return OV_EINVAL; - if(vf->ready_state>STREAMSET){ - /* clear out stream state; dumping the decode machine is needed to - reinit the MDCT lookups. */ - vorbis_dsp_clear(&vf->vd); - vorbis_block_clear(&vf->vb); - vf->ready_state=STREAMSET; - if(vf->pcm_offset>=0){ - ogg_int64_t pos=vf->pcm_offset; - vf->pcm_offset=-1; /* make sure the pos is dumped if unseekable */ - ov_pcm_seek(vf,pos); - } - } - - for(i=0;ilinks;i++){ - if(vorbis_synthesis_halfrate(vf->vi+i,flag)){ - if(flag) ov_halfrate(vf,0); - return OV_EINVAL; - } - } - return 0; -} - -int ov_halfrate_p(OggVorbis_File *vf){ - if(vf->vi==NULL)return OV_EINVAL; - return vorbis_synthesis_halfrate_p(vf->vi); -} - -/* Only partially open the vorbis file; test for Vorbisness, and load - the headers for the first chain. Do not seek (although test for - seekability). Use ov_test_open to finish opening the file, else - ov_clear to close/free it. Same return codes as open. - - Note that vorbisfile does _not_ take ownership of the file if the - call fails; the calling applicaiton is responsible for closing the file - if this call returns an error. */ - -int ov_test_callbacks(void *f,OggVorbis_File *vf, - const char *initial,long ibytes,ov_callbacks callbacks) -{ - return _ov_open1(f,vf,initial,ibytes,callbacks); -} - -int ov_test(FILE *f,OggVorbis_File *vf,const char *initial,long ibytes){ - ov_callbacks callbacks = { - (size_t (*)(void *, size_t, size_t, void *)) fread, - (int (*)(void *, ogg_int64_t, int)) _fseek64_wrap, - (int (*)(void *)) fclose, - (long (*)(void *)) ftell - }; - - return ov_test_callbacks((void *)f, vf, initial, ibytes, callbacks); -} - -int ov_test_open(OggVorbis_File *vf){ - if(vf->ready_state!=PARTOPEN)return(OV_EINVAL); - return _ov_open2(vf); -} - -/* How many logical bitstreams in this physical bitstream? */ -long ov_streams(OggVorbis_File *vf){ - return vf->links; -} - -/* Is the FILE * associated with vf seekable? */ -long ov_seekable(OggVorbis_File *vf){ - return vf->seekable; -} - -/* returns the bitrate for a given logical bitstream or the entire - physical bitstream. If the file is open for random access, it will - find the *actual* average bitrate. If the file is streaming, it - returns the nominal bitrate (if set) else the average of the - upper/lower bounds (if set) else -1 (unset). - - If you want the actual bitrate field settings, get them from the - vorbis_info structs */ - -long ov_bitrate(OggVorbis_File *vf,int i){ - if(vf->ready_state=vf->links)return(OV_EINVAL); - if(!vf->seekable && i!=0)return(ov_bitrate(vf,0)); - if(i<0){ - ogg_int64_t bits=0; - int i; - float br; - for(i=0;ilinks;i++) - bits+=(vf->offsets[i+1]-vf->dataoffsets[i])*8; - /* This once read: return(rint(bits/ov_time_total(vf,-1))); - * gcc 3.x on x86 miscompiled this at optimisation level 2 and above, - * so this is slightly transformed to make it work. - */ - br = bits/ov_time_total(vf,-1); - return(rint(br)); - }else{ - if(vf->seekable){ - /* return the actual bitrate */ - return(rint((vf->offsets[i+1]-vf->dataoffsets[i])*8/ov_time_total(vf,i))); - }else{ - /* return nominal if set */ - if(vf->vi[i].bitrate_nominal>0){ - return vf->vi[i].bitrate_nominal; - }else{ - if(vf->vi[i].bitrate_upper>0){ - if(vf->vi[i].bitrate_lower>0){ - return (vf->vi[i].bitrate_upper+vf->vi[i].bitrate_lower)/2; - }else{ - return vf->vi[i].bitrate_upper; - } - } - return(OV_FALSE); - } - } - } -} - -/* returns the actual bitrate since last call. returns -1 if no - additional data to offer since last call (or at beginning of stream), - EINVAL if stream is only partially open -*/ -long ov_bitrate_instant(OggVorbis_File *vf){ - int link=(vf->seekable?vf->current_link:0); - long ret; - if(vf->ready_statesamptrack==0)return(OV_FALSE); - ret=vf->bittrack/vf->samptrack*vf->vi[link].rate+.5; - vf->bittrack=0.f; - vf->samptrack=0.f; - return(ret); -} - -/* Guess */ -long ov_serialnumber(OggVorbis_File *vf,int i){ - if(i>=vf->links)return(ov_serialnumber(vf,vf->links-1)); - if(!vf->seekable && i>=0)return(ov_serialnumber(vf,-1)); - if(i<0){ - return(vf->current_serialno); - }else{ - return(vf->serialnos[i]); - } -} - -/* returns: total raw (compressed) length of content if i==-1 - raw (compressed) length of that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the length) - or if stream is only partially open -*/ -ogg_int64_t ov_raw_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); - if(i<0){ - ogg_int64_t acc=0; - int i; - for(i=0;ilinks;i++) - acc+=ov_raw_total(vf,i); - return(acc); - }else{ - return(vf->offsets[i+1]-vf->offsets[i]); - } -} - -/* returns: total PCM length (samples) of content if i==-1 PCM length - (samples) of that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the - length) or only partially open -*/ -ogg_int64_t ov_pcm_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); - if(i<0){ - ogg_int64_t acc=0; - int i; - for(i=0;ilinks;i++) - acc+=ov_pcm_total(vf,i); - return(acc); - }else{ - return(vf->pcmlengths[i*2+1]); - } -} - -/* returns: total seconds of content if i==-1 - seconds in that logical bitstream for i==0 to n - OV_EINVAL if the stream is not seekable (we can't know the - length) or only partially open -*/ -double ov_time_total(OggVorbis_File *vf,int i){ - if(vf->ready_stateseekable || i>=vf->links)return(OV_EINVAL); - if(i<0){ - double acc=0; - int i; - for(i=0;ilinks;i++) - acc+=ov_time_total(vf,i); - return(acc); - }else{ - return((double)(vf->pcmlengths[i*2+1])/vf->vi[i].rate); - } -} - -/* seek to an offset relative to the *compressed* data. This also - scans packets to update the PCM cursor. It will cross a logical - bitstream boundary, but only if it can't get any packets out of the - tail of the bitstream we seek to (so no surprises). - - returns zero on success, nonzero on failure */ - -int ov_raw_seek(OggVorbis_File *vf,ogg_int64_t pos){ - ogg_stream_state work_os; - - if(vf->ready_stateseekable) - return(OV_ENOSEEK); /* don't dump machine if we can't seek */ - - if(pos<0 || pos>vf->end)return(OV_EINVAL); - - /* is the seek position outside our current link [if any]? */ - if(vf->ready_state>=STREAMSET){ - if(posoffsets[vf->current_link] || pos>=vf->offsets[vf->current_link+1]) - _decode_clear(vf); /* clear out stream state */ - } - - /* don't yet clear out decoding machine (if it's initialized), in - the case we're in the same link. Restart the decode lapping, and - let _fetch_and_process_packet deal with a potential bitstream - boundary */ - vf->pcm_offset=-1; - ogg_stream_reset_serialno(&vf->os, - vf->current_serialno); /* must set serialno */ - vorbis_synthesis_restart(&vf->vd); - - if(_seek_helper(vf,pos)) { - /* dump the machine so we're in a known state */ - vf->pcm_offset=-1; - _decode_clear(vf); - return OV_EBADLINK; - } - - /* we need to make sure the pcm_offset is set, but we don't want to - advance the raw cursor past good packets just to get to the first - with a granulepos. That's not equivalent behavior to beginning - decoding as immediately after the seek position as possible. - - So, a hack. We use two stream states; a local scratch state and - the shared vf->os stream state. We use the local state to - scan, and the shared state as a buffer for later decode. - - Unfortuantely, on the last page we still advance to last packet - because the granulepos on the last page is not necessarily on a - packet boundary, and we need to make sure the granpos is - correct. - */ - - { - ogg_page og; - ogg_packet op; - int lastblock=0; - int accblock=0; - int thisblock=0; - int lastflag=0; - int firstflag=0; - ogg_int64_t pagepos=-1; - - ogg_stream_init(&work_os,vf->current_serialno); /* get the memory ready */ - ogg_stream_reset(&work_os); /* eliminate the spurious OV_HOLE - return from not necessarily - starting from the beginning */ - - while(1){ - if(vf->ready_state>=STREAMSET){ - /* snarf/scan a packet if we can */ - int result=ogg_stream_packetout(&work_os,&op); - - if(result>0){ - - if(vf->vi[vf->current_link].codec_setup){ - thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); - if(thisblock<0){ - ogg_stream_packetout(&vf->os,NULL); - thisblock=0; - }else{ - - /* We can't get a guaranteed correct pcm position out of the - last page in a stream because it might have a 'short' - granpos, which can only be detected in the presence of a - preceding page. However, if the last page is also the first - page, the granpos rules of a first page take precedence. Not - only that, but for first==last, the EOS page must be treated - as if its a normal first page for the stream to open/play. */ - if(lastflag && !firstflag) - ogg_stream_packetout(&vf->os,NULL); - else - if(lastblock)accblock+=(lastblock+thisblock)>>2; - } - - if(op.granulepos!=-1){ - int i,link=vf->current_link; - ogg_int64_t granulepos=op.granulepos-vf->pcmlengths[link*2]; - if(granulepos<0)granulepos=0; - - for(i=0;ipcmlengths[i*2+1]; - vf->pcm_offset=granulepos-accblock; - if(vf->pcm_offset<0)vf->pcm_offset=0; - break; - } - lastblock=thisblock; - continue; - }else - ogg_stream_packetout(&vf->os,NULL); - } - } - - if(!lastblock){ - pagepos=_get_next_page(vf,&og,-1); - if(pagepos<0){ - vf->pcm_offset=ov_pcm_total(vf,-1); - break; - } - }else{ - /* huh? Bogus stream with packets but no granulepos */ - vf->pcm_offset=-1; - break; - } - - /* has our decoding just traversed a bitstream boundary? */ - if(vf->ready_state>=STREAMSET){ - if(vf->current_serialno!=ogg_page_serialno(&og)){ - - /* two possibilities: - 1) our decoding just traversed a bitstream boundary - 2) another stream is multiplexed into this logical section? */ - - if(ogg_page_bos(&og)){ - /* we traversed */ - _decode_clear(vf); /* clear out stream state */ - ogg_stream_clear(&work_os); - } /* else, do nothing; next loop will scoop another page */ - } - } - - if(vf->ready_statelinks;link++) - if(vf->serialnos[link]==serialno)break; - - if(link==vf->links) continue; /* not the desired Vorbis - bitstream section; keep - trying */ - vf->current_link=link; - vf->current_serialno=serialno; - ogg_stream_reset_serialno(&vf->os,serialno); - ogg_stream_reset_serialno(&work_os,serialno); - vf->ready_state=STREAMSET; - firstflag=(pagepos<=vf->dataoffsets[link]); - } - - ogg_stream_pagein(&vf->os,&og); - ogg_stream_pagein(&work_os,&og); - lastflag=ogg_page_eos(&og); - - } - } - - ogg_stream_clear(&work_os); - vf->bittrack=0.f; - vf->samptrack=0.f; - return(0); -} - -/* Page granularity seek (faster than sample granularity because we - don't do the last bit of decode to find a specific sample). - - Seek to the last [granule marked] page preceding the specified pos - location, such that decoding past the returned point will quickly - arrive at the requested position. */ -int ov_pcm_seek_page(OggVorbis_File *vf,ogg_int64_t pos){ - int link=-1; - ogg_int64_t result=0; - ogg_int64_t total=ov_pcm_total(vf,-1); - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - - if(pos<0 || pos>total)return(OV_EINVAL); - - /* which bitstream section does this pcm offset occur in? */ - for(link=vf->links-1;link>=0;link--){ - total-=vf->pcmlengths[link*2+1]; - if(pos>=total)break; - } - - /* Search within the logical bitstream for the page with the highest - pcm_pos preceding pos. If we're looking for a position on the - first page, bisection will halt without finding our position as - it's before the first explicit granulepos fencepost. That case is - handled separately below. - - There is a danger here; missing pages or incorrect frame number - information in the bitstream could make our task impossible. - Account for that (it would be an error condition) */ - - /* new search algorithm originally by HB (Nicholas Vinen) */ - - { - ogg_int64_t end=vf->offsets[link+1]; - ogg_int64_t begin=vf->dataoffsets[link]; - ogg_int64_t begintime = vf->pcmlengths[link*2]; - ogg_int64_t endtime = vf->pcmlengths[link*2+1]+begintime; - ogg_int64_t target=pos-total+begintime; - ogg_int64_t best=-1; - int got_page=0; - - ogg_page og; - - /* if we have only one page, there will be no bisection. Grab the page here */ - if(begin==end){ - result=_seek_helper(vf,begin); - if(result) goto seek_error; - - result=_get_next_page(vf,&og,1); - if(result<0) goto seek_error; - - got_page=1; - } - - /* bisection loop */ - while(beginoffset); - if(result==OV_EREAD) goto seek_error; - if(result<0){ - /* there is no next page! */ - if(bisect<=begin+1) - /* No bisection left to perform. We've either found the - best candidate already or failed. Exit loop. */ - end=begin; - else{ - /* We tried to load a fraction of the last page; back up a - bit and try to get the whole last page */ - if(bisect==0) goto seek_error; - bisect-=CHUNKSIZE; - - /* don't repeat/loop on a read we've already performed */ - if(bisect<=begin)bisect=begin+1; - - /* seek and cntinue bisection */ - result=_seek_helper(vf,bisect); - if(result) goto seek_error; - } - }else{ - ogg_int64_t granulepos; - got_page=1; - - /* got a page. analyze it */ - /* only consider pages from primary vorbis stream */ - if(ogg_page_serialno(&og)!=vf->serialnos[link]) - continue; - - /* only consider pages with the granulepos set */ - granulepos=ogg_page_granulepos(&og); - if(granulepos==-1)continue; - - if(granuleposoffset; /* raw offset of next page */ - begintime=granulepos; - - /* if we're before our target but within a short distance, - don't bisect; read forward */ - if(target-begintime>44100)break; - - bisect=begin; /* *not* begin + 1 as above */ - }else{ - - /* This is one of our pages, but the granpos is - post-target; it is not a bisection return - candidate. (The only way we'd use it is if it's the - first page in the stream; we handle that case later - outside the bisection) */ - if(bisect<=begin+1){ - /* No bisection left to perform. We've either found the - best candidate already or failed. Exit loop. */ - end=begin; - }else{ - if(end==vf->offset){ - /* bisection read to the end; use the known page - boundary (result) to update bisection, back up a - little bit, and try again */ - end=result; - bisect-=CHUNKSIZE; - if(bisect<=begin)bisect=begin+1; - result=_seek_helper(vf,bisect); - if(result) goto seek_error; - }else{ - /* Normal bisection */ - end=bisect; - endtime=granulepos; - break; - } - } - } - } - } - } - - /* Out of bisection: did it 'fail?' */ - if(best == -1){ - - /* Check the 'looking for data in first page' special case; - bisection would 'fail' because our search target was before the - first PCM granule position fencepost. */ - - if(got_page && - begin == vf->dataoffsets[link] && - ogg_page_serialno(&og)==vf->serialnos[link]){ - - /* Yes, this is the beginning-of-stream case. We already have - our page, right at the beginning of PCM data. Set state - and return. */ - - vf->pcm_offset=total; - - if(link!=vf->current_link){ - /* Different link; dump entire decode machine */ - _decode_clear(vf); - - vf->current_link=link; - vf->current_serialno=vf->serialnos[link]; - vf->ready_state=STREAMSET; - - }else{ - vorbis_synthesis_restart(&vf->vd); - } - - ogg_stream_reset_serialno(&vf->os,vf->current_serialno); - ogg_stream_pagein(&vf->os,&og); - - }else - goto seek_error; - - }else{ - - /* Bisection found our page. seek to it, update pcm offset. Easier case than - raw_seek, don't keep packets preceding granulepos. */ - - ogg_page og; - ogg_packet op; - - /* seek */ - result=_seek_helper(vf,best); - vf->pcm_offset=-1; - if(result) goto seek_error; - result=_get_next_page(vf,&og,-1); - if(result<0) goto seek_error; - - if(link!=vf->current_link){ - /* Different link; dump entire decode machine */ - _decode_clear(vf); - - vf->current_link=link; - vf->current_serialno=vf->serialnos[link]; - vf->ready_state=STREAMSET; - - }else{ - vorbis_synthesis_restart(&vf->vd); - } - - ogg_stream_reset_serialno(&vf->os,vf->current_serialno); - ogg_stream_pagein(&vf->os,&og); - - /* pull out all but last packet; the one with granulepos */ - while(1){ - result=ogg_stream_packetpeek(&vf->os,&op); - if(result==0){ - /* No packet returned; we exited the bisection with 'best' - pointing to a page with a granule position, so the packet - finishing this page ('best') originated on a preceding - page. Keep fetching previous pages until we get one with - a granulepos or without the 'continued' flag set. Then - just use raw_seek for simplicity. */ - /* Do not rewind past the beginning of link data; if we do, - it's either a bug or a broken stream */ - result=best; - while(result>vf->dataoffsets[link]){ - result=_get_prev_page(vf,result,&og); - if(result<0) goto seek_error; - if(ogg_page_serialno(&og)==vf->current_serialno && - (ogg_page_granulepos(&og)>-1 || - !ogg_page_continued(&og))){ - return ov_raw_seek(vf,result); - } - } - } - if(result<0){ - result = OV_EBADPACKET; - goto seek_error; - } - if(op.granulepos!=-1){ - vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; - if(vf->pcm_offset<0)vf->pcm_offset=0; - vf->pcm_offset+=total; - break; - }else - result=ogg_stream_packetout(&vf->os,NULL); - } - } - } - - /* verify result */ - if(vf->pcm_offset>pos || pos>ov_pcm_total(vf,-1)){ - result=OV_EFAULT; - goto seek_error; - } - vf->bittrack=0.f; - vf->samptrack=0.f; - return(0); - - seek_error: - /* dump machine so we're in a known state */ - vf->pcm_offset=-1; - _decode_clear(vf); - return (int)result; -} - -/* seek to a sample offset relative to the decompressed pcm stream - returns zero on success, nonzero on failure */ - -int ov_pcm_seek(OggVorbis_File *vf,ogg_int64_t pos){ - int thisblock,lastblock=0; - int ret=ov_pcm_seek_page(vf,pos); - if(ret<0)return(ret); - if((ret=_make_decode_ready(vf)))return ret; - - /* discard leading packets we don't need for the lapping of the - position we want; don't decode them */ - - while(1){ - ogg_packet op; - ogg_page og; - - int ret=ogg_stream_packetpeek(&vf->os,&op); - if(ret>0){ - thisblock=vorbis_packet_blocksize(vf->vi+vf->current_link,&op); - if(thisblock<0){ - ogg_stream_packetout(&vf->os,NULL); - continue; /* non audio packet */ - } - if(lastblock)vf->pcm_offset+=(lastblock+thisblock)>>2; - - if(vf->pcm_offset+((thisblock+ - vorbis_info_blocksize(vf->vi,1))>>2)>=pos)break; - - /* remove the packet from packet queue and track its granulepos */ - ogg_stream_packetout(&vf->os,NULL); - vorbis_synthesis_trackonly(&vf->vb,&op); /* set up a vb with - only tracking, no - pcm_decode */ - vorbis_synthesis_blockin(&vf->vd,&vf->vb); - - /* end of logical stream case is hard, especially with exact - length positioning. */ - - if(op.granulepos>-1){ - int i; - /* always believe the stream markers */ - vf->pcm_offset=op.granulepos-vf->pcmlengths[vf->current_link*2]; - if(vf->pcm_offset<0)vf->pcm_offset=0; - for(i=0;icurrent_link;i++) - vf->pcm_offset+=vf->pcmlengths[i*2+1]; - } - - lastblock=thisblock; - - }else{ - if(ret<0 && ret!=OV_HOLE)break; - - /* suck in a new page */ - if(_get_next_page(vf,&og,-1)<0)break; - if(ogg_page_bos(&og))_decode_clear(vf); - - if(vf->ready_statelinks;link++) - if(vf->serialnos[link]==serialno)break; - if(link==vf->links) continue; - vf->current_link=link; - - vf->ready_state=STREAMSET; - vf->current_serialno=ogg_page_serialno(&og); - ogg_stream_reset_serialno(&vf->os,serialno); - ret=_make_decode_ready(vf); - if(ret)return ret; - lastblock=0; - } - - ogg_stream_pagein(&vf->os,&og); - } - } - - vf->bittrack=0.f; - vf->samptrack=0.f; - /* discard samples until we reach the desired position. Crossing a - logical bitstream boundary with abandon is OK. */ - { - /* note that halfrate could be set differently in each link, but - vorbisfile encoforces all links are set or unset */ - int hs=vorbis_synthesis_halfrate_p(vf->vi); - while(vf->pcm_offset<((pos>>hs)<pcm_offset)>>hs; - long samples=vorbis_synthesis_pcmout(&vf->vd,NULL); - - if(samples>target)samples=target; - vorbis_synthesis_read(&vf->vd,samples); - vf->pcm_offset+=samples<pcm_offset=ov_pcm_total(vf,-1); /* eof */ - } - } - return 0; -} - -/* seek to a playback time relative to the decompressed pcm stream - returns zero on success, nonzero on failure */ -int ov_time_seek(OggVorbis_File *vf,double seconds){ - /* translate time to PCM position and call ov_pcm_seek */ - - int link=-1; - ogg_int64_t pcm_total=0; - double time_total=0.; - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - if(seconds<0)return(OV_EINVAL); - - /* which bitstream section does this time offset occur in? */ - for(link=0;linklinks;link++){ - double addsec = ov_time_total(vf,link); - if(secondspcmlengths[link*2+1]; - } - - if(link==vf->links)return(OV_EINVAL); - - /* enough information to convert time offset to pcm offset */ - { - ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; - return(ov_pcm_seek(vf,target)); - } -} - -/* page-granularity version of ov_time_seek - returns zero on success, nonzero on failure */ -int ov_time_seek_page(OggVorbis_File *vf,double seconds){ - /* translate time to PCM position and call ov_pcm_seek */ - - int link=-1; - ogg_int64_t pcm_total=0; - double time_total=0.; - - if(vf->ready_stateseekable)return(OV_ENOSEEK); - if(seconds<0)return(OV_EINVAL); - - /* which bitstream section does this time offset occur in? */ - for(link=0;linklinks;link++){ - double addsec = ov_time_total(vf,link); - if(secondspcmlengths[link*2+1]; - } - - if(link==vf->links)return(OV_EINVAL); - - /* enough information to convert time offset to pcm offset */ - { - ogg_int64_t target=pcm_total+(seconds-time_total)*vf->vi[link].rate; - return(ov_pcm_seek_page(vf,target)); - } -} - -/* tell the current stream offset cursor. Note that seek followed by - tell will likely not give the set offset due to caching */ -ogg_int64_t ov_raw_tell(OggVorbis_File *vf){ - if(vf->ready_stateoffset); -} - -/* return PCM offset (sample) of next PCM sample to be read */ -ogg_int64_t ov_pcm_tell(OggVorbis_File *vf){ - if(vf->ready_statepcm_offset); -} - -/* return time offset (seconds) of next PCM sample to be read */ -double ov_time_tell(OggVorbis_File *vf){ - int link=0; - ogg_int64_t pcm_total=0; - double time_total=0.f; - - if(vf->ready_stateseekable){ - pcm_total=ov_pcm_total(vf,-1); - time_total=ov_time_total(vf,-1); - - /* which bitstream section does this time offset occur in? */ - for(link=vf->links-1;link>=0;link--){ - pcm_total-=vf->pcmlengths[link*2+1]; - time_total-=ov_time_total(vf,link); - if(vf->pcm_offset>=pcm_total)break; - } - } - - return((double)time_total+(double)(vf->pcm_offset-pcm_total)/vf->vi[link].rate); -} - -/* link: -1) return the vorbis_info struct for the bitstream section - currently being decoded - 0-n) to request information for a specific bitstream section - - In the case of a non-seekable bitstream, any call returns the - current bitstream. NULL in the case that the machine is not - initialized */ - -vorbis_info *ov_info(OggVorbis_File *vf,int link){ - if(vf->seekable){ - if(link<0) - if(vf->ready_state>=STREAMSET) - return vf->vi+vf->current_link; - else - return vf->vi; - else - if(link>=vf->links) - return NULL; - else - return vf->vi+link; - }else{ - return vf->vi; - } -} - -/* grr, strong typing, grr, no templates/inheritence, grr */ -vorbis_comment *ov_comment(OggVorbis_File *vf,int link){ - if(vf->seekable){ - if(link<0) - if(vf->ready_state>=STREAMSET) - return vf->vc+vf->current_link; - else - return vf->vc; - else - if(link>=vf->links) - return NULL; - else - return vf->vc+link; - }else{ - return vf->vc; - } -} - -static int host_is_big_endian() { - ogg_int32_t pattern = 0xfeedface; /* deadbeef */ - unsigned char *bytewise = (unsigned char *)&pattern; - if (bytewise[0] == 0xfe) return 1; - return 0; -} - -/* up to this point, everything could more or less hide the multiple - logical bitstream nature of chaining from the toplevel application - if the toplevel application didn't particularly care. However, at - the point that we actually read audio back, the multiple-section - nature must surface: Multiple bitstream sections do not necessarily - have to have the same number of channels or sampling rate. - - ov_read returns the sequential logical bitstream number currently - being decoded along with the PCM data in order that the toplevel - application can take action on channel/sample rate changes. This - number will be incremented even for streamed (non-seekable) streams - (for seekable streams, it represents the actual logical bitstream - index within the physical bitstream. Note that the accessor - functions above are aware of this dichotomy). - - ov_read_filter is exactly the same as ov_read except that it processes - the decoded audio data through a filter before packing it into the - requested format. This gives greater accuracy than applying a filter - after the audio has been converted into integral PCM. - - input values: buffer) a buffer to hold packed PCM data for return - length) the byte length requested to be placed into buffer - bigendianp) should the data be packed LSB first (0) or - MSB first (1) - word) word size for output. currently 1 (byte) or - 2 (16 bit short) - - return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) - 0) EOF - n) number of bytes of PCM actually returned. The - below works on a packet-by-packet basis, so the - return length is not related to the 'length' passed - in, just guaranteed to fit. - - *section) set to the logical bitstream number */ - -long ov_read_filter(OggVorbis_File *vf,char *buffer,int length, - int bigendianp,int word,int sgned,int *bitstream, - void (*filter)(float **pcm,long channels,long samples,void *filter_param),void *filter_param){ - int i,j; - int host_endian = host_is_big_endian(); - int hs; - - float **pcm; - long samples; - - if(vf->ready_stateready_state==INITSET){ - samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); - if(samples)break; - } - - /* suck in another packet */ - { - int ret=_fetch_and_process_packet(vf,NULL,1,1); - if(ret==OV_EOF) - return(0); - if(ret<=0) - return(ret); - } - - } - - if(samples>0){ - - /* yay! proceed to pack data into the byte buffer */ - - long channels=ov_info(vf,-1)->channels; - long bytespersample=word * channels; - vorbis_fpu_control fpu; - - if(channels<1||channels>255)return(OV_EINVAL); - if(samples>length/bytespersample)samples=length/bytespersample; - - if(samples <= 0) - return OV_EINVAL; - - /* Here. */ - if(filter) - filter(pcm,channels,samples,filter_param); - - /* a tight loop to pack each size */ - { - int val; - if(word==1){ - int off=(sgned?0:128); - vorbis_fpu_setround(&fpu); - for(j=0;j127)val=127; - else if(val<-128)val=-128; - *buffer++=val+off; - } - vorbis_fpu_restore(fpu); - }else{ - int off=(sgned?0:32768); - - if(host_endian==bigendianp){ - if(sgned){ - - vorbis_fpu_setround(&fpu); - for(i=0;i32767)val=32767; - else if(val<-32768)val=-32768; - *dest=val; - dest+=channels; - } - } - vorbis_fpu_restore(fpu); - - }else{ - - vorbis_fpu_setround(&fpu); - for(i=0;i32767)val=32767; - else if(val<-32768)val=-32768; - *dest=val+off; - dest+=channels; - } - } - vorbis_fpu_restore(fpu); - - } - }else if(bigendianp){ - - vorbis_fpu_setround(&fpu); - for(j=0;j32767)val=32767; - else if(val<-32768)val=-32768; - val+=off; - *buffer++=(val>>8); - *buffer++=(val&0xff); - } - vorbis_fpu_restore(fpu); - - }else{ - int val; - vorbis_fpu_setround(&fpu); - for(j=0;j32767)val=32767; - else if(val<-32768)val=-32768; - val+=off; - *buffer++=(val&0xff); - *buffer++=(val>>8); - } - vorbis_fpu_restore(fpu); - - } - } - } - - vorbis_synthesis_read(&vf->vd,samples); - hs=vorbis_synthesis_halfrate_p(vf->vi); - vf->pcm_offset+=(samples<current_link; - return(samples*bytespersample); - }else{ - return(samples); - } -} - -long ov_read(OggVorbis_File *vf,char *buffer,int length, - int bigendianp,int word,int sgned,int *bitstream){ - return ov_read_filter(vf, buffer, length, bigendianp, word, sgned, bitstream, NULL, NULL); -} - -/* input values: pcm_channels) a float vector per channel of output - length) the sample length being read by the app - - return values: <0) error/hole in data (OV_HOLE), partial open (OV_EINVAL) - 0) EOF - n) number of samples of PCM actually returned. The - below works on a packet-by-packet basis, so the - return length is not related to the 'length' passed - in, just guaranteed to fit. - - *section) set to the logical bitstream number */ - - - -long ov_read_float(OggVorbis_File *vf,float ***pcm_channels,int length, - int *bitstream){ - - if(vf->ready_stateready_state==INITSET){ - float **pcm; - long samples=vorbis_synthesis_pcmout(&vf->vd,&pcm); - if(samples){ - int hs=vorbis_synthesis_halfrate_p(vf->vi); - if(pcm_channels)*pcm_channels=pcm; - if(samples>length)samples=length; - vorbis_synthesis_read(&vf->vd,samples); - vf->pcm_offset+=samples<current_link; - return samples; - - } - } - - /* suck in another packet */ - { - int ret=_fetch_and_process_packet(vf,NULL,1,1); - if(ret==OV_EOF)return(0); - if(ret<=0)return(ret); - } - - } -} - -extern const float *vorbis_window(vorbis_dsp_state *v,int W); - -static void _ov_splice(float **pcm,float **lappcm, - int n1, int n2, - int ch1, int ch2, - const float *w1, const float *w2){ - int i,j; - const float *w=w1; - int n=n1; - - if(n1>n2){ - n=n2; - w=w2; - } - - /* splice */ - for(j=0;jready_state==INITSET)break; - /* suck in another packet */ - { - int ret=_fetch_and_process_packet(vf,NULL,1,0); - if(ret<0 && ret!=OV_HOLE)return(ret); - } - } - return 0; -} - -/* make sure vf is INITSET and that we have a primed buffer; if - we're crosslapping at a stream section boundary, this also makes - sure we're sanity checking against the right stream information */ -static int _ov_initprime(OggVorbis_File *vf){ - vorbis_dsp_state *vd=&vf->vd; - while(1){ - if(vf->ready_state==INITSET) - if(vorbis_synthesis_pcmout(vd,NULL))break; - - /* suck in another packet */ - { - int ret=_fetch_and_process_packet(vf,NULL,1,0); - if(ret<0 && ret!=OV_HOLE)return(ret); - } - } - return 0; -} - -/* grab enough data for lapping from vf; this may be in the form of - unreturned, already-decoded pcm, remaining PCM we will need to - decode, or synthetic postextrapolation from last packets. */ -static void _ov_getlap(OggVorbis_File *vf,vorbis_info *vi,vorbis_dsp_state *vd, - float **lappcm,int lapsize){ - int lapcount=0,i; - float **pcm; - - /* try first to decode the lapping data */ - while(lapcountlapsize-lapcount)samples=lapsize-lapcount; - for(i=0;ichannels;i++) - memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples); - lapcount+=samples; - vorbis_synthesis_read(vd,samples); - }else{ - /* suck in another packet */ - int ret=_fetch_and_process_packet(vf,NULL,1,0); /* do *not* span */ - if(ret==OV_EOF)break; - } - } - if(lapcountvd,&pcm); - if(samples==0){ - for(i=0;ichannels;i++) - memset(lappcm[i]+lapcount,0,sizeof(**pcm)*lapsize-lapcount); - lapcount=lapsize; - }else{ - if(samples>lapsize-lapcount)samples=lapsize-lapcount; - for(i=0;ichannels;i++) - memcpy(lappcm[i]+lapcount,pcm[i],sizeof(**pcm)*samples); - lapcount+=samples; - } - } -} - -/* this sets up crosslapping of a sample by using trailing data from - sample 1 and lapping it into the windowing buffer of sample 2 */ -int ov_crosslap(OggVorbis_File *vf1, OggVorbis_File *vf2){ - vorbis_info *vi1,*vi2; - float **lappcm; - float **pcm; - const float *w1,*w2; - int n1,n2,i,ret,hs1,hs2; - - if(vf1==vf2)return(0); /* degenerate case */ - if(vf1->ready_stateready_statechannels); - n1=vorbis_info_blocksize(vi1,0)>>(1+hs1); - n2=vorbis_info_blocksize(vi2,0)>>(1+hs2); - w1=vorbis_window(&vf1->vd,0); - w2=vorbis_window(&vf2->vd,0); - - for(i=0;ichannels;i++) - lappcm[i]=alloca(sizeof(**lappcm)*n1); - - _ov_getlap(vf1,vi1,&vf1->vd,lappcm,n1); - - /* have a lapping buffer from vf1; now to splice it into the lapping - buffer of vf2 */ - /* consolidate and expose the buffer. */ - vorbis_synthesis_lapout(&vf2->vd,&pcm); - -#if 0 - _analysis_output_always("pcmL",0,pcm[0],n1*2,0,0,0); - _analysis_output_always("pcmR",0,pcm[1],n1*2,0,0,0); -#endif - - /* splice */ - _ov_splice(pcm,lappcm,n1,n2,vi1->channels,vi2->channels,w1,w2); - - /* done */ - return(0); -} - -static int _ov_64_seek_lap(OggVorbis_File *vf,ogg_int64_t pos, - int (*localseek)(OggVorbis_File *,ogg_int64_t)){ - vorbis_info *vi; - float **lappcm; - float **pcm; - const float *w1,*w2; - int n1,n2,ch1,ch2,hs; - int i,ret; - - if(vf->ready_statechannels; - n1=vorbis_info_blocksize(vi,0)>>(1+hs); - w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are - persistent; even if the decode state - from this link gets dumped, this - window array continues to exist */ - - lappcm=alloca(sizeof(*lappcm)*ch1); - for(i=0;ivd,lappcm,n1); - - /* have lapping data; seek and prime the buffer */ - ret=localseek(vf,pos); - if(ret)return ret; - ret=_ov_initprime(vf); - if(ret)return(ret); - - /* Guard against cross-link changes; they're perfectly legal */ - vi=ov_info(vf,-1); - ch2=vi->channels; - n2=vorbis_info_blocksize(vi,0)>>(1+hs); - w2=vorbis_window(&vf->vd,0); - - /* consolidate and expose the buffer. */ - vorbis_synthesis_lapout(&vf->vd,&pcm); - - /* splice */ - _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2); - - /* done */ - return(0); -} - -int ov_raw_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){ - return _ov_64_seek_lap(vf,pos,ov_raw_seek); -} - -int ov_pcm_seek_lap(OggVorbis_File *vf,ogg_int64_t pos){ - return _ov_64_seek_lap(vf,pos,ov_pcm_seek); -} - -int ov_pcm_seek_page_lap(OggVorbis_File *vf,ogg_int64_t pos){ - return _ov_64_seek_lap(vf,pos,ov_pcm_seek_page); -} - -static int _ov_d_seek_lap(OggVorbis_File *vf,double pos, - int (*localseek)(OggVorbis_File *,double)){ - vorbis_info *vi; - float **lappcm; - float **pcm; - const float *w1,*w2; - int n1,n2,ch1,ch2,hs; - int i,ret; - - if(vf->ready_statechannels; - n1=vorbis_info_blocksize(vi,0)>>(1+hs); - w1=vorbis_window(&vf->vd,0); /* window arrays from libvorbis are - persistent; even if the decode state - from this link gets dumped, this - window array continues to exist */ - - lappcm=alloca(sizeof(*lappcm)*ch1); - for(i=0;ivd,lappcm,n1); - - /* have lapping data; seek and prime the buffer */ - ret=localseek(vf,pos); - if(ret)return ret; - ret=_ov_initprime(vf); - if(ret)return(ret); - - /* Guard against cross-link changes; they're perfectly legal */ - vi=ov_info(vf,-1); - ch2=vi->channels; - n2=vorbis_info_blocksize(vi,0)>>(1+hs); - w2=vorbis_window(&vf->vd,0); - - /* consolidate and expose the buffer. */ - vorbis_synthesis_lapout(&vf->vd,&pcm); - - /* splice */ - _ov_splice(pcm,lappcm,n1,n2,ch1,ch2,w1,w2); - - /* done */ - return(0); -} - -int ov_time_seek_lap(OggVorbis_File *vf,double pos){ - return _ov_d_seek_lap(vf,pos,ov_time_seek); -} - -int ov_time_seek_page_lap(OggVorbis_File *vf,double pos){ - return _ov_d_seek_lap(vf,pos,ov_time_seek_page); -} diff --git a/src/lib/vorbis/src/window.c b/src/lib/vorbis/src/window.c deleted file mode 100644 index 2151b278..00000000 --- a/src/lib/vorbis/src/window.c +++ /dev/null @@ -1,2135 +0,0 @@ -/******************************************************************** - * * - * THIS FILE IS PART OF THE OggVorbis SOFTWARE CODEC SOURCE CODE. * - * USE, DISTRIBUTION AND REPRODUCTION OF THIS LIBRARY SOURCE IS * - * GOVERNED BY A BSD-STYLE SOURCE LICENSE INCLUDED WITH THIS SOURCE * - * IN 'COPYING'. PLEASE READ THESE TERMS BEFORE DISTRIBUTING. * - * * - * THE OggVorbis SOURCE CODE IS (C) COPYRIGHT 1994-2009 * - * by the Xiph.Org Foundation https://xiph.org/ * - * * - ******************************************************************** - - function: window functions - - ********************************************************************/ - -#include -#include -#include "os.h" -#include "misc.h" -#include "window.h" - -static const float vwin64[32] = { - 0.0009460463F, 0.0085006468F, 0.0235352254F, 0.0458950567F, - 0.0753351908F, 0.1115073077F, 0.1539457973F, 0.2020557475F, - 0.2551056759F, 0.3122276645F, 0.3724270287F, 0.4346027792F, - 0.4975789974F, 0.5601459521F, 0.6211085051F, 0.6793382689F, - 0.7338252629F, 0.7837245849F, 0.8283939355F, 0.8674186656F, - 0.9006222429F, 0.9280614787F, 0.9500073081F, 0.9669131782F, - 0.9793740220F, 0.9880792941F, 0.9937636139F, 0.9971582668F, - 0.9989462667F, 0.9997230082F, 0.9999638688F, 0.9999995525F, -}; - -static const float vwin128[64] = { - 0.0002365472F, 0.0021280687F, 0.0059065254F, 0.0115626550F, - 0.0190823442F, 0.0284463735F, 0.0396300935F, 0.0526030430F, - 0.0673285281F, 0.0837631763F, 0.1018564887F, 0.1215504095F, - 0.1427789367F, 0.1654677960F, 0.1895342001F, 0.2148867160F, - 0.2414252576F, 0.2690412240F, 0.2976177952F, 0.3270303960F, - 0.3571473350F, 0.3878306189F, 0.4189369387F, 0.4503188188F, - 0.4818259135F, 0.5133064334F, 0.5446086751F, 0.5755826278F, - 0.6060816248F, 0.6359640047F, 0.6650947483F, 0.6933470543F, - 0.7206038179F, 0.7467589810F, 0.7717187213F, 0.7954024542F, - 0.8177436264F, 0.8386902831F, 0.8582053981F, 0.8762669622F, - 0.8928678298F, 0.9080153310F, 0.9217306608F, 0.9340480615F, - 0.9450138200F, 0.9546851041F, 0.9631286621F, 0.9704194171F, - 0.9766389810F, 0.9818741197F, 0.9862151938F, 0.9897546035F, - 0.9925852598F, 0.9947991032F, 0.9964856900F, 0.9977308602F, - 0.9986155015F, 0.9992144193F, 0.9995953200F, 0.9998179155F, - 0.9999331503F, 0.9999825563F, 0.9999977357F, 0.9999999720F, -}; - -static const float vwin256[128] = { - 0.0000591390F, 0.0005321979F, 0.0014780301F, 0.0028960636F, - 0.0047854363F, 0.0071449926F, 0.0099732775F, 0.0132685298F, - 0.0170286741F, 0.0212513119F, 0.0259337111F, 0.0310727950F, - 0.0366651302F, 0.0427069140F, 0.0491939614F, 0.0561216907F, - 0.0634851102F, 0.0712788035F, 0.0794969160F, 0.0881331402F, - 0.0971807028F, 0.1066323515F, 0.1164803426F, 0.1267164297F, - 0.1373318534F, 0.1483173323F, 0.1596630553F, 0.1713586755F, - 0.1833933062F, 0.1957555184F, 0.2084333404F, 0.2214142599F, - 0.2346852280F, 0.2482326664F, 0.2620424757F, 0.2761000481F, - 0.2903902813F, 0.3048975959F, 0.3196059553F, 0.3344988887F, - 0.3495595160F, 0.3647705766F, 0.3801144597F, 0.3955732382F, - 0.4111287047F, 0.4267624093F, 0.4424557009F, 0.4581897696F, - 0.4739456913F, 0.4897044744F, 0.5054471075F, 0.5211546088F, - 0.5368080763F, 0.5523887395F, 0.5678780103F, 0.5832575361F, - 0.5985092508F, 0.6136154277F, 0.6285587300F, 0.6433222619F, - 0.6578896175F, 0.6722449294F, 0.6863729144F, 0.7002589187F, - 0.7138889597F, 0.7272497662F, 0.7403288154F, 0.7531143679F, - 0.7655954985F, 0.7777621249F, 0.7896050322F, 0.8011158947F, - 0.8122872932F, 0.8231127294F, 0.8335866365F, 0.8437043850F, - 0.8534622861F, 0.8628575905F, 0.8718884835F, 0.8805540765F, - 0.8888543947F, 0.8967903616F, 0.9043637797F, 0.9115773078F, - 0.9184344360F, 0.9249394562F, 0.9310974312F, 0.9369141608F, - 0.9423961446F, 0.9475505439F, 0.9523851406F, 0.9569082947F, - 0.9611289005F, 0.9650563408F, 0.9687004405F, 0.9720714191F, - 0.9751798427F, 0.9780365753F, 0.9806527301F, 0.9830396204F, - 0.9852087111F, 0.9871715701F, 0.9889398207F, 0.9905250941F, - 0.9919389832F, 0.9931929973F, 0.9942985174F, 0.9952667537F, - 0.9961087037F, 0.9968351119F, 0.9974564312F, 0.9979827858F, - 0.9984239359F, 0.9987892441F, 0.9990876435F, 0.9993276081F, - 0.9995171241F, 0.9996636648F, 0.9997741654F, 0.9998550016F, - 0.9999119692F, 0.9999502656F, 0.9999744742F, 0.9999885497F, - 0.9999958064F, 0.9999989077F, 0.9999998584F, 0.9999999983F, -}; - -static const float vwin512[256] = { - 0.0000147849F, 0.0001330607F, 0.0003695946F, 0.0007243509F, - 0.0011972759F, 0.0017882983F, 0.0024973285F, 0.0033242588F, - 0.0042689632F, 0.0053312973F, 0.0065110982F, 0.0078081841F, - 0.0092223540F, 0.0107533880F, 0.0124010466F, 0.0141650703F, - 0.0160451800F, 0.0180410758F, 0.0201524373F, 0.0223789233F, - 0.0247201710F, 0.0271757958F, 0.0297453914F, 0.0324285286F, - 0.0352247556F, 0.0381335972F, 0.0411545545F, 0.0442871045F, - 0.0475306997F, 0.0508847676F, 0.0543487103F, 0.0579219038F, - 0.0616036982F, 0.0653934164F, 0.0692903546F, 0.0732937809F, - 0.0774029356F, 0.0816170305F, 0.0859352485F, 0.0903567428F, - 0.0948806375F, 0.0995060259F, 0.1042319712F, 0.1090575056F, - 0.1139816300F, 0.1190033137F, 0.1241214941F, 0.1293350764F, - 0.1346429333F, 0.1400439046F, 0.1455367974F, 0.1511203852F, - 0.1567934083F, 0.1625545735F, 0.1684025537F, 0.1743359881F, - 0.1803534820F, 0.1864536069F, 0.1926349000F, 0.1988958650F, - 0.2052349715F, 0.2116506555F, 0.2181413191F, 0.2247053313F, - 0.2313410275F, 0.2380467105F, 0.2448206500F, 0.2516610835F, - 0.2585662164F, 0.2655342226F, 0.2725632448F, 0.2796513950F, - 0.2867967551F, 0.2939973773F, 0.3012512852F, 0.3085564739F, - 0.3159109111F, 0.3233125375F, 0.3307592680F, 0.3382489922F, - 0.3457795756F, 0.3533488602F, 0.3609546657F, 0.3685947904F, - 0.3762670121F, 0.3839690896F, 0.3916987634F, 0.3994537572F, - 0.4072317788F, 0.4150305215F, 0.4228476653F, 0.4306808783F, - 0.4385278181F, 0.4463861329F, 0.4542534630F, 0.4621274424F, - 0.4700057001F, 0.4778858615F, 0.4857655502F, 0.4936423891F, - 0.5015140023F, 0.5093780165F, 0.5172320626F, 0.5250737772F, - 0.5329008043F, 0.5407107971F, 0.5485014192F, 0.5562703465F, - 0.5640152688F, 0.5717338914F, 0.5794239366F, 0.5870831457F, - 0.5947092801F, 0.6023001235F, 0.6098534829F, 0.6173671907F, - 0.6248391059F, 0.6322671161F, 0.6396491384F, 0.6469831217F, - 0.6542670475F, 0.6614989319F, 0.6686768267F, 0.6757988210F, - 0.6828630426F, 0.6898676592F, 0.6968108799F, 0.7036909564F, - 0.7105061843F, 0.7172549043F, 0.7239355032F, 0.7305464154F, - 0.7370861235F, 0.7435531598F, 0.7499461068F, 0.7562635986F, - 0.7625043214F, 0.7686670148F, 0.7747504721F, 0.7807535410F, - 0.7866751247F, 0.7925141825F, 0.7982697296F, 0.8039408387F, - 0.8095266395F, 0.8150263196F, 0.8204391248F, 0.8257643590F, - 0.8310013848F, 0.8361496236F, 0.8412085555F, 0.8461777194F, - 0.8510567129F, 0.8558451924F, 0.8605428730F, 0.8651495278F, - 0.8696649882F, 0.8740891432F, 0.8784219392F, 0.8826633797F, - 0.8868135244F, 0.8908724888F, 0.8948404441F, 0.8987176157F, - 0.9025042831F, 0.9062007791F, 0.9098074886F, 0.9133248482F, - 0.9167533451F, 0.9200935163F, 0.9233459472F, 0.9265112712F, - 0.9295901680F, 0.9325833632F, 0.9354916263F, 0.9383157705F, - 0.9410566504F, 0.9437151618F, 0.9462922398F, 0.9487888576F, - 0.9512060252F, 0.9535447882F, 0.9558062262F, 0.9579914516F, - 0.9601016078F, 0.9621378683F, 0.9641014348F, 0.9659935361F, - 0.9678154261F, 0.9695683830F, 0.9712537071F, 0.9728727198F, - 0.9744267618F, 0.9759171916F, 0.9773453842F, 0.9787127293F, - 0.9800206298F, 0.9812705006F, 0.9824637665F, 0.9836018613F, - 0.9846862258F, 0.9857183066F, 0.9866995544F, 0.9876314227F, - 0.9885153662F, 0.9893528393F, 0.9901452948F, 0.9908941823F, - 0.9916009470F, 0.9922670279F, 0.9928938570F, 0.9934828574F, - 0.9940354423F, 0.9945530133F, 0.9950369595F, 0.9954886562F, - 0.9959094633F, 0.9963007242F, 0.9966637649F, 0.9969998925F, - 0.9973103939F, 0.9975965351F, 0.9978595598F, 0.9981006885F, - 0.9983211172F, 0.9985220166F, 0.9987045311F, 0.9988697776F, - 0.9990188449F, 0.9991527924F, 0.9992726499F, 0.9993794157F, - 0.9994740570F, 0.9995575079F, 0.9996306699F, 0.9996944099F, - 0.9997495605F, 0.9997969190F, 0.9998372465F, 0.9998712678F, - 0.9998996704F, 0.9999231041F, 0.9999421807F, 0.9999574732F, - 0.9999695157F, 0.9999788026F, 0.9999857885F, 0.9999908879F, - 0.9999944746F, 0.9999968817F, 0.9999984010F, 0.9999992833F, - 0.9999997377F, 0.9999999317F, 0.9999999911F, 0.9999999999F, -}; - -static const float vwin1024[512] = { - 0.0000036962F, 0.0000332659F, 0.0000924041F, 0.0001811086F, - 0.0002993761F, 0.0004472021F, 0.0006245811F, 0.0008315063F, - 0.0010679699F, 0.0013339631F, 0.0016294757F, 0.0019544965F, - 0.0023090133F, 0.0026930125F, 0.0031064797F, 0.0035493989F, - 0.0040217533F, 0.0045235250F, 0.0050546946F, 0.0056152418F, - 0.0062051451F, 0.0068243817F, 0.0074729278F, 0.0081507582F, - 0.0088578466F, 0.0095941655F, 0.0103596863F, 0.0111543789F, - 0.0119782122F, 0.0128311538F, 0.0137131701F, 0.0146242260F, - 0.0155642855F, 0.0165333111F, 0.0175312640F, 0.0185581042F, - 0.0196137903F, 0.0206982797F, 0.0218115284F, 0.0229534910F, - 0.0241241208F, 0.0253233698F, 0.0265511886F, 0.0278075263F, - 0.0290923308F, 0.0304055484F, 0.0317471241F, 0.0331170013F, - 0.0345151222F, 0.0359414274F, 0.0373958560F, 0.0388783456F, - 0.0403888325F, 0.0419272511F, 0.0434935347F, 0.0450876148F, - 0.0467094213F, 0.0483588828F, 0.0500359261F, 0.0517404765F, - 0.0534724575F, 0.0552317913F, 0.0570183983F, 0.0588321971F, - 0.0606731048F, 0.0625410369F, 0.0644359070F, 0.0663576272F, - 0.0683061077F, 0.0702812571F, 0.0722829821F, 0.0743111878F, - 0.0763657775F, 0.0784466526F, 0.0805537129F, 0.0826868561F, - 0.0848459782F, 0.0870309736F, 0.0892417345F, 0.0914781514F, - 0.0937401128F, 0.0960275056F, 0.0983402145F, 0.1006781223F, - 0.1030411101F, 0.1054290568F, 0.1078418397F, 0.1102793336F, - 0.1127414119F, 0.1152279457F, 0.1177388042F, 0.1202738544F, - 0.1228329618F, 0.1254159892F, 0.1280227980F, 0.1306532471F, - 0.1333071937F, 0.1359844927F, 0.1386849970F, 0.1414085575F, - 0.1441550230F, 0.1469242403F, 0.1497160539F, 0.1525303063F, - 0.1553668381F, 0.1582254875F, 0.1611060909F, 0.1640084822F, - 0.1669324936F, 0.1698779549F, 0.1728446939F, 0.1758325362F, - 0.1788413055F, 0.1818708232F, 0.1849209084F, 0.1879913785F, - 0.1910820485F, 0.1941927312F, 0.1973232376F, 0.2004733764F, - 0.2036429541F, 0.2068317752F, 0.2100396421F, 0.2132663552F, - 0.2165117125F, 0.2197755102F, 0.2230575422F, 0.2263576007F, - 0.2296754753F, 0.2330109540F, 0.2363638225F, 0.2397338646F, - 0.2431208619F, 0.2465245941F, 0.2499448389F, 0.2533813719F, - 0.2568339669F, 0.2603023956F, 0.2637864277F, 0.2672858312F, - 0.2708003718F, 0.2743298135F, 0.2778739186F, 0.2814324472F, - 0.2850051576F, 0.2885918065F, 0.2921921485F, 0.2958059366F, - 0.2994329219F, 0.3030728538F, 0.3067254799F, 0.3103905462F, - 0.3140677969F, 0.3177569747F, 0.3214578205F, 0.3251700736F, - 0.3288934718F, 0.3326277513F, 0.3363726468F, 0.3401278914F, - 0.3438932168F, 0.3476683533F, 0.3514530297F, 0.3552469734F, - 0.3590499106F, 0.3628615659F, 0.3666816630F, 0.3705099239F, - 0.3743460698F, 0.3781898204F, 0.3820408945F, 0.3858990095F, - 0.3897638820F, 0.3936352274F, 0.3975127601F, 0.4013961936F, - 0.4052852405F, 0.4091796123F, 0.4130790198F, 0.4169831732F, - 0.4208917815F, 0.4248045534F, 0.4287211965F, 0.4326414181F, - 0.4365649248F, 0.4404914225F, 0.4444206167F, 0.4483522125F, - 0.4522859146F, 0.4562214270F, 0.4601584538F, 0.4640966984F, - 0.4680358644F, 0.4719756548F, 0.4759157726F, 0.4798559209F, - 0.4837958024F, 0.4877351199F, 0.4916735765F, 0.4956108751F, - 0.4995467188F, 0.5034808109F, 0.5074128550F, 0.5113425550F, - 0.5152696149F, 0.5191937395F, 0.5231146336F, 0.5270320028F, - 0.5309455530F, 0.5348549910F, 0.5387600239F, 0.5426603597F, - 0.5465557070F, 0.5504457754F, 0.5543302752F, 0.5582089175F, - 0.5620814145F, 0.5659474793F, 0.5698068262F, 0.5736591704F, - 0.5775042283F, 0.5813417176F, 0.5851713571F, 0.5889928670F, - 0.5928059689F, 0.5966103856F, 0.6004058415F, 0.6041920626F, - 0.6079687761F, 0.6117357113F, 0.6154925986F, 0.6192391705F, - 0.6229751612F, 0.6267003064F, 0.6304143441F, 0.6341170137F, - 0.6378080569F, 0.6414872173F, 0.6451542405F, 0.6488088741F, - 0.6524508681F, 0.6560799742F, 0.6596959469F, 0.6632985424F, - 0.6668875197F, 0.6704626398F, 0.6740236662F, 0.6775703649F, - 0.6811025043F, 0.6846198554F, 0.6881221916F, 0.6916092892F, - 0.6950809269F, 0.6985368861F, 0.7019769510F, 0.7054009085F, - 0.7088085484F, 0.7121996632F, 0.7155740484F, 0.7189315023F, - 0.7222718263F, 0.7255948245F, 0.7289003043F, 0.7321880760F, - 0.7354579530F, 0.7387097518F, 0.7419432921F, 0.7451583966F, - 0.7483548915F, 0.7515326059F, 0.7546913723F, 0.7578310265F, - 0.7609514077F, 0.7640523581F, 0.7671337237F, 0.7701953535F, - 0.7732371001F, 0.7762588195F, 0.7792603711F, 0.7822416178F, - 0.7852024259F, 0.7881426654F, 0.7910622097F, 0.7939609356F, - 0.7968387237F, 0.7996954579F, 0.8025310261F, 0.8053453193F, - 0.8081382324F, 0.8109096638F, 0.8136595156F, 0.8163876936F, - 0.8190941071F, 0.8217786690F, 0.8244412960F, 0.8270819086F, - 0.8297004305F, 0.8322967896F, 0.8348709171F, 0.8374227481F, - 0.8399522213F, 0.8424592789F, 0.8449438672F, 0.8474059356F, - 0.8498454378F, 0.8522623306F, 0.8546565748F, 0.8570281348F, - 0.8593769787F, 0.8617030779F, 0.8640064080F, 0.8662869477F, - 0.8685446796F, 0.8707795899F, 0.8729916682F, 0.8751809079F, - 0.8773473059F, 0.8794908626F, 0.8816115819F, 0.8837094713F, - 0.8857845418F, 0.8878368079F, 0.8898662874F, 0.8918730019F, - 0.8938569760F, 0.8958182380F, 0.8977568194F, 0.8996727552F, - 0.9015660837F, 0.9034368465F, 0.9052850885F, 0.9071108577F, - 0.9089142057F, 0.9106951869F, 0.9124538591F, 0.9141902832F, - 0.9159045233F, 0.9175966464F, 0.9192667228F, 0.9209148257F, - 0.9225410313F, 0.9241454187F, 0.9257280701F, 0.9272890704F, - 0.9288285075F, 0.9303464720F, 0.9318430576F, 0.9333183603F, - 0.9347724792F, 0.9362055158F, 0.9376175745F, 0.9390087622F, - 0.9403791881F, 0.9417289644F, 0.9430582055F, 0.9443670283F, - 0.9456555521F, 0.9469238986F, 0.9481721917F, 0.9494005577F, - 0.9506091252F, 0.9517980248F, 0.9529673894F, 0.9541173540F, - 0.9552480557F, 0.9563596334F, 0.9574522282F, 0.9585259830F, - 0.9595810428F, 0.9606175542F, 0.9616356656F, 0.9626355274F, - 0.9636172915F, 0.9645811114F, 0.9655271425F, 0.9664555414F, - 0.9673664664F, 0.9682600774F, 0.9691365355F, 0.9699960034F, - 0.9708386448F, 0.9716646250F, 0.9724741103F, 0.9732672685F, - 0.9740442683F, 0.9748052795F, 0.9755504729F, 0.9762800205F, - 0.9769940950F, 0.9776928703F, 0.9783765210F, 0.9790452223F, - 0.9796991504F, 0.9803384823F, 0.9809633954F, 0.9815740679F, - 0.9821706784F, 0.9827534063F, 0.9833224312F, 0.9838779332F, - 0.9844200928F, 0.9849490910F, 0.9854651087F, 0.9859683274F, - 0.9864589286F, 0.9869370940F, 0.9874030054F, 0.9878568447F, - 0.9882987937F, 0.9887290343F, 0.9891477481F, 0.9895551169F, - 0.9899513220F, 0.9903365446F, 0.9907109658F, 0.9910747662F, - 0.9914281260F, 0.9917712252F, 0.9921042433F, 0.9924273593F, - 0.9927407516F, 0.9930445982F, 0.9933390763F, 0.9936243626F, - 0.9939006331F, 0.9941680631F, 0.9944268269F, 0.9946770982F, - 0.9949190498F, 0.9951528537F, 0.9953786808F, 0.9955967011F, - 0.9958070836F, 0.9960099963F, 0.9962056061F, 0.9963940787F, - 0.9965755786F, 0.9967502693F, 0.9969183129F, 0.9970798704F, - 0.9972351013F, 0.9973841640F, 0.9975272151F, 0.9976644103F, - 0.9977959036F, 0.9979218476F, 0.9980423932F, 0.9981576901F, - 0.9982678862F, 0.9983731278F, 0.9984735596F, 0.9985693247F, - 0.9986605645F, 0.9987474186F, 0.9988300248F, 0.9989085193F, - 0.9989830364F, 0.9990537085F, 0.9991206662F, 0.9991840382F, - 0.9992439513F, 0.9993005303F, 0.9993538982F, 0.9994041757F, - 0.9994514817F, 0.9994959330F, 0.9995376444F, 0.9995767286F, - 0.9996132960F, 0.9996474550F, 0.9996793121F, 0.9997089710F, - 0.9997365339F, 0.9997621003F, 0.9997857677F, 0.9998076311F, - 0.9998277836F, 0.9998463156F, 0.9998633155F, 0.9998788692F, - 0.9998930603F, 0.9999059701F, 0.9999176774F, 0.9999282586F, - 0.9999377880F, 0.9999463370F, 0.9999539749F, 0.9999607685F, - 0.9999667820F, 0.9999720773F, 0.9999767136F, 0.9999807479F, - 0.9999842344F, 0.9999872249F, 0.9999897688F, 0.9999919127F, - 0.9999937009F, 0.9999951749F, 0.9999963738F, 0.9999973342F, - 0.9999980900F, 0.9999986724F, 0.9999991103F, 0.9999994297F, - 0.9999996543F, 0.9999998049F, 0.9999999000F, 0.9999999552F, - 0.9999999836F, 0.9999999957F, 0.9999999994F, 1.0000000000F, -}; - -static const float vwin2048[1024] = { - 0.0000009241F, 0.0000083165F, 0.0000231014F, 0.0000452785F, - 0.0000748476F, 0.0001118085F, 0.0001561608F, 0.0002079041F, - 0.0002670379F, 0.0003335617F, 0.0004074748F, 0.0004887765F, - 0.0005774661F, 0.0006735427F, 0.0007770054F, 0.0008878533F, - 0.0010060853F, 0.0011317002F, 0.0012646969F, 0.0014050742F, - 0.0015528307F, 0.0017079650F, 0.0018704756F, 0.0020403610F, - 0.0022176196F, 0.0024022497F, 0.0025942495F, 0.0027936173F, - 0.0030003511F, 0.0032144490F, 0.0034359088F, 0.0036647286F, - 0.0039009061F, 0.0041444391F, 0.0043953253F, 0.0046535621F, - 0.0049191472F, 0.0051920781F, 0.0054723520F, 0.0057599664F, - 0.0060549184F, 0.0063572052F, 0.0066668239F, 0.0069837715F, - 0.0073080449F, 0.0076396410F, 0.0079785566F, 0.0083247884F, - 0.0086783330F, 0.0090391871F, 0.0094073470F, 0.0097828092F, - 0.0101655700F, 0.0105556258F, 0.0109529726F, 0.0113576065F, - 0.0117695237F, 0.0121887200F, 0.0126151913F, 0.0130489335F, - 0.0134899422F, 0.0139382130F, 0.0143937415F, 0.0148565233F, - 0.0153265536F, 0.0158038279F, 0.0162883413F, 0.0167800889F, - 0.0172790660F, 0.0177852675F, 0.0182986882F, 0.0188193231F, - 0.0193471668F, 0.0198822141F, 0.0204244594F, 0.0209738974F, - 0.0215305225F, 0.0220943289F, 0.0226653109F, 0.0232434627F, - 0.0238287784F, 0.0244212519F, 0.0250208772F, 0.0256276481F, - 0.0262415582F, 0.0268626014F, 0.0274907711F, 0.0281260608F, - 0.0287684638F, 0.0294179736F, 0.0300745833F, 0.0307382859F, - 0.0314090747F, 0.0320869424F, 0.0327718819F, 0.0334638860F, - 0.0341629474F, 0.0348690586F, 0.0355822122F, 0.0363024004F, - 0.0370296157F, 0.0377638502F, 0.0385050960F, 0.0392533451F, - 0.0400085896F, 0.0407708211F, 0.0415400315F, 0.0423162123F, - 0.0430993552F, 0.0438894515F, 0.0446864926F, 0.0454904698F, - 0.0463013742F, 0.0471191969F, 0.0479439288F, 0.0487755607F, - 0.0496140836F, 0.0504594879F, 0.0513117642F, 0.0521709031F, - 0.0530368949F, 0.0539097297F, 0.0547893979F, 0.0556758894F, - 0.0565691941F, 0.0574693019F, 0.0583762026F, 0.0592898858F, - 0.0602103410F, 0.0611375576F, 0.0620715250F, 0.0630122324F, - 0.0639596688F, 0.0649138234F, 0.0658746848F, 0.0668422421F, - 0.0678164838F, 0.0687973985F, 0.0697849746F, 0.0707792005F, - 0.0717800645F, 0.0727875547F, 0.0738016591F, 0.0748223656F, - 0.0758496620F, 0.0768835359F, 0.0779239751F, 0.0789709668F, - 0.0800244985F, 0.0810845574F, 0.0821511306F, 0.0832242052F, - 0.0843037679F, 0.0853898056F, 0.0864823050F, 0.0875812525F, - 0.0886866347F, 0.0897984378F, 0.0909166480F, 0.0920412513F, - 0.0931722338F, 0.0943095813F, 0.0954532795F, 0.0966033140F, - 0.0977596702F, 0.0989223336F, 0.1000912894F, 0.1012665227F, - 0.1024480185F, 0.1036357616F, 0.1048297369F, 0.1060299290F, - 0.1072363224F, 0.1084489014F, 0.1096676504F, 0.1108925534F, - 0.1121235946F, 0.1133607577F, 0.1146040267F, 0.1158533850F, - 0.1171088163F, 0.1183703040F, 0.1196378312F, 0.1209113812F, - 0.1221909370F, 0.1234764815F, 0.1247679974F, 0.1260654674F, - 0.1273688740F, 0.1286781995F, 0.1299934263F, 0.1313145365F, - 0.1326415121F, 0.1339743349F, 0.1353129866F, 0.1366574490F, - 0.1380077035F, 0.1393637315F, 0.1407255141F, 0.1420930325F, - 0.1434662677F, 0.1448452004F, 0.1462298115F, 0.1476200814F, - 0.1490159906F, 0.1504175195F, 0.1518246482F, 0.1532373569F, - 0.1546556253F, 0.1560794333F, 0.1575087606F, 0.1589435866F, - 0.1603838909F, 0.1618296526F, 0.1632808509F, 0.1647374648F, - 0.1661994731F, 0.1676668546F, 0.1691395880F, 0.1706176516F, - 0.1721010238F, 0.1735896829F, 0.1750836068F, 0.1765827736F, - 0.1780871610F, 0.1795967468F, 0.1811115084F, 0.1826314234F, - 0.1841564689F, 0.1856866221F, 0.1872218600F, 0.1887621595F, - 0.1903074974F, 0.1918578503F, 0.1934131947F, 0.1949735068F, - 0.1965387630F, 0.1981089393F, 0.1996840117F, 0.2012639560F, - 0.2028487479F, 0.2044383630F, 0.2060327766F, 0.2076319642F, - 0.2092359007F, 0.2108445614F, 0.2124579211F, 0.2140759545F, - 0.2156986364F, 0.2173259411F, 0.2189578432F, 0.2205943168F, - 0.2222353361F, 0.2238808751F, 0.2255309076F, 0.2271854073F, - 0.2288443480F, 0.2305077030F, 0.2321754457F, 0.2338475493F, - 0.2355239869F, 0.2372047315F, 0.2388897560F, 0.2405790329F, - 0.2422725350F, 0.2439702347F, 0.2456721043F, 0.2473781159F, - 0.2490882418F, 0.2508024539F, 0.2525207240F, 0.2542430237F, - 0.2559693248F, 0.2576995986F, 0.2594338166F, 0.2611719498F, - 0.2629139695F, 0.2646598466F, 0.2664095520F, 0.2681630564F, - 0.2699203304F, 0.2716813445F, 0.2734460691F, 0.2752144744F, - 0.2769865307F, 0.2787622079F, 0.2805414760F, 0.2823243047F, - 0.2841106637F, 0.2859005227F, 0.2876938509F, 0.2894906179F, - 0.2912907928F, 0.2930943447F, 0.2949012426F, 0.2967114554F, - 0.2985249520F, 0.3003417009F, 0.3021616708F, 0.3039848301F, - 0.3058111471F, 0.3076405901F, 0.3094731273F, 0.3113087266F, - 0.3131473560F, 0.3149889833F, 0.3168335762F, 0.3186811024F, - 0.3205315294F, 0.3223848245F, 0.3242409552F, 0.3260998886F, - 0.3279615918F, 0.3298260319F, 0.3316931758F, 0.3335629903F, - 0.3354354423F, 0.3373104982F, 0.3391881247F, 0.3410682882F, - 0.3429509551F, 0.3448360917F, 0.3467236642F, 0.3486136387F, - 0.3505059811F, 0.3524006575F, 0.3542976336F, 0.3561968753F, - 0.3580983482F, 0.3600020179F, 0.3619078499F, 0.3638158096F, - 0.3657258625F, 0.3676379737F, 0.3695521086F, 0.3714682321F, - 0.3733863094F, 0.3753063055F, 0.3772281852F, 0.3791519134F, - 0.3810774548F, 0.3830047742F, 0.3849338362F, 0.3868646053F, - 0.3887970459F, 0.3907311227F, 0.3926667998F, 0.3946040417F, - 0.3965428125F, 0.3984830765F, 0.4004247978F, 0.4023679403F, - 0.4043124683F, 0.4062583455F, 0.4082055359F, 0.4101540034F, - 0.4121037117F, 0.4140546246F, 0.4160067058F, 0.4179599190F, - 0.4199142277F, 0.4218695956F, 0.4238259861F, 0.4257833627F, - 0.4277416888F, 0.4297009279F, 0.4316610433F, 0.4336219983F, - 0.4355837562F, 0.4375462803F, 0.4395095337F, 0.4414734797F, - 0.4434380815F, 0.4454033021F, 0.4473691046F, 0.4493354521F, - 0.4513023078F, 0.4532696345F, 0.4552373954F, 0.4572055533F, - 0.4591740713F, 0.4611429123F, 0.4631120393F, 0.4650814151F, - 0.4670510028F, 0.4690207650F, 0.4709906649F, 0.4729606651F, - 0.4749307287F, 0.4769008185F, 0.4788708972F, 0.4808409279F, - 0.4828108732F, 0.4847806962F, 0.4867503597F, 0.4887198264F, - 0.4906890593F, 0.4926580213F, 0.4946266753F, 0.4965949840F, - 0.4985629105F, 0.5005304176F, 0.5024974683F, 0.5044640255F, - 0.5064300522F, 0.5083955114F, 0.5103603659F, 0.5123245790F, - 0.5142881136F, 0.5162509328F, 0.5182129997F, 0.5201742774F, - 0.5221347290F, 0.5240943178F, 0.5260530070F, 0.5280107598F, - 0.5299675395F, 0.5319233095F, 0.5338780330F, 0.5358316736F, - 0.5377841946F, 0.5397355596F, 0.5416857320F, 0.5436346755F, - 0.5455823538F, 0.5475287304F, 0.5494737691F, 0.5514174337F, - 0.5533596881F, 0.5553004962F, 0.5572398218F, 0.5591776291F, - 0.5611138821F, 0.5630485449F, 0.5649815818F, 0.5669129570F, - 0.5688426349F, 0.5707705799F, 0.5726967564F, 0.5746211290F, - 0.5765436624F, 0.5784643212F, 0.5803830702F, 0.5822998743F, - 0.5842146984F, 0.5861275076F, 0.5880382669F, 0.5899469416F, - 0.5918534968F, 0.5937578981F, 0.5956601107F, 0.5975601004F, - 0.5994578326F, 0.6013532732F, 0.6032463880F, 0.6051371429F, - 0.6070255039F, 0.6089114372F, 0.6107949090F, 0.6126758856F, - 0.6145543334F, 0.6164302191F, 0.6183035092F, 0.6201741706F, - 0.6220421700F, 0.6239074745F, 0.6257700513F, 0.6276298674F, - 0.6294868903F, 0.6313410873F, 0.6331924262F, 0.6350408745F, - 0.6368864001F, 0.6387289710F, 0.6405685552F, 0.6424051209F, - 0.6442386364F, 0.6460690702F, 0.6478963910F, 0.6497205673F, - 0.6515415682F, 0.6533593625F, 0.6551739194F, 0.6569852082F, - 0.6587931984F, 0.6605978593F, 0.6623991609F, 0.6641970728F, - 0.6659915652F, 0.6677826081F, 0.6695701718F, 0.6713542268F, - 0.6731347437F, 0.6749116932F, 0.6766850461F, 0.6784547736F, - 0.6802208469F, 0.6819832374F, 0.6837419164F, 0.6854968559F, - 0.6872480275F, 0.6889954034F, 0.6907389556F, 0.6924786566F, - 0.6942144788F, 0.6959463950F, 0.6976743780F, 0.6993984008F, - 0.7011184365F, 0.7028344587F, 0.7045464407F, 0.7062543564F, - 0.7079581796F, 0.7096578844F, 0.7113534450F, 0.7130448359F, - 0.7147320316F, 0.7164150070F, 0.7180937371F, 0.7197681970F, - 0.7214383620F, 0.7231042077F, 0.7247657098F, 0.7264228443F, - 0.7280755871F, 0.7297239147F, 0.7313678035F, 0.7330072301F, - 0.7346421715F, 0.7362726046F, 0.7378985069F, 0.7395198556F, - 0.7411366285F, 0.7427488034F, 0.7443563584F, 0.7459592717F, - 0.7475575218F, 0.7491510873F, 0.7507399471F, 0.7523240803F, - 0.7539034661F, 0.7554780839F, 0.7570479136F, 0.7586129349F, - 0.7601731279F, 0.7617284730F, 0.7632789506F, 0.7648245416F, - 0.7663652267F, 0.7679009872F, 0.7694318044F, 0.7709576599F, - 0.7724785354F, 0.7739944130F, 0.7755052749F, 0.7770111035F, - 0.7785118815F, 0.7800075916F, 0.7814982170F, 0.7829837410F, - 0.7844641472F, 0.7859394191F, 0.7874095408F, 0.7888744965F, - 0.7903342706F, 0.7917888476F, 0.7932382124F, 0.7946823501F, - 0.7961212460F, 0.7975548855F, 0.7989832544F, 0.8004063386F, - 0.8018241244F, 0.8032365981F, 0.8046437463F, 0.8060455560F, - 0.8074420141F, 0.8088331080F, 0.8102188253F, 0.8115991536F, - 0.8129740810F, 0.8143435957F, 0.8157076861F, 0.8170663409F, - 0.8184195489F, 0.8197672994F, 0.8211095817F, 0.8224463853F, - 0.8237777001F, 0.8251035161F, 0.8264238235F, 0.8277386129F, - 0.8290478750F, 0.8303516008F, 0.8316497814F, 0.8329424083F, - 0.8342294731F, 0.8355109677F, 0.8367868841F, 0.8380572148F, - 0.8393219523F, 0.8405810893F, 0.8418346190F, 0.8430825345F, - 0.8443248294F, 0.8455614974F, 0.8467925323F, 0.8480179285F, - 0.8492376802F, 0.8504517822F, 0.8516602292F, 0.8528630164F, - 0.8540601391F, 0.8552515928F, 0.8564373733F, 0.8576174766F, - 0.8587918990F, 0.8599606368F, 0.8611236868F, 0.8622810460F, - 0.8634327113F, 0.8645786802F, 0.8657189504F, 0.8668535195F, - 0.8679823857F, 0.8691055472F, 0.8702230025F, 0.8713347503F, - 0.8724407896F, 0.8735411194F, 0.8746357394F, 0.8757246489F, - 0.8768078479F, 0.8778853364F, 0.8789571146F, 0.8800231832F, - 0.8810835427F, 0.8821381942F, 0.8831871387F, 0.8842303777F, - 0.8852679127F, 0.8862997456F, 0.8873258784F, 0.8883463132F, - 0.8893610527F, 0.8903700994F, 0.8913734562F, 0.8923711263F, - 0.8933631129F, 0.8943494196F, 0.8953300500F, 0.8963050083F, - 0.8972742985F, 0.8982379249F, 0.8991958922F, 0.9001482052F, - 0.9010948688F, 0.9020358883F, 0.9029712690F, 0.9039010165F, - 0.9048251367F, 0.9057436357F, 0.9066565195F, 0.9075637946F, - 0.9084654678F, 0.9093615456F, 0.9102520353F, 0.9111369440F, - 0.9120162792F, 0.9128900484F, 0.9137582595F, 0.9146209204F, - 0.9154780394F, 0.9163296248F, 0.9171756853F, 0.9180162296F, - 0.9188512667F, 0.9196808057F, 0.9205048559F, 0.9213234270F, - 0.9221365285F, 0.9229441704F, 0.9237463629F, 0.9245431160F, - 0.9253344404F, 0.9261203465F, 0.9269008453F, 0.9276759477F, - 0.9284456648F, 0.9292100080F, 0.9299689889F, 0.9307226190F, - 0.9314709103F, 0.9322138747F, 0.9329515245F, 0.9336838721F, - 0.9344109300F, 0.9351327108F, 0.9358492275F, 0.9365604931F, - 0.9372665208F, 0.9379673239F, 0.9386629160F, 0.9393533107F, - 0.9400385220F, 0.9407185637F, 0.9413934501F, 0.9420631954F, - 0.9427278141F, 0.9433873208F, 0.9440417304F, 0.9446910576F, - 0.9453353176F, 0.9459745255F, 0.9466086968F, 0.9472378469F, - 0.9478619915F, 0.9484811463F, 0.9490953274F, 0.9497045506F, - 0.9503088323F, 0.9509081888F, 0.9515026365F, 0.9520921921F, - 0.9526768723F, 0.9532566940F, 0.9538316742F, 0.9544018300F, - 0.9549671786F, 0.9555277375F, 0.9560835241F, 0.9566345562F, - 0.9571808513F, 0.9577224275F, 0.9582593027F, 0.9587914949F, - 0.9593190225F, 0.9598419038F, 0.9603601571F, 0.9608738012F, - 0.9613828546F, 0.9618873361F, 0.9623872646F, 0.9628826591F, - 0.9633735388F, 0.9638599227F, 0.9643418303F, 0.9648192808F, - 0.9652922939F, 0.9657608890F, 0.9662250860F, 0.9666849046F, - 0.9671403646F, 0.9675914861F, 0.9680382891F, 0.9684807937F, - 0.9689190202F, 0.9693529890F, 0.9697827203F, 0.9702082347F, - 0.9706295529F, 0.9710466953F, 0.9714596828F, 0.9718685362F, - 0.9722732762F, 0.9726739240F, 0.9730705005F, 0.9734630267F, - 0.9738515239F, 0.9742360134F, 0.9746165163F, 0.9749930540F, - 0.9753656481F, 0.9757343198F, 0.9760990909F, 0.9764599829F, - 0.9768170175F, 0.9771702164F, 0.9775196013F, 0.9778651941F, - 0.9782070167F, 0.9785450909F, 0.9788794388F, 0.9792100824F, - 0.9795370437F, 0.9798603449F, 0.9801800080F, 0.9804960554F, - 0.9808085092F, 0.9811173916F, 0.9814227251F, 0.9817245318F, - 0.9820228343F, 0.9823176549F, 0.9826090160F, 0.9828969402F, - 0.9831814498F, 0.9834625674F, 0.9837403156F, 0.9840147169F, - 0.9842857939F, 0.9845535692F, 0.9848180654F, 0.9850793052F, - 0.9853373113F, 0.9855921062F, 0.9858437127F, 0.9860921535F, - 0.9863374512F, 0.9865796287F, 0.9868187085F, 0.9870547136F, - 0.9872876664F, 0.9875175899F, 0.9877445067F, 0.9879684396F, - 0.9881894112F, 0.9884074444F, 0.9886225619F, 0.9888347863F, - 0.9890441404F, 0.9892506468F, 0.9894543284F, 0.9896552077F, - 0.9898533074F, 0.9900486502F, 0.9902412587F, 0.9904311555F, - 0.9906183633F, 0.9908029045F, 0.9909848019F, 0.9911640779F, - 0.9913407550F, 0.9915148557F, 0.9916864025F, 0.9918554179F, - 0.9920219241F, 0.9921859437F, 0.9923474989F, 0.9925066120F, - 0.9926633054F, 0.9928176012F, 0.9929695218F, 0.9931190891F, - 0.9932663254F, 0.9934112527F, 0.9935538932F, 0.9936942686F, - 0.9938324012F, 0.9939683126F, 0.9941020248F, 0.9942335597F, - 0.9943629388F, 0.9944901841F, 0.9946153170F, 0.9947383593F, - 0.9948593325F, 0.9949782579F, 0.9950951572F, 0.9952100516F, - 0.9953229625F, 0.9954339111F, 0.9955429186F, 0.9956500062F, - 0.9957551948F, 0.9958585056F, 0.9959599593F, 0.9960595769F, - 0.9961573792F, 0.9962533869F, 0.9963476206F, 0.9964401009F, - 0.9965308483F, 0.9966198833F, 0.9967072261F, 0.9967928971F, - 0.9968769164F, 0.9969593041F, 0.9970400804F, 0.9971192651F, - 0.9971968781F, 0.9972729391F, 0.9973474680F, 0.9974204842F, - 0.9974920074F, 0.9975620569F, 0.9976306521F, 0.9976978122F, - 0.9977635565F, 0.9978279039F, 0.9978908736F, 0.9979524842F, - 0.9980127547F, 0.9980717037F, 0.9981293499F, 0.9981857116F, - 0.9982408073F, 0.9982946554F, 0.9983472739F, 0.9983986810F, - 0.9984488947F, 0.9984979328F, 0.9985458132F, 0.9985925534F, - 0.9986381711F, 0.9986826838F, 0.9987261086F, 0.9987684630F, - 0.9988097640F, 0.9988500286F, 0.9988892738F, 0.9989275163F, - 0.9989647727F, 0.9990010597F, 0.9990363938F, 0.9990707911F, - 0.9991042679F, 0.9991368404F, 0.9991685244F, 0.9991993358F, - 0.9992292905F, 0.9992584038F, 0.9992866914F, 0.9993141686F, - 0.9993408506F, 0.9993667526F, 0.9993918895F, 0.9994162761F, - 0.9994399273F, 0.9994628576F, 0.9994850815F, 0.9995066133F, - 0.9995274672F, 0.9995476574F, 0.9995671978F, 0.9995861021F, - 0.9996043841F, 0.9996220573F, 0.9996391352F, 0.9996556310F, - 0.9996715579F, 0.9996869288F, 0.9997017568F, 0.9997160543F, - 0.9997298342F, 0.9997431088F, 0.9997558905F, 0.9997681914F, - 0.9997800236F, 0.9997913990F, 0.9998023292F, 0.9998128261F, - 0.9998229009F, 0.9998325650F, 0.9998418296F, 0.9998507058F, - 0.9998592044F, 0.9998673362F, 0.9998751117F, 0.9998825415F, - 0.9998896358F, 0.9998964047F, 0.9999028584F, 0.9999090066F, - 0.9999148590F, 0.9999204253F, 0.9999257148F, 0.9999307368F, - 0.9999355003F, 0.9999400144F, 0.9999442878F, 0.9999483293F, - 0.9999521472F, 0.9999557499F, 0.9999591457F, 0.9999623426F, - 0.9999653483F, 0.9999681708F, 0.9999708175F, 0.9999732959F, - 0.9999756132F, 0.9999777765F, 0.9999797928F, 0.9999816688F, - 0.9999834113F, 0.9999850266F, 0.9999865211F, 0.9999879009F, - 0.9999891721F, 0.9999903405F, 0.9999914118F, 0.9999923914F, - 0.9999932849F, 0.9999940972F, 0.9999948336F, 0.9999954989F, - 0.9999960978F, 0.9999966349F, 0.9999971146F, 0.9999975411F, - 0.9999979185F, 0.9999982507F, 0.9999985414F, 0.9999987944F, - 0.9999990129F, 0.9999992003F, 0.9999993596F, 0.9999994939F, - 0.9999996059F, 0.9999996981F, 0.9999997732F, 0.9999998333F, - 0.9999998805F, 0.9999999170F, 0.9999999444F, 0.9999999643F, - 0.9999999784F, 0.9999999878F, 0.9999999937F, 0.9999999972F, - 0.9999999990F, 0.9999999997F, 1.0000000000F, 1.0000000000F, -}; - -static const float vwin4096[2048] = { - 0.0000002310F, 0.0000020791F, 0.0000057754F, 0.0000113197F, - 0.0000187121F, 0.0000279526F, 0.0000390412F, 0.0000519777F, - 0.0000667623F, 0.0000833949F, 0.0001018753F, 0.0001222036F, - 0.0001443798F, 0.0001684037F, 0.0001942754F, 0.0002219947F, - 0.0002515616F, 0.0002829761F, 0.0003162380F, 0.0003513472F, - 0.0003883038F, 0.0004271076F, 0.0004677584F, 0.0005102563F, - 0.0005546011F, 0.0006007928F, 0.0006488311F, 0.0006987160F, - 0.0007504474F, 0.0008040251F, 0.0008594490F, 0.0009167191F, - 0.0009758351F, 0.0010367969F, 0.0010996044F, 0.0011642574F, - 0.0012307558F, 0.0012990994F, 0.0013692880F, 0.0014413216F, - 0.0015151998F, 0.0015909226F, 0.0016684898F, 0.0017479011F, - 0.0018291565F, 0.0019122556F, 0.0019971983F, 0.0020839845F, - 0.0021726138F, 0.0022630861F, 0.0023554012F, 0.0024495588F, - 0.0025455588F, 0.0026434008F, 0.0027430847F, 0.0028446103F, - 0.0029479772F, 0.0030531853F, 0.0031602342F, 0.0032691238F, - 0.0033798538F, 0.0034924239F, 0.0036068338F, 0.0037230833F, - 0.0038411721F, 0.0039610999F, 0.0040828664F, 0.0042064714F, - 0.0043319145F, 0.0044591954F, 0.0045883139F, 0.0047192696F, - 0.0048520622F, 0.0049866914F, 0.0051231569F, 0.0052614583F, - 0.0054015953F, 0.0055435676F, 0.0056873748F, 0.0058330166F, - 0.0059804926F, 0.0061298026F, 0.0062809460F, 0.0064339226F, - 0.0065887320F, 0.0067453738F, 0.0069038476F, 0.0070641531F, - 0.0072262899F, 0.0073902575F, 0.0075560556F, 0.0077236838F, - 0.0078931417F, 0.0080644288F, 0.0082375447F, 0.0084124891F, - 0.0085892615F, 0.0087678614F, 0.0089482885F, 0.0091305422F, - 0.0093146223F, 0.0095005281F, 0.0096882592F, 0.0098778153F, - 0.0100691958F, 0.0102624002F, 0.0104574281F, 0.0106542791F, - 0.0108529525F, 0.0110534480F, 0.0112557651F, 0.0114599032F, - 0.0116658618F, 0.0118736405F, 0.0120832387F, 0.0122946560F, - 0.0125078917F, 0.0127229454F, 0.0129398166F, 0.0131585046F, - 0.0133790090F, 0.0136013292F, 0.0138254647F, 0.0140514149F, - 0.0142791792F, 0.0145087572F, 0.0147401481F, 0.0149733515F, - 0.0152083667F, 0.0154451932F, 0.0156838304F, 0.0159242777F, - 0.0161665345F, 0.0164106001F, 0.0166564741F, 0.0169041557F, - 0.0171536443F, 0.0174049393F, 0.0176580401F, 0.0179129461F, - 0.0181696565F, 0.0184281708F, 0.0186884883F, 0.0189506084F, - 0.0192145303F, 0.0194802535F, 0.0197477772F, 0.0200171008F, - 0.0202882236F, 0.0205611449F, 0.0208358639F, 0.0211123801F, - 0.0213906927F, 0.0216708011F, 0.0219527043F, 0.0222364019F, - 0.0225218930F, 0.0228091769F, 0.0230982529F, 0.0233891203F, - 0.0236817782F, 0.0239762259F, 0.0242724628F, 0.0245704880F, - 0.0248703007F, 0.0251719002F, 0.0254752858F, 0.0257804565F, - 0.0260874117F, 0.0263961506F, 0.0267066722F, 0.0270189760F, - 0.0273330609F, 0.0276489263F, 0.0279665712F, 0.0282859949F, - 0.0286071966F, 0.0289301753F, 0.0292549303F, 0.0295814607F, - 0.0299097656F, 0.0302398442F, 0.0305716957F, 0.0309053191F, - 0.0312407135F, 0.0315778782F, 0.0319168122F, 0.0322575145F, - 0.0325999844F, 0.0329442209F, 0.0332902231F, 0.0336379900F, - 0.0339875208F, 0.0343388146F, 0.0346918703F, 0.0350466871F, - 0.0354032640F, 0.0357616000F, 0.0361216943F, 0.0364835458F, - 0.0368471535F, 0.0372125166F, 0.0375796339F, 0.0379485046F, - 0.0383191276F, 0.0386915020F, 0.0390656267F, 0.0394415008F, - 0.0398191231F, 0.0401984927F, 0.0405796086F, 0.0409624698F, - 0.0413470751F, 0.0417334235F, 0.0421215141F, 0.0425113457F, - 0.0429029172F, 0.0432962277F, 0.0436912760F, 0.0440880610F, - 0.0444865817F, 0.0448868370F, 0.0452888257F, 0.0456925468F, - 0.0460979992F, 0.0465051816F, 0.0469140931F, 0.0473247325F, - 0.0477370986F, 0.0481511902F, 0.0485670064F, 0.0489845458F, - 0.0494038074F, 0.0498247899F, 0.0502474922F, 0.0506719131F, - 0.0510980514F, 0.0515259060F, 0.0519554756F, 0.0523867590F, - 0.0528197550F, 0.0532544624F, 0.0536908800F, 0.0541290066F, - 0.0545688408F, 0.0550103815F, 0.0554536274F, 0.0558985772F, - 0.0563452297F, 0.0567935837F, 0.0572436377F, 0.0576953907F, - 0.0581488412F, 0.0586039880F, 0.0590608297F, 0.0595193651F, - 0.0599795929F, 0.0604415117F, 0.0609051202F, 0.0613704170F, - 0.0618374009F, 0.0623060704F, 0.0627764243F, 0.0632484611F, - 0.0637221795F, 0.0641975781F, 0.0646746555F, 0.0651534104F, - 0.0656338413F, 0.0661159469F, 0.0665997257F, 0.0670851763F, - 0.0675722973F, 0.0680610873F, 0.0685515448F, 0.0690436684F, - 0.0695374567F, 0.0700329081F, 0.0705300213F, 0.0710287947F, - 0.0715292269F, 0.0720313163F, 0.0725350616F, 0.0730404612F, - 0.0735475136F, 0.0740562172F, 0.0745665707F, 0.0750785723F, - 0.0755922207F, 0.0761075143F, 0.0766244515F, 0.0771430307F, - 0.0776632505F, 0.0781851092F, 0.0787086052F, 0.0792337371F, - 0.0797605032F, 0.0802889018F, 0.0808189315F, 0.0813505905F, - 0.0818838773F, 0.0824187903F, 0.0829553277F, 0.0834934881F, - 0.0840332697F, 0.0845746708F, 0.0851176899F, 0.0856623252F, - 0.0862085751F, 0.0867564379F, 0.0873059119F, 0.0878569954F, - 0.0884096867F, 0.0889639840F, 0.0895198858F, 0.0900773902F, - 0.0906364955F, 0.0911972000F, 0.0917595019F, 0.0923233995F, - 0.0928888909F, 0.0934559745F, 0.0940246485F, 0.0945949110F, - 0.0951667604F, 0.0957401946F, 0.0963152121F, 0.0968918109F, - 0.0974699893F, 0.0980497454F, 0.0986310773F, 0.0992139832F, - 0.0997984614F, 0.1003845098F, 0.1009721267F, 0.1015613101F, - 0.1021520582F, 0.1027443692F, 0.1033382410F, 0.1039336718F, - 0.1045306597F, 0.1051292027F, 0.1057292990F, 0.1063309466F, - 0.1069341435F, 0.1075388878F, 0.1081451776F, 0.1087530108F, - 0.1093623856F, 0.1099732998F, 0.1105857516F, 0.1111997389F, - 0.1118152597F, 0.1124323121F, 0.1130508939F, 0.1136710032F, - 0.1142926379F, 0.1149157960F, 0.1155404755F, 0.1161666742F, - 0.1167943901F, 0.1174236211F, 0.1180543652F, 0.1186866202F, - 0.1193203841F, 0.1199556548F, 0.1205924300F, 0.1212307078F, - 0.1218704860F, 0.1225117624F, 0.1231545349F, 0.1237988013F, - 0.1244445596F, 0.1250918074F, 0.1257405427F, 0.1263907632F, - 0.1270424667F, 0.1276956512F, 0.1283503142F, 0.1290064537F, - 0.1296640674F, 0.1303231530F, 0.1309837084F, 0.1316457312F, - 0.1323092193F, 0.1329741703F, 0.1336405820F, 0.1343084520F, - 0.1349777782F, 0.1356485582F, 0.1363207897F, 0.1369944704F, - 0.1376695979F, 0.1383461700F, 0.1390241842F, 0.1397036384F, - 0.1403845300F, 0.1410668567F, 0.1417506162F, 0.1424358061F, - 0.1431224240F, 0.1438104674F, 0.1444999341F, 0.1451908216F, - 0.1458831274F, 0.1465768492F, 0.1472719844F, 0.1479685308F, - 0.1486664857F, 0.1493658468F, 0.1500666115F, 0.1507687775F, - 0.1514723422F, 0.1521773031F, 0.1528836577F, 0.1535914035F, - 0.1543005380F, 0.1550110587F, 0.1557229631F, 0.1564362485F, - 0.1571509124F, 0.1578669524F, 0.1585843657F, 0.1593031499F, - 0.1600233024F, 0.1607448205F, 0.1614677017F, 0.1621919433F, - 0.1629175428F, 0.1636444975F, 0.1643728047F, 0.1651024619F, - 0.1658334665F, 0.1665658156F, 0.1672995067F, 0.1680345371F, - 0.1687709041F, 0.1695086050F, 0.1702476372F, 0.1709879978F, - 0.1717296843F, 0.1724726938F, 0.1732170237F, 0.1739626711F, - 0.1747096335F, 0.1754579079F, 0.1762074916F, 0.1769583819F, - 0.1777105760F, 0.1784640710F, 0.1792188642F, 0.1799749529F, - 0.1807323340F, 0.1814910049F, 0.1822509628F, 0.1830122046F, - 0.1837747277F, 0.1845385292F, 0.1853036062F, 0.1860699558F, - 0.1868375751F, 0.1876064613F, 0.1883766114F, 0.1891480226F, - 0.1899206919F, 0.1906946164F, 0.1914697932F, 0.1922462194F, - 0.1930238919F, 0.1938028079F, 0.1945829643F, 0.1953643583F, - 0.1961469868F, 0.1969308468F, 0.1977159353F, 0.1985022494F, - 0.1992897859F, 0.2000785420F, 0.2008685145F, 0.2016597005F, - 0.2024520968F, 0.2032457005F, 0.2040405084F, 0.2048365175F, - 0.2056337247F, 0.2064321269F, 0.2072317211F, 0.2080325041F, - 0.2088344727F, 0.2096376240F, 0.2104419547F, 0.2112474618F, - 0.2120541420F, 0.2128619923F, 0.2136710094F, 0.2144811902F, - 0.2152925315F, 0.2161050301F, 0.2169186829F, 0.2177334866F, - 0.2185494381F, 0.2193665340F, 0.2201847712F, 0.2210041465F, - 0.2218246565F, 0.2226462981F, 0.2234690680F, 0.2242929629F, - 0.2251179796F, 0.2259441147F, 0.2267713650F, 0.2275997272F, - 0.2284291979F, 0.2292597739F, 0.2300914518F, 0.2309242283F, - 0.2317581001F, 0.2325930638F, 0.2334291160F, 0.2342662534F, - 0.2351044727F, 0.2359437703F, 0.2367841431F, 0.2376255875F, - 0.2384681001F, 0.2393116776F, 0.2401563165F, 0.2410020134F, - 0.2418487649F, 0.2426965675F, 0.2435454178F, 0.2443953122F, - 0.2452462474F, 0.2460982199F, 0.2469512262F, 0.2478052628F, - 0.2486603262F, 0.2495164129F, 0.2503735194F, 0.2512316421F, - 0.2520907776F, 0.2529509222F, 0.2538120726F, 0.2546742250F, - 0.2555373760F, 0.2564015219F, 0.2572666593F, 0.2581327845F, - 0.2589998939F, 0.2598679840F, 0.2607370510F, 0.2616070916F, - 0.2624781019F, 0.2633500783F, 0.2642230173F, 0.2650969152F, - 0.2659717684F, 0.2668475731F, 0.2677243257F, 0.2686020226F, - 0.2694806601F, 0.2703602344F, 0.2712407419F, 0.2721221789F, - 0.2730045417F, 0.2738878265F, 0.2747720297F, 0.2756571474F, - 0.2765431760F, 0.2774301117F, 0.2783179508F, 0.2792066895F, - 0.2800963240F, 0.2809868505F, 0.2818782654F, 0.2827705647F, - 0.2836637447F, 0.2845578016F, 0.2854527315F, 0.2863485307F, - 0.2872451953F, 0.2881427215F, 0.2890411055F, 0.2899403433F, - 0.2908404312F, 0.2917413654F, 0.2926431418F, 0.2935457567F, - 0.2944492061F, 0.2953534863F, 0.2962585932F, 0.2971645230F, - 0.2980712717F, 0.2989788356F, 0.2998872105F, 0.3007963927F, - 0.3017063781F, 0.3026171629F, 0.3035287430F, 0.3044411145F, - 0.3053542736F, 0.3062682161F, 0.3071829381F, 0.3080984356F, - 0.3090147047F, 0.3099317413F, 0.3108495414F, 0.3117681011F, - 0.3126874163F, 0.3136074830F, 0.3145282972F, 0.3154498548F, - 0.3163721517F, 0.3172951841F, 0.3182189477F, 0.3191434385F, - 0.3200686525F, 0.3209945856F, 0.3219212336F, 0.3228485927F, - 0.3237766585F, 0.3247054271F, 0.3256348943F, 0.3265650560F, - 0.3274959081F, 0.3284274465F, 0.3293596671F, 0.3302925657F, - 0.3312261382F, 0.3321603804F, 0.3330952882F, 0.3340308574F, - 0.3349670838F, 0.3359039634F, 0.3368414919F, 0.3377796651F, - 0.3387184789F, 0.3396579290F, 0.3405980113F, 0.3415387216F, - 0.3424800556F, 0.3434220091F, 0.3443645779F, 0.3453077578F, - 0.3462515446F, 0.3471959340F, 0.3481409217F, 0.3490865036F, - 0.3500326754F, 0.3509794328F, 0.3519267715F, 0.3528746873F, - 0.3538231759F, 0.3547722330F, 0.3557218544F, 0.3566720357F, - 0.3576227727F, 0.3585740610F, 0.3595258964F, 0.3604782745F, - 0.3614311910F, 0.3623846417F, 0.3633386221F, 0.3642931280F, - 0.3652481549F, 0.3662036987F, 0.3671597548F, 0.3681163191F, - 0.3690733870F, 0.3700309544F, 0.3709890167F, 0.3719475696F, - 0.3729066089F, 0.3738661299F, 0.3748261285F, 0.3757866002F, - 0.3767475406F, 0.3777089453F, 0.3786708100F, 0.3796331302F, - 0.3805959014F, 0.3815591194F, 0.3825227796F, 0.3834868777F, - 0.3844514093F, 0.3854163698F, 0.3863817549F, 0.3873475601F, - 0.3883137810F, 0.3892804131F, 0.3902474521F, 0.3912148933F, - 0.3921827325F, 0.3931509650F, 0.3941195865F, 0.3950885925F, - 0.3960579785F, 0.3970277400F, 0.3979978725F, 0.3989683716F, - 0.3999392328F, 0.4009104516F, 0.4018820234F, 0.4028539438F, - 0.4038262084F, 0.4047988125F, 0.4057717516F, 0.4067450214F, - 0.4077186172F, 0.4086925345F, 0.4096667688F, 0.4106413155F, - 0.4116161703F, 0.4125913284F, 0.4135667854F, 0.4145425368F, - 0.4155185780F, 0.4164949044F, 0.4174715116F, 0.4184483949F, - 0.4194255498F, 0.4204029718F, 0.4213806563F, 0.4223585987F, - 0.4233367946F, 0.4243152392F, 0.4252939281F, 0.4262728566F, - 0.4272520202F, 0.4282314144F, 0.4292110345F, 0.4301908760F, - 0.4311709343F, 0.4321512047F, 0.4331316828F, 0.4341123639F, - 0.4350932435F, 0.4360743168F, 0.4370555794F, 0.4380370267F, - 0.4390186540F, 0.4400004567F, 0.4409824303F, 0.4419645701F, - 0.4429468716F, 0.4439293300F, 0.4449119409F, 0.4458946996F, - 0.4468776014F, 0.4478606418F, 0.4488438162F, 0.4498271199F, - 0.4508105483F, 0.4517940967F, 0.4527777607F, 0.4537615355F, - 0.4547454165F, 0.4557293991F, 0.4567134786F, 0.4576976505F, - 0.4586819101F, 0.4596662527F, 0.4606506738F, 0.4616351687F, - 0.4626197328F, 0.4636043614F, 0.4645890499F, 0.4655737936F, - 0.4665585880F, 0.4675434284F, 0.4685283101F, 0.4695132286F, - 0.4704981791F, 0.4714831570F, 0.4724681577F, 0.4734531766F, - 0.4744382089F, 0.4754232501F, 0.4764082956F, 0.4773933406F, - 0.4783783806F, 0.4793634108F, 0.4803484267F, 0.4813334237F, - 0.4823183969F, 0.4833033419F, 0.4842882540F, 0.4852731285F, - 0.4862579608F, 0.4872427462F, 0.4882274802F, 0.4892121580F, - 0.4901967751F, 0.4911813267F, 0.4921658083F, 0.4931502151F, - 0.4941345427F, 0.4951187863F, 0.4961029412F, 0.4970870029F, - 0.4980709667F, 0.4990548280F, 0.5000385822F, 0.5010222245F, - 0.5020057505F, 0.5029891553F, 0.5039724345F, 0.5049555834F, - 0.5059385973F, 0.5069214716F, 0.5079042018F, 0.5088867831F, - 0.5098692110F, 0.5108514808F, 0.5118335879F, 0.5128155277F, - 0.5137972956F, 0.5147788869F, 0.5157602971F, 0.5167415215F, - 0.5177225555F, 0.5187033945F, 0.5196840339F, 0.5206644692F, - 0.5216446956F, 0.5226247086F, 0.5236045035F, 0.5245840759F, - 0.5255634211F, 0.5265425344F, 0.5275214114F, 0.5285000474F, - 0.5294784378F, 0.5304565781F, 0.5314344637F, 0.5324120899F, - 0.5333894522F, 0.5343665461F, 0.5353433670F, 0.5363199102F, - 0.5372961713F, 0.5382721457F, 0.5392478287F, 0.5402232159F, - 0.5411983027F, 0.5421730845F, 0.5431475569F, 0.5441217151F, - 0.5450955548F, 0.5460690714F, 0.5470422602F, 0.5480151169F, - 0.5489876368F, 0.5499598155F, 0.5509316484F, 0.5519031310F, - 0.5528742587F, 0.5538450271F, 0.5548154317F, 0.5557854680F, - 0.5567551314F, 0.5577244174F, 0.5586933216F, 0.5596618395F, - 0.5606299665F, 0.5615976983F, 0.5625650302F, 0.5635319580F, - 0.5644984770F, 0.5654645828F, 0.5664302709F, 0.5673955370F, - 0.5683603765F, 0.5693247850F, 0.5702887580F, 0.5712522912F, - 0.5722153800F, 0.5731780200F, 0.5741402069F, 0.5751019362F, - 0.5760632034F, 0.5770240042F, 0.5779843341F, 0.5789441889F, - 0.5799035639F, 0.5808624549F, 0.5818208575F, 0.5827787673F, - 0.5837361800F, 0.5846930910F, 0.5856494961F, 0.5866053910F, - 0.5875607712F, 0.5885156324F, 0.5894699703F, 0.5904237804F, - 0.5913770586F, 0.5923298004F, 0.5932820016F, 0.5942336578F, - 0.5951847646F, 0.5961353179F, 0.5970853132F, 0.5980347464F, - 0.5989836131F, 0.5999319090F, 0.6008796298F, 0.6018267713F, - 0.6027733292F, 0.6037192993F, 0.6046646773F, 0.6056094589F, - 0.6065536400F, 0.6074972162F, 0.6084401833F, 0.6093825372F, - 0.6103242736F, 0.6112653884F, 0.6122058772F, 0.6131457359F, - 0.6140849604F, 0.6150235464F, 0.6159614897F, 0.6168987862F, - 0.6178354318F, 0.6187714223F, 0.6197067535F, 0.6206414213F, - 0.6215754215F, 0.6225087501F, 0.6234414028F, 0.6243733757F, - 0.6253046646F, 0.6262352654F, 0.6271651739F, 0.6280943862F, - 0.6290228982F, 0.6299507057F, 0.6308778048F, 0.6318041913F, - 0.6327298612F, 0.6336548105F, 0.6345790352F, 0.6355025312F, - 0.6364252945F, 0.6373473211F, 0.6382686070F, 0.6391891483F, - 0.6401089409F, 0.6410279808F, 0.6419462642F, 0.6428637869F, - 0.6437805452F, 0.6446965350F, 0.6456117524F, 0.6465261935F, - 0.6474398544F, 0.6483527311F, 0.6492648197F, 0.6501761165F, - 0.6510866174F, 0.6519963186F, 0.6529052162F, 0.6538133064F, - 0.6547205854F, 0.6556270492F, 0.6565326941F, 0.6574375162F, - 0.6583415117F, 0.6592446769F, 0.6601470079F, 0.6610485009F, - 0.6619491521F, 0.6628489578F, 0.6637479143F, 0.6646460177F, - 0.6655432643F, 0.6664396505F, 0.6673351724F, 0.6682298264F, - 0.6691236087F, 0.6700165157F, 0.6709085436F, 0.6717996889F, - 0.6726899478F, 0.6735793167F, 0.6744677918F, 0.6753553697F, - 0.6762420466F, 0.6771278190F, 0.6780126832F, 0.6788966357F, - 0.6797796728F, 0.6806617909F, 0.6815429866F, 0.6824232562F, - 0.6833025961F, 0.6841810030F, 0.6850584731F, 0.6859350031F, - 0.6868105894F, 0.6876852284F, 0.6885589168F, 0.6894316510F, - 0.6903034275F, 0.6911742430F, 0.6920440939F, 0.6929129769F, - 0.6937808884F, 0.6946478251F, 0.6955137837F, 0.6963787606F, - 0.6972427525F, 0.6981057560F, 0.6989677678F, 0.6998287845F, - 0.7006888028F, 0.7015478194F, 0.7024058309F, 0.7032628340F, - 0.7041188254F, 0.7049738019F, 0.7058277601F, 0.7066806969F, - 0.7075326089F, 0.7083834929F, 0.7092333457F, 0.7100821640F, - 0.7109299447F, 0.7117766846F, 0.7126223804F, 0.7134670291F, - 0.7143106273F, 0.7151531721F, 0.7159946602F, 0.7168350885F, - 0.7176744539F, 0.7185127534F, 0.7193499837F, 0.7201861418F, - 0.7210212247F, 0.7218552293F, 0.7226881526F, 0.7235199914F, - 0.7243507428F, 0.7251804039F, 0.7260089715F, 0.7268364426F, - 0.7276628144F, 0.7284880839F, 0.7293122481F, 0.7301353040F, - 0.7309572487F, 0.7317780794F, 0.7325977930F, 0.7334163868F, - 0.7342338579F, 0.7350502033F, 0.7358654202F, 0.7366795059F, - 0.7374924573F, 0.7383042718F, 0.7391149465F, 0.7399244787F, - 0.7407328655F, 0.7415401041F, 0.7423461920F, 0.7431511261F, - 0.7439549040F, 0.7447575227F, 0.7455589797F, 0.7463592723F, - 0.7471583976F, 0.7479563532F, 0.7487531363F, 0.7495487443F, - 0.7503431745F, 0.7511364244F, 0.7519284913F, 0.7527193726F, - 0.7535090658F, 0.7542975683F, 0.7550848776F, 0.7558709910F, - 0.7566559062F, 0.7574396205F, 0.7582221314F, 0.7590034366F, - 0.7597835334F, 0.7605624194F, 0.7613400923F, 0.7621165495F, - 0.7628917886F, 0.7636658072F, 0.7644386030F, 0.7652101735F, - 0.7659805164F, 0.7667496292F, 0.7675175098F, 0.7682841556F, - 0.7690495645F, 0.7698137341F, 0.7705766622F, 0.7713383463F, - 0.7720987844F, 0.7728579741F, 0.7736159132F, 0.7743725994F, - 0.7751280306F, 0.7758822046F, 0.7766351192F, 0.7773867722F, - 0.7781371614F, 0.7788862848F, 0.7796341401F, 0.7803807253F, - 0.7811260383F, 0.7818700769F, 0.7826128392F, 0.7833543230F, - 0.7840945263F, 0.7848334471F, 0.7855710833F, 0.7863074330F, - 0.7870424941F, 0.7877762647F, 0.7885087428F, 0.7892399264F, - 0.7899698137F, 0.7906984026F, 0.7914256914F, 0.7921516780F, - 0.7928763607F, 0.7935997375F, 0.7943218065F, 0.7950425661F, - 0.7957620142F, 0.7964801492F, 0.7971969692F, 0.7979124724F, - 0.7986266570F, 0.7993395214F, 0.8000510638F, 0.8007612823F, - 0.8014701754F, 0.8021777413F, 0.8028839784F, 0.8035888849F, - 0.8042924592F, 0.8049946997F, 0.8056956048F, 0.8063951727F, - 0.8070934020F, 0.8077902910F, 0.8084858381F, 0.8091800419F, - 0.8098729007F, 0.8105644130F, 0.8112545774F, 0.8119433922F, - 0.8126308561F, 0.8133169676F, 0.8140017251F, 0.8146851272F, - 0.8153671726F, 0.8160478598F, 0.8167271874F, 0.8174051539F, - 0.8180817582F, 0.8187569986F, 0.8194308741F, 0.8201033831F, - 0.8207745244F, 0.8214442966F, 0.8221126986F, 0.8227797290F, - 0.8234453865F, 0.8241096700F, 0.8247725781F, 0.8254341097F, - 0.8260942636F, 0.8267530385F, 0.8274104334F, 0.8280664470F, - 0.8287210782F, 0.8293743259F, 0.8300261889F, 0.8306766662F, - 0.8313257566F, 0.8319734591F, 0.8326197727F, 0.8332646963F, - 0.8339082288F, 0.8345503692F, 0.8351911167F, 0.8358304700F, - 0.8364684284F, 0.8371049907F, 0.8377401562F, 0.8383739238F, - 0.8390062927F, 0.8396372618F, 0.8402668305F, 0.8408949977F, - 0.8415217626F, 0.8421471245F, 0.8427710823F, 0.8433936354F, - 0.8440147830F, 0.8446345242F, 0.8452528582F, 0.8458697844F, - 0.8464853020F, 0.8470994102F, 0.8477121084F, 0.8483233958F, - 0.8489332718F, 0.8495417356F, 0.8501487866F, 0.8507544243F, - 0.8513586479F, 0.8519614568F, 0.8525628505F, 0.8531628283F, - 0.8537613897F, 0.8543585341F, 0.8549542611F, 0.8555485699F, - 0.8561414603F, 0.8567329315F, 0.8573229832F, 0.8579116149F, - 0.8584988262F, 0.8590846165F, 0.8596689855F, 0.8602519327F, - 0.8608334577F, 0.8614135603F, 0.8619922399F, 0.8625694962F, - 0.8631453289F, 0.8637197377F, 0.8642927222F, 0.8648642821F, - 0.8654344172F, 0.8660031272F, 0.8665704118F, 0.8671362708F, - 0.8677007039F, 0.8682637109F, 0.8688252917F, 0.8693854460F, - 0.8699441737F, 0.8705014745F, 0.8710573485F, 0.8716117953F, - 0.8721648150F, 0.8727164073F, 0.8732665723F, 0.8738153098F, - 0.8743626197F, 0.8749085021F, 0.8754529569F, 0.8759959840F, - 0.8765375835F, 0.8770777553F, 0.8776164996F, 0.8781538162F, - 0.8786897054F, 0.8792241670F, 0.8797572013F, 0.8802888082F, - 0.8808189880F, 0.8813477407F, 0.8818750664F, 0.8824009653F, - 0.8829254375F, 0.8834484833F, 0.8839701028F, 0.8844902961F, - 0.8850090636F, 0.8855264054F, 0.8860423218F, 0.8865568131F, - 0.8870698794F, 0.8875815212F, 0.8880917386F, 0.8886005319F, - 0.8891079016F, 0.8896138479F, 0.8901183712F, 0.8906214719F, - 0.8911231503F, 0.8916234067F, 0.8921222417F, 0.8926196556F, - 0.8931156489F, 0.8936102219F, 0.8941033752F, 0.8945951092F, - 0.8950854244F, 0.8955743212F, 0.8960618003F, 0.8965478621F, - 0.8970325071F, 0.8975157359F, 0.8979975490F, 0.8984779471F, - 0.8989569307F, 0.8994345004F, 0.8999106568F, 0.9003854005F, - 0.9008587323F, 0.9013306526F, 0.9018011623F, 0.9022702619F, - 0.9027379521F, 0.9032042337F, 0.9036691074F, 0.9041325739F, - 0.9045946339F, 0.9050552882F, 0.9055145376F, 0.9059723828F, - 0.9064288246F, 0.9068838638F, 0.9073375013F, 0.9077897379F, - 0.9082405743F, 0.9086900115F, 0.9091380503F, 0.9095846917F, - 0.9100299364F, 0.9104737854F, 0.9109162397F, 0.9113573001F, - 0.9117969675F, 0.9122352430F, 0.9126721275F, 0.9131076219F, - 0.9135417273F, 0.9139744447F, 0.9144057750F, 0.9148357194F, - 0.9152642787F, 0.9156914542F, 0.9161172468F, 0.9165416576F, - 0.9169646877F, 0.9173863382F, 0.9178066102F, 0.9182255048F, - 0.9186430232F, 0.9190591665F, 0.9194739359F, 0.9198873324F, - 0.9202993574F, 0.9207100120F, 0.9211192973F, 0.9215272147F, - 0.9219337653F, 0.9223389504F, 0.9227427713F, 0.9231452290F, - 0.9235463251F, 0.9239460607F, 0.9243444371F, 0.9247414557F, - 0.9251371177F, 0.9255314245F, 0.9259243774F, 0.9263159778F, - 0.9267062270F, 0.9270951264F, 0.9274826774F, 0.9278688814F, - 0.9282537398F, 0.9286372540F, 0.9290194254F, 0.9294002555F, - 0.9297797458F, 0.9301578976F, 0.9305347125F, 0.9309101919F, - 0.9312843373F, 0.9316571503F, 0.9320286323F, 0.9323987849F, - 0.9327676097F, 0.9331351080F, 0.9335012816F, 0.9338661320F, - 0.9342296607F, 0.9345918694F, 0.9349527596F, 0.9353123330F, - 0.9356705911F, 0.9360275357F, 0.9363831683F, 0.9367374905F, - 0.9370905042F, 0.9374422108F, 0.9377926122F, 0.9381417099F, - 0.9384895057F, 0.9388360014F, 0.9391811985F, 0.9395250989F, - 0.9398677043F, 0.9402090165F, 0.9405490371F, 0.9408877680F, - 0.9412252110F, 0.9415613678F, 0.9418962402F, 0.9422298301F, - 0.9425621392F, 0.9428931695F, 0.9432229226F, 0.9435514005F, - 0.9438786050F, 0.9442045381F, 0.9445292014F, 0.9448525971F, - 0.9451747268F, 0.9454955926F, 0.9458151963F, 0.9461335399F, - 0.9464506253F, 0.9467664545F, 0.9470810293F, 0.9473943517F, - 0.9477064238F, 0.9480172474F, 0.9483268246F, 0.9486351573F, - 0.9489422475F, 0.9492480973F, 0.9495527087F, 0.9498560837F, - 0.9501582243F, 0.9504591325F, 0.9507588105F, 0.9510572603F, - 0.9513544839F, 0.9516504834F, 0.9519452609F, 0.9522388186F, - 0.9525311584F, 0.9528222826F, 0.9531121932F, 0.9534008923F, - 0.9536883821F, 0.9539746647F, 0.9542597424F, 0.9545436171F, - 0.9548262912F, 0.9551077667F, 0.9553880459F, 0.9556671309F, - 0.9559450239F, 0.9562217272F, 0.9564972429F, 0.9567715733F, - 0.9570447206F, 0.9573166871F, 0.9575874749F, 0.9578570863F, - 0.9581255236F, 0.9583927890F, 0.9586588849F, 0.9589238134F, - 0.9591875769F, 0.9594501777F, 0.9597116180F, 0.9599719003F, - 0.9602310267F, 0.9604889995F, 0.9607458213F, 0.9610014942F, - 0.9612560206F, 0.9615094028F, 0.9617616433F, 0.9620127443F, - 0.9622627083F, 0.9625115376F, 0.9627592345F, 0.9630058016F, - 0.9632512411F, 0.9634955555F, 0.9637387471F, 0.9639808185F, - 0.9642217720F, 0.9644616100F, 0.9647003349F, 0.9649379493F, - 0.9651744556F, 0.9654098561F, 0.9656441534F, 0.9658773499F, - 0.9661094480F, 0.9663404504F, 0.9665703593F, 0.9667991774F, - 0.9670269071F, 0.9672535509F, 0.9674791114F, 0.9677035909F, - 0.9679269921F, 0.9681493174F, 0.9683705694F, 0.9685907506F, - 0.9688098636F, 0.9690279108F, 0.9692448948F, 0.9694608182F, - 0.9696756836F, 0.9698894934F, 0.9701022503F, 0.9703139569F, - 0.9705246156F, 0.9707342291F, 0.9709428000F, 0.9711503309F, - 0.9713568243F, 0.9715622829F, 0.9717667093F, 0.9719701060F, - 0.9721724757F, 0.9723738210F, 0.9725741446F, 0.9727734490F, - 0.9729717369F, 0.9731690109F, 0.9733652737F, 0.9735605279F, - 0.9737547762F, 0.9739480212F, 0.9741402656F, 0.9743315120F, - 0.9745217631F, 0.9747110216F, 0.9748992901F, 0.9750865714F, - 0.9752728681F, 0.9754581829F, 0.9756425184F, 0.9758258775F, - 0.9760082627F, 0.9761896768F, 0.9763701224F, 0.9765496024F, - 0.9767281193F, 0.9769056760F, 0.9770822751F, 0.9772579193F, - 0.9774326114F, 0.9776063542F, 0.9777791502F, 0.9779510023F, - 0.9781219133F, 0.9782918858F, 0.9784609226F, 0.9786290264F, - 0.9787962000F, 0.9789624461F, 0.9791277676F, 0.9792921671F, - 0.9794556474F, 0.9796182113F, 0.9797798615F, 0.9799406009F, - 0.9801004321F, 0.9802593580F, 0.9804173813F, 0.9805745049F, - 0.9807307314F, 0.9808860637F, 0.9810405046F, 0.9811940568F, - 0.9813467232F, 0.9814985065F, 0.9816494095F, 0.9817994351F, - 0.9819485860F, 0.9820968650F, 0.9822442750F, 0.9823908186F, - 0.9825364988F, 0.9826813184F, 0.9828252801F, 0.9829683868F, - 0.9831106413F, 0.9832520463F, 0.9833926048F, 0.9835323195F, - 0.9836711932F, 0.9838092288F, 0.9839464291F, 0.9840827969F, - 0.9842183351F, 0.9843530464F, 0.9844869337F, 0.9846199998F, - 0.9847522475F, 0.9848836798F, 0.9850142993F, 0.9851441090F, - 0.9852731117F, 0.9854013101F, 0.9855287073F, 0.9856553058F, - 0.9857811087F, 0.9859061188F, 0.9860303388F, 0.9861537717F, - 0.9862764202F, 0.9863982872F, 0.9865193756F, 0.9866396882F, - 0.9867592277F, 0.9868779972F, 0.9869959993F, 0.9871132370F, - 0.9872297131F, 0.9873454304F, 0.9874603918F, 0.9875746001F, - 0.9876880581F, 0.9878007688F, 0.9879127348F, 0.9880239592F, - 0.9881344447F, 0.9882441941F, 0.9883532104F, 0.9884614962F, - 0.9885690546F, 0.9886758883F, 0.9887820001F, 0.9888873930F, - 0.9889920697F, 0.9890960331F, 0.9891992859F, 0.9893018312F, - 0.9894036716F, 0.9895048100F, 0.9896052493F, 0.9897049923F, - 0.9898040418F, 0.9899024006F, 0.9900000717F, 0.9900970577F, - 0.9901933616F, 0.9902889862F, 0.9903839343F, 0.9904782087F, - 0.9905718122F, 0.9906647477F, 0.9907570180F, 0.9908486259F, - 0.9909395742F, 0.9910298658F, 0.9911195034F, 0.9912084899F, - 0.9912968281F, 0.9913845208F, 0.9914715708F, 0.9915579810F, - 0.9916437540F, 0.9917288928F, 0.9918134001F, 0.9918972788F, - 0.9919805316F, 0.9920631613F, 0.9921451707F, 0.9922265626F, - 0.9923073399F, 0.9923875052F, 0.9924670615F, 0.9925460114F, - 0.9926243577F, 0.9927021033F, 0.9927792508F, 0.9928558032F, - 0.9929317631F, 0.9930071333F, 0.9930819167F, 0.9931561158F, - 0.9932297337F, 0.9933027728F, 0.9933752362F, 0.9934471264F, - 0.9935184462F, 0.9935891985F, 0.9936593859F, 0.9937290112F, - 0.9937980771F, 0.9938665864F, 0.9939345418F, 0.9940019460F, - 0.9940688018F, 0.9941351118F, 0.9942008789F, 0.9942661057F, - 0.9943307950F, 0.9943949494F, 0.9944585717F, 0.9945216645F, - 0.9945842307F, 0.9946462728F, 0.9947077936F, 0.9947687957F, - 0.9948292820F, 0.9948892550F, 0.9949487174F, 0.9950076719F, - 0.9950661212F, 0.9951240679F, 0.9951815148F, 0.9952384645F, - 0.9952949196F, 0.9953508828F, 0.9954063568F, 0.9954613442F, - 0.9955158476F, 0.9955698697F, 0.9956234132F, 0.9956764806F, - 0.9957290746F, 0.9957811978F, 0.9958328528F, 0.9958840423F, - 0.9959347688F, 0.9959850351F, 0.9960348435F, 0.9960841969F, - 0.9961330977F, 0.9961815486F, 0.9962295521F, 0.9962771108F, - 0.9963242274F, 0.9963709043F, 0.9964171441F, 0.9964629494F, - 0.9965083228F, 0.9965532668F, 0.9965977840F, 0.9966418768F, - 0.9966855479F, 0.9967287998F, 0.9967716350F, 0.9968140559F, - 0.9968560653F, 0.9968976655F, 0.9969388591F, 0.9969796485F, - 0.9970200363F, 0.9970600250F, 0.9970996170F, 0.9971388149F, - 0.9971776211F, 0.9972160380F, 0.9972540683F, 0.9972917142F, - 0.9973289783F, 0.9973658631F, 0.9974023709F, 0.9974385042F, - 0.9974742655F, 0.9975096571F, 0.9975446816F, 0.9975793413F, - 0.9976136386F, 0.9976475759F, 0.9976811557F, 0.9977143803F, - 0.9977472521F, 0.9977797736F, 0.9978119470F, 0.9978437748F, - 0.9978752593F, 0.9979064029F, 0.9979372079F, 0.9979676768F, - 0.9979978117F, 0.9980276151F, 0.9980570893F, 0.9980862367F, - 0.9981150595F, 0.9981435600F, 0.9981717406F, 0.9981996035F, - 0.9982271511F, 0.9982543856F, 0.9982813093F, 0.9983079246F, - 0.9983342336F, 0.9983602386F, 0.9983859418F, 0.9984113456F, - 0.9984364522F, 0.9984612638F, 0.9984857825F, 0.9985100108F, - 0.9985339507F, 0.9985576044F, 0.9985809743F, 0.9986040624F, - 0.9986268710F, 0.9986494022F, 0.9986716583F, 0.9986936413F, - 0.9987153535F, 0.9987367969F, 0.9987579738F, 0.9987788864F, - 0.9987995366F, 0.9988199267F, 0.9988400587F, 0.9988599348F, - 0.9988795572F, 0.9988989278F, 0.9989180487F, 0.9989369222F, - 0.9989555501F, 0.9989739347F, 0.9989920780F, 0.9990099820F, - 0.9990276487F, 0.9990450803F, 0.9990622787F, 0.9990792460F, - 0.9990959841F, 0.9991124952F, 0.9991287812F, 0.9991448440F, - 0.9991606858F, 0.9991763084F, 0.9991917139F, 0.9992069042F, - 0.9992218813F, 0.9992366471F, 0.9992512035F, 0.9992655525F, - 0.9992796961F, 0.9992936361F, 0.9993073744F, 0.9993209131F, - 0.9993342538F, 0.9993473987F, 0.9993603494F, 0.9993731080F, - 0.9993856762F, 0.9993980559F, 0.9994102490F, 0.9994222573F, - 0.9994340827F, 0.9994457269F, 0.9994571918F, 0.9994684793F, - 0.9994795910F, 0.9994905288F, 0.9995012945F, 0.9995118898F, - 0.9995223165F, 0.9995325765F, 0.9995426713F, 0.9995526029F, - 0.9995623728F, 0.9995719829F, 0.9995814349F, 0.9995907304F, - 0.9995998712F, 0.9996088590F, 0.9996176954F, 0.9996263821F, - 0.9996349208F, 0.9996433132F, 0.9996515609F, 0.9996596656F, - 0.9996676288F, 0.9996754522F, 0.9996831375F, 0.9996906862F, - 0.9996981000F, 0.9997053804F, 0.9997125290F, 0.9997195474F, - 0.9997264371F, 0.9997331998F, 0.9997398369F, 0.9997463500F, - 0.9997527406F, 0.9997590103F, 0.9997651606F, 0.9997711930F, - 0.9997771089F, 0.9997829098F, 0.9997885973F, 0.9997941728F, - 0.9997996378F, 0.9998049936F, 0.9998102419F, 0.9998153839F, - 0.9998204211F, 0.9998253550F, 0.9998301868F, 0.9998349182F, - 0.9998395503F, 0.9998440847F, 0.9998485226F, 0.9998528654F, - 0.9998571146F, 0.9998612713F, 0.9998653370F, 0.9998693130F, - 0.9998732007F, 0.9998770012F, 0.9998807159F, 0.9998843461F, - 0.9998878931F, 0.9998913581F, 0.9998947424F, 0.9998980473F, - 0.9999012740F, 0.9999044237F, 0.9999074976F, 0.9999104971F, - 0.9999134231F, 0.9999162771F, 0.9999190601F, 0.9999217733F, - 0.9999244179F, 0.9999269950F, 0.9999295058F, 0.9999319515F, - 0.9999343332F, 0.9999366519F, 0.9999389088F, 0.9999411050F, - 0.9999432416F, 0.9999453196F, 0.9999473402F, 0.9999493044F, - 0.9999512132F, 0.9999530677F, 0.9999548690F, 0.9999566180F, - 0.9999583157F, 0.9999599633F, 0.9999615616F, 0.9999631116F, - 0.9999646144F, 0.9999660709F, 0.9999674820F, 0.9999688487F, - 0.9999701719F, 0.9999714526F, 0.9999726917F, 0.9999738900F, - 0.9999750486F, 0.9999761682F, 0.9999772497F, 0.9999782941F, - 0.9999793021F, 0.9999802747F, 0.9999812126F, 0.9999821167F, - 0.9999829878F, 0.9999838268F, 0.9999846343F, 0.9999854113F, - 0.9999861584F, 0.9999868765F, 0.9999875664F, 0.9999882287F, - 0.9999888642F, 0.9999894736F, 0.9999900577F, 0.9999906172F, - 0.9999911528F, 0.9999916651F, 0.9999921548F, 0.9999926227F, - 0.9999930693F, 0.9999934954F, 0.9999939015F, 0.9999942883F, - 0.9999946564F, 0.9999950064F, 0.9999953390F, 0.9999956547F, - 0.9999959541F, 0.9999962377F, 0.9999965062F, 0.9999967601F, - 0.9999969998F, 0.9999972260F, 0.9999974392F, 0.9999976399F, - 0.9999978285F, 0.9999980056F, 0.9999981716F, 0.9999983271F, - 0.9999984724F, 0.9999986081F, 0.9999987345F, 0.9999988521F, - 0.9999989613F, 0.9999990625F, 0.9999991562F, 0.9999992426F, - 0.9999993223F, 0.9999993954F, 0.9999994625F, 0.9999995239F, - 0.9999995798F, 0.9999996307F, 0.9999996768F, 0.9999997184F, - 0.9999997559F, 0.9999997895F, 0.9999998195F, 0.9999998462F, - 0.9999998698F, 0.9999998906F, 0.9999999088F, 0.9999999246F, - 0.9999999383F, 0.9999999500F, 0.9999999600F, 0.9999999684F, - 0.9999999754F, 0.9999999811F, 0.9999999858F, 0.9999999896F, - 0.9999999925F, 0.9999999948F, 0.9999999965F, 0.9999999978F, - 0.9999999986F, 0.9999999992F, 0.9999999996F, 0.9999999998F, - 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F, -}; - -static const float vwin8192[4096] = { - 0.0000000578F, 0.0000005198F, 0.0000014438F, 0.0000028299F, - 0.0000046780F, 0.0000069882F, 0.0000097604F, 0.0000129945F, - 0.0000166908F, 0.0000208490F, 0.0000254692F, 0.0000305515F, - 0.0000360958F, 0.0000421021F, 0.0000485704F, 0.0000555006F, - 0.0000628929F, 0.0000707472F, 0.0000790635F, 0.0000878417F, - 0.0000970820F, 0.0001067842F, 0.0001169483F, 0.0001275744F, - 0.0001386625F, 0.0001502126F, 0.0001622245F, 0.0001746984F, - 0.0001876343F, 0.0002010320F, 0.0002148917F, 0.0002292132F, - 0.0002439967F, 0.0002592421F, 0.0002749493F, 0.0002911184F, - 0.0003077493F, 0.0003248421F, 0.0003423967F, 0.0003604132F, - 0.0003788915F, 0.0003978316F, 0.0004172335F, 0.0004370971F, - 0.0004574226F, 0.0004782098F, 0.0004994587F, 0.0005211694F, - 0.0005433418F, 0.0005659759F, 0.0005890717F, 0.0006126292F, - 0.0006366484F, 0.0006611292F, 0.0006860716F, 0.0007114757F, - 0.0007373414F, 0.0007636687F, 0.0007904576F, 0.0008177080F, - 0.0008454200F, 0.0008735935F, 0.0009022285F, 0.0009313250F, - 0.0009608830F, 0.0009909025F, 0.0010213834F, 0.0010523257F, - 0.0010837295F, 0.0011155946F, 0.0011479211F, 0.0011807090F, - 0.0012139582F, 0.0012476687F, 0.0012818405F, 0.0013164736F, - 0.0013515679F, 0.0013871235F, 0.0014231402F, 0.0014596182F, - 0.0014965573F, 0.0015339576F, 0.0015718190F, 0.0016101415F, - 0.0016489251F, 0.0016881698F, 0.0017278754F, 0.0017680421F, - 0.0018086698F, 0.0018497584F, 0.0018913080F, 0.0019333185F, - 0.0019757898F, 0.0020187221F, 0.0020621151F, 0.0021059690F, - 0.0021502837F, 0.0021950591F, 0.0022402953F, 0.0022859921F, - 0.0023321497F, 0.0023787679F, 0.0024258467F, 0.0024733861F, - 0.0025213861F, 0.0025698466F, 0.0026187676F, 0.0026681491F, - 0.0027179911F, 0.0027682935F, 0.0028190562F, 0.0028702794F, - 0.0029219628F, 0.0029741066F, 0.0030267107F, 0.0030797749F, - 0.0031332994F, 0.0031872841F, 0.0032417289F, 0.0032966338F, - 0.0033519988F, 0.0034078238F, 0.0034641089F, 0.0035208539F, - 0.0035780589F, 0.0036357237F, 0.0036938485F, 0.0037524331F, - 0.0038114775F, 0.0038709817F, 0.0039309456F, 0.0039913692F, - 0.0040522524F, 0.0041135953F, 0.0041753978F, 0.0042376599F, - 0.0043003814F, 0.0043635624F, 0.0044272029F, 0.0044913028F, - 0.0045558620F, 0.0046208806F, 0.0046863585F, 0.0047522955F, - 0.0048186919F, 0.0048855473F, 0.0049528619F, 0.0050206356F, - 0.0050888684F, 0.0051575601F, 0.0052267108F, 0.0052963204F, - 0.0053663890F, 0.0054369163F, 0.0055079025F, 0.0055793474F, - 0.0056512510F, 0.0057236133F, 0.0057964342F, 0.0058697137F, - 0.0059434517F, 0.0060176482F, 0.0060923032F, 0.0061674166F, - 0.0062429883F, 0.0063190183F, 0.0063955066F, 0.0064724532F, - 0.0065498579F, 0.0066277207F, 0.0067060416F, 0.0067848205F, - 0.0068640575F, 0.0069437523F, 0.0070239051F, 0.0071045157F, - 0.0071855840F, 0.0072671102F, 0.0073490940F, 0.0074315355F, - 0.0075144345F, 0.0075977911F, 0.0076816052F, 0.0077658768F, - 0.0078506057F, 0.0079357920F, 0.0080214355F, 0.0081075363F, - 0.0081940943F, 0.0082811094F, 0.0083685816F, 0.0084565108F, - 0.0085448970F, 0.0086337401F, 0.0087230401F, 0.0088127969F, - 0.0089030104F, 0.0089936807F, 0.0090848076F, 0.0091763911F, - 0.0092684311F, 0.0093609276F, 0.0094538805F, 0.0095472898F, - 0.0096411554F, 0.0097354772F, 0.0098302552F, 0.0099254894F, - 0.0100211796F, 0.0101173259F, 0.0102139281F, 0.0103109863F, - 0.0104085002F, 0.0105064700F, 0.0106048955F, 0.0107037766F, - 0.0108031133F, 0.0109029056F, 0.0110031534F, 0.0111038565F, - 0.0112050151F, 0.0113066289F, 0.0114086980F, 0.0115112222F, - 0.0116142015F, 0.0117176359F, 0.0118215252F, 0.0119258695F, - 0.0120306686F, 0.0121359225F, 0.0122416312F, 0.0123477944F, - 0.0124544123F, 0.0125614847F, 0.0126690116F, 0.0127769928F, - 0.0128854284F, 0.0129943182F, 0.0131036623F, 0.0132134604F, - 0.0133237126F, 0.0134344188F, 0.0135455790F, 0.0136571929F, - 0.0137692607F, 0.0138817821F, 0.0139947572F, 0.0141081859F, - 0.0142220681F, 0.0143364037F, 0.0144511927F, 0.0145664350F, - 0.0146821304F, 0.0147982791F, 0.0149148808F, 0.0150319355F, - 0.0151494431F, 0.0152674036F, 0.0153858168F, 0.0155046828F, - 0.0156240014F, 0.0157437726F, 0.0158639962F, 0.0159846723F, - 0.0161058007F, 0.0162273814F, 0.0163494142F, 0.0164718991F, - 0.0165948361F, 0.0167182250F, 0.0168420658F, 0.0169663584F, - 0.0170911027F, 0.0172162987F, 0.0173419462F, 0.0174680452F, - 0.0175945956F, 0.0177215974F, 0.0178490504F, 0.0179769545F, - 0.0181053098F, 0.0182341160F, 0.0183633732F, 0.0184930812F, - 0.0186232399F, 0.0187538494F, 0.0188849094F, 0.0190164200F, - 0.0191483809F, 0.0192807923F, 0.0194136539F, 0.0195469656F, - 0.0196807275F, 0.0198149394F, 0.0199496012F, 0.0200847128F, - 0.0202202742F, 0.0203562853F, 0.0204927460F, 0.0206296561F, - 0.0207670157F, 0.0209048245F, 0.0210430826F, 0.0211817899F, - 0.0213209462F, 0.0214605515F, 0.0216006057F, 0.0217411086F, - 0.0218820603F, 0.0220234605F, 0.0221653093F, 0.0223076066F, - 0.0224503521F, 0.0225935459F, 0.0227371879F, 0.0228812779F, - 0.0230258160F, 0.0231708018F, 0.0233162355F, 0.0234621169F, - 0.0236084459F, 0.0237552224F, 0.0239024462F, 0.0240501175F, - 0.0241982359F, 0.0243468015F, 0.0244958141F, 0.0246452736F, - 0.0247951800F, 0.0249455331F, 0.0250963329F, 0.0252475792F, - 0.0253992720F, 0.0255514111F, 0.0257039965F, 0.0258570281F, - 0.0260105057F, 0.0261644293F, 0.0263187987F, 0.0264736139F, - 0.0266288747F, 0.0267845811F, 0.0269407330F, 0.0270973302F, - 0.0272543727F, 0.0274118604F, 0.0275697930F, 0.0277281707F, - 0.0278869932F, 0.0280462604F, 0.0282059723F, 0.0283661287F, - 0.0285267295F, 0.0286877747F, 0.0288492641F, 0.0290111976F, - 0.0291735751F, 0.0293363965F, 0.0294996617F, 0.0296633706F, - 0.0298275231F, 0.0299921190F, 0.0301571583F, 0.0303226409F, - 0.0304885667F, 0.0306549354F, 0.0308217472F, 0.0309890017F, - 0.0311566989F, 0.0313248388F, 0.0314934211F, 0.0316624459F, - 0.0318319128F, 0.0320018220F, 0.0321721732F, 0.0323429663F, - 0.0325142013F, 0.0326858779F, 0.0328579962F, 0.0330305559F, - 0.0332035570F, 0.0333769994F, 0.0335508829F, 0.0337252074F, - 0.0338999728F, 0.0340751790F, 0.0342508259F, 0.0344269134F, - 0.0346034412F, 0.0347804094F, 0.0349578178F, 0.0351356663F, - 0.0353139548F, 0.0354926831F, 0.0356718511F, 0.0358514588F, - 0.0360315059F, 0.0362119924F, 0.0363929182F, 0.0365742831F, - 0.0367560870F, 0.0369383297F, 0.0371210113F, 0.0373041315F, - 0.0374876902F, 0.0376716873F, 0.0378561226F, 0.0380409961F, - 0.0382263077F, 0.0384120571F, 0.0385982443F, 0.0387848691F, - 0.0389719315F, 0.0391594313F, 0.0393473683F, 0.0395357425F, - 0.0397245537F, 0.0399138017F, 0.0401034866F, 0.0402936080F, - 0.0404841660F, 0.0406751603F, 0.0408665909F, 0.0410584576F, - 0.0412507603F, 0.0414434988F, 0.0416366731F, 0.0418302829F, - 0.0420243282F, 0.0422188088F, 0.0424137246F, 0.0426090755F, - 0.0428048613F, 0.0430010819F, 0.0431977371F, 0.0433948269F, - 0.0435923511F, 0.0437903095F, 0.0439887020F, 0.0441875285F, - 0.0443867889F, 0.0445864830F, 0.0447866106F, 0.0449871717F, - 0.0451881661F, 0.0453895936F, 0.0455914542F, 0.0457937477F, - 0.0459964738F, 0.0461996326F, 0.0464032239F, 0.0466072475F, - 0.0468117032F, 0.0470165910F, 0.0472219107F, 0.0474276622F, - 0.0476338452F, 0.0478404597F, 0.0480475056F, 0.0482549827F, - 0.0484628907F, 0.0486712297F, 0.0488799994F, 0.0490891998F, - 0.0492988306F, 0.0495088917F, 0.0497193830F, 0.0499303043F, - 0.0501416554F, 0.0503534363F, 0.0505656468F, 0.0507782867F, - 0.0509913559F, 0.0512048542F, 0.0514187815F, 0.0516331376F, - 0.0518479225F, 0.0520631358F, 0.0522787775F, 0.0524948475F, - 0.0527113455F, 0.0529282715F, 0.0531456252F, 0.0533634066F, - 0.0535816154F, 0.0538002515F, 0.0540193148F, 0.0542388051F, - 0.0544587222F, 0.0546790660F, 0.0548998364F, 0.0551210331F, - 0.0553426561F, 0.0555647051F, 0.0557871801F, 0.0560100807F, - 0.0562334070F, 0.0564571587F, 0.0566813357F, 0.0569059378F, - 0.0571309649F, 0.0573564168F, 0.0575822933F, 0.0578085942F, - 0.0580353195F, 0.0582624689F, 0.0584900423F, 0.0587180396F, - 0.0589464605F, 0.0591753049F, 0.0594045726F, 0.0596342635F, - 0.0598643774F, 0.0600949141F, 0.0603258735F, 0.0605572555F, - 0.0607890597F, 0.0610212862F, 0.0612539346F, 0.0614870049F, - 0.0617204968F, 0.0619544103F, 0.0621887451F, 0.0624235010F, - 0.0626586780F, 0.0628942758F, 0.0631302942F, 0.0633667331F, - 0.0636035923F, 0.0638408717F, 0.0640785710F, 0.0643166901F, - 0.0645552288F, 0.0647941870F, 0.0650335645F, 0.0652733610F, - 0.0655135765F, 0.0657542108F, 0.0659952636F, 0.0662367348F, - 0.0664786242F, 0.0667209316F, 0.0669636570F, 0.0672068000F, - 0.0674503605F, 0.0676943384F, 0.0679387334F, 0.0681835454F, - 0.0684287742F, 0.0686744196F, 0.0689204814F, 0.0691669595F, - 0.0694138536F, 0.0696611637F, 0.0699088894F, 0.0701570307F, - 0.0704055873F, 0.0706545590F, 0.0709039458F, 0.0711537473F, - 0.0714039634F, 0.0716545939F, 0.0719056387F, 0.0721570975F, - 0.0724089702F, 0.0726612565F, 0.0729139563F, 0.0731670694F, - 0.0734205956F, 0.0736745347F, 0.0739288866F, 0.0741836510F, - 0.0744388277F, 0.0746944166F, 0.0749504175F, 0.0752068301F, - 0.0754636543F, 0.0757208899F, 0.0759785367F, 0.0762365946F, - 0.0764950632F, 0.0767539424F, 0.0770132320F, 0.0772729319F, - 0.0775330418F, 0.0777935616F, 0.0780544909F, 0.0783158298F, - 0.0785775778F, 0.0788397349F, 0.0791023009F, 0.0793652755F, - 0.0796286585F, 0.0798924498F, 0.0801566492F, 0.0804212564F, - 0.0806862712F, 0.0809516935F, 0.0812175231F, 0.0814837597F, - 0.0817504031F, 0.0820174532F, 0.0822849097F, 0.0825527724F, - 0.0828210412F, 0.0830897158F, 0.0833587960F, 0.0836282816F, - 0.0838981724F, 0.0841684682F, 0.0844391688F, 0.0847102740F, - 0.0849817835F, 0.0852536973F, 0.0855260150F, 0.0857987364F, - 0.0860718614F, 0.0863453897F, 0.0866193211F, 0.0868936554F, - 0.0871683924F, 0.0874435319F, 0.0877190737F, 0.0879950175F, - 0.0882713632F, 0.0885481105F, 0.0888252592F, 0.0891028091F, - 0.0893807600F, 0.0896591117F, 0.0899378639F, 0.0902170165F, - 0.0904965692F, 0.0907765218F, 0.0910568740F, 0.0913376258F, - 0.0916187767F, 0.0919003268F, 0.0921822756F, 0.0924646230F, - 0.0927473687F, 0.0930305126F, 0.0933140545F, 0.0935979940F, - 0.0938823310F, 0.0941670653F, 0.0944521966F, 0.0947377247F, - 0.0950236494F, 0.0953099704F, 0.0955966876F, 0.0958838007F, - 0.0961713094F, 0.0964592136F, 0.0967475131F, 0.0970362075F, - 0.0973252967F, 0.0976147805F, 0.0979046585F, 0.0981949307F, - 0.0984855967F, 0.0987766563F, 0.0990681093F, 0.0993599555F, - 0.0996521945F, 0.0999448263F, 0.1002378506F, 0.1005312671F, - 0.1008250755F, 0.1011192757F, 0.1014138675F, 0.1017088505F, - 0.1020042246F, 0.1022999895F, 0.1025961450F, 0.1028926909F, - 0.1031896268F, 0.1034869526F, 0.1037846680F, 0.1040827729F, - 0.1043812668F, 0.1046801497F, 0.1049794213F, 0.1052790813F, - 0.1055791294F, 0.1058795656F, 0.1061803894F, 0.1064816006F, - 0.1067831991F, 0.1070851846F, 0.1073875568F, 0.1076903155F, - 0.1079934604F, 0.1082969913F, 0.1086009079F, 0.1089052101F, - 0.1092098975F, 0.1095149699F, 0.1098204270F, 0.1101262687F, - 0.1104324946F, 0.1107391045F, 0.1110460982F, 0.1113534754F, - 0.1116612359F, 0.1119693793F, 0.1122779055F, 0.1125868142F, - 0.1128961052F, 0.1132057781F, 0.1135158328F, 0.1138262690F, - 0.1141370863F, 0.1144482847F, 0.1147598638F, 0.1150718233F, - 0.1153841631F, 0.1156968828F, 0.1160099822F, 0.1163234610F, - 0.1166373190F, 0.1169515559F, 0.1172661714F, 0.1175811654F, - 0.1178965374F, 0.1182122874F, 0.1185284149F, 0.1188449198F, - 0.1191618018F, 0.1194790606F, 0.1197966960F, 0.1201147076F, - 0.1204330953F, 0.1207518587F, 0.1210709976F, 0.1213905118F, - 0.1217104009F, 0.1220306647F, 0.1223513029F, 0.1226723153F, - 0.1229937016F, 0.1233154615F, 0.1236375948F, 0.1239601011F, - 0.1242829803F, 0.1246062319F, 0.1249298559F, 0.1252538518F, - 0.1255782195F, 0.1259029586F, 0.1262280689F, 0.1265535501F, - 0.1268794019F, 0.1272056241F, 0.1275322163F, 0.1278591784F, - 0.1281865099F, 0.1285142108F, 0.1288422805F, 0.1291707190F, - 0.1294995259F, 0.1298287009F, 0.1301582437F, 0.1304881542F, - 0.1308184319F, 0.1311490766F, 0.1314800881F, 0.1318114660F, - 0.1321432100F, 0.1324753200F, 0.1328077955F, 0.1331406364F, - 0.1334738422F, 0.1338074129F, 0.1341413479F, 0.1344756472F, - 0.1348103103F, 0.1351453370F, 0.1354807270F, 0.1358164801F, - 0.1361525959F, 0.1364890741F, 0.1368259145F, 0.1371631167F, - 0.1375006805F, 0.1378386056F, 0.1381768917F, 0.1385155384F, - 0.1388545456F, 0.1391939129F, 0.1395336400F, 0.1398737266F, - 0.1402141724F, 0.1405549772F, 0.1408961406F, 0.1412376623F, - 0.1415795421F, 0.1419217797F, 0.1422643746F, 0.1426073268F, - 0.1429506358F, 0.1432943013F, 0.1436383231F, 0.1439827008F, - 0.1443274342F, 0.1446725229F, 0.1450179667F, 0.1453637652F, - 0.1457099181F, 0.1460564252F, 0.1464032861F, 0.1467505006F, - 0.1470980682F, 0.1474459888F, 0.1477942620F, 0.1481428875F, - 0.1484918651F, 0.1488411942F, 0.1491908748F, 0.1495409065F, - 0.1498912889F, 0.1502420218F, 0.1505931048F, 0.1509445376F, - 0.1512963200F, 0.1516484516F, 0.1520009321F, 0.1523537612F, - 0.1527069385F, 0.1530604638F, 0.1534143368F, 0.1537685571F, - 0.1541231244F, 0.1544780384F, 0.1548332987F, 0.1551889052F, - 0.1555448574F, 0.1559011550F, 0.1562577978F, 0.1566147853F, - 0.1569721173F, 0.1573297935F, 0.1576878135F, 0.1580461771F, - 0.1584048838F, 0.1587639334F, 0.1591233255F, 0.1594830599F, - 0.1598431361F, 0.1602035540F, 0.1605643131F, 0.1609254131F, - 0.1612868537F, 0.1616486346F, 0.1620107555F, 0.1623732160F, - 0.1627360158F, 0.1630991545F, 0.1634626319F, 0.1638264476F, - 0.1641906013F, 0.1645550926F, 0.1649199212F, 0.1652850869F, - 0.1656505892F, 0.1660164278F, 0.1663826024F, 0.1667491127F, - 0.1671159583F, 0.1674831388F, 0.1678506541F, 0.1682185036F, - 0.1685866872F, 0.1689552044F, 0.1693240549F, 0.1696932384F, - 0.1700627545F, 0.1704326029F, 0.1708027833F, 0.1711732952F, - 0.1715441385F, 0.1719153127F, 0.1722868175F, 0.1726586526F, - 0.1730308176F, 0.1734033121F, 0.1737761359F, 0.1741492886F, - 0.1745227698F, 0.1748965792F, 0.1752707164F, 0.1756451812F, - 0.1760199731F, 0.1763950918F, 0.1767705370F, 0.1771463083F, - 0.1775224054F, 0.1778988279F, 0.1782755754F, 0.1786526477F, - 0.1790300444F, 0.1794077651F, 0.1797858094F, 0.1801641771F, - 0.1805428677F, 0.1809218810F, 0.1813012165F, 0.1816808739F, - 0.1820608528F, 0.1824411530F, 0.1828217739F, 0.1832027154F, - 0.1835839770F, 0.1839655584F, 0.1843474592F, 0.1847296790F, - 0.1851122175F, 0.1854950744F, 0.1858782492F, 0.1862617417F, - 0.1866455514F, 0.1870296780F, 0.1874141211F, 0.1877988804F, - 0.1881839555F, 0.1885693461F, 0.1889550517F, 0.1893410721F, - 0.1897274068F, 0.1901140555F, 0.1905010178F, 0.1908882933F, - 0.1912758818F, 0.1916637828F, 0.1920519959F, 0.1924405208F, - 0.1928293571F, 0.1932185044F, 0.1936079625F, 0.1939977308F, - 0.1943878091F, 0.1947781969F, 0.1951688939F, 0.1955598998F, - 0.1959512141F, 0.1963428364F, 0.1967347665F, 0.1971270038F, - 0.1975195482F, 0.1979123990F, 0.1983055561F, 0.1986990190F, - 0.1990927873F, 0.1994868607F, 0.1998812388F, 0.2002759212F, - 0.2006709075F, 0.2010661974F, 0.2014617904F, 0.2018576862F, - 0.2022538844F, 0.2026503847F, 0.2030471865F, 0.2034442897F, - 0.2038416937F, 0.2042393982F, 0.2046374028F, 0.2050357071F, - 0.2054343107F, 0.2058332133F, 0.2062324145F, 0.2066319138F, - 0.2070317110F, 0.2074318055F, 0.2078321970F, 0.2082328852F, - 0.2086338696F, 0.2090351498F, 0.2094367255F, 0.2098385962F, - 0.2102407617F, 0.2106432213F, 0.2110459749F, 0.2114490220F, - 0.2118523621F, 0.2122559950F, 0.2126599202F, 0.2130641373F, - 0.2134686459F, 0.2138734456F, 0.2142785361F, 0.2146839168F, - 0.2150895875F, 0.2154955478F, 0.2159017972F, 0.2163083353F, - 0.2167151617F, 0.2171222761F, 0.2175296780F, 0.2179373670F, - 0.2183453428F, 0.2187536049F, 0.2191621529F, 0.2195709864F, - 0.2199801051F, 0.2203895085F, 0.2207991961F, 0.2212091677F, - 0.2216194228F, 0.2220299610F, 0.2224407818F, 0.2228518850F, - 0.2232632699F, 0.2236749364F, 0.2240868839F, 0.2244991121F, - 0.2249116204F, 0.2253244086F, 0.2257374763F, 0.2261508229F, - 0.2265644481F, 0.2269783514F, 0.2273925326F, 0.2278069911F, - 0.2282217265F, 0.2286367384F, 0.2290520265F, 0.2294675902F, - 0.2298834292F, 0.2302995431F, 0.2307159314F, 0.2311325937F, - 0.2315495297F, 0.2319667388F, 0.2323842207F, 0.2328019749F, - 0.2332200011F, 0.2336382988F, 0.2340568675F, 0.2344757070F, - 0.2348948166F, 0.2353141961F, 0.2357338450F, 0.2361537629F, - 0.2365739493F, 0.2369944038F, 0.2374151261F, 0.2378361156F, - 0.2382573720F, 0.2386788948F, 0.2391006836F, 0.2395227380F, - 0.2399450575F, 0.2403676417F, 0.2407904902F, 0.2412136026F, - 0.2416369783F, 0.2420606171F, 0.2424845185F, 0.2429086820F, - 0.2433331072F, 0.2437577936F, 0.2441827409F, 0.2446079486F, - 0.2450334163F, 0.2454591435F, 0.2458851298F, 0.2463113747F, - 0.2467378779F, 0.2471646389F, 0.2475916573F, 0.2480189325F, - 0.2484464643F, 0.2488742521F, 0.2493022955F, 0.2497305940F, - 0.2501591473F, 0.2505879549F, 0.2510170163F, 0.2514463311F, - 0.2518758989F, 0.2523057193F, 0.2527357916F, 0.2531661157F, - 0.2535966909F, 0.2540275169F, 0.2544585931F, 0.2548899193F, - 0.2553214948F, 0.2557533193F, 0.2561853924F, 0.2566177135F, - 0.2570502822F, 0.2574830981F, 0.2579161608F, 0.2583494697F, - 0.2587830245F, 0.2592168246F, 0.2596508697F, 0.2600851593F, - 0.2605196929F, 0.2609544701F, 0.2613894904F, 0.2618247534F, - 0.2622602586F, 0.2626960055F, 0.2631319938F, 0.2635682230F, - 0.2640046925F, 0.2644414021F, 0.2648783511F, 0.2653155391F, - 0.2657529657F, 0.2661906305F, 0.2666285329F, 0.2670666725F, - 0.2675050489F, 0.2679436616F, 0.2683825101F, 0.2688215940F, - 0.2692609127F, 0.2697004660F, 0.2701402532F, 0.2705802739F, - 0.2710205278F, 0.2714610142F, 0.2719017327F, 0.2723426830F, - 0.2727838644F, 0.2732252766F, 0.2736669191F, 0.2741087914F, - 0.2745508930F, 0.2749932235F, 0.2754357824F, 0.2758785693F, - 0.2763215837F, 0.2767648251F, 0.2772082930F, 0.2776519870F, - 0.2780959066F, 0.2785400513F, 0.2789844207F, 0.2794290143F, - 0.2798738316F, 0.2803188722F, 0.2807641355F, 0.2812096211F, - 0.2816553286F, 0.2821012574F, 0.2825474071F, 0.2829937773F, - 0.2834403673F, 0.2838871768F, 0.2843342053F, 0.2847814523F, - 0.2852289174F, 0.2856765999F, 0.2861244996F, 0.2865726159F, - 0.2870209482F, 0.2874694962F, 0.2879182594F, 0.2883672372F, - 0.2888164293F, 0.2892658350F, 0.2897154540F, 0.2901652858F, - 0.2906153298F, 0.2910655856F, 0.2915160527F, 0.2919667306F, - 0.2924176189F, 0.2928687171F, 0.2933200246F, 0.2937715409F, - 0.2942232657F, 0.2946751984F, 0.2951273386F, 0.2955796856F, - 0.2960322391F, 0.2964849986F, 0.2969379636F, 0.2973911335F, - 0.2978445080F, 0.2982980864F, 0.2987518684F, 0.2992058534F, - 0.2996600409F, 0.3001144305F, 0.3005690217F, 0.3010238139F, - 0.3014788067F, 0.3019339995F, 0.3023893920F, 0.3028449835F, - 0.3033007736F, 0.3037567618F, 0.3042129477F, 0.3046693306F, - 0.3051259102F, 0.3055826859F, 0.3060396572F, 0.3064968236F, - 0.3069541847F, 0.3074117399F, 0.3078694887F, 0.3083274307F, - 0.3087855653F, 0.3092438920F, 0.3097024104F, 0.3101611199F, - 0.3106200200F, 0.3110791103F, 0.3115383902F, 0.3119978592F, - 0.3124575169F, 0.3129173627F, 0.3133773961F, 0.3138376166F, - 0.3142980238F, 0.3147586170F, 0.3152193959F, 0.3156803598F, - 0.3161415084F, 0.3166028410F, 0.3170643573F, 0.3175260566F, - 0.3179879384F, 0.3184500023F, 0.3189122478F, 0.3193746743F, - 0.3198372814F, 0.3203000685F, 0.3207630351F, 0.3212261807F, - 0.3216895048F, 0.3221530069F, 0.3226166865F, 0.3230805430F, - 0.3235445760F, 0.3240087849F, 0.3244731693F, 0.3249377285F, - 0.3254024622F, 0.3258673698F, 0.3263324507F, 0.3267977045F, - 0.3272631306F, 0.3277287286F, 0.3281944978F, 0.3286604379F, - 0.3291265482F, 0.3295928284F, 0.3300592777F, 0.3305258958F, - 0.3309926821F, 0.3314596361F, 0.3319267573F, 0.3323940451F, - 0.3328614990F, 0.3333291186F, 0.3337969033F, 0.3342648525F, - 0.3347329658F, 0.3352012427F, 0.3356696825F, 0.3361382849F, - 0.3366070492F, 0.3370759749F, 0.3375450616F, 0.3380143087F, - 0.3384837156F, 0.3389532819F, 0.3394230071F, 0.3398928905F, - 0.3403629317F, 0.3408331302F, 0.3413034854F, 0.3417739967F, - 0.3422446638F, 0.3427154860F, 0.3431864628F, 0.3436575938F, - 0.3441288782F, 0.3446003158F, 0.3450719058F, 0.3455436478F, - 0.3460155412F, 0.3464875856F, 0.3469597804F, 0.3474321250F, - 0.3479046189F, 0.3483772617F, 0.3488500527F, 0.3493229914F, - 0.3497960774F, 0.3502693100F, 0.3507426887F, 0.3512162131F, - 0.3516898825F, 0.3521636965F, 0.3526376545F, 0.3531117559F, - 0.3535860003F, 0.3540603870F, 0.3545349157F, 0.3550095856F, - 0.3554843964F, 0.3559593474F, 0.3564344381F, 0.3569096680F, - 0.3573850366F, 0.3578605432F, 0.3583361875F, 0.3588119687F, - 0.3592878865F, 0.3597639402F, 0.3602401293F, 0.3607164533F, - 0.3611929117F, 0.3616695038F, 0.3621462292F, 0.3626230873F, - 0.3631000776F, 0.3635771995F, 0.3640544525F, 0.3645318360F, - 0.3650093496F, 0.3654869926F, 0.3659647645F, 0.3664426648F, - 0.3669206930F, 0.3673988484F, 0.3678771306F, 0.3683555390F, - 0.3688340731F, 0.3693127322F, 0.3697915160F, 0.3702704237F, - 0.3707494549F, 0.3712286091F, 0.3717078857F, 0.3721872840F, - 0.3726668037F, 0.3731464441F, 0.3736262047F, 0.3741060850F, - 0.3745860843F, 0.3750662023F, 0.3755464382F, 0.3760267915F, - 0.3765072618F, 0.3769878484F, 0.3774685509F, 0.3779493686F, - 0.3784303010F, 0.3789113475F, 0.3793925076F, 0.3798737809F, - 0.3803551666F, 0.3808366642F, 0.3813182733F, 0.3817999932F, - 0.3822818234F, 0.3827637633F, 0.3832458124F, 0.3837279702F, - 0.3842102360F, 0.3846926093F, 0.3851750897F, 0.3856576764F, - 0.3861403690F, 0.3866231670F, 0.3871060696F, 0.3875890765F, - 0.3880721870F, 0.3885554007F, 0.3890387168F, 0.3895221349F, - 0.3900056544F, 0.3904892748F, 0.3909729955F, 0.3914568160F, - 0.3919407356F, 0.3924247539F, 0.3929088702F, 0.3933930841F, - 0.3938773949F, 0.3943618021F, 0.3948463052F, 0.3953309035F, - 0.3958155966F, 0.3963003838F, 0.3967852646F, 0.3972702385F, - 0.3977553048F, 0.3982404631F, 0.3987257127F, 0.3992110531F, - 0.3996964838F, 0.4001820041F, 0.4006676136F, 0.4011533116F, - 0.4016390976F, 0.4021249710F, 0.4026109313F, 0.4030969779F, - 0.4035831102F, 0.4040693277F, 0.4045556299F, 0.4050420160F, - 0.4055284857F, 0.4060150383F, 0.4065016732F, 0.4069883899F, - 0.4074751879F, 0.4079620665F, 0.4084490252F, 0.4089360635F, - 0.4094231807F, 0.4099103763F, 0.4103976498F, 0.4108850005F, - 0.4113724280F, 0.4118599315F, 0.4123475107F, 0.4128351648F, - 0.4133228934F, 0.4138106959F, 0.4142985716F, 0.4147865201F, - 0.4152745408F, 0.4157626330F, 0.4162507963F, 0.4167390301F, - 0.4172273337F, 0.4177157067F, 0.4182041484F, 0.4186926583F, - 0.4191812359F, 0.4196698805F, 0.4201585915F, 0.4206473685F, - 0.4211362108F, 0.4216251179F, 0.4221140892F, 0.4226031241F, - 0.4230922221F, 0.4235813826F, 0.4240706050F, 0.4245598887F, - 0.4250492332F, 0.4255386379F, 0.4260281022F, 0.4265176256F, - 0.4270072075F, 0.4274968473F, 0.4279865445F, 0.4284762984F, - 0.4289661086F, 0.4294559743F, 0.4299458951F, 0.4304358704F, - 0.4309258996F, 0.4314159822F, 0.4319061175F, 0.4323963050F, - 0.4328865441F, 0.4333768342F, 0.4338671749F, 0.4343575654F, - 0.4348480052F, 0.4353384938F, 0.4358290306F, 0.4363196149F, - 0.4368102463F, 0.4373009241F, 0.4377916478F, 0.4382824168F, - 0.4387732305F, 0.4392640884F, 0.4397549899F, 0.4402459343F, - 0.4407369212F, 0.4412279499F, 0.4417190198F, 0.4422101305F, - 0.4427012813F, 0.4431924717F, 0.4436837010F, 0.4441749686F, - 0.4446662742F, 0.4451576169F, 0.4456489963F, 0.4461404118F, - 0.4466318628F, 0.4471233487F, 0.4476148690F, 0.4481064230F, - 0.4485980103F, 0.4490896302F, 0.4495812821F, 0.4500729654F, - 0.4505646797F, 0.4510564243F, 0.4515481986F, 0.4520400021F, - 0.4525318341F, 0.4530236942F, 0.4535155816F, 0.4540074959F, - 0.4544994365F, 0.4549914028F, 0.4554833941F, 0.4559754100F, - 0.4564674499F, 0.4569595131F, 0.4574515991F, 0.4579437074F, - 0.4584358372F, 0.4589279881F, 0.4594201595F, 0.4599123508F, - 0.4604045615F, 0.4608967908F, 0.4613890383F, 0.4618813034F, - 0.4623735855F, 0.4628658841F, 0.4633581984F, 0.4638505281F, - 0.4643428724F, 0.4648352308F, 0.4653276028F, 0.4658199877F, - 0.4663123849F, 0.4668047940F, 0.4672972143F, 0.4677896451F, - 0.4682820861F, 0.4687745365F, 0.4692669958F, 0.4697594634F, - 0.4702519387F, 0.4707444211F, 0.4712369102F, 0.4717294052F, - 0.4722219056F, 0.4727144109F, 0.4732069204F, 0.4736994336F, - 0.4741919498F, 0.4746844686F, 0.4751769893F, 0.4756695113F, - 0.4761620341F, 0.4766545571F, 0.4771470797F, 0.4776396013F, - 0.4781321213F, 0.4786246392F, 0.4791171544F, 0.4796096663F, - 0.4801021744F, 0.4805946779F, 0.4810871765F, 0.4815796694F, - 0.4820721561F, 0.4825646360F, 0.4830571086F, 0.4835495732F, - 0.4840420293F, 0.4845344763F, 0.4850269136F, 0.4855193407F, - 0.4860117569F, 0.4865041617F, 0.4869965545F, 0.4874889347F, - 0.4879813018F, 0.4884736551F, 0.4889659941F, 0.4894583182F, - 0.4899506268F, 0.4904429193F, 0.4909351952F, 0.4914274538F, - 0.4919196947F, 0.4924119172F, 0.4929041207F, 0.4933963046F, - 0.4938884685F, 0.4943806116F, 0.4948727335F, 0.4953648335F, - 0.4958569110F, 0.4963489656F, 0.4968409965F, 0.4973330032F, - 0.4978249852F, 0.4983169419F, 0.4988088726F, 0.4993007768F, - 0.4997926539F, 0.5002845034F, 0.5007763247F, 0.5012681171F, - 0.5017598801F, 0.5022516132F, 0.5027433157F, 0.5032349871F, - 0.5037266268F, 0.5042182341F, 0.5047098086F, 0.5052013497F, - 0.5056928567F, 0.5061843292F, 0.5066757664F, 0.5071671679F, - 0.5076585330F, 0.5081498613F, 0.5086411520F, 0.5091324047F, - 0.5096236187F, 0.5101147934F, 0.5106059284F, 0.5110970230F, - 0.5115880766F, 0.5120790887F, 0.5125700587F, 0.5130609860F, - 0.5135518700F, 0.5140427102F, 0.5145335059F, 0.5150242566F, - 0.5155149618F, 0.5160056208F, 0.5164962331F, 0.5169867980F, - 0.5174773151F, 0.5179677837F, 0.5184582033F, 0.5189485733F, - 0.5194388931F, 0.5199291621F, 0.5204193798F, 0.5209095455F, - 0.5213996588F, 0.5218897190F, 0.5223797256F, 0.5228696779F, - 0.5233595755F, 0.5238494177F, 0.5243392039F, 0.5248289337F, - 0.5253186063F, 0.5258082213F, 0.5262977781F, 0.5267872760F, - 0.5272767146F, 0.5277660932F, 0.5282554112F, 0.5287446682F, - 0.5292338635F, 0.5297229965F, 0.5302120667F, 0.5307010736F, - 0.5311900164F, 0.5316788947F, 0.5321677079F, 0.5326564554F, - 0.5331451366F, 0.5336337511F, 0.5341222981F, 0.5346107771F, - 0.5350991876F, 0.5355875290F, 0.5360758007F, 0.5365640021F, - 0.5370521327F, 0.5375401920F, 0.5380281792F, 0.5385160939F, - 0.5390039355F, 0.5394917034F, 0.5399793971F, 0.5404670159F, - 0.5409545594F, 0.5414420269F, 0.5419294179F, 0.5424167318F, - 0.5429039680F, 0.5433911261F, 0.5438782053F, 0.5443652051F, - 0.5448521250F, 0.5453389644F, 0.5458257228F, 0.5463123995F, - 0.5467989940F, 0.5472855057F, 0.5477719341F, 0.5482582786F, - 0.5487445387F, 0.5492307137F, 0.5497168031F, 0.5502028063F, - 0.5506887228F, 0.5511745520F, 0.5516602934F, 0.5521459463F, - 0.5526315103F, 0.5531169847F, 0.5536023690F, 0.5540876626F, - 0.5545728649F, 0.5550579755F, 0.5555429937F, 0.5560279189F, - 0.5565127507F, 0.5569974884F, 0.5574821315F, 0.5579666794F, - 0.5584511316F, 0.5589354875F, 0.5594197465F, 0.5599039080F, - 0.5603879716F, 0.5608719367F, 0.5613558026F, 0.5618395689F, - 0.5623232350F, 0.5628068002F, 0.5632902642F, 0.5637736262F, - 0.5642568858F, 0.5647400423F, 0.5652230953F, 0.5657060442F, - 0.5661888883F, 0.5666716272F, 0.5671542603F, 0.5676367870F, - 0.5681192069F, 0.5686015192F, 0.5690837235F, 0.5695658192F, - 0.5700478058F, 0.5705296827F, 0.5710114494F, 0.5714931052F, - 0.5719746497F, 0.5724560822F, 0.5729374023F, 0.5734186094F, - 0.5738997029F, 0.5743806823F, 0.5748615470F, 0.5753422965F, - 0.5758229301F, 0.5763034475F, 0.5767838480F, 0.5772641310F, - 0.5777442960F, 0.5782243426F, 0.5787042700F, 0.5791840778F, - 0.5796637654F, 0.5801433322F, 0.5806227778F, 0.5811021016F, - 0.5815813029F, 0.5820603814F, 0.5825393363F, 0.5830181673F, - 0.5834968737F, 0.5839754549F, 0.5844539105F, 0.5849322399F, - 0.5854104425F, 0.5858885179F, 0.5863664653F, 0.5868442844F, - 0.5873219746F, 0.5877995353F, 0.5882769660F, 0.5887542661F, - 0.5892314351F, 0.5897084724F, 0.5901853776F, 0.5906621500F, - 0.5911387892F, 0.5916152945F, 0.5920916655F, 0.5925679016F, - 0.5930440022F, 0.5935199669F, 0.5939957950F, 0.5944714861F, - 0.5949470396F, 0.5954224550F, 0.5958977317F, 0.5963728692F, - 0.5968478669F, 0.5973227244F, 0.5977974411F, 0.5982720163F, - 0.5987464497F, 0.5992207407F, 0.5996948887F, 0.6001688932F, - 0.6006427537F, 0.6011164696F, 0.6015900405F, 0.6020634657F, - 0.6025367447F, 0.6030098770F, 0.6034828621F, 0.6039556995F, - 0.6044283885F, 0.6049009288F, 0.6053733196F, 0.6058455606F, - 0.6063176512F, 0.6067895909F, 0.6072613790F, 0.6077330152F, - 0.6082044989F, 0.6086758295F, 0.6091470065F, 0.6096180294F, - 0.6100888977F, 0.6105596108F, 0.6110301682F, 0.6115005694F, - 0.6119708139F, 0.6124409011F, 0.6129108305F, 0.6133806017F, - 0.6138502139F, 0.6143196669F, 0.6147889599F, 0.6152580926F, - 0.6157270643F, 0.6161958746F, 0.6166645230F, 0.6171330088F, - 0.6176013317F, 0.6180694910F, 0.6185374863F, 0.6190053171F, - 0.6194729827F, 0.6199404828F, 0.6204078167F, 0.6208749841F, - 0.6213419842F, 0.6218088168F, 0.6222754811F, 0.6227419768F, - 0.6232083032F, 0.6236744600F, 0.6241404465F, 0.6246062622F, - 0.6250719067F, 0.6255373795F, 0.6260026799F, 0.6264678076F, - 0.6269327619F, 0.6273975425F, 0.6278621487F, 0.6283265800F, - 0.6287908361F, 0.6292549163F, 0.6297188201F, 0.6301825471F, - 0.6306460966F, 0.6311094683F, 0.6315726617F, 0.6320356761F, - 0.6324985111F, 0.6329611662F, 0.6334236410F, 0.6338859348F, - 0.6343480472F, 0.6348099777F, 0.6352717257F, 0.6357332909F, - 0.6361946726F, 0.6366558704F, 0.6371168837F, 0.6375777122F, - 0.6380383552F, 0.6384988123F, 0.6389590830F, 0.6394191668F, - 0.6398790631F, 0.6403387716F, 0.6407982916F, 0.6412576228F, - 0.6417167645F, 0.6421757163F, 0.6426344778F, 0.6430930483F, - 0.6435514275F, 0.6440096149F, 0.6444676098F, 0.6449254119F, - 0.6453830207F, 0.6458404356F, 0.6462976562F, 0.6467546820F, - 0.6472115125F, 0.6476681472F, 0.6481245856F, 0.6485808273F, - 0.6490368717F, 0.6494927183F, 0.6499483667F, 0.6504038164F, - 0.6508590670F, 0.6513141178F, 0.6517689684F, 0.6522236185F, - 0.6526780673F, 0.6531323146F, 0.6535863598F, 0.6540402024F, - 0.6544938419F, 0.6549472779F, 0.6554005099F, 0.6558535373F, - 0.6563063598F, 0.6567589769F, 0.6572113880F, 0.6576635927F, - 0.6581155906F, 0.6585673810F, 0.6590189637F, 0.6594703380F, - 0.6599215035F, 0.6603724598F, 0.6608232064F, 0.6612737427F, - 0.6617240684F, 0.6621741829F, 0.6626240859F, 0.6630737767F, - 0.6635232550F, 0.6639725202F, 0.6644215720F, 0.6648704098F, - 0.6653190332F, 0.6657674417F, 0.6662156348F, 0.6666636121F, - 0.6671113731F, 0.6675589174F, 0.6680062445F, 0.6684533538F, - 0.6689002450F, 0.6693469177F, 0.6697933712F, 0.6702396052F, - 0.6706856193F, 0.6711314129F, 0.6715769855F, 0.6720223369F, - 0.6724674664F, 0.6729123736F, 0.6733570581F, 0.6738015194F, - 0.6742457570F, 0.6746897706F, 0.6751335596F, 0.6755771236F, - 0.6760204621F, 0.6764635747F, 0.6769064609F, 0.6773491204F, - 0.6777915525F, 0.6782337570F, 0.6786757332F, 0.6791174809F, - 0.6795589995F, 0.6800002886F, 0.6804413477F, 0.6808821765F, - 0.6813227743F, 0.6817631409F, 0.6822032758F, 0.6826431785F, - 0.6830828485F, 0.6835222855F, 0.6839614890F, 0.6844004585F, - 0.6848391936F, 0.6852776939F, 0.6857159589F, 0.6861539883F, - 0.6865917815F, 0.6870293381F, 0.6874666576F, 0.6879037398F, - 0.6883405840F, 0.6887771899F, 0.6892135571F, 0.6896496850F, - 0.6900855733F, 0.6905212216F, 0.6909566294F, 0.6913917963F, - 0.6918267218F, 0.6922614055F, 0.6926958471F, 0.6931300459F, - 0.6935640018F, 0.6939977141F, 0.6944311825F, 0.6948644066F, - 0.6952973859F, 0.6957301200F, 0.6961626085F, 0.6965948510F, - 0.6970268470F, 0.6974585961F, 0.6978900980F, 0.6983213521F, - 0.6987523580F, 0.6991831154F, 0.6996136238F, 0.7000438828F, - 0.7004738921F, 0.7009036510F, 0.7013331594F, 0.7017624166F, - 0.7021914224F, 0.7026201763F, 0.7030486779F, 0.7034769268F, - 0.7039049226F, 0.7043326648F, 0.7047601531F, 0.7051873870F, - 0.7056143662F, 0.7060410902F, 0.7064675586F, 0.7068937711F, - 0.7073197271F, 0.7077454264F, 0.7081708684F, 0.7085960529F, - 0.7090209793F, 0.7094456474F, 0.7098700566F, 0.7102942066F, - 0.7107180970F, 0.7111417274F, 0.7115650974F, 0.7119882066F, - 0.7124110545F, 0.7128336409F, 0.7132559653F, 0.7136780272F, - 0.7140998264F, 0.7145213624F, 0.7149426348F, 0.7153636433F, - 0.7157843874F, 0.7162048668F, 0.7166250810F, 0.7170450296F, - 0.7174647124F, 0.7178841289F, 0.7183032786F, 0.7187221613F, - 0.7191407765F, 0.7195591239F, 0.7199772030F, 0.7203950135F, - 0.7208125550F, 0.7212298271F, 0.7216468294F, 0.7220635616F, - 0.7224800233F, 0.7228962140F, 0.7233121335F, 0.7237277813F, - 0.7241431571F, 0.7245582604F, 0.7249730910F, 0.7253876484F, - 0.7258019322F, 0.7262159422F, 0.7266296778F, 0.7270431388F, - 0.7274563247F, 0.7278692353F, 0.7282818700F, 0.7286942287F, - 0.7291063108F, 0.7295181160F, 0.7299296440F, 0.7303408944F, - 0.7307518669F, 0.7311625609F, 0.7315729763F, 0.7319831126F, - 0.7323929695F, 0.7328025466F, 0.7332118435F, 0.7336208600F, - 0.7340295955F, 0.7344380499F, 0.7348462226F, 0.7352541134F, - 0.7356617220F, 0.7360690478F, 0.7364760907F, 0.7368828502F, - 0.7372893259F, 0.7376955176F, 0.7381014249F, 0.7385070475F, - 0.7389123849F, 0.7393174368F, 0.7397222029F, 0.7401266829F, - 0.7405308763F, 0.7409347829F, 0.7413384023F, 0.7417417341F, - 0.7421447780F, 0.7425475338F, 0.7429500009F, 0.7433521791F, - 0.7437540681F, 0.7441556674F, 0.7445569769F, 0.7449579960F, - 0.7453587245F, 0.7457591621F, 0.7461593084F, 0.7465591631F, - 0.7469587259F, 0.7473579963F, 0.7477569741F, 0.7481556590F, - 0.7485540506F, 0.7489521486F, 0.7493499526F, 0.7497474623F, - 0.7501446775F, 0.7505415977F, 0.7509382227F, 0.7513345521F, - 0.7517305856F, 0.7521263229F, 0.7525217636F, 0.7529169074F, - 0.7533117541F, 0.7537063032F, 0.7541005545F, 0.7544945076F, - 0.7548881623F, 0.7552815182F, 0.7556745749F, 0.7560673323F, - 0.7564597899F, 0.7568519474F, 0.7572438046F, 0.7576353611F, - 0.7580266166F, 0.7584175708F, 0.7588082235F, 0.7591985741F, - 0.7595886226F, 0.7599783685F, 0.7603678116F, 0.7607569515F, - 0.7611457879F, 0.7615343206F, 0.7619225493F, 0.7623104735F, - 0.7626980931F, 0.7630854078F, 0.7634724171F, 0.7638591209F, - 0.7642455188F, 0.7646316106F, 0.7650173959F, 0.7654028744F, - 0.7657880459F, 0.7661729100F, 0.7665574664F, 0.7669417150F, - 0.7673256553F, 0.7677092871F, 0.7680926100F, 0.7684756239F, - 0.7688583284F, 0.7692407232F, 0.7696228080F, 0.7700045826F, - 0.7703860467F, 0.7707671999F, 0.7711480420F, 0.7715285728F, - 0.7719087918F, 0.7722886989F, 0.7726682938F, 0.7730475762F, - 0.7734265458F, 0.7738052023F, 0.7741835454F, 0.7745615750F, - 0.7749392906F, 0.7753166921F, 0.7756937791F, 0.7760705514F, - 0.7764470087F, 0.7768231508F, 0.7771989773F, 0.7775744880F, - 0.7779496827F, 0.7783245610F, 0.7786991227F, 0.7790733676F, - 0.7794472953F, 0.7798209056F, 0.7801941982F, 0.7805671729F, - 0.7809398294F, 0.7813121675F, 0.7816841869F, 0.7820558873F, - 0.7824272684F, 0.7827983301F, 0.7831690720F, 0.7835394940F, - 0.7839095957F, 0.7842793768F, 0.7846488373F, 0.7850179767F, - 0.7853867948F, 0.7857552914F, 0.7861234663F, 0.7864913191F, - 0.7868588497F, 0.7872260578F, 0.7875929431F, 0.7879595055F, - 0.7883257445F, 0.7886916601F, 0.7890572520F, 0.7894225198F, - 0.7897874635F, 0.7901520827F, 0.7905163772F, 0.7908803468F, - 0.7912439912F, 0.7916073102F, 0.7919703035F, 0.7923329710F, - 0.7926953124F, 0.7930573274F, 0.7934190158F, 0.7937803774F, - 0.7941414120F, 0.7945021193F, 0.7948624991F, 0.7952225511F, - 0.7955822752F, 0.7959416711F, 0.7963007387F, 0.7966594775F, - 0.7970178875F, 0.7973759685F, 0.7977337201F, 0.7980911422F, - 0.7984482346F, 0.7988049970F, 0.7991614292F, 0.7995175310F, - 0.7998733022F, 0.8002287426F, 0.8005838519F, 0.8009386299F, - 0.8012930765F, 0.8016471914F, 0.8020009744F, 0.8023544253F, - 0.8027075438F, 0.8030603298F, 0.8034127831F, 0.8037649035F, - 0.8041166906F, 0.8044681445F, 0.8048192647F, 0.8051700512F, - 0.8055205038F, 0.8058706222F, 0.8062204062F, 0.8065698556F, - 0.8069189702F, 0.8072677499F, 0.8076161944F, 0.8079643036F, - 0.8083120772F, 0.8086595151F, 0.8090066170F, 0.8093533827F, - 0.8096998122F, 0.8100459051F, 0.8103916613F, 0.8107370806F, - 0.8110821628F, 0.8114269077F, 0.8117713151F, 0.8121153849F, - 0.8124591169F, 0.8128025108F, 0.8131455666F, 0.8134882839F, - 0.8138306627F, 0.8141727027F, 0.8145144038F, 0.8148557658F, - 0.8151967886F, 0.8155374718F, 0.8158778154F, 0.8162178192F, - 0.8165574830F, 0.8168968067F, 0.8172357900F, 0.8175744328F, - 0.8179127349F, 0.8182506962F, 0.8185883164F, 0.8189255955F, - 0.8192625332F, 0.8195991295F, 0.8199353840F, 0.8202712967F, - 0.8206068673F, 0.8209420958F, 0.8212769820F, 0.8216115256F, - 0.8219457266F, 0.8222795848F, 0.8226131000F, 0.8229462721F, - 0.8232791009F, 0.8236115863F, 0.8239437280F, 0.8242755260F, - 0.8246069801F, 0.8249380901F, 0.8252688559F, 0.8255992774F, - 0.8259293544F, 0.8262590867F, 0.8265884741F, 0.8269175167F, - 0.8272462141F, 0.8275745663F, 0.8279025732F, 0.8282302344F, - 0.8285575501F, 0.8288845199F, 0.8292111437F, 0.8295374215F, - 0.8298633530F, 0.8301889382F, 0.8305141768F, 0.8308390688F, - 0.8311636141F, 0.8314878124F, 0.8318116637F, 0.8321351678F, - 0.8324583246F, 0.8327811340F, 0.8331035957F, 0.8334257098F, - 0.8337474761F, 0.8340688944F, 0.8343899647F, 0.8347106867F, - 0.8350310605F, 0.8353510857F, 0.8356707624F, 0.8359900904F, - 0.8363090696F, 0.8366276999F, 0.8369459811F, 0.8372639131F, - 0.8375814958F, 0.8378987292F, 0.8382156130F, 0.8385321472F, - 0.8388483316F, 0.8391641662F, 0.8394796508F, 0.8397947853F, - 0.8401095697F, 0.8404240037F, 0.8407380873F, 0.8410518204F, - 0.8413652029F, 0.8416782347F, 0.8419909156F, 0.8423032456F, - 0.8426152245F, 0.8429268523F, 0.8432381289F, 0.8435490541F, - 0.8438596279F, 0.8441698502F, 0.8444797208F, 0.8447892396F, - 0.8450984067F, 0.8454072218F, 0.8457156849F, 0.8460237959F, - 0.8463315547F, 0.8466389612F, 0.8469460154F, 0.8472527170F, - 0.8475590661F, 0.8478650625F, 0.8481707063F, 0.8484759971F, - 0.8487809351F, 0.8490855201F, 0.8493897521F, 0.8496936308F, - 0.8499971564F, 0.8503003286F, 0.8506031474F, 0.8509056128F, - 0.8512077246F, 0.8515094828F, 0.8518108872F, 0.8521119379F, - 0.8524126348F, 0.8527129777F, 0.8530129666F, 0.8533126015F, - 0.8536118822F, 0.8539108087F, 0.8542093809F, 0.8545075988F, - 0.8548054623F, 0.8551029712F, 0.8554001257F, 0.8556969255F, - 0.8559933707F, 0.8562894611F, 0.8565851968F, 0.8568805775F, - 0.8571756034F, 0.8574702743F, 0.8577645902F, 0.8580585509F, - 0.8583521566F, 0.8586454070F, 0.8589383021F, 0.8592308420F, - 0.8595230265F, 0.8598148556F, 0.8601063292F, 0.8603974473F, - 0.8606882098F, 0.8609786167F, 0.8612686680F, 0.8615583636F, - 0.8618477034F, 0.8621366874F, 0.8624253156F, 0.8627135878F, - 0.8630015042F, 0.8632890646F, 0.8635762690F, 0.8638631173F, - 0.8641496096F, 0.8644357457F, 0.8647215257F, 0.8650069495F, - 0.8652920171F, 0.8655767283F, 0.8658610833F, 0.8661450820F, - 0.8664287243F, 0.8667120102F, 0.8669949397F, 0.8672775127F, - 0.8675597293F, 0.8678415894F, 0.8681230929F, 0.8684042398F, - 0.8686850302F, 0.8689654640F, 0.8692455412F, 0.8695252617F, - 0.8698046255F, 0.8700836327F, 0.8703622831F, 0.8706405768F, - 0.8709185138F, 0.8711960940F, 0.8714733174F, 0.8717501840F, - 0.8720266939F, 0.8723028469F, 0.8725786430F, 0.8728540824F, - 0.8731291648F, 0.8734038905F, 0.8736782592F, 0.8739522711F, - 0.8742259261F, 0.8744992242F, 0.8747721653F, 0.8750447496F, - 0.8753169770F, 0.8755888475F, 0.8758603611F, 0.8761315177F, - 0.8764023175F, 0.8766727603F, 0.8769428462F, 0.8772125752F, - 0.8774819474F, 0.8777509626F, 0.8780196209F, 0.8782879224F, - 0.8785558669F, 0.8788234546F, 0.8790906854F, 0.8793575594F, - 0.8796240765F, 0.8798902368F, 0.8801560403F, 0.8804214870F, - 0.8806865768F, 0.8809513099F, 0.8812156863F, 0.8814797059F, - 0.8817433687F, 0.8820066749F, 0.8822696243F, 0.8825322171F, - 0.8827944532F, 0.8830563327F, 0.8833178556F, 0.8835790219F, - 0.8838398316F, 0.8841002848F, 0.8843603815F, 0.8846201217F, - 0.8848795054F, 0.8851385327F, 0.8853972036F, 0.8856555182F, - 0.8859134764F, 0.8861710783F, 0.8864283239F, 0.8866852133F, - 0.8869417464F, 0.8871979234F, 0.8874537443F, 0.8877092090F, - 0.8879643177F, 0.8882190704F, 0.8884734671F, 0.8887275078F, - 0.8889811927F, 0.8892345216F, 0.8894874948F, 0.8897401122F, - 0.8899923738F, 0.8902442798F, 0.8904958301F, 0.8907470248F, - 0.8909978640F, 0.8912483477F, 0.8914984759F, 0.8917482487F, - 0.8919976662F, 0.8922467284F, 0.8924954353F, 0.8927437871F, - 0.8929917837F, 0.8932394252F, 0.8934867118F, 0.8937336433F, - 0.8939802199F, 0.8942264417F, 0.8944723087F, 0.8947178210F, - 0.8949629785F, 0.8952077815F, 0.8954522299F, 0.8956963239F, - 0.8959400634F, 0.8961834486F, 0.8964264795F, 0.8966691561F, - 0.8969114786F, 0.8971534470F, 0.8973950614F, 0.8976363219F, - 0.8978772284F, 0.8981177812F, 0.8983579802F, 0.8985978256F, - 0.8988373174F, 0.8990764556F, 0.8993152405F, 0.8995536720F, - 0.8997917502F, 0.9000294751F, 0.9002668470F, 0.9005038658F, - 0.9007405317F, 0.9009768446F, 0.9012128048F, 0.9014484123F, - 0.9016836671F, 0.9019185693F, 0.9021531191F, 0.9023873165F, - 0.9026211616F, 0.9028546546F, 0.9030877954F, 0.9033205841F, - 0.9035530210F, 0.9037851059F, 0.9040168392F, 0.9042482207F, - 0.9044792507F, 0.9047099293F, 0.9049402564F, 0.9051702323F, - 0.9053998569F, 0.9056291305F, 0.9058580531F, 0.9060866248F, - 0.9063148457F, 0.9065427159F, 0.9067702355F, 0.9069974046F, - 0.9072242233F, 0.9074506917F, 0.9076768100F, 0.9079025782F, - 0.9081279964F, 0.9083530647F, 0.9085777833F, 0.9088021523F, - 0.9090261717F, 0.9092498417F, 0.9094731623F, 0.9096961338F, - 0.9099187561F, 0.9101410295F, 0.9103629540F, 0.9105845297F, - 0.9108057568F, 0.9110266354F, 0.9112471656F, 0.9114673475F, - 0.9116871812F, 0.9119066668F, 0.9121258046F, 0.9123445945F, - 0.9125630367F, 0.9127811314F, 0.9129988786F, 0.9132162785F, - 0.9134333312F, 0.9136500368F, 0.9138663954F, 0.9140824073F, - 0.9142980724F, 0.9145133910F, 0.9147283632F, 0.9149429890F, - 0.9151572687F, 0.9153712023F, 0.9155847900F, 0.9157980319F, - 0.9160109282F, 0.9162234790F, 0.9164356844F, 0.9166475445F, - 0.9168590595F, 0.9170702296F, 0.9172810548F, 0.9174915354F, - 0.9177016714F, 0.9179114629F, 0.9181209102F, 0.9183300134F, - 0.9185387726F, 0.9187471879F, 0.9189552595F, 0.9191629876F, - 0.9193703723F, 0.9195774136F, 0.9197841119F, 0.9199904672F, - 0.9201964797F, 0.9204021495F, 0.9206074767F, 0.9208124616F, - 0.9210171043F, 0.9212214049F, 0.9214253636F, 0.9216289805F, - 0.9218322558F, 0.9220351896F, 0.9222377821F, 0.9224400335F, - 0.9226419439F, 0.9228435134F, 0.9230447423F, 0.9232456307F, - 0.9234461787F, 0.9236463865F, 0.9238462543F, 0.9240457822F, - 0.9242449704F, 0.9244438190F, 0.9246423282F, 0.9248404983F, - 0.9250383293F, 0.9252358214F, 0.9254329747F, 0.9256297896F, - 0.9258262660F, 0.9260224042F, 0.9262182044F, 0.9264136667F, - 0.9266087913F, 0.9268035783F, 0.9269980280F, 0.9271921405F, - 0.9273859160F, 0.9275793546F, 0.9277724566F, 0.9279652221F, - 0.9281576513F, 0.9283497443F, 0.9285415014F, 0.9287329227F, - 0.9289240084F, 0.9291147586F, 0.9293051737F, 0.9294952536F, - 0.9296849987F, 0.9298744091F, 0.9300634850F, 0.9302522266F, - 0.9304406340F, 0.9306287074F, 0.9308164471F, 0.9310038532F, - 0.9311909259F, 0.9313776654F, 0.9315640719F, 0.9317501455F, - 0.9319358865F, 0.9321212951F, 0.9323063713F, 0.9324911155F, - 0.9326755279F, 0.9328596085F, 0.9330433577F, 0.9332267756F, - 0.9334098623F, 0.9335926182F, 0.9337750434F, 0.9339571380F, - 0.9341389023F, 0.9343203366F, 0.9345014409F, 0.9346822155F, - 0.9348626606F, 0.9350427763F, 0.9352225630F, 0.9354020207F, - 0.9355811498F, 0.9357599503F, 0.9359384226F, 0.9361165667F, - 0.9362943830F, 0.9364718716F, 0.9366490327F, 0.9368258666F, - 0.9370023733F, 0.9371785533F, 0.9373544066F, 0.9375299335F, - 0.9377051341F, 0.9378800087F, 0.9380545576F, 0.9382287809F, - 0.9384026787F, 0.9385762515F, 0.9387494993F, 0.9389224223F, - 0.9390950209F, 0.9392672951F, 0.9394392453F, 0.9396108716F, - 0.9397821743F, 0.9399531536F, 0.9401238096F, 0.9402941427F, - 0.9404641530F, 0.9406338407F, 0.9408032061F, 0.9409722495F, - 0.9411409709F, 0.9413093707F, 0.9414774491F, 0.9416452062F, - 0.9418126424F, 0.9419797579F, 0.9421465528F, 0.9423130274F, - 0.9424791819F, 0.9426450166F, 0.9428105317F, 0.9429757274F, - 0.9431406039F, 0.9433051616F, 0.9434694005F, 0.9436333209F, - 0.9437969232F, 0.9439602074F, 0.9441231739F, 0.9442858229F, - 0.9444481545F, 0.9446101691F, 0.9447718669F, 0.9449332481F, - 0.9450943129F, 0.9452550617F, 0.9454154945F, 0.9455756118F, - 0.9457354136F, 0.9458949003F, 0.9460540721F, 0.9462129292F, - 0.9463714719F, 0.9465297003F, 0.9466876149F, 0.9468452157F, - 0.9470025031F, 0.9471594772F, 0.9473161384F, 0.9474724869F, - 0.9476285229F, 0.9477842466F, 0.9479396584F, 0.9480947585F, - 0.9482495470F, 0.9484040243F, 0.9485581906F, 0.9487120462F, - 0.9488655913F, 0.9490188262F, 0.9491717511F, 0.9493243662F, - 0.9494766718F, 0.9496286683F, 0.9497803557F, 0.9499317345F, - 0.9500828047F, 0.9502335668F, 0.9503840209F, 0.9505341673F, - 0.9506840062F, 0.9508335380F, 0.9509827629F, 0.9511316810F, - 0.9512802928F, 0.9514285984F, 0.9515765982F, 0.9517242923F, - 0.9518716810F, 0.9520187646F, 0.9521655434F, 0.9523120176F, - 0.9524581875F, 0.9526040534F, 0.9527496154F, 0.9528948739F, - 0.9530398292F, 0.9531844814F, 0.9533288310F, 0.9534728780F, - 0.9536166229F, 0.9537600659F, 0.9539032071F, 0.9540460470F, - 0.9541885858F, 0.9543308237F, 0.9544727611F, 0.9546143981F, - 0.9547557351F, 0.9548967723F, 0.9550375100F, 0.9551779485F, - 0.9553180881F, 0.9554579290F, 0.9555974714F, 0.9557367158F, - 0.9558756623F, 0.9560143112F, 0.9561526628F, 0.9562907174F, - 0.9564284752F, 0.9565659366F, 0.9567031017F, 0.9568399710F, - 0.9569765446F, 0.9571128229F, 0.9572488061F, 0.9573844944F, - 0.9575198883F, 0.9576549879F, 0.9577897936F, 0.9579243056F, - 0.9580585242F, 0.9581924497F, 0.9583260824F, 0.9584594226F, - 0.9585924705F, 0.9587252264F, 0.9588576906F, 0.9589898634F, - 0.9591217452F, 0.9592533360F, 0.9593846364F, 0.9595156465F, - 0.9596463666F, 0.9597767971F, 0.9599069382F, 0.9600367901F, - 0.9601663533F, 0.9602956279F, 0.9604246143F, 0.9605533128F, - 0.9606817236F, 0.9608098471F, 0.9609376835F, 0.9610652332F, - 0.9611924963F, 0.9613194733F, 0.9614461644F, 0.9615725699F, - 0.9616986901F, 0.9618245253F, 0.9619500757F, 0.9620753418F, - 0.9622003238F, 0.9623250219F, 0.9624494365F, 0.9625735679F, - 0.9626974163F, 0.9628209821F, 0.9629442656F, 0.9630672671F, - 0.9631899868F, 0.9633124251F, 0.9634345822F, 0.9635564585F, - 0.9636780543F, 0.9637993699F, 0.9639204056F, 0.9640411616F, - 0.9641616383F, 0.9642818359F, 0.9644017549F, 0.9645213955F, - 0.9646407579F, 0.9647598426F, 0.9648786497F, 0.9649971797F, - 0.9651154328F, 0.9652334092F, 0.9653511095F, 0.9654685337F, - 0.9655856823F, 0.9657025556F, 0.9658191538F, 0.9659354773F, - 0.9660515263F, 0.9661673013F, 0.9662828024F, 0.9663980300F, - 0.9665129845F, 0.9666276660F, 0.9667420750F, 0.9668562118F, - 0.9669700766F, 0.9670836698F, 0.9671969917F, 0.9673100425F, - 0.9674228227F, 0.9675353325F, 0.9676475722F, 0.9677595422F, - 0.9678712428F, 0.9679826742F, 0.9680938368F, 0.9682047309F, - 0.9683153569F, 0.9684257150F, 0.9685358056F, 0.9686456289F, - 0.9687551853F, 0.9688644752F, 0.9689734987F, 0.9690822564F, - 0.9691907483F, 0.9692989750F, 0.9694069367F, 0.9695146337F, - 0.9696220663F, 0.9697292349F, 0.9698361398F, 0.9699427813F, - 0.9700491597F, 0.9701552754F, 0.9702611286F, 0.9703667197F, - 0.9704720490F, 0.9705771169F, 0.9706819236F, 0.9707864695F, - 0.9708907549F, 0.9709947802F, 0.9710985456F, 0.9712020514F, - 0.9713052981F, 0.9714082859F, 0.9715110151F, 0.9716134862F, - 0.9717156993F, 0.9718176549F, 0.9719193532F, 0.9720207946F, - 0.9721219794F, 0.9722229080F, 0.9723235806F, 0.9724239976F, - 0.9725241593F, 0.9726240661F, 0.9727237183F, 0.9728231161F, - 0.9729222601F, 0.9730211503F, 0.9731197873F, 0.9732181713F, - 0.9733163027F, 0.9734141817F, 0.9735118088F, 0.9736091842F, - 0.9737063083F, 0.9738031814F, 0.9738998039F, 0.9739961760F, - 0.9740922981F, 0.9741881706F, 0.9742837938F, 0.9743791680F, - 0.9744742935F, 0.9745691707F, 0.9746637999F, 0.9747581814F, - 0.9748523157F, 0.9749462029F, 0.9750398435F, 0.9751332378F, - 0.9752263861F, 0.9753192887F, 0.9754119461F, 0.9755043585F, - 0.9755965262F, 0.9756884496F, 0.9757801291F, 0.9758715650F, - 0.9759627575F, 0.9760537071F, 0.9761444141F, 0.9762348789F, - 0.9763251016F, 0.9764150828F, 0.9765048228F, 0.9765943218F, - 0.9766835802F, 0.9767725984F, 0.9768613767F, 0.9769499154F, - 0.9770382149F, 0.9771262755F, 0.9772140976F, 0.9773016815F, - 0.9773890275F, 0.9774761360F, 0.9775630073F, 0.9776496418F, - 0.9777360398F, 0.9778222016F, 0.9779081277F, 0.9779938182F, - 0.9780792736F, 0.9781644943F, 0.9782494805F, 0.9783342326F, - 0.9784187509F, 0.9785030359F, 0.9785870877F, 0.9786709069F, - 0.9787544936F, 0.9788378484F, 0.9789209714F, 0.9790038631F, - 0.9790865238F, 0.9791689538F, 0.9792511535F, 0.9793331232F, - 0.9794148633F, 0.9794963742F, 0.9795776561F, 0.9796587094F, - 0.9797395345F, 0.9798201316F, 0.9799005013F, 0.9799806437F, - 0.9800605593F, 0.9801402483F, 0.9802197112F, 0.9802989483F, - 0.9803779600F, 0.9804567465F, 0.9805353082F, 0.9806136455F, - 0.9806917587F, 0.9807696482F, 0.9808473143F, 0.9809247574F, - 0.9810019778F, 0.9810789759F, 0.9811557519F, 0.9812323064F, - 0.9813086395F, 0.9813847517F, 0.9814606433F, 0.9815363147F, - 0.9816117662F, 0.9816869981F, 0.9817620108F, 0.9818368047F, - 0.9819113801F, 0.9819857374F, 0.9820598769F, 0.9821337989F, - 0.9822075038F, 0.9822809920F, 0.9823542638F, 0.9824273195F, - 0.9825001596F, 0.9825727843F, 0.9826451940F, 0.9827173891F, - 0.9827893700F, 0.9828611368F, 0.9829326901F, 0.9830040302F, - 0.9830751574F, 0.9831460720F, 0.9832167745F, 0.9832872652F, - 0.9833575444F, 0.9834276124F, 0.9834974697F, 0.9835671166F, - 0.9836365535F, 0.9837057806F, 0.9837747983F, 0.9838436071F, - 0.9839122072F, 0.9839805990F, 0.9840487829F, 0.9841167591F, - 0.9841845282F, 0.9842520903F, 0.9843194459F, 0.9843865953F, - 0.9844535389F, 0.9845202771F, 0.9845868101F, 0.9846531383F, - 0.9847192622F, 0.9847851820F, 0.9848508980F, 0.9849164108F, - 0.9849817205F, 0.9850468276F, 0.9851117324F, 0.9851764352F, - 0.9852409365F, 0.9853052366F, 0.9853693358F, 0.9854332344F, - 0.9854969330F, 0.9855604317F, 0.9856237309F, 0.9856868310F, - 0.9857497325F, 0.9858124355F, 0.9858749404F, 0.9859372477F, - 0.9859993577F, 0.9860612707F, 0.9861229871F, 0.9861845072F, - 0.9862458315F, 0.9863069601F, 0.9863678936F, 0.9864286322F, - 0.9864891764F, 0.9865495264F, 0.9866096826F, 0.9866696454F, - 0.9867294152F, 0.9867889922F, 0.9868483769F, 0.9869075695F, - 0.9869665706F, 0.9870253803F, 0.9870839991F, 0.9871424273F, - 0.9872006653F, 0.9872587135F, 0.9873165721F, 0.9873742415F, - 0.9874317222F, 0.9874890144F, 0.9875461185F, 0.9876030348F, - 0.9876597638F, 0.9877163057F, 0.9877726610F, 0.9878288300F, - 0.9878848130F, 0.9879406104F, 0.9879962225F, 0.9880516497F, - 0.9881068924F, 0.9881619509F, 0.9882168256F, 0.9882715168F, - 0.9883260249F, 0.9883803502F, 0.9884344931F, 0.9884884539F, - 0.9885422331F, 0.9885958309F, 0.9886492477F, 0.9887024838F, - 0.9887555397F, 0.9888084157F, 0.9888611120F, 0.9889136292F, - 0.9889659675F, 0.9890181273F, 0.9890701089F, 0.9891219128F, - 0.9891735392F, 0.9892249885F, 0.9892762610F, 0.9893273572F, - 0.9893782774F, 0.9894290219F, 0.9894795911F, 0.9895299853F, - 0.9895802049F, 0.9896302502F, 0.9896801217F, 0.9897298196F, - 0.9897793443F, 0.9898286961F, 0.9898778755F, 0.9899268828F, - 0.9899757183F, 0.9900243823F, 0.9900728753F, 0.9901211976F, - 0.9901693495F, 0.9902173314F, 0.9902651436F, 0.9903127865F, - 0.9903602605F, 0.9904075659F, 0.9904547031F, 0.9905016723F, - 0.9905484740F, 0.9905951086F, 0.9906415763F, 0.9906878775F, - 0.9907340126F, 0.9907799819F, 0.9908257858F, 0.9908714247F, - 0.9909168988F, 0.9909622086F, 0.9910073543F, 0.9910523364F, - 0.9910971552F, 0.9911418110F, 0.9911863042F, 0.9912306351F, - 0.9912748042F, 0.9913188117F, 0.9913626580F, 0.9914063435F, - 0.9914498684F, 0.9914932333F, 0.9915364383F, 0.9915794839F, - 0.9916223703F, 0.9916650981F, 0.9917076674F, 0.9917500787F, - 0.9917923323F, 0.9918344286F, 0.9918763679F, 0.9919181505F, - 0.9919597769F, 0.9920012473F, 0.9920425621F, 0.9920837217F, - 0.9921247263F, 0.9921655765F, 0.9922062724F, 0.9922468145F, - 0.9922872030F, 0.9923274385F, 0.9923675211F, 0.9924074513F, - 0.9924472294F, 0.9924868557F, 0.9925263306F, 0.9925656544F, - 0.9926048275F, 0.9926438503F, 0.9926827230F, 0.9927214461F, - 0.9927600199F, 0.9927984446F, 0.9928367208F, 0.9928748486F, - 0.9929128285F, 0.9929506608F, 0.9929883459F, 0.9930258841F, - 0.9930632757F, 0.9931005211F, 0.9931376207F, 0.9931745747F, - 0.9932113836F, 0.9932480476F, 0.9932845671F, 0.9933209425F, - 0.9933571742F, 0.9933932623F, 0.9934292074F, 0.9934650097F, - 0.9935006696F, 0.9935361874F, 0.9935715635F, 0.9936067982F, - 0.9936418919F, 0.9936768448F, 0.9937116574F, 0.9937463300F, - 0.9937808629F, 0.9938152565F, 0.9938495111F, 0.9938836271F, - 0.9939176047F, 0.9939514444F, 0.9939851465F, 0.9940187112F, - 0.9940521391F, 0.9940854303F, 0.9941185853F, 0.9941516044F, - 0.9941844879F, 0.9942172361F, 0.9942498495F, 0.9942823283F, - 0.9943146729F, 0.9943468836F, 0.9943789608F, 0.9944109047F, - 0.9944427158F, 0.9944743944F, 0.9945059408F, 0.9945373553F, - 0.9945686384F, 0.9945997902F, 0.9946308112F, 0.9946617017F, - 0.9946924621F, 0.9947230926F, 0.9947535937F, 0.9947839656F, - 0.9948142086F, 0.9948443232F, 0.9948743097F, 0.9949041683F, - 0.9949338995F, 0.9949635035F, 0.9949929807F, 0.9950223315F, - 0.9950515561F, 0.9950806549F, 0.9951096282F, 0.9951384764F, - 0.9951671998F, 0.9951957987F, 0.9952242735F, 0.9952526245F, - 0.9952808520F, 0.9953089564F, 0.9953369380F, 0.9953647971F, - 0.9953925340F, 0.9954201491F, 0.9954476428F, 0.9954750153F, - 0.9955022670F, 0.9955293981F, 0.9955564092F, 0.9955833003F, - 0.9956100720F, 0.9956367245F, 0.9956632582F, 0.9956896733F, - 0.9957159703F, 0.9957421494F, 0.9957682110F, 0.9957941553F, - 0.9958199828F, 0.9958456937F, 0.9958712884F, 0.9958967672F, - 0.9959221305F, 0.9959473784F, 0.9959725115F, 0.9959975300F, - 0.9960224342F, 0.9960472244F, 0.9960719011F, 0.9960964644F, - 0.9961209148F, 0.9961452525F, 0.9961694779F, 0.9961935913F, - 0.9962175930F, 0.9962414834F, 0.9962652627F, 0.9962889313F, - 0.9963124895F, 0.9963359377F, 0.9963592761F, 0.9963825051F, - 0.9964056250F, 0.9964286361F, 0.9964515387F, 0.9964743332F, - 0.9964970198F, 0.9965195990F, 0.9965420709F, 0.9965644360F, - 0.9965866946F, 0.9966088469F, 0.9966308932F, 0.9966528340F, - 0.9966746695F, 0.9966964001F, 0.9967180260F, 0.9967395475F, - 0.9967609651F, 0.9967822789F, 0.9968034894F, 0.9968245968F, - 0.9968456014F, 0.9968665036F, 0.9968873037F, 0.9969080019F, - 0.9969285987F, 0.9969490942F, 0.9969694889F, 0.9969897830F, - 0.9970099769F, 0.9970300708F, 0.9970500651F, 0.9970699601F, - 0.9970897561F, 0.9971094533F, 0.9971290522F, 0.9971485531F, - 0.9971679561F, 0.9971872617F, 0.9972064702F, 0.9972255818F, - 0.9972445968F, 0.9972635157F, 0.9972823386F, 0.9973010659F, - 0.9973196980F, 0.9973382350F, 0.9973566773F, 0.9973750253F, - 0.9973932791F, 0.9974114392F, 0.9974295059F, 0.9974474793F, - 0.9974653599F, 0.9974831480F, 0.9975008438F, 0.9975184476F, - 0.9975359598F, 0.9975533806F, 0.9975707104F, 0.9975879495F, - 0.9976050981F, 0.9976221566F, 0.9976391252F, 0.9976560043F, - 0.9976727941F, 0.9976894950F, 0.9977061073F, 0.9977226312F, - 0.9977390671F, 0.9977554152F, 0.9977716759F, 0.9977878495F, - 0.9978039361F, 0.9978199363F, 0.9978358501F, 0.9978516780F, - 0.9978674202F, 0.9978830771F, 0.9978986488F, 0.9979141358F, - 0.9979295383F, 0.9979448566F, 0.9979600909F, 0.9979752417F, - 0.9979903091F, 0.9980052936F, 0.9980201952F, 0.9980350145F, - 0.9980497515F, 0.9980644067F, 0.9980789804F, 0.9980934727F, - 0.9981078841F, 0.9981222147F, 0.9981364649F, 0.9981506350F, - 0.9981647253F, 0.9981787360F, 0.9981926674F, 0.9982065199F, - 0.9982202936F, 0.9982339890F, 0.9982476062F, 0.9982611456F, - 0.9982746074F, 0.9982879920F, 0.9983012996F, 0.9983145304F, - 0.9983276849F, 0.9983407632F, 0.9983537657F, 0.9983666926F, - 0.9983795442F, 0.9983923208F, 0.9984050226F, 0.9984176501F, - 0.9984302033F, 0.9984426827F, 0.9984550884F, 0.9984674208F, - 0.9984796802F, 0.9984918667F, 0.9985039808F, 0.9985160227F, - 0.9985279926F, 0.9985398909F, 0.9985517177F, 0.9985634734F, - 0.9985751583F, 0.9985867727F, 0.9985983167F, 0.9986097907F, - 0.9986211949F, 0.9986325297F, 0.9986437953F, 0.9986549919F, - 0.9986661199F, 0.9986771795F, 0.9986881710F, 0.9986990946F, - 0.9987099507F, 0.9987207394F, 0.9987314611F, 0.9987421161F, - 0.9987527045F, 0.9987632267F, 0.9987736829F, 0.9987840734F, - 0.9987943985F, 0.9988046584F, 0.9988148534F, 0.9988249838F, - 0.9988350498F, 0.9988450516F, 0.9988549897F, 0.9988648641F, - 0.9988746753F, 0.9988844233F, 0.9988941086F, 0.9989037313F, - 0.9989132918F, 0.9989227902F, 0.9989322269F, 0.9989416021F, - 0.9989509160F, 0.9989601690F, 0.9989693613F, 0.9989784931F, - 0.9989875647F, 0.9989965763F, 0.9990055283F, 0.9990144208F, - 0.9990232541F, 0.9990320286F, 0.9990407443F, 0.9990494016F, - 0.9990580008F, 0.9990665421F, 0.9990750257F, 0.9990834519F, - 0.9990918209F, 0.9991001331F, 0.9991083886F, 0.9991165877F, - 0.9991247307F, 0.9991328177F, 0.9991408491F, 0.9991488251F, - 0.9991567460F, 0.9991646119F, 0.9991724232F, 0.9991801801F, - 0.9991878828F, 0.9991955316F, 0.9992031267F, 0.9992106684F, - 0.9992181569F, 0.9992255925F, 0.9992329753F, 0.9992403057F, - 0.9992475839F, 0.9992548101F, 0.9992619846F, 0.9992691076F, - 0.9992761793F, 0.9992832001F, 0.9992901701F, 0.9992970895F, - 0.9993039587F, 0.9993107777F, 0.9993175470F, 0.9993242667F, - 0.9993309371F, 0.9993375583F, 0.9993441307F, 0.9993506545F, - 0.9993571298F, 0.9993635570F, 0.9993699362F, 0.9993762678F, - 0.9993825519F, 0.9993887887F, 0.9993949785F, 0.9994011216F, - 0.9994072181F, 0.9994132683F, 0.9994192725F, 0.9994252307F, - 0.9994311434F, 0.9994370107F, 0.9994428327F, 0.9994486099F, - 0.9994543423F, 0.9994600303F, 0.9994656739F, 0.9994712736F, - 0.9994768294F, 0.9994823417F, 0.9994878105F, 0.9994932363F, - 0.9994986191F, 0.9995039592F, 0.9995092568F, 0.9995145122F, - 0.9995197256F, 0.9995248971F, 0.9995300270F, 0.9995351156F, - 0.9995401630F, 0.9995451695F, 0.9995501352F, 0.9995550604F, - 0.9995599454F, 0.9995647903F, 0.9995695953F, 0.9995743607F, - 0.9995790866F, 0.9995837734F, 0.9995884211F, 0.9995930300F, - 0.9995976004F, 0.9996021324F, 0.9996066263F, 0.9996110822F, - 0.9996155004F, 0.9996198810F, 0.9996242244F, 0.9996285306F, - 0.9996327999F, 0.9996370326F, 0.9996412287F, 0.9996453886F, - 0.9996495125F, 0.9996536004F, 0.9996576527F, 0.9996616696F, - 0.9996656512F, 0.9996695977F, 0.9996735094F, 0.9996773865F, - 0.9996812291F, 0.9996850374F, 0.9996888118F, 0.9996925523F, - 0.9996962591F, 0.9996999325F, 0.9997035727F, 0.9997071798F, - 0.9997107541F, 0.9997142957F, 0.9997178049F, 0.9997212818F, - 0.9997247266F, 0.9997281396F, 0.9997315209F, 0.9997348708F, - 0.9997381893F, 0.9997414767F, 0.9997447333F, 0.9997479591F, - 0.9997511544F, 0.9997543194F, 0.9997574542F, 0.9997605591F, - 0.9997636342F, 0.9997666797F, 0.9997696958F, 0.9997726828F, - 0.9997756407F, 0.9997785698F, 0.9997814703F, 0.9997843423F, - 0.9997871860F, 0.9997900016F, 0.9997927894F, 0.9997955494F, - 0.9997982818F, 0.9998009869F, 0.9998036648F, 0.9998063157F, - 0.9998089398F, 0.9998115373F, 0.9998141082F, 0.9998166529F, - 0.9998191715F, 0.9998216642F, 0.9998241311F, 0.9998265724F, - 0.9998289884F, 0.9998313790F, 0.9998337447F, 0.9998360854F, - 0.9998384015F, 0.9998406930F, 0.9998429602F, 0.9998452031F, - 0.9998474221F, 0.9998496171F, 0.9998517885F, 0.9998539364F, - 0.9998560610F, 0.9998581624F, 0.9998602407F, 0.9998622962F, - 0.9998643291F, 0.9998663394F, 0.9998683274F, 0.9998702932F, - 0.9998722370F, 0.9998741589F, 0.9998760591F, 0.9998779378F, - 0.9998797952F, 0.9998816313F, 0.9998834464F, 0.9998852406F, - 0.9998870141F, 0.9998887670F, 0.9998904995F, 0.9998922117F, - 0.9998939039F, 0.9998955761F, 0.9998972285F, 0.9998988613F, - 0.9999004746F, 0.9999020686F, 0.9999036434F, 0.9999051992F, - 0.9999067362F, 0.9999082544F, 0.9999097541F, 0.9999112354F, - 0.9999126984F, 0.9999141433F, 0.9999155703F, 0.9999169794F, - 0.9999183709F, 0.9999197449F, 0.9999211014F, 0.9999224408F, - 0.9999237631F, 0.9999250684F, 0.9999263570F, 0.9999276289F, - 0.9999288843F, 0.9999301233F, 0.9999313461F, 0.9999325529F, - 0.9999337437F, 0.9999349187F, 0.9999360780F, 0.9999372218F, - 0.9999383503F, 0.9999394635F, 0.9999405616F, 0.9999416447F, - 0.9999427129F, 0.9999437665F, 0.9999448055F, 0.9999458301F, - 0.9999468404F, 0.9999478365F, 0.9999488185F, 0.9999497867F, - 0.9999507411F, 0.9999516819F, 0.9999526091F, 0.9999535230F, - 0.9999544236F, 0.9999553111F, 0.9999561856F, 0.9999570472F, - 0.9999578960F, 0.9999587323F, 0.9999595560F, 0.9999603674F, - 0.9999611666F, 0.9999619536F, 0.9999627286F, 0.9999634917F, - 0.9999642431F, 0.9999649828F, 0.9999657110F, 0.9999664278F, - 0.9999671334F, 0.9999678278F, 0.9999685111F, 0.9999691835F, - 0.9999698451F, 0.9999704960F, 0.9999711364F, 0.9999717662F, - 0.9999723858F, 0.9999729950F, 0.9999735942F, 0.9999741834F, - 0.9999747626F, 0.9999753321F, 0.9999758919F, 0.9999764421F, - 0.9999769828F, 0.9999775143F, 0.9999780364F, 0.9999785495F, - 0.9999790535F, 0.9999795485F, 0.9999800348F, 0.9999805124F, - 0.9999809813F, 0.9999814417F, 0.9999818938F, 0.9999823375F, - 0.9999827731F, 0.9999832005F, 0.9999836200F, 0.9999840316F, - 0.9999844353F, 0.9999848314F, 0.9999852199F, 0.9999856008F, - 0.9999859744F, 0.9999863407F, 0.9999866997F, 0.9999870516F, - 0.9999873965F, 0.9999877345F, 0.9999880656F, 0.9999883900F, - 0.9999887078F, 0.9999890190F, 0.9999893237F, 0.9999896220F, - 0.9999899140F, 0.9999901999F, 0.9999904796F, 0.9999907533F, - 0.9999910211F, 0.9999912830F, 0.9999915391F, 0.9999917896F, - 0.9999920345F, 0.9999922738F, 0.9999925077F, 0.9999927363F, - 0.9999929596F, 0.9999931777F, 0.9999933907F, 0.9999935987F, - 0.9999938018F, 0.9999940000F, 0.9999941934F, 0.9999943820F, - 0.9999945661F, 0.9999947456F, 0.9999949206F, 0.9999950912F, - 0.9999952575F, 0.9999954195F, 0.9999955773F, 0.9999957311F, - 0.9999958807F, 0.9999960265F, 0.9999961683F, 0.9999963063F, - 0.9999964405F, 0.9999965710F, 0.9999966979F, 0.9999968213F, - 0.9999969412F, 0.9999970576F, 0.9999971707F, 0.9999972805F, - 0.9999973871F, 0.9999974905F, 0.9999975909F, 0.9999976881F, - 0.9999977824F, 0.9999978738F, 0.9999979624F, 0.9999980481F, - 0.9999981311F, 0.9999982115F, 0.9999982892F, 0.9999983644F, - 0.9999984370F, 0.9999985072F, 0.9999985750F, 0.9999986405F, - 0.9999987037F, 0.9999987647F, 0.9999988235F, 0.9999988802F, - 0.9999989348F, 0.9999989873F, 0.9999990379F, 0.9999990866F, - 0.9999991334F, 0.9999991784F, 0.9999992217F, 0.9999992632F, - 0.9999993030F, 0.9999993411F, 0.9999993777F, 0.9999994128F, - 0.9999994463F, 0.9999994784F, 0.9999995091F, 0.9999995384F, - 0.9999995663F, 0.9999995930F, 0.9999996184F, 0.9999996426F, - 0.9999996657F, 0.9999996876F, 0.9999997084F, 0.9999997282F, - 0.9999997469F, 0.9999997647F, 0.9999997815F, 0.9999997973F, - 0.9999998123F, 0.9999998265F, 0.9999998398F, 0.9999998524F, - 0.9999998642F, 0.9999998753F, 0.9999998857F, 0.9999998954F, - 0.9999999045F, 0.9999999130F, 0.9999999209F, 0.9999999282F, - 0.9999999351F, 0.9999999414F, 0.9999999472F, 0.9999999526F, - 0.9999999576F, 0.9999999622F, 0.9999999664F, 0.9999999702F, - 0.9999999737F, 0.9999999769F, 0.9999999798F, 0.9999999824F, - 0.9999999847F, 0.9999999868F, 0.9999999887F, 0.9999999904F, - 0.9999999919F, 0.9999999932F, 0.9999999943F, 0.9999999953F, - 0.9999999961F, 0.9999999969F, 0.9999999975F, 0.9999999980F, - 0.9999999985F, 0.9999999988F, 0.9999999991F, 0.9999999993F, - 0.9999999995F, 0.9999999997F, 0.9999999998F, 0.9999999999F, - 0.9999999999F, 1.0000000000F, 1.0000000000F, 1.0000000000F, - 1.0000000000F, 1.0000000000F, 1.0000000000F, 1.0000000000F, -}; - -static const float *const vwin[8] = { - vwin64, - vwin128, - vwin256, - vwin512, - vwin1024, - vwin2048, - vwin4096, - vwin8192, -}; - -const float *_vorbis_window_get(int n){ - return vwin[n]; -} - -void _vorbis_apply_window(float *d,int *winno,long *blocksizes, - int lW,int W,int nW){ - lW=(W?lW:0); - nW=(W?nW:0); - - { - const float *windowLW=vwin[winno[lW]]; - const float *windowNW=vwin[winno[nW]]; - - long n=blocksizes[W]; - long ln=blocksizes[lW]; - long rn=blocksizes[nW]; - - long leftbegin=n/4-ln/4; - long leftend=leftbegin+ln/2; - - long rightbegin=n/2+n/4-rn/4; - long rightend=rightbegin+rn/2; - - int i,p; - - for(i=0;i +#include #include #include #include @@ -621,6 +622,13 @@ class Registrator register_flush(); } + // The tests above leave their scratch file in the working directory; + // remove it once the run is over. + ~Registrator() + { + std::remove(test_data_file_name); + } + private: void register_file_stream() { diff --git a/src/tests/src/tests/src/bstone_tests_flac_audio_decoder.cpp b/src/tests/src/tests/src/bstone_tests_flac_audio_decoder.cpp new file mode 100644 index 00000000..9bc18a32 --- /dev/null +++ b/src/tests/src/tests/src/bstone_tests_flac_audio_decoder.cpp @@ -0,0 +1,953 @@ +#include +#include +#include +#include +#include +#include + +#include "bstone_flac_audio_decoder.h" +#include "bstone_tester.h" + +namespace { + +auto tester = bstone::Tester{}; + +// A quarter of a second of a 440 Hz sine: mono, 16-bit, 8 kHz, encoded with the flac reference encoder. +const unsigned char flac_fixture[] = { + 0x66, 0x4C, 0x61, 0x43, 0x00, 0x00, 0x00, 0x22, 0x10, 0x00, 0x10, 0x00, + 0x00, 0x03, 0x19, 0x00, 0x03, 0x19, 0x01, 0xF4, 0x00, 0xF0, 0x00, 0x00, + 0x07, 0xD0, 0xDD, 0x97, 0x63, 0x57, 0x57, 0xC2, 0x51, 0x50, 0x77, 0xA3, + 0xF7, 0x9D, 0xC1, 0x02, 0xF8, 0x2C, 0x03, 0x00, 0x00, 0x12, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x07, 0xD0, 0x04, 0x00, 0x00, 0x28, 0x20, 0x00, 0x00, 0x00, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6E, 0x63, 0x65, 0x20, 0x6C, 0x69, + 0x62, 0x46, 0x4C, 0x41, 0x43, 0x20, 0x31, 0x2E, 0x35, 0x2E, 0x30, 0x20, + 0x32, 0x30, 0x32, 0x35, 0x30, 0x32, 0x31, 0x31, 0x00, 0x00, 0x00, 0x00, + 0x81, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xF8, 0x74, 0x08, 0x00, 0x07, 0xCF, 0x9D, 0x42, 0x00, 0x00, 0x22, + 0xAF, 0xB5, 0x3C, 0x3E, 0x00, 0x00, 0x2B, 0xDC, 0xF4, 0xA2, 0x41, 0x10, + 0x89, 0x6A, 0xDB, 0xE6, 0x52, 0x11, 0x10, 0x89, 0x55, 0xB7, 0xB8, 0xB2, + 0x22, 0x11, 0x11, 0x65, 0x3D, 0xBE, 0xA4, 0x42, 0x22, 0x12, 0x89, 0xDB, + 0x7C, 0xB4, 0x42, 0x20, 0x91, 0x49, 0x6E, 0x7E, 0xA8, 0x88, 0x48, 0x45, + 0x4B, 0x8F, 0x7C, 0x52, 0x21, 0x08, 0x90, 0xB5, 0x3F, 0x7C, 0x92, 0x21, + 0x08, 0x84, 0xB2, 0xFD, 0xFE, 0x5A, 0x11, 0x08, 0x44, 0x92, 0xB7, 0xEE, + 0x58, 0x91, 0x08, 0x44, 0xA2, 0xB7, 0x9D, 0xAA, 0x21, 0x21, 0x11, 0x52, + 0xF7, 0x3D, 0x28, 0x90, 0x44, 0x22, 0x5A, 0xB6, 0xF9, 0x94, 0x84, 0x44, + 0x22, 0x55, 0x6D, 0xEE, 0x2C, 0x88, 0x84, 0x44, 0x59, 0x4F, 0x6F, 0xA9, + 0x10, 0x88, 0x84, 0xA2, 0x76, 0xDF, 0x2D, 0x10, 0x88, 0x24, 0x52, 0x5B, + 0x9F, 0xAA, 0x22, 0x12, 0x11, 0x52, 0xE3, 0xDF, 0x14, 0x88, 0x42, 0x24, + 0x2D, 0x4F, 0xDF, 0x24, 0x88, 0x42, 0x21, 0x2C, 0xBF, 0x7F, 0x96, 0x84, + 0x42, 0x11, 0x24, 0xAD, 0xFB, 0x96, 0x24, 0x42, 0x11, 0x28, 0xAD, 0xE7, + 0x6A, 0x88, 0x48, 0x44, 0x54, 0xBD, 0xCF, 0x4A, 0x24, 0x11, 0x08, 0x96, + 0xAD, 0xBE, 0x65, 0x21, 0x11, 0x08, 0x95, 0x5B, 0x7B, 0x8B, 0x22, 0x21, + 0x11, 0x16, 0x53, 0xDB, 0xEA, 0x44, 0x22, 0x21, 0x28, 0x9D, 0xB7, 0xCB, + 0x44, 0x22, 0x09, 0x14, 0x96, 0xE7, 0xEA, 0x88, 0x84, 0x84, 0x54, 0xB8, + 0xF7, 0xC5, 0x22, 0x10, 0x89, 0x0B, 0x53, 0xF7, 0xC9, 0x22, 0x10, 0x88, + 0x4B, 0x2F, 0xDF, 0xE5, 0xA1, 0x10, 0x84, 0x49, 0x2B, 0x7E, 0xE5, 0x89, + 0x10, 0x84, 0x4A, 0x2B, 0x79, 0xDA, 0xA2, 0x12, 0x11, 0x15, 0x2F, 0x73, + 0xD2, 0x89, 0x04, 0x42, 0x25, 0xAB, 0x6F, 0x99, 0x48, 0x44, 0x42, 0x25, + 0x56, 0xDE, 0xE2, 0xC8, 0x88, 0x44, 0x45, 0x94, 0xF6, 0xFA, 0x91, 0x08, + 0x88, 0x4A, 0x27, 0x6D, 0xF2, 0xD1, 0x08, 0x82, 0x45, 0x25, 0xB9, 0xFA, + 0xA2, 0x21, 0x21, 0x15, 0x2E, 0x3D, 0xF1, 0x48, 0x84, 0x22, 0x42, 0xD4, + 0xFD, 0xF2, 0x48, 0x84, 0x22, 0x12, 0xCB, 0xF7, 0xF9, 0x68, 0x44, 0x21, + 0x12, 0x4A, 0xDF, 0xB9, 0x62, 0x44, 0x21, 0x12, 0x8A, 0xDE, 0x76, 0xA8, + 0x84, 0x84, 0x45, 0x4B, 0xDC, 0xF4, 0xA2, 0x41, 0x10, 0x89, 0x6A, 0xDB, + 0xE6, 0x52, 0x11, 0x10, 0x89, 0x55, 0xB7, 0xB8, 0xB2, 0x22, 0x11, 0x11, + 0x65, 0x3D, 0xBE, 0xA4, 0x42, 0x22, 0x12, 0x89, 0xDB, 0x7C, 0xB4, 0x42, + 0x20, 0x91, 0x49, 0x6E, 0x7E, 0xA8, 0x88, 0x48, 0x45, 0x4B, 0x8F, 0x7C, + 0x52, 0x21, 0x08, 0x90, 0xB5, 0x3F, 0x7C, 0x92, 0x21, 0x08, 0x84, 0xB2, + 0xFD, 0xFE, 0x5A, 0x11, 0x08, 0x44, 0x92, 0xB7, 0xEE, 0x58, 0x91, 0x08, + 0x44, 0xA2, 0xB7, 0x9D, 0xAA, 0x21, 0x21, 0x11, 0x52, 0xF7, 0x3D, 0x28, + 0x90, 0x44, 0x22, 0x5A, 0xB6, 0xF9, 0x94, 0x84, 0x44, 0x22, 0x55, 0x6D, + 0xEE, 0x2C, 0x88, 0x84, 0x44, 0x59, 0x4F, 0x6F, 0xA9, 0x10, 0x88, 0x84, + 0xA2, 0x76, 0xDF, 0x2D, 0x10, 0x88, 0x24, 0x52, 0x5B, 0x9F, 0xAA, 0x22, + 0x12, 0x11, 0x52, 0xE3, 0xDF, 0x14, 0x88, 0x42, 0x24, 0x2D, 0x4F, 0xDF, + 0x24, 0x88, 0x42, 0x21, 0x2C, 0xBF, 0x7F, 0x96, 0x84, 0x42, 0x11, 0x24, + 0xAD, 0xFB, 0x96, 0x24, 0x42, 0x11, 0x28, 0xAD, 0xE7, 0x6A, 0x88, 0x48, + 0x44, 0x54, 0xBD, 0xCF, 0x4A, 0x24, 0x11, 0x08, 0x96, 0xAD, 0xBE, 0x65, + 0x21, 0x11, 0x08, 0x95, 0x5B, 0x7B, 0x8B, 0x22, 0x21, 0x11, 0x16, 0x53, + 0xDB, 0xEA, 0x44, 0x22, 0x21, 0x28, 0x9D, 0xB7, 0xCB, 0x44, 0x22, 0x09, + 0x14, 0x96, 0xE7, 0xEA, 0x88, 0x84, 0x84, 0x54, 0xB8, 0xF7, 0xC5, 0x22, + 0x10, 0x89, 0x0B, 0x53, 0xF7, 0xC9, 0x22, 0x10, 0x88, 0x4B, 0x2F, 0xDF, + 0xE5, 0xA1, 0x10, 0x84, 0x49, 0x2B, 0x7E, 0xE5, 0x89, 0x10, 0x84, 0x4A, + 0x2B, 0x79, 0xDA, 0xA2, 0x12, 0x11, 0x15, 0x2F, 0x73, 0xD2, 0x89, 0x04, + 0x42, 0x25, 0xAB, 0x6F, 0x99, 0x48, 0x44, 0x42, 0x25, 0x56, 0xDE, 0xE2, + 0xC8, 0x88, 0x44, 0x45, 0x94, 0xF6, 0xFA, 0x91, 0x08, 0x88, 0x4A, 0x27, + 0x6D, 0xF2, 0xD1, 0x08, 0x82, 0x45, 0x25, 0xB9, 0xFA, 0xA2, 0x21, 0x21, + 0x15, 0x2E, 0x3D, 0xF1, 0x48, 0x84, 0x22, 0x42, 0xD4, 0xFD, 0xF2, 0x48, + 0x84, 0x22, 0x12, 0xCB, 0xF7, 0xF9, 0x68, 0x44, 0x21, 0x12, 0x4A, 0xDF, + 0xB9, 0x62, 0x44, 0x21, 0x12, 0x8A, 0xDE, 0x76, 0xA8, 0x84, 0x84, 0x45, + 0x4B, 0xDC, 0xF4, 0xA2, 0x41, 0x10, 0x89, 0x6A, 0xDB, 0xE6, 0x52, 0x11, + 0x10, 0x89, 0x55, 0xB7, 0xB8, 0xB2, 0x22, 0x11, 0x11, 0x65, 0x3D, 0xBE, + 0xA4, 0x42, 0x22, 0x12, 0x89, 0xDB, 0x7C, 0xB4, 0x42, 0x20, 0x91, 0x49, + 0x6E, 0x7E, 0xA8, 0x88, 0x48, 0x45, 0x4B, 0x8F, 0x7C, 0x52, 0x21, 0x08, + 0x90, 0xB5, 0x3F, 0x7C, 0x92, 0x21, 0x08, 0x84, 0xB2, 0xFD, 0xFE, 0x5A, + 0x11, 0x08, 0x44, 0x92, 0xB7, 0xEE, 0x58, 0x91, 0x08, 0x44, 0xA2, 0xB7, + 0x9D, 0xAA, 0x21, 0x21, 0x11, 0x52, 0xF7, 0x3D, 0x28, 0x90, 0x44, 0x22, + 0x5A, 0xB6, 0xF9, 0x94, 0x84, 0x44, 0x22, 0x55, 0x6D, 0xEE, 0x2C, 0x88, + 0x84, 0x44, 0x59, 0x4F, 0x6F, 0xA9, 0x10, 0x88, 0x84, 0xA2, 0x76, 0xDF, + 0x2D, 0x10, 0x88, 0x24, 0x52, 0x5B, 0x9F, 0xAA, 0x22, 0x12, 0x11, 0x52, + 0xE3, 0xDF, 0x14, 0x88, 0x42, 0x24, 0x2D, 0x4F, 0xDF, 0x24, 0x88, 0x42, + 0x21, 0x2C, 0xBF, 0x7F, 0x96, 0x84, 0x42, 0x11, 0x24, 0xAD, 0xFB, 0x96, + 0x24, 0x42, 0x11, 0x28, 0xAD, 0xE7, 0x6A, 0x88, 0x48, 0x44, 0x40, 0x26, + 0xC9, +}; + +constexpr int fixture_frame_count = 2000; +constexpr int fixture_frame_rate = 8000; + +// Serves the fixture in bounded chunks so the decoder has to stream. +class FixtureStream final : public bstone::VfsInputStream +{ +public: + explicit FixtureStream(int max_chunk_size) + : + max_chunk_size_{max_chunk_size} + {} + + int get_pathname_index() const override + { + return 0; + } + + int get_size() override + { + return static_cast(sizeof(flac_fixture)); + } + + bool rewind() override + { + position_ = 0; + return true; + } + + int read(void* buffer, int buffer_size) override + { + const int remaining_size = static_cast(sizeof(flac_fixture)) - position_; + const int read_size = std::min(std::min(buffer_size, remaining_size), max_chunk_size_); + if (read_size <= 0) + { + return 0; + } + std::memcpy(buffer, flac_fixture + position_, read_size); + position_ += read_size; + return read_size; + } + +private: + int max_chunk_size_{}; + int position_{}; +}; + +struct DecodeResult +{ + int frame_count; + float peak; +}; + +bstone::AudioDecoderUPtr open_decoder(int max_chunk_size, int dst_rate) +{ + bstone::VfsInputStreamUPtr stream = std::make_unique(max_chunk_size); + auto decoder = bstone::make_flac_audio_decoder(); + const auto param = bstone::AudioDecoderInitParam{ + .vfs_stream = std::move(stream), + .src_raw_data = nullptr, + .src_raw_size = 0, + .dst_rate = dst_rate}; + if (!decoder->initialize(param)) + { + return nullptr; + } + return decoder; +} + +DecodeResult decode_all(bstone::AudioDecoder& decoder) +{ + constexpr int max_frames = 1024; + const int channel_count = decoder.get_channel_count(); + std::vector samples(static_cast(max_frames) * channel_count); + DecodeResult result{}; + while (true) + { + const int frame_count = decoder.decode_frames(samples.data(), max_frames); + if (frame_count <= 0) + { + break; + } + result.frame_count += frame_count; + for (int i = 0; i < frame_count * channel_count; ++i) + { + result.peak = std::max(result.peak, std::abs(samples[i])); + } + } + return result; +} + +// initialize(const AudioDecoderInitParam&) / decode_frames(float*, int) +void test_fd2q9w4ke7r1mx8s() +{ + const auto decoder = open_decoder(1 << 30, fixture_frame_rate); + tester.check(decoder != nullptr); + tester.check(decoder->get_channel_count() == 1); + const DecodeResult result = decode_all(*decoder); + tester.check(result.frame_count == fixture_frame_count); + tester.check(result.peak > 0.5F); +} + +// rewind() +void test_fr6t3y8un5o2pl0a() +{ + const auto decoder = open_decoder(1 << 30, fixture_frame_rate); + tester.check(decoder != nullptr); + const DecodeResult first = decode_all(*decoder); + tester.check(decoder->rewind()); + const DecodeResult second = decode_all(*decoder); + tester.check(first.frame_count > 0); + tester.check(second.frame_count == first.frame_count); +} + +// decode_frames(float*, int) +// Reads arrive a few bytes at a time. +void test_fc1z5v7bh9j4gd6w() +{ + const auto whole_decoder = open_decoder(1 << 30, fixture_frame_rate); + const auto chunked_decoder = open_decoder(7, fixture_frame_rate); + tester.check(whole_decoder != nullptr && chunked_decoder != nullptr); + const DecodeResult whole = decode_all(*whole_decoder); + const DecodeResult chunked = decode_all(*chunked_decoder); + tester.check(whole.frame_count > 0); + tester.check(chunked.frame_count == whole.frame_count); +} + +// decode_frames(float*, int) +// Resampling to a doubled rate. +void test_fs8n4m0cx2k7qe3r() +{ + const auto decoder = open_decoder(1 << 30, fixture_frame_rate); + const auto resampling_decoder = open_decoder(1 << 30, 2 * fixture_frame_rate); + tester.check(decoder != nullptr && resampling_decoder != nullptr); + const DecodeResult as_is = decode_all(*decoder); + const DecodeResult resampled = decode_all(*resampling_decoder); + const int expected_frame_count = 2 * as_is.frame_count; + tester.check(resampled.frame_count >= expected_frame_count - 8); + tester.check(resampled.frame_count <= expected_frame_count + 8); +} + +class Registrator +{ +public: + Registrator() + { + register_decode(); + register_rewind(); + register_streaming(); + register_resample(); + } + +private: + void register_decode() + { + tester.register_test("FlacAudioDecoder#fd2q9w4ke7r1mx8s", test_fd2q9w4ke7r1mx8s); + } + + void register_rewind() + { + tester.register_test("FlacAudioDecoder#fr6t3y8un5o2pl0a", test_fr6t3y8un5o2pl0a); + } + + void register_streaming() + { + tester.register_test("FlacAudioDecoder#fc1z5v7bh9j4gd6w", test_fc1z5v7bh9j4gd6w); + } + + void register_resample() + { + tester.register_test("FlacAudioDecoder#fs8n4m0cx2k7qe3r", test_fs8n4m0cx2k7qe3r); + } +}; + +auto registrator = Registrator{}; + +} // namespace diff --git a/src/tests/src/tests/src/bstone_tests_vorbis_audio_decoder.cpp b/src/tests/src/tests/src/bstone_tests_vorbis_audio_decoder.cpp new file mode 100644 index 00000000..70023d3c --- /dev/null +++ b/src/tests/src/tests/src/bstone_tests_vorbis_audio_decoder.cpp @@ -0,0 +1,436 @@ +#include +#include +#include +#include +#include +#include + +#include "bstone_vorbis_audio_decoder.h" +#include "bstone_tester.h" + +namespace { + +auto tester = bstone::Tester{}; + +// A quarter of a second of a 440 Hz sine: mono, 16-bit, 8 kHz, encoded with oggenc. +const unsigned char vorbis_fixture[] = { + 0x4F, 0x67, 0x67, 0x53, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0xEF, 0xFD, 0x55, 0x00, 0x00, 0x00, 0x00, 0xE2, 0xDB, + 0x45, 0x0F, 0x01, 0x1E, 0x01, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x40, 0x1F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x6D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x4F, 0x67, + 0x67, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0xEF, 0xFD, 0x55, 0x01, 0x00, 0x00, 0x00, 0xB5, 0x4D, 0x63, 0x88, + 0x0B, 0x44, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xB5, + 0x03, 0x76, 0x6F, 0x72, 0x62, 0x69, 0x73, 0x34, 0x00, 0x00, 0x00, 0x58, + 0x69, 0x70, 0x68, 0x2E, 0x4F, 0x72, 0x67, 0x20, 0x6C, 0x69, 0x62, 0x56, + 0x6F, 0x72, 0x62, 0x69, 0x73, 0x20, 0x49, 0x20, 0x32, 0x30, 0x32, 0x30, + 0x30, 0x37, 0x30, 0x34, 0x20, 0x28, 0x52, 0x65, 0x64, 0x75, 0x63, 0x69, + 0x6E, 0x67, 0x20, 0x45, 0x6E, 0x76, 0x69, 0x72, 0x6F, 0x6E, 0x6D, 0x65, + 0x6E, 0x74, 0x29, 0x00, 0x00, 0x00, 0x00, 0x01, 0x05, 0x76, 0x6F, 0x72, + 0x62, 0x69, 0x73, 0x12, 0x42, 0x43, 0x56, 0x01, 0x00, 0x00, 0x01, 0x00, + 0x0C, 0x52, 0x14, 0x21, 0x25, 0x19, 0x53, 0x4A, 0x63, 0x08, 0x95, 0x52, + 0x52, 0x29, 0x05, 0x1D, 0x63, 0x50, 0x5B, 0x47, 0x1D, 0x63, 0xD4, 0x39, + 0x46, 0x21, 0x64, 0x10, 0x53, 0x88, 0x49, 0x19, 0xA5, 0x7B, 0x4F, 0x2A, + 0x95, 0x58, 0x4A, 0xC8, 0x11, 0x52, 0x58, 0x29, 0x45, 0x1D, 0x53, 0x4C, + 0x53, 0x49, 0x95, 0x52, 0x96, 0x29, 0x45, 0x1D, 0x63, 0x14, 0x53, 0x48, + 0x21, 0x53, 0xD6, 0x31, 0x65, 0xA1, 0x73, 0x14, 0x4B, 0x86, 0x49, 0x09, + 0x25, 0x6C, 0x4D, 0xAE, 0x74, 0x16, 0x4B, 0xE8, 0x99, 0x63, 0x96, 0x31, + 0x46, 0x1D, 0x63, 0xCE, 0x5A, 0x4A, 0x9D, 0x63, 0xD6, 0x31, 0x45, 0x1D, + 0x63, 0x52, 0x52, 0x49, 0xA1, 0x73, 0x18, 0x3A, 0x66, 0x25, 0x64, 0x14, + 0x3A, 0x46, 0xC5, 0xE8, 0x62, 0x7C, 0x30, 0x3A, 0x95, 0xA2, 0x42, 0x28, + 0xBE, 0xC7, 0xDE, 0x52, 0xE9, 0x2D, 0x85, 0x8A, 0x5B, 0x8A, 0xBD, 0xD7, + 0x1A, 0x53, 0xEB, 0x2D, 0x84, 0x18, 0x4B, 0x69, 0xC1, 0x08, 0x61, 0x73, + 0xED, 0xB5, 0xD5, 0xDC, 0x4A, 0x6A, 0xC5, 0x18, 0x63, 0x8C, 0x31, 0xC6, + 0xC5, 0xE2, 0x53, 0x28, 0x82, 0xD0, 0x90, 0x55, 0x00, 0x00, 0x01, 0x00, + 0x00, 0x40, 0x04, 0x01, 0x42, 0x43, 0x56, 0x01, 0x00, 0x0A, 0x00, 0x00, + 0xC2, 0x50, 0x0C, 0x45, 0x51, 0x80, 0xD0, 0x90, 0x55, 0x00, 0x40, 0x06, + 0x00, 0x80, 0x00, 0x14, 0x45, 0x71, 0x14, 0xC7, 0x71, 0x1C, 0x47, 0x92, + 0x24, 0xCB, 0x02, 0x42, 0x43, 0x56, 0x01, 0x00, 0x40, 0x00, 0x00, 0x02, + 0x00, 0x00, 0x28, 0x8E, 0xE1, 0x28, 0x92, 0x23, 0x49, 0x92, 0x64, 0x59, + 0x96, 0x65, 0x59, 0x96, 0xA6, 0x79, 0x96, 0xA8, 0xB9, 0xAA, 0x2F, 0xFB, + 0xAE, 0x2E, 0xEB, 0xAE, 0xED, 0xEA, 0xBA, 0x0E, 0x84, 0x86, 0xAC, 0x04, + 0x00, 0xC8, 0x00, 0x00, 0x18, 0x86, 0x21, 0x87, 0xDE, 0x49, 0xCC, 0x90, + 0x53, 0x90, 0x49, 0x26, 0x29, 0x55, 0xCC, 0x39, 0x08, 0xA1, 0xF5, 0x0E, + 0x39, 0xE5, 0x14, 0x64, 0xD2, 0x52, 0xC6, 0x98, 0x62, 0x8C, 0x51, 0xCE, + 0x90, 0x53, 0x0C, 0x31, 0x05, 0x31, 0x86, 0xD0, 0x29, 0x85, 0x10, 0xD4, + 0x4E, 0x39, 0xA5, 0x0C, 0x22, 0x08, 0x43, 0x48, 0x9D, 0x64, 0xCE, 0x20, + 0x4B, 0x3D, 0xE8, 0xE0, 0x62, 0xE7, 0x38, 0x10, 0x1A, 0xB2, 0x22, 0x00, + 0x88, 0x02, 0x00, 0x00, 0x8C, 0x41, 0x8C, 0x21, 0xC6, 0x90, 0x73, 0x0C, + 0x4A, 0x06, 0x21, 0x72, 0x8E, 0x49, 0xC8, 0x20, 0x44, 0xCE, 0x39, 0x29, + 0x9D, 0x94, 0x4C, 0x4A, 0x28, 0xAD, 0xB4, 0x96, 0x49, 0x09, 0x2D, 0x95, + 0xD6, 0x22, 0xE7, 0x9C, 0x94, 0x4E, 0x4A, 0x26, 0xA5, 0xB4, 0x16, 0x52, + 0xCB, 0xA4, 0x94, 0xD6, 0x42, 0x2B, 0x05, 0x00, 0x00, 0x04, 0x38, 0x00, + 0x00, 0x04, 0x58, 0x08, 0x85, 0x86, 0xAC, 0x08, 0x00, 0xA2, 0x00, 0x00, + 0x10, 0x83, 0x90, 0x52, 0x48, 0x29, 0xC4, 0x94, 0x62, 0x4E, 0x31, 0x87, + 0x94, 0x52, 0x8E, 0x29, 0xC7, 0x90, 0x52, 0xCC, 0x39, 0xC5, 0x98, 0x72, + 0x8C, 0x31, 0xE8, 0x20, 0x54, 0xCC, 0x31, 0xC8, 0x1C, 0x84, 0x48, 0x29, + 0xC5, 0x18, 0x73, 0x4E, 0x39, 0xE6, 0x20, 0x64, 0x0C, 0x2A, 0xE6, 0x1C, + 0x84, 0x0C, 0x32, 0x01, 0x00, 0x00, 0x01, 0x0E, 0x00, 0x00, 0x01, 0x16, + 0x42, 0xA1, 0x21, 0x2B, 0x02, 0x80, 0x38, 0x01, 0x00, 0x83, 0x24, 0x69, + 0x9A, 0xA5, 0x69, 0xA2, 0x68, 0x69, 0x9A, 0x28, 0x7A, 0xA6, 0xA8, 0xAA, + 0xA2, 0x28, 0xAA, 0xAA, 0xE5, 0x79, 0xA6, 0xE9, 0x99, 0xA6, 0xAA, 0x7A, + 0xA2, 0xA9, 0xAA, 0xA6, 0xAA, 0xBA, 0xAE, 0xA9, 0xAA, 0xAE, 0x6C, 0x79, + 0x9E, 0x69, 0x7A, 0xA6, 0xA8, 0xAA, 0x9E, 0x29, 0xAA, 0xAA, 0xA9, 0xAA, + 0xAE, 0x6B, 0xAA, 0xAA, 0xEB, 0x8A, 0xAA, 0x6A, 0xCB, 0xA6, 0xAB, 0xDA, + 0xB6, 0xE9, 0xAA, 0xB6, 0xEC, 0xCA, 0xB2, 0x6E, 0xBB, 0xB2, 0xAC, 0xDB, + 0x9E, 0xAA, 0xCA, 0xB6, 0xA9, 0xBA, 0xB2, 0x6E, 0xAA, 0xAE, 0x6D, 0xBB, + 0xB2, 0x6C, 0xEB, 0xAE, 0x2C, 0xDB, 0xBA, 0xE4, 0x79, 0xAA, 0xEA, 0x99, + 0xA6, 0xEB, 0x7A, 0xA6, 0xE9, 0xBA, 0xAA, 0xEB, 0xDA, 0xB2, 0xEA, 0xBA, + 0xB2, 0xED, 0x99, 0xA6, 0xEB, 0x8A, 0xAA, 0x2B, 0xDB, 0xA6, 0xEB, 0xCA, + 0xB2, 0xEB, 0xCA, 0xB6, 0xAD, 0xCA, 0xB2, 0xAE, 0x6B, 0xA6, 0xE9, 0xBA, + 0xA2, 0xAB, 0xDA, 0xAE, 0xA9, 0xBA, 0xB2, 0xED, 0xCA, 0xAE, 0x6D, 0xBB, + 0xB2, 0xAC, 0xFB, 0xA6, 0xEB, 0xEA, 0xB6, 0xEA, 0xCA, 0xBA, 0xAE, 0xCA, + 0xB2, 0xEE, 0xDB, 0xB6, 0xAE, 0xFB, 0xB2, 0xAD, 0x0B, 0xBB, 0xE8, 0xBA, + 0xB6, 0xAE, 0xCA, 0xAE, 0xAE, 0xAB, 0xB2, 0xAC, 0xEB, 0xB2, 0x2D, 0xEB, + 0xB6, 0x6C, 0xDB, 0x42, 0xC9, 0xF3, 0x54, 0xD5, 0x33, 0x4D, 0xD7, 0xF5, + 0x4C, 0xD3, 0x75, 0x55, 0xD7, 0xB5, 0x6D, 0xD5, 0x75, 0x6D, 0x5B, 0x33, + 0x4D, 0xD7, 0x35, 0x5D, 0x57, 0x96, 0x45, 0xD5, 0x75, 0x65, 0xD5, 0x95, + 0x75, 0x5D, 0x75, 0x65, 0x5B, 0xF7, 0x4C, 0xD3, 0x75, 0x4D, 0x57, 0x95, + 0x65, 0xD3, 0x55, 0x65, 0x59, 0x95, 0x65, 0xDD, 0x76, 0x65, 0x57, 0x97, + 0x45, 0xD7, 0xB5, 0x6D, 0x55, 0x96, 0x7D, 0x5D, 0x75, 0x65, 0x5F, 0x97, + 0x6D, 0xDD, 0xF7, 0x65, 0x59, 0xD7, 0x7D, 0xD3, 0x75, 0x75, 0x5B, 0x95, + 0x65, 0xDB, 0x57, 0x65, 0x59, 0xF7, 0x65, 0x5D, 0xF7, 0x85, 0x59, 0xB7, + 0x7D, 0xDD, 0x53, 0x55, 0x5B, 0x37, 0x5D, 0x57, 0xD7, 0x4D, 0xD7, 0xD5, + 0x7D, 0x5B, 0xD7, 0x7D, 0x61, 0xB6, 0x6D, 0xDF, 0x17, 0x5D, 0x57, 0xD7, + 0x55, 0xD9, 0xD6, 0x85, 0x55, 0x96, 0x75, 0xDF, 0xD6, 0x7D, 0x65, 0x98, + 0x75, 0x9D, 0x30, 0xBA, 0xAE, 0xAE, 0xAB, 0xB6, 0xEC, 0xEB, 0xAA, 0x2C, + 0xEB, 0xBE, 0xAE, 0xEB, 0xC6, 0x30, 0xEB, 0xBA, 0x30, 0xAC, 0xBA, 0x6D, + 0xFC, 0xAE, 0xAD, 0x0B, 0xC3, 0xAB, 0xEB, 0xC6, 0xB1, 0xEB, 0xBE, 0xAE, + 0xDC, 0xBE, 0x8F, 0x6A, 0xDB, 0xBE, 0xF0, 0xEA, 0xB6, 0x31, 0xBC, 0xBA, + 0x6E, 0x1C, 0xBB, 0xB0, 0x1B, 0xBF, 0xED, 0xFB, 0xC6, 0xB1, 0xA9, 0xAA, + 0x6D, 0x9B, 0xAE, 0xAB, 0xEB, 0xA6, 0x2B, 0xEB, 0xBA, 0x6C, 0xEB, 0xBE, + 0x6F, 0xEB, 0xBA, 0x71, 0x8C, 0xAE, 0xAB, 0xEB, 0xAA, 0x2C, 0xFB, 0xBA, + 0xEA, 0xCA, 0xBE, 0x6F, 0xEB, 0xBA, 0xF0, 0xEB, 0xBE, 0x2F, 0x0C, 0xA3, + 0xEB, 0xEA, 0xBA, 0x2A, 0xCB, 0xBA, 0xB0, 0xDA, 0xB2, 0xAF, 0xCB, 0xBA, + 0x2E, 0x0C, 0xBB, 0xAE, 0x1B, 0xC3, 0x6A, 0xDB, 0xC2, 0xEE, 0xDA, 0xBA, + 0x70, 0xCC, 0xB2, 0x2E, 0x0C, 0xB7, 0xEF, 0x2B, 0xC7, 0xAF, 0x0B, 0x43, + 0xD5, 0xB6, 0x85, 0xE1, 0xD5, 0x75, 0xA3, 0xAB, 0xDB, 0xC6, 0x6F, 0x0B, + 0xC3, 0xD2, 0x37, 0x76, 0xBE, 0x00, 0x00, 0x80, 0x01, 0x07, 0x00, 0x80, + 0x00, 0x13, 0xCA, 0x40, 0xA1, 0x21, 0x2B, 0x02, 0x80, 0x38, 0x01, 0x00, + 0x06, 0x21, 0x08, 0x15, 0x63, 0x10, 0x2A, 0xC6, 0x20, 0x84, 0x10, 0x52, + 0x0A, 0x21, 0xA4, 0x54, 0x31, 0x06, 0x21, 0x63, 0x0E, 0x4A, 0xC6, 0x1C, + 0x94, 0x10, 0x4A, 0x49, 0x21, 0x94, 0xD2, 0x2A, 0xC6, 0x20, 0x64, 0x8E, + 0x49, 0xC8, 0x1C, 0x93, 0x10, 0x4A, 0x68, 0xA9, 0x94, 0xD0, 0x4A, 0x28, + 0xA5, 0xA5, 0x50, 0x4A, 0x4B, 0xA1, 0x94, 0xD6, 0x52, 0x6A, 0x2D, 0xA6, + 0xD4, 0x5A, 0x0C, 0xA1, 0xB4, 0x14, 0x4A, 0x69, 0xAD, 0x94, 0xD2, 0x5A, + 0x6A, 0x29, 0xB6, 0xD4, 0x52, 0x6C, 0x15, 0x63, 0x10, 0x32, 0xE7, 0xA4, + 0x64, 0x8E, 0x49, 0x28, 0xA5, 0xB4, 0x56, 0x4A, 0x69, 0x29, 0x73, 0x4C, + 0x4A, 0xC6, 0xA0, 0xA4, 0x0E, 0x42, 0x2A, 0xA5, 0xA4, 0xD2, 0x4A, 0x49, + 0xAD, 0x65, 0xCE, 0x49, 0xC9, 0xA0, 0xA3, 0xD2, 0x39, 0x48, 0xA9, 0xA4, + 0xD2, 0x52, 0x49, 0xA9, 0xB5, 0x50, 0x4A, 0x6B, 0xA1, 0x94, 0xD6, 0x4A, + 0x4A, 0xB1, 0xA5, 0xD2, 0x4A, 0x6D, 0xAD, 0xC5, 0x1A, 0x4A, 0x69, 0x2D, + 0xA4, 0xD2, 0x5A, 0x49, 0xA9, 0xB5, 0xD4, 0x52, 0x6D, 0xAD, 0xB5, 0x5A, + 0x23, 0xC6, 0x20, 0x64, 0x8C, 0x41, 0xC9, 0x9C, 0x93, 0x52, 0x4A, 0x49, + 0xA9, 0x94, 0xD2, 0x5A, 0xE6, 0x9C, 0x94, 0x0E, 0x3A, 0x2A, 0x99, 0x83, + 0x92, 0x4A, 0x29, 0xA9, 0x95, 0x92, 0x52, 0xAC, 0x98, 0x93, 0xD2, 0x41, + 0x28, 0x25, 0x83, 0x8C, 0x4A, 0x49, 0xA5, 0xB5, 0x92, 0x4A, 0x2B, 0xA1, + 0x94, 0xD6, 0x4A, 0x4A, 0xB1, 0x85, 0x52, 0x5A, 0x6B, 0xAD, 0xD5, 0x98, + 0x52, 0x4B, 0x35, 0x94, 0x92, 0x5A, 0x49, 0xA9, 0xC5, 0x50, 0x4A, 0x6B, + 0xAD, 0xB5, 0x1A, 0x53, 0x2B, 0x35, 0x85, 0x50, 0x52, 0x0B, 0xA5, 0xB4, + 0x16, 0x4A, 0x69, 0xAD, 0xB5, 0x56, 0x6B, 0x6A, 0x2D, 0xB6, 0x50, 0x42, + 0x6B, 0xA1, 0xA4, 0x16, 0x4B, 0x2A, 0x31, 0xB5, 0x16, 0x63, 0x6D, 0xAD, + 0xC5, 0x18, 0x4A, 0x69, 0xAD, 0xA4, 0x12, 0x5B, 0x29, 0xA9, 0xC5, 0x16, + 0x5B, 0x8D, 0xAD, 0xB5, 0x58, 0x53, 0x4B, 0x35, 0x96, 0x92, 0x62, 0x6C, + 0xAD, 0xD5, 0xD8, 0x4A, 0x2D, 0x39, 0xD6, 0x5A, 0x6B, 0x4A, 0x2D, 0xD6, + 0xD2, 0x52, 0x8C, 0xAD, 0xB5, 0x98, 0x5B, 0x4C, 0xB9, 0xC5, 0x58, 0x6B, + 0x0D, 0x25, 0xB4, 0x16, 0x4A, 0x69, 0xAD, 0x94, 0xD2, 0x5A, 0x4A, 0xAD, + 0xC5, 0xD6, 0x5A, 0xAD, 0xA1, 0x94, 0xD6, 0x4A, 0x2A, 0xB1, 0x95, 0x92, + 0x5A, 0x6C, 0xAD, 0xD5, 0xD8, 0x5A, 0x8C, 0x35, 0x94, 0xD2, 0x62, 0x29, + 0x29, 0xB5, 0x90, 0x4A, 0x6C, 0xAD, 0xB5, 0x58, 0x5B, 0x6C, 0x35, 0xA6, + 0x96, 0x62, 0x6C, 0xB1, 0xD5, 0x58, 0x52, 0x8B, 0x31, 0xC6, 0x58, 0x73, + 0x4B, 0xB5, 0xD5, 0x94, 0x5A, 0x8B, 0xAD, 0xB5, 0x58, 0x4B, 0x2B, 0x35, + 0xC6, 0x18, 0x6B, 0x6E, 0x35, 0xE5, 0x52, 0x00, 0x00, 0xC0, 0x80, 0x03, + 0x00, 0x40, 0x80, 0x09, 0x65, 0xA0, 0xD0, 0x90, 0x95, 0x00, 0x40, 0x14, + 0x00, 0x00, 0x60, 0x0C, 0x63, 0x8C, 0x41, 0x68, 0x14, 0x72, 0xCC, 0x39, + 0x29, 0x8D, 0x52, 0xCE, 0x39, 0x27, 0x25, 0x73, 0x0E, 0x42, 0x08, 0x29, + 0x65, 0xCE, 0x41, 0x08, 0x21, 0xA5, 0xCE, 0x39, 0x08, 0xA5, 0xB4, 0xD4, + 0x39, 0x07, 0xA1, 0x94, 0x94, 0x42, 0x29, 0x29, 0xA5, 0x14, 0x5B, 0x28, + 0x25, 0xA5, 0xD6, 0x5A, 0x2C, 0x00, 0x00, 0xA0, 0xC0, 0x01, 0x00, 0x20, + 0xC0, 0x06, 0x4D, 0x89, 0xC5, 0x01, 0x0A, 0x0D, 0x59, 0x09, 0x00, 0x44, + 0x01, 0x00, 0x20, 0xC6, 0x28, 0xC5, 0x18, 0x84, 0xC6, 0x20, 0xA5, 0x18, + 0x83, 0xD0, 0x18, 0xA3, 0x14, 0x63, 0x10, 0x2A, 0xA5, 0x18, 0x73, 0x0E, + 0x42, 0xA5, 0x14, 0x63, 0xCE, 0x41, 0xC8, 0x18, 0x73, 0xCE, 0x41, 0x29, + 0x19, 0x63, 0xCE, 0x41, 0x27, 0x25, 0x84, 0x10, 0x42, 0x29, 0xA5, 0x84, + 0x10, 0x42, 0x28, 0xA5, 0x94, 0x02, 0x00, 0x00, 0x0A, 0x1C, 0x00, 0x00, + 0x02, 0x6C, 0xD0, 0x94, 0x58, 0x1C, 0xA0, 0xD0, 0x90, 0x15, 0x01, 0x40, + 0x14, 0x00, 0x00, 0x60, 0x0C, 0x62, 0x0C, 0x31, 0x86, 0x20, 0x74, 0x52, + 0x3A, 0x29, 0x11, 0x84, 0x4C, 0x4A, 0x27, 0xA5, 0x91, 0x12, 0x5A, 0x0B, + 0x29, 0x65, 0x96, 0x4A, 0x8A, 0x25, 0xC6, 0xCC, 0x5A, 0x89, 0xAD, 0xC4, + 0xD8, 0x48, 0x09, 0xAD, 0x85, 0xD6, 0x32, 0x6B, 0x25, 0xC6, 0xD2, 0x62, + 0x46, 0xAD, 0xC4, 0x58, 0x62, 0x2A, 0x00, 0x00, 0xEC, 0xC0, 0x01, 0x00, + 0xEC, 0xC0, 0x42, 0x28, 0x34, 0x64, 0x25, 0x00, 0x90, 0x07, 0x00, 0x40, + 0x18, 0xA3, 0x14, 0x63, 0xCE, 0x39, 0x67, 0x10, 0x62, 0xCC, 0x39, 0x08, + 0x21, 0x34, 0x08, 0x31, 0xE6, 0x1C, 0x84, 0x10, 0x2A, 0xC6, 0x9C, 0x73, + 0x0E, 0x42, 0x08, 0x15, 0x63, 0xCE, 0x39, 0x07, 0x21, 0x84, 0xCE, 0x39, + 0xE7, 0x20, 0x84, 0x10, 0x42, 0xE7, 0x9C, 0x73, 0x10, 0x42, 0x08, 0xA1, + 0x83, 0x10, 0x42, 0x08, 0xA5, 0x94, 0xD2, 0x41, 0x08, 0x21, 0x84, 0x52, + 0x4A, 0xE9, 0x20, 0x84, 0x10, 0x42, 0x29, 0xA5, 0x74, 0x10, 0x42, 0x08, + 0xA1, 0x94, 0x52, 0x0A, 0x00, 0x00, 0x2A, 0x70, 0x00, 0x00, 0x08, 0xB0, + 0x51, 0x64, 0x73, 0x82, 0x91, 0xA0, 0x42, 0x43, 0x56, 0x02, 0x00, 0x79, + 0x00, 0x00, 0x80, 0x31, 0x4A, 0x39, 0x27, 0x25, 0xA5, 0x46, 0x29, 0xC6, + 0x20, 0xA4, 0x14, 0x5B, 0xA3, 0x14, 0x63, 0x10, 0x52, 0x6A, 0xAD, 0x62, + 0x0C, 0x42, 0x4A, 0xAD, 0xC5, 0x58, 0x31, 0x06, 0x21, 0xA5, 0xD6, 0x62, + 0xEC, 0x20, 0xA4, 0xD4, 0x5A, 0x8C, 0xB5, 0x76, 0x10, 0x52, 0x6A, 0x2D, + 0xC6, 0x5A, 0x43, 0x4A, 0xAD, 0xC5, 0x58, 0x6B, 0xCE, 0x21, 0xA5, 0xD6, + 0x62, 0xAC, 0x35, 0xD7, 0xD4, 0x5A, 0x8C, 0xB5, 0xE6, 0xDC, 0x7B, 0x6A, + 0x2D, 0xC6, 0x5A, 0x73, 0xCE, 0xB9, 0x00, 0x00, 0xDC, 0x05, 0x07, 0x00, + 0xB0, 0x03, 0x1B, 0x45, 0x36, 0x27, 0x18, 0x09, 0x2A, 0x34, 0x64, 0x25, + 0x00, 0x90, 0x07, 0x00, 0x40, 0x20, 0xA4, 0x14, 0x63, 0x8C, 0x39, 0x87, + 0x94, 0x62, 0x8C, 0x31, 0xE7, 0x9C, 0x43, 0x4A, 0x31, 0xC6, 0x98, 0x73, + 0xCE, 0x29, 0xC6, 0x18, 0x73, 0xCE, 0x39, 0xE7, 0x14, 0x63, 0x8C, 0x39, + 0xE7, 0x9C, 0x73, 0x8C, 0x31, 0xE7, 0x9C, 0x73, 0xCE, 0x39, 0xC6, 0x98, + 0x73, 0xCE, 0x39, 0xE7, 0x9C, 0x73, 0xCE, 0x39, 0xE7, 0xA0, 0x83, 0x90, + 0x39, 0xE7, 0x9C, 0x73, 0xD0, 0x41, 0xE8, 0x9C, 0x73, 0xCE, 0x39, 0x08, + 0x21, 0x74, 0xCE, 0x39, 0xE7, 0x1C, 0x84, 0x10, 0x0A, 0x00, 0x00, 0x2A, + 0x70, 0x00, 0x00, 0x08, 0xB0, 0x51, 0x64, 0x73, 0x82, 0x91, 0xA0, 0x42, + 0x43, 0x56, 0x02, 0x00, 0xE1, 0x00, 0x00, 0x80, 0x31, 0x94, 0x52, 0x4A, + 0x29, 0xA5, 0x94, 0x52, 0x4A, 0xA8, 0xA3, 0x94, 0x52, 0x4A, 0x29, 0xA5, + 0x94, 0x52, 0x02, 0x21, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, + 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, + 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, + 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, + 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, + 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, + 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, + 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, + 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, + 0x29, 0x95, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, + 0x52, 0x4A, 0x29, 0xA5, 0x00, 0x20, 0xDF, 0x0A, 0x07, 0x00, 0xFF, 0x07, + 0x1B, 0x67, 0x58, 0x49, 0x3A, 0x2B, 0x1C, 0x0D, 0x2E, 0x34, 0x64, 0x25, + 0x00, 0x10, 0x0E, 0x00, 0x00, 0x18, 0xC3, 0x18, 0x84, 0x8C, 0x39, 0x27, + 0x25, 0xA5, 0x86, 0x31, 0x08, 0xA5, 0x74, 0x4E, 0x4A, 0x49, 0x25, 0x35, + 0x8C, 0x41, 0x28, 0xA5, 0x73, 0x12, 0x52, 0x4A, 0x29, 0x83, 0xD0, 0x5A, + 0x6A, 0xA5, 0xA4, 0xD2, 0x52, 0x4A, 0x19, 0x84, 0x94, 0x62, 0x0B, 0x21, + 0x95, 0x94, 0x5A, 0x0A, 0xA5, 0xB4, 0x56, 0x6B, 0x29, 0xA9, 0xB5, 0x94, + 0x52, 0x28, 0x29, 0xC5, 0x1A, 0x4B, 0x4A, 0xA9, 0xA5, 0xD6, 0x32, 0xE7, + 0x24, 0xA4, 0x92, 0x5A, 0x4B, 0xAD, 0xB6, 0x98, 0x39, 0x07, 0xA5, 0xA4, + 0xD6, 0x5A, 0x6A, 0xAD, 0xC5, 0x10, 0x42, 0x4A, 0xB1, 0xB5, 0xD6, 0x52, + 0x6B, 0xB1, 0x75, 0x52, 0x52, 0x49, 0xAD, 0xB5, 0xD6, 0x5A, 0x6D, 0x2D, + 0xA4, 0x94, 0x5A, 0x6B, 0x2D, 0xC6, 0xD6, 0x62, 0x6C, 0x25, 0xA5, 0x96, + 0x5A, 0x6B, 0xA9, 0xC5, 0xD6, 0x5A, 0x4C, 0xA9, 0xB5, 0x16, 0x5B, 0x4B, + 0x2D, 0xC6, 0xD6, 0x62, 0x4B, 0xAD, 0xC5, 0xD8, 0x62, 0x8B, 0x31, 0xC6, + 0x1A, 0x0B, 0x00, 0xE0, 0x6E, 0x70, 0x00, 0x80, 0x48, 0xB0, 0x71, 0x86, + 0x95, 0xA4, 0xB3, 0xC2, 0xD1, 0xE0, 0x42, 0x43, 0x56, 0x02, 0x00, 0x21, + 0x01, 0x00, 0x04, 0x32, 0x4A, 0x39, 0xE7, 0x9C, 0x83, 0x10, 0x42, 0x08, + 0x21, 0x52, 0x8A, 0x31, 0xE7, 0xA0, 0x83, 0x10, 0x42, 0x08, 0x21, 0x44, + 0x4A, 0x31, 0xE6, 0x9C, 0x83, 0x10, 0x42, 0x08, 0x21, 0x84, 0x8C, 0x31, + 0xE7, 0x20, 0x84, 0x10, 0x42, 0x08, 0xA1, 0x94, 0x90, 0x31, 0xE6, 0x1C, + 0x84, 0x10, 0x42, 0x08, 0x21, 0x84, 0x52, 0x3A, 0xE7, 0x20, 0x84, 0x50, + 0x4A, 0x09, 0xA5, 0x94, 0x52, 0x4A, 0xE7, 0x1C, 0x84, 0x10, 0x42, 0x08, + 0xA5, 0x94, 0x52, 0x4A, 0x09, 0x21, 0x84, 0x10, 0x42, 0x28, 0xA5, 0x94, + 0x52, 0x4A, 0x29, 0x21, 0x84, 0x10, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, + 0x29, 0x25, 0x84, 0x10, 0x42, 0x28, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, + 0x84, 0x10, 0x42, 0x28, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x10, + 0x42, 0x28, 0xA5, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x12, 0x42, 0x08, + 0xA1, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x42, 0x08, 0xA5, 0x94, + 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x28, 0x21, 0x84, 0x52, 0x4A, + 0x29, 0xA5, 0x94, 0x52, 0x4A, 0x09, 0x25, 0x94, 0x52, 0x4A, 0x29, 0xA5, + 0x94, 0x52, 0x4A, 0x29, 0x21, 0x94, 0x52, 0x4A, 0x29, 0xA5, 0x94, 0x52, + 0x4A, 0x29, 0xA5, 0x00, 0x00, 0x80, 0x03, 0x07, 0x00, 0x80, 0x00, 0x23, + 0xE8, 0x24, 0xA3, 0xCA, 0x22, 0x6C, 0x34, 0xE1, 0xC2, 0x03, 0x10, 0x00, + 0x00, 0x00, 0x02, 0x00, 0x02, 0x4C, 0x00, 0x81, 0x01, 0x82, 0x82, 0x51, + 0x08, 0x02, 0x84, 0x11, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, + 0xF8, 0x00, 0x00, 0x48, 0x0A, 0x80, 0x88, 0x88, 0x68, 0xE6, 0x0C, 0x0E, + 0x10, 0x12, 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x1E, 0x20, 0x22, 0x24, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, + 0x4F, 0x67, 0x67, 0x53, 0x00, 0x04, 0xD0, 0x07, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x47, 0xEF, 0xFD, 0x55, 0x02, 0x00, 0x00, 0x00, 0xA4, 0x5F, + 0xEE, 0xE5, 0x09, 0x18, 0x17, 0x16, 0x17, 0x18, 0x16, 0x18, 0x17, 0x2B, + 0x9E, 0x99, 0x99, 0x59, 0xE5, 0x15, 0x00, 0xFC, 0xBF, 0x77, 0x01, 0x00, + 0x80, 0x14, 0x52, 0x49, 0xF9, 0xF4, 0x56, 0x74, 0xFB, 0x14, 0xB3, 0x11, + 0xA6, 0x9B, 0x99, 0xED, 0x94, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, + 0x4B, 0x01, 0x00, 0x08, 0x15, 0xDE, 0xD9, 0xEF, 0x1C, 0x35, 0x02, 0xA6, + 0x9B, 0x99, 0xDD, 0x4D, 0xE6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA8, 0x06, + 0x00, 0x80, 0x50, 0xA1, 0x96, 0xEB, 0x32, 0x4D, 0x00, 0xA6, 0x9B, 0x99, + 0xED, 0x94, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0x4B, 0x01, 0x00, + 0x08, 0xB5, 0x93, 0x1B, 0xED, 0x57, 0x8D, 0x00, 0xA6, 0x9B, 0x99, 0xDD, + 0x4D, 0xE6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xDD, 0x68, 0x00, 0x80, + 0x68, 0x27, 0x76, 0x73, 0xF7, 0x91, 0xE3, 0x24, 0xA6, 0x9B, 0x99, 0xDD, + 0x4D, 0xE6, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xC7, 0x02, 0x00, 0xA2, + 0x8B, 0xAE, 0x3E, 0xDC, 0x3D, 0x03, 0xA6, 0x9B, 0x99, 0xDD, 0x4D, 0xE6, + 0x01, 0x00, 0x00, 0x00, 0x00, 0xFA, 0xDD, 0xE8, 0x00, 0x80, 0xE8, 0x45, + 0xAF, 0xB1, 0xEB, 0xFD, 0x16, 0x32, 0xA6, 0x9B, 0x99, 0xED, 0x94, 0x79, + 0x00, 0x00, 0x00, 0x00, 0x00, 0xE7, 0xAB, 0x00, 0x00, 0xD8, 0xD1, 0x4B, + 0xDD, 0xD5, 0xFB, 0x9A, 0x31, 0x9A, 0x50, 0xAD, 0xD6, 0x4B, 0x48, 0x70, + 0x00, 0x00, 0x00, 0xC8, 0x01, 0xC0, 0xF9, 0x61, 0x8E, 0xD0, 0x79, 0x0D, + 0x69, 0xE6, 0x98, 0x89, 0x1B, 0x33, 0x57, 0xBC, 0xF4, 0x41, 0xB6, 0x00, + 0xE0, 0x4D, 0xE5, 0x60, 0xA0, 0xA1, 0x76, 0x52, 0xC4, 0xEB, 0x9F, 0x36, +}; + +constexpr int fixture_frame_count = 2000; +constexpr int fixture_frame_rate = 8000; + +// Serves the fixture in bounded chunks so the decoder has to stream. +class FixtureStream final : public bstone::VfsInputStream +{ +public: + explicit FixtureStream(int max_chunk_size) + : + max_chunk_size_{max_chunk_size} + {} + + int get_pathname_index() const override + { + return 0; + } + + int get_size() override + { + return static_cast(sizeof(vorbis_fixture)); + } + + bool rewind() override + { + position_ = 0; + return true; + } + + int read(void* buffer, int buffer_size) override + { + const int remaining_size = static_cast(sizeof(vorbis_fixture)) - position_; + const int read_size = std::min(std::min(buffer_size, remaining_size), max_chunk_size_); + if (read_size <= 0) + { + return 0; + } + std::memcpy(buffer, vorbis_fixture + position_, read_size); + position_ += read_size; + return read_size; + } + +private: + int max_chunk_size_{}; + int position_{}; +}; + +struct DecodeResult +{ + int frame_count; + float peak; +}; + +bstone::AudioDecoderUPtr open_decoder(int max_chunk_size, int dst_rate) +{ + bstone::VfsInputStreamUPtr stream = std::make_unique(max_chunk_size); + auto decoder = bstone::make_vorbis_audio_decoder(); + const auto param = bstone::AudioDecoderInitParam{ + .vfs_stream = std::move(stream), + .src_raw_data = nullptr, + .src_raw_size = 0, + .dst_rate = dst_rate}; + if (!decoder->initialize(param)) + { + return nullptr; + } + return decoder; +} + +DecodeResult decode_all(bstone::AudioDecoder& decoder) +{ + constexpr int max_frames = 1024; + const int channel_count = decoder.get_channel_count(); + std::vector samples(static_cast(max_frames) * channel_count); + DecodeResult result{}; + while (true) + { + const int frame_count = decoder.decode_frames(samples.data(), max_frames); + if (frame_count <= 0) + { + break; + } + result.frame_count += frame_count; + for (int i = 0; i < frame_count * channel_count; ++i) + { + result.peak = std::max(result.peak, std::abs(samples[i])); + } + } + return result; +} + +// initialize(const AudioDecoderInitParam&) / decode_frames(float*, int) +void test_vd8s2k1qw9x0mnp4() +{ + const auto decoder = open_decoder(1 << 30, fixture_frame_rate); + tester.check(decoder != nullptr); + tester.check(decoder->get_channel_count() == 1); + const DecodeResult result = decode_all(*decoder); + tester.check(result.frame_count >= 1000 && result.frame_count <= 6000); + tester.check(result.peak > 0.5F); +} + +// rewind() +void test_re3jb7nq2m8ttz5c() +{ + const auto decoder = open_decoder(1 << 30, fixture_frame_rate); + tester.check(decoder != nullptr); + const DecodeResult first = decode_all(*decoder); + tester.check(decoder->rewind()); + const DecodeResult second = decode_all(*decoder); + tester.check(first.frame_count > 0); + tester.check(second.frame_count == first.frame_count); +} + +// decode_frames(float*, int) +// Reads arrive a few bytes at a time. +void test_ch7k0p2vw4y9q1sd() +{ + const auto whole_decoder = open_decoder(1 << 30, fixture_frame_rate); + const auto chunked_decoder = open_decoder(7, fixture_frame_rate); + tester.check(whole_decoder != nullptr && chunked_decoder != nullptr); + const DecodeResult whole = decode_all(*whole_decoder); + const DecodeResult chunked = decode_all(*chunked_decoder); + tester.check(whole.frame_count > 0); + tester.check(chunked.frame_count == whole.frame_count); +} + +// decode_frames(float*, int) +// Resampling to a doubled rate. +void test_rs5m1x8zj3w6qn2v() +{ + const auto decoder = open_decoder(1 << 30, fixture_frame_rate); + const auto resampling_decoder = open_decoder(1 << 30, 2 * fixture_frame_rate); + tester.check(decoder != nullptr && resampling_decoder != nullptr); + const DecodeResult as_is = decode_all(*decoder); + const DecodeResult resampled = decode_all(*resampling_decoder); + const int expected_frame_count = 2 * as_is.frame_count; + tester.check(resampled.frame_count >= expected_frame_count - 8); + tester.check(resampled.frame_count <= expected_frame_count + 8); +} + +class Registrator +{ +public: + Registrator() + { + register_decode(); + register_rewind(); + register_streaming(); + register_resample(); + } + +private: + void register_decode() + { + tester.register_test("VorbisAudioDecoder#vd8s2k1qw9x0mnp4", test_vd8s2k1qw9x0mnp4); + } + + void register_rewind() + { + tester.register_test("VorbisAudioDecoder#re3jb7nq2m8ttz5c", test_re3jb7nq2m8ttz5c); + } + + void register_streaming() + { + tester.register_test("VorbisAudioDecoder#ch7k0p2vw4y9q1sd", test_ch7k0p2vw4y9q1sd); + } + + void register_resample() + { + tester.register_test("VorbisAudioDecoder#rs5m1x8zj3w6qn2v", test_rs5m1x8zj3w6qn2v); + } +}; + +auto registrator = Registrator{}; + +} // namespace