From 233b4f2ca888f3f91283095e188efcce90c1ffc4 Mon Sep 17 00:00:00 2001 From: Jelle Raaijmakers Date: Mon, 30 Sep 2024 14:49:59 +0200 Subject: [PATCH] LibMedia+everywhere: Remove superfluous and unused audio code We had numerous NiH-based implementations of audio formats and metadata that we now no longer need because we either don't make use of the code, or we replaced its implementation by FFmpeg. --- AK/Debug.h.in | 8 - Ladybird/Qt/AudioThread.h | 1 + Meta/CMake/all_the_debug_macros.cmake | 2 - Meta/Lagom/Fuzzers/FuzzFlacLoader.cpp | 14 - Meta/Lagom/Fuzzers/FuzzMP3Loader.cpp | 14 - Meta/Lagom/Fuzzers/FuzzQOALoader.cpp | 14 - Meta/Lagom/Fuzzers/FuzzWAVLoader.cpp | 14 - Meta/Lagom/Fuzzers/fuzzers.cmake | 8 - Meta/gn/secondary/AK/BUILD.gn | 2 - .../Userland/Libraries/LibMedia/BUILD.gn | 8 - Tests/LibMedia/CMakeLists.txt | 3 - Tests/LibMedia/TestFLACSpec.cpp | 58 - Tests/LibMedia/TestWav.cpp | 2 +- .../Libraries/LibMedia/Audio/FlacLoader.cpp | 1049 ---------- .../Libraries/LibMedia/Audio/FlacLoader.h | 119 -- Userland/Libraries/LibMedia/Audio/FlacTypes.h | 164 -- Userland/Libraries/LibMedia/Audio/Forward.h | 5 - .../Libraries/LibMedia/Audio/GenericTypes.cpp | 95 - .../Libraries/LibMedia/Audio/GenericTypes.h | 79 - Userland/Libraries/LibMedia/Audio/Loader.cpp | 8 - Userland/Libraries/LibMedia/Audio/Loader.h | 14 +- Userland/Libraries/LibMedia/Audio/MDCT.h | 43 - .../LibMedia/Audio/MP3HuffmanTables.h | 1726 ----------------- .../Libraries/LibMedia/Audio/MP3Loader.cpp | 895 --------- Userland/Libraries/LibMedia/Audio/MP3Loader.h | 77 - Userland/Libraries/LibMedia/Audio/MP3Tables.h | 447 ----- Userland/Libraries/LibMedia/Audio/MP3Types.h | 107 - .../Libraries/LibMedia/Audio/Metadata.cpp | 82 - Userland/Libraries/LibMedia/Audio/Metadata.h | 68 - .../Libraries/LibMedia/Audio/MultiChannel.h | 103 - .../Libraries/LibMedia/Audio/QOALoader.cpp | 249 --- Userland/Libraries/LibMedia/Audio/QOALoader.h | 70 - .../Libraries/LibMedia/Audio/QOATypes.cpp | 59 - Userland/Libraries/LibMedia/Audio/QOATypes.h | 142 -- Userland/Libraries/LibMedia/Audio/Resampler.h | 100 - .../LibMedia/Audio/SampleFormats.cpp | 27 - .../Libraries/LibMedia/Audio/SampleFormats.h | 4 +- .../LibMedia/Audio/VorbisComment.cpp | 189 -- .../Libraries/LibMedia/Audio/VorbisComment.h | 19 - .../Libraries/LibMedia/Audio/WavLoader.cpp | 337 ---- Userland/Libraries/LibMedia/Audio/WavLoader.h | 64 - Userland/Libraries/LibMedia/Audio/WavTypes.h | 27 - Userland/Libraries/LibMedia/CMakeLists.txt | 10 +- .../LibWeb/HTML/HTMLMediaElement.cpp | 13 +- .../LibWeb/Platform/AudioCodecPlugin.cpp | 2 +- .../Platform/AudioCodecPluginAgnostic.cpp | 1 + 46 files changed, 12 insertions(+), 6530 deletions(-) delete mode 100644 Meta/Lagom/Fuzzers/FuzzFlacLoader.cpp delete mode 100644 Meta/Lagom/Fuzzers/FuzzMP3Loader.cpp delete mode 100644 Meta/Lagom/Fuzzers/FuzzQOALoader.cpp delete mode 100644 Meta/Lagom/Fuzzers/FuzzWAVLoader.cpp delete mode 100644 Tests/LibMedia/TestFLACSpec.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/FlacLoader.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/FlacLoader.h delete mode 100644 Userland/Libraries/LibMedia/Audio/FlacTypes.h delete mode 100644 Userland/Libraries/LibMedia/Audio/GenericTypes.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/GenericTypes.h delete mode 100644 Userland/Libraries/LibMedia/Audio/MDCT.h delete mode 100644 Userland/Libraries/LibMedia/Audio/MP3HuffmanTables.h delete mode 100644 Userland/Libraries/LibMedia/Audio/MP3Loader.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/MP3Loader.h delete mode 100644 Userland/Libraries/LibMedia/Audio/MP3Tables.h delete mode 100644 Userland/Libraries/LibMedia/Audio/MP3Types.h delete mode 100644 Userland/Libraries/LibMedia/Audio/Metadata.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/Metadata.h delete mode 100644 Userland/Libraries/LibMedia/Audio/MultiChannel.h delete mode 100644 Userland/Libraries/LibMedia/Audio/QOALoader.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/QOALoader.h delete mode 100644 Userland/Libraries/LibMedia/Audio/QOATypes.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/QOATypes.h delete mode 100644 Userland/Libraries/LibMedia/Audio/Resampler.h delete mode 100644 Userland/Libraries/LibMedia/Audio/VorbisComment.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/VorbisComment.h delete mode 100644 Userland/Libraries/LibMedia/Audio/WavLoader.cpp delete mode 100644 Userland/Libraries/LibMedia/Audio/WavLoader.h delete mode 100644 Userland/Libraries/LibMedia/Audio/WavTypes.h diff --git a/AK/Debug.h.in b/AK/Debug.h.in index 7ebcc69073d..1f4ac87a0c7 100644 --- a/AK/Debug.h.in +++ b/AK/Debug.h.in @@ -10,14 +10,6 @@ # cmakedefine01 AUDIO_DEBUG #endif -#ifndef AWAVLOADER_DEBUG -# cmakedefine01 AWAVLOADER_DEBUG -#endif - -#ifndef AFLACLOADER_DEBUG -# cmakedefine01 AFLACLOADER_DEBUG -#endif - #ifndef BMP_DEBUG # cmakedefine01 BMP_DEBUG #endif diff --git a/Ladybird/Qt/AudioThread.h b/Ladybird/Qt/AudioThread.h index 3bf53aa8646..9388b98783b 100644 --- a/Ladybird/Qt/AudioThread.h +++ b/Ladybird/Qt/AudioThread.h @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include diff --git a/Meta/CMake/all_the_debug_macros.cmake b/Meta/CMake/all_the_debug_macros.cmake index c8448035857..1859173cc14 100644 --- a/Meta/CMake/all_the_debug_macros.cmake +++ b/Meta/CMake/all_the_debug_macros.cmake @@ -1,6 +1,4 @@ set(AUDIO_DEBUG ON) -set(AWAVLOADER_DEBUG ON) -set(AFLACLOADER_DEBUG ON) set(BMP_DEBUG ON) set(CACHE_DEBUG ON) set(CALLBACK_MACHINE_DEBUG ON) diff --git a/Meta/Lagom/Fuzzers/FuzzFlacLoader.cpp b/Meta/Lagom/Fuzzers/FuzzFlacLoader.cpp deleted file mode 100644 index 3f1fe5737fa..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzFlacLoader.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AudioFuzzerCommon.h" -#include - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size) -{ - AK::set_debug_enabled(false); - return fuzz_audio_loader(data, size); -} diff --git a/Meta/Lagom/Fuzzers/FuzzMP3Loader.cpp b/Meta/Lagom/Fuzzers/FuzzMP3Loader.cpp deleted file mode 100644 index f7ed72b4526..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzMP3Loader.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AudioFuzzerCommon.h" -#include - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size) -{ - AK::set_debug_enabled(false); - return fuzz_audio_loader(data, size); -} diff --git a/Meta/Lagom/Fuzzers/FuzzQOALoader.cpp b/Meta/Lagom/Fuzzers/FuzzQOALoader.cpp deleted file mode 100644 index 6ae5f6817f4..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzQOALoader.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AudioFuzzerCommon.h" -#include - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size) -{ - AK::set_debug_enabled(false); - return fuzz_audio_loader(data, size); -} diff --git a/Meta/Lagom/Fuzzers/FuzzWAVLoader.cpp b/Meta/Lagom/Fuzzers/FuzzWAVLoader.cpp deleted file mode 100644 index 5377da9acd3..00000000000 --- a/Meta/Lagom/Fuzzers/FuzzWAVLoader.cpp +++ /dev/null @@ -1,14 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "AudioFuzzerCommon.h" -#include - -extern "C" int LLVMFuzzerTestOneInput(uint8_t const* data, size_t size) -{ - AK::set_debug_enabled(false); - return fuzz_audio_loader(data, size); -} diff --git a/Meta/Lagom/Fuzzers/fuzzers.cmake b/Meta/Lagom/Fuzzers/fuzzers.cmake index c941fb414e3..8f1d73d4b35 100644 --- a/Meta/Lagom/Fuzzers/fuzzers.cmake +++ b/Meta/Lagom/Fuzzers/fuzzers.cmake @@ -6,7 +6,6 @@ set(FUZZER_TARGETS Brotli DeflateCompression DeflateDecompression - FlacLoader GIFLoader GzipDecompression GzipRoundtrip @@ -19,11 +18,9 @@ set(FUZZER_TARGETS LzmaRoundtrip MatroskaReader MD5 - MP3Loader PEM PNGLoader Poly1305 - QOALoader RegexECMA262 RegexPosixBasic RegexPosixExtended @@ -38,7 +35,6 @@ set(FUZZER_TARGETS TinyVGLoader URL WasmParser - WAVLoader WebPLoader WOFF WOFF2 @@ -59,7 +55,6 @@ set(FUZZER_DEPENDENCIES_CSSParser LibWeb) set(FUZZER_DEPENDENCIES_DeflateCompression LibCompress) set(FUZZER_DEPENDENCIES_DeflateDecompression LibCompress) set(FUZZER_DEPENDENCIES_ELF LibELF) -set(FUZZER_DEPENDENCIES_FlacLoader LibMedia) set(FUZZER_DEPENDENCIES_GIFLoader LibGfx) set(FUZZER_DEPENDENCIES_GzipDecompression LibCompress) set(FUZZER_DEPENDENCIES_GzipRoundtrip LibCompress) @@ -71,11 +66,9 @@ set(FUZZER_DEPENDENCIES_LzmaDecompression LibArchive LibCompress) set(FUZZER_DEPENDENCIES_LzmaRoundtrip LibCompress) set(FUZZER_DEPENDENCIES_MatroskaReader LibMedia) set(FUZZER_DEPENDENCIES_MD5 LibCrypto) -set(FUZZER_DEPENDENCIES_MP3Loader LibMedia) set(FUZZER_DEPENDENCIES_PEM LibCrypto) set(FUZZER_DEPENDENCIES_PNGLoader LibGfx) set(FUZZER_DEPENDENCIES_Poly1305 LibCrypto) -set(FUZZER_DEPENDENCIES_QOALoader LibMedia) set(FUZZER_DEPENDENCIES_RegexECMA262 LibRegex) set(FUZZER_DEPENDENCIES_RegexPosixBasic LibRegex) set(FUZZER_DEPENDENCIES_RegexPosixExtended LibRegex) @@ -91,7 +84,6 @@ set(FUZZER_DEPENDENCIES_TTF LibGfx) set(FUZZER_DEPENDENCIES_TinyVGLoader LibGfx) set(FUZZER_DEPENDENCIES_URL LibURL) set(FUZZER_DEPENDENCIES_WasmParser LibWasm) -set(FUZZER_DEPENDENCIES_WAVLoader LibMedia) set(FUZZER_DEPENDENCIES_WebPLoader LibGfx) set(FUZZER_DEPENDENCIES_WOFF LibGfx) set(FUZZER_DEPENDENCIES_WOFF2 LibGfx) diff --git a/Meta/gn/secondary/AK/BUILD.gn b/Meta/gn/secondary/AK/BUILD.gn index 23142652710..b39976a1cf7 100644 --- a/Meta/gn/secondary/AK/BUILD.gn +++ b/Meta/gn/secondary/AK/BUILD.gn @@ -220,8 +220,6 @@ write_cmake_config("ak_debug_gen") { output = "$root_gen_dir/AK/Debug.h" values = [ "AUDIO_DEBUG=", - "AWAVLOADER_DEBUG=", - "AFLACLOADER_DEBUG=", "BINDINGS_GENERATOR_DEBUG=", "BMP_DEBUG=", "CACHE_DEBUG=", diff --git a/Meta/gn/secondary/Userland/Libraries/LibMedia/BUILD.gn b/Meta/gn/secondary/Userland/Libraries/LibMedia/BUILD.gn index cca68e8499f..8f3980069ef 100644 --- a/Meta/gn/secondary/Userland/Libraries/LibMedia/BUILD.gn +++ b/Meta/gn/secondary/Userland/Libraries/LibMedia/BUILD.gn @@ -4,17 +4,9 @@ import("//Meta/gn/build/libs/pulse/enable.gni") shared_library("LibMedia") { include_dirs = [ "//Userland/Libraries" ] sources = [ - "Audio/FlacLoader.cpp", - "Audio/GenericTypes.cpp", "Audio/Loader.cpp", - "Audio/MP3Loader.cpp", - "Audio/Metadata.cpp", "Audio/PlaybackStream.cpp", - "Audio/QOALoader.cpp", - "Audio/QOATypes.cpp", "Audio/SampleFormats.cpp", - "Audio/VorbisComment.cpp", - "Audio/WavLoader.cpp", "Color/ColorConverter.cpp", "Color/ColorPrimaries.cpp", "Color/TransferCharacteristics.cpp", diff --git a/Tests/LibMedia/CMakeLists.txt b/Tests/LibMedia/CMakeLists.txt index f0ea67926ea..d7740641a9d 100644 --- a/Tests/LibMedia/CMakeLists.txt +++ b/Tests/LibMedia/CMakeLists.txt @@ -11,9 +11,6 @@ foreach(source IN LISTS TEST_SOURCES) lagom_test("${source}" LibMedia LIBS LibMedia LibFileSystem WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}") endforeach() -# The FLAC tests need a special working directory to find the test files -lagom_test(TestFLACSpec.cpp LIBS LibMedia WORKING_DIRECTORY "${FLAC_TEST_PATH}/..") - if (HAVE_PULSEAUDIO) target_compile_definitions(TestPlaybackStream PRIVATE HAVE_PULSEAUDIO=1) endif() diff --git a/Tests/LibMedia/TestFLACSpec.cpp b/Tests/LibMedia/TestFLACSpec.cpp deleted file mode 100644 index f1034efaa3e..00000000000 --- a/Tests/LibMedia/TestFLACSpec.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2022, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include -#include -#include -#include - -struct DiscoverFLACTestsHack { - DiscoverFLACTestsHack() - { - // FIXME: Also run (our own) tests in this directory. - (void)Core::Directory::for_each_entry("./FLAC/SpecTests"sv, Core::DirIterator::Flags::SkipParentAndBaseDir, [](auto const& entry, auto const& directory) -> ErrorOr { - auto path = LexicalPath::join(directory.path().string(), entry.name); - if (path.extension() == "flac"sv) { - Test::add_test_case_to_suite(adopt_ref(*new ::Test::TestCase( - ByteString::formatted("flac_spec_test_{}", path.basename()), - [path = move(path)]() { - auto file = Core::File::open(path.string(), Core::File::OpenMode::Read); - if (file.is_error()) { - FAIL(ByteString::formatted("{}", file.error())); - return; - } - auto buffered_file = Core::InputBufferedFile::create(file.release_value()); - if (buffered_file.is_error()) { - FAIL(ByteString::formatted("{}", buffered_file.error())); - return; - } - auto result = Audio::FlacLoaderPlugin::create(buffered_file.release_value()); - if (result.is_error()) { - FAIL(ByteString::formatted("{}", result.error())); - return; - } - - auto loader = result.release_value(); - - while (true) { - auto maybe_samples = loader->load_chunks(2 * MiB); - if (maybe_samples.is_error()) { - FAIL(ByteString::formatted("{}", maybe_samples.error())); - return; - } - maybe_samples.value().remove_all_matching([](auto& chunk) { return chunk.is_empty(); }); - if (maybe_samples.value().is_empty()) - return; - } - }, - false))); - } - return IterationDecision::Continue; - }); - } -}; -// Hack taken from TEST_CASE; the above constructor will run as part of global initialization before the tests are actually executed -static struct DiscoverFLACTestsHack hack; diff --git a/Tests/LibMedia/TestWav.cpp b/Tests/LibMedia/TestWav.cpp index f4b0037533c..d93af32a528 100644 --- a/Tests/LibMedia/TestWav.cpp +++ b/Tests/LibMedia/TestWav.cpp @@ -5,7 +5,7 @@ */ #include -#include +#include #include static void run_test(StringView file_name, int const num_samples, int const channels, u32 const rate) diff --git a/Userland/Libraries/LibMedia/Audio/FlacLoader.cpp b/Userland/Libraries/LibMedia/Audio/FlacLoader.cpp deleted file mode 100644 index 1077ab6fc44..00000000000 --- a/Userland/Libraries/LibMedia/Audio/FlacLoader.cpp +++ /dev/null @@ -1,1049 +0,0 @@ -/* - * Copyright (c) 2021, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "FlacLoader.h" -#include "FlacTypes.h" -#include "GenericTypes.h" -#include "LoaderError.h" -#include "MultiChannel.h" -#include "Resampler.h" -#include "VorbisComment.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Audio { - -FlacLoaderPlugin::FlacLoaderPlugin(NonnullOwnPtr stream) - : LoaderPlugin(move(stream)) -{ -} - -ErrorOr, LoaderError> FlacLoaderPlugin::create(NonnullOwnPtr stream) -{ - auto loader = make(move(stream)); - TRY(loader->initialize()); - return loader; -} - -MaybeLoaderError FlacLoaderPlugin::initialize() -{ - TRY(parse_header()); - TRY(reset()); - return {}; -} - -bool FlacLoaderPlugin::sniff(SeekableStream& stream) -{ - BigEndianInputBitStream bit_input { MaybeOwned(stream) }; - auto maybe_flac = bit_input.read_bits(32); - return !maybe_flac.is_error() && maybe_flac.value() == 0x664C6143; // "flaC" -} - -// 11.5 STREAM -MaybeLoaderError FlacLoaderPlugin::parse_header() -{ - BigEndianInputBitStream bit_input { MaybeOwned(*m_stream) }; - - // A mixture of VERIFY and the non-crashing TRY(). -#define FLAC_VERIFY(check, category, msg) \ - do { \ - if (!(check)) { \ - return LoaderError { category, TRY(m_stream->tell()), ByteString::formatted("FLAC header: {}", msg) }; \ - } \ - } while (0) - - // Magic number - u32 flac = TRY(bit_input.read_bits(32)); - m_data_start_location += 4; - FLAC_VERIFY(flac == 0x664C6143, LoaderError::Category::Format, "Magic number must be 'flaC'"); // "flaC" - - // Receive the streaminfo block - auto streaminfo = TRY(next_meta_block(bit_input)); - FLAC_VERIFY(streaminfo.type == FlacMetadataBlockType::STREAMINFO, LoaderError::Category::Format, "First block must be STREAMINFO"); - FixedMemoryStream streaminfo_data_memory { streaminfo.data.bytes() }; - BigEndianInputBitStream streaminfo_data { MaybeOwned(streaminfo_data_memory) }; - - // 11.10 METADATA_BLOCK_STREAMINFO - m_min_block_size = TRY(streaminfo_data.read_bits(16)); - FLAC_VERIFY(m_min_block_size >= 16, LoaderError::Category::Format, "Minimum block size must be 16"); - m_max_block_size = TRY(streaminfo_data.read_bits(16)); - FLAC_VERIFY(m_max_block_size >= 16, LoaderError::Category::Format, "Maximum block size"); - m_min_frame_size = TRY(streaminfo_data.read_bits(24)); - m_max_frame_size = TRY(streaminfo_data.read_bits(24)); - m_sample_rate = TRY(streaminfo_data.read_bits(20)); - FLAC_VERIFY(m_sample_rate <= 655350, LoaderError::Category::Format, "Sample rate"); - m_num_channels = TRY(streaminfo_data.read_bits(3)) + 1; // 0 = one channel - - m_bits_per_sample = TRY(streaminfo_data.read_bits(5)) + 1; - if (m_bits_per_sample <= 8) { - // FIXME: Signed/Unsigned issues? - m_sample_format = PcmSampleFormat::Uint8; - } else if (m_bits_per_sample <= 16) { - m_sample_format = PcmSampleFormat::Int16; - } else if (m_bits_per_sample <= 24) { - m_sample_format = PcmSampleFormat::Int24; - } else if (m_bits_per_sample <= 32) { - m_sample_format = PcmSampleFormat::Int32; - } else { - FLAC_VERIFY(false, LoaderError::Category::Format, "Sample bit depth too large"); - } - - m_total_samples = TRY(streaminfo_data.read_bits(36)); - if (m_total_samples == 0) { - // "A value of zero here means the number of total samples is unknown." - dbgln("FLAC Warning: File has unknown amount of samples, the loader will not stop before EOF"); - m_total_samples = NumericLimits::max(); - } - - VERIFY(streaminfo_data.is_aligned_to_byte_boundary()); - TRY(streaminfo_data.read_until_filled({ m_md5_checksum, sizeof(m_md5_checksum) })); - - // Parse other blocks - [[maybe_unused]] u16 meta_blocks_parsed = 1; - [[maybe_unused]] u16 total_meta_blocks = meta_blocks_parsed; - FlacRawMetadataBlock block = streaminfo; - while (!block.is_last_block) { - block = TRY(next_meta_block(bit_input)); - switch (block.type) { - case (FlacMetadataBlockType::SEEKTABLE): - TRY(load_seektable(block)); - break; - case FlacMetadataBlockType::PICTURE: - TRY(load_picture(block)); - break; - case FlacMetadataBlockType::APPLICATION: - // Note: Third-party library can encode specific data in this. - dbgln("FLAC Warning: Unknown 'Application' metadata block encountered."); - [[fallthrough]]; - case FlacMetadataBlockType::PADDING: - // Note: A padding block is empty and does not need any treatment. - break; - case FlacMetadataBlockType::VORBIS_COMMENT: - load_vorbis_comment(block); - break; - default: - // TODO: Parse the remaining metadata block types. - break; - } - ++total_meta_blocks; - } - - dbgln_if(AFLACLOADER_DEBUG, "Parsed FLAC header: blocksize {}-{}{}, framesize {}-{}, {}Hz, {}bit, {} channels, {} samples total ({:.2f}s), MD5 {}, data start at {:x} bytes, {} headers total (skipped {})", m_min_block_size, m_max_block_size, is_fixed_blocksize_stream() ? " (constant)" : "", m_min_frame_size, m_max_frame_size, m_sample_rate, pcm_bits_per_sample(m_sample_format), m_num_channels, m_total_samples, static_cast(m_total_samples) / static_cast(m_sample_rate), m_md5_checksum, m_data_start_location, total_meta_blocks, total_meta_blocks - meta_blocks_parsed); - TRY(m_seektable.insert_seek_point({ 0, 0 })); - - return {}; -} - -// 11.19. METADATA_BLOCK_PICTURE -MaybeLoaderError FlacLoaderPlugin::load_picture(FlacRawMetadataBlock& block) -{ - FixedMemoryStream memory_stream { block.data.bytes() }; - BigEndianInputBitStream picture_block_bytes { MaybeOwned(memory_stream) }; - - PictureData picture; - - picture.type = static_cast(TRY(picture_block_bytes.read_bits(32))); - - auto const mime_string_length = TRY(picture_block_bytes.read_bits(32)); - auto offset_before_seeking = memory_stream.offset(); - if (offset_before_seeking + mime_string_length >= block.data.size()) - return LoaderError { LoaderError::Category::Format, TRY(m_stream->tell()), "Picture MIME type exceeds available data" }; - - // "The MIME type string, in printable ASCII characters 0x20-0x7E." - picture.mime_string = TRY(String::from_stream(memory_stream, mime_string_length)); - for (auto code_point : picture.mime_string.code_points()) { - if (code_point < 0x20 || code_point > 0x7E) - return LoaderError { LoaderError::Category::Format, TRY(m_stream->tell()), "Picture MIME type is not ASCII in range 0x20 - 0x7E" }; - } - - auto const description_string_length = TRY(picture_block_bytes.read_bits(32)); - offset_before_seeking = memory_stream.offset(); - if (offset_before_seeking + description_string_length >= block.data.size()) - return LoaderError { LoaderError::Category::Format, TRY(m_stream->tell()), "Picture description exceeds available data" }; - - picture.description_string = TRY(String::from_stream(memory_stream, description_string_length)); - - picture.width = TRY(picture_block_bytes.read_bits(32)); - picture.height = TRY(picture_block_bytes.read_bits(32)); - - picture.color_depth = TRY(picture_block_bytes.read_bits(32)); - picture.colors = TRY(picture_block_bytes.read_bits(32)); - - auto const picture_size = TRY(picture_block_bytes.read_bits(32)); - offset_before_seeking = memory_stream.offset(); - if (offset_before_seeking + picture_size > block.data.size()) - return LoaderError { LoaderError::Category::Format, static_cast(TRY(m_stream->tell())), "Picture size exceeds available data" }; - - TRY(memory_stream.seek(picture_size, SeekMode::FromCurrentPosition)); - picture.data = Vector { block.data.bytes().slice(offset_before_seeking, picture_size) }; - - m_pictures.append(move(picture)); - - return {}; -} - -// 11.15. METADATA_BLOCK_VORBIS_COMMENT -void FlacLoaderPlugin::load_vorbis_comment(FlacRawMetadataBlock& block) -{ - auto metadata_or_error = Audio::load_vorbis_comment(block.data); - if (metadata_or_error.is_error()) { - dbgln("FLAC Warning: Vorbis comment invalid, error: {}", metadata_or_error.release_error()); - return; - } - m_metadata = metadata_or_error.release_value(); -} - -// 11.13. METADATA_BLOCK_SEEKTABLE -MaybeLoaderError FlacLoaderPlugin::load_seektable(FlacRawMetadataBlock& block) -{ - FixedMemoryStream memory_stream { block.data.bytes() }; - BigEndianInputBitStream seektable_bytes { MaybeOwned(memory_stream) }; - for (size_t i = 0; i < block.length / 18; ++i) { - // 11.14. SEEKPOINT - u64 sample_index = TRY(seektable_bytes.read_bits(64)); - u64 byte_offset = TRY(seektable_bytes.read_bits(64)); - // The sample count of a seek point is not relevant to us. - [[maybe_unused]] u16 sample_count = TRY(seektable_bytes.read_bits(16)); - // Placeholder, to be ignored. - if (sample_index == 0xFFFFFFFFFFFFFFFF) - continue; - - SeekPoint seekpoint { - .sample_index = sample_index, - .byte_offset = byte_offset, - }; - TRY(m_seektable.insert_seek_point(seekpoint)); - } - dbgln_if(AFLACLOADER_DEBUG, "Loaded seektable of size {}", m_seektable.size()); - return {}; -} - -// 11.6 METADATA_BLOCK -ErrorOr FlacLoaderPlugin::next_meta_block(BigEndianInputBitStream& bit_input) -{ - // 11.7 METADATA_BLOCK_HEADER - bool is_last_block = TRY(bit_input.read_bit()); - // The block type enum constants agree with the specification - FlacMetadataBlockType type = (FlacMetadataBlockType)TRY(bit_input.read_bits(7)); - m_data_start_location += 1; - FLAC_VERIFY(type != FlacMetadataBlockType::INVALID, LoaderError::Category::Format, "Invalid metadata block"); - - u32 block_length = TRY(bit_input.read_bits(24)); - m_data_start_location += 3; - // Blocks can be zero-sized, which would trip up the raw data reader below. - if (block_length == 0) - return FlacRawMetadataBlock { - .is_last_block = is_last_block, - .type = type, - .length = 0, - .data = TRY(ByteBuffer::create_uninitialized(0)) - }; - auto block_data_result = ByteBuffer::create_uninitialized(block_length); - FLAC_VERIFY(!block_data_result.is_error(), LoaderError::Category::IO, "Out of memory"); - auto block_data = block_data_result.release_value(); - - TRY(bit_input.read_until_filled(block_data)); - - m_data_start_location += block_length; - return FlacRawMetadataBlock { - is_last_block, - type, - block_length, - block_data, - }; -} -#undef FLAC_VERIFY - -MaybeLoaderError FlacLoaderPlugin::reset() -{ - TRY(seek(0)); - m_current_frame.clear(); - return {}; -} - -MaybeLoaderError FlacLoaderPlugin::seek(int int_sample_index) -{ - auto sample_index = static_cast(int_sample_index); - if (sample_index == m_loaded_samples) - return {}; - - auto maybe_target_seekpoint = m_seektable.seek_point_before(sample_index); - // No seektable or no fitting entry: Perform normal forward read - if (!maybe_target_seekpoint.has_value()) { - if (sample_index < m_loaded_samples) { - TRY(m_stream->seek(m_data_start_location, SeekMode::SetPosition)); - m_loaded_samples = 0; - } - if (sample_index - m_loaded_samples == 0) - return {}; - dbgln_if(AFLACLOADER_DEBUG, "Seeking {} samples manually", sample_index - m_loaded_samples); - } else { - auto target_seekpoint = maybe_target_seekpoint.release_value(); - - // When a small seek happens, we may already be closer to the target than the seekpoint. - if (sample_index - target_seekpoint.sample_index > sample_index - m_loaded_samples) { - dbgln_if(AFLACLOADER_DEBUG, "Close enough to target ({} samples): ignoring seek point", sample_index - m_loaded_samples); - } else { - dbgln_if(AFLACLOADER_DEBUG, "Seeking to seektable: sample index {}, byte offset {}", target_seekpoint.sample_index, target_seekpoint.byte_offset); - auto position = target_seekpoint.byte_offset + m_data_start_location; - if (m_stream->seek(static_cast(position), SeekMode::SetPosition).is_error()) - return LoaderError { LoaderError::Category::IO, m_loaded_samples, ByteString::formatted("Invalid seek position {}", position) }; - m_loaded_samples = target_seekpoint.sample_index; - } - } - - // Skip frames until we're just before the target sample. - VERIFY(m_loaded_samples <= sample_index); - size_t frame_start_location; - while (m_loaded_samples <= sample_index) { - frame_start_location = TRY(m_stream->tell()); - (void)TRY(next_frame()); - m_loaded_samples += m_current_frame->sample_count; - } - TRY(m_stream->seek(frame_start_location, SeekMode::SetPosition)); - - return {}; -} - -bool FlacLoaderPlugin::should_insert_seekpoint_at(u64 sample_index) const -{ - auto const max_seekpoint_distance = (maximum_seekpoint_distance_ms * m_sample_rate) / 1000; - auto const seek_tolerance = (seek_tolerance_ms * m_sample_rate) / 1000; - auto const current_seekpoint_distance = m_seektable.seek_point_sample_distance_around(sample_index).value_or(NumericLimits::max()); - auto const previous_seekpoint = m_seektable.seek_point_before(sample_index); - auto const distance_to_previous_seekpoint = previous_seekpoint.has_value() ? sample_index - previous_seekpoint->sample_index : NumericLimits::max(); - - // We insert a seekpoint only under two conditions: - // - The seek points around us are spaced too far for what the loader recommends. - // Prevents inserting too many seek points between pre-loaded seek points. - // - We are so far away from the previous seek point that seeking will become too imprecise if we don't insert a seek point at least here. - // Prevents inserting too many seek points at the end of files without pre-loaded seek points. - return current_seekpoint_distance >= max_seekpoint_distance && distance_to_previous_seekpoint >= seek_tolerance; -} - -ErrorOr>, LoaderError> FlacLoaderPlugin::load_chunks(size_t samples_to_read_from_input) -{ - ssize_t remaining_samples = static_cast(m_total_samples - m_loaded_samples); - // The first condition is relevant for unknown-size streams (total samples = 0 in the header) - if (m_stream->is_eof() || (m_total_samples < NumericLimits::max() && remaining_samples <= 0)) - return Vector> {}; - - size_t samples_to_read = min(samples_to_read_from_input, remaining_samples); - Vector> frames; - // In this case we can know exactly how many frames we're going to read. - if (is_fixed_blocksize_stream() && m_current_frame.has_value()) - TRY(frames.try_ensure_capacity(samples_to_read / m_current_frame->sample_count + 1)); - - size_t sample_index = 0; - - while (!m_stream->is_eof() && sample_index < samples_to_read) { - TRY(frames.try_append(TRY(next_frame()))); - sample_index += m_current_frame->sample_count; - } - - m_loaded_samples += sample_index; - - return frames; -} - -// 11.21. FRAME -LoaderSamples FlacLoaderPlugin::next_frame() -{ -#define FLAC_VERIFY(check, category, msg) \ - do { \ - if (!(check)) { \ - return LoaderError { category, static_cast(m_current_sample_or_frame), ByteString::formatted("FLAC header: {}", msg) }; \ - } \ - } while (0) - - auto frame_byte_index = TRY(m_stream->tell()); - auto sample_index = m_loaded_samples; - // Insert a new seek point if we don't have enough here. - if (should_insert_seekpoint_at(sample_index)) { - dbgln_if(AFLACLOADER_DEBUG, "Inserting ad-hoc seek point for sample {} at byte {:x} (seekpoint spacing {} samples)", sample_index, frame_byte_index, m_seektable.seek_point_sample_distance_around(sample_index).value_or(NumericLimits::max())); - auto maybe_error = m_seektable.insert_seek_point({ .sample_index = sample_index, .byte_offset = frame_byte_index - m_data_start_location }); - if (maybe_error.is_error()) - dbgln("FLAC Warning: Inserting seek point for sample {} failed: {}", sample_index, maybe_error.release_error()); - } - - auto frame_checksum_stream = TRY(try_make>(MaybeOwned(*m_stream))); - auto header_checksum_stream = TRY(try_make>(MaybeOwned(*frame_checksum_stream))); - BigEndianInputBitStream bit_stream { MaybeOwned { *header_checksum_stream } }; - - // 11.22. FRAME_HEADER - u16 sync_code = TRY(bit_stream.read_bits(14)); - FLAC_VERIFY(sync_code == 0b11111111111110, LoaderError::Category::Format, "Sync code"); - bool reserved_bit = TRY(bit_stream.read_bit()); - FLAC_VERIFY(reserved_bit == 0, LoaderError::Category::Format, "Reserved frame header bit"); - // 11.22.2. BLOCKING STRATEGY - [[maybe_unused]] bool blocking_strategy = TRY(bit_stream.read_bit()); - - u32 sample_count = TRY(convert_sample_count_code(TRY(bit_stream.read_bits(4)))); - - u32 frame_sample_rate = TRY(convert_sample_rate_code(TRY(bit_stream.read_bits(4)))); - - u8 channel_type_num = TRY(bit_stream.read_bits(4)); - FLAC_VERIFY(channel_type_num < 0b1011, LoaderError::Category::Format, "Channel assignment"); - FlacFrameChannelType channel_type = (FlacFrameChannelType)channel_type_num; - - u8 bit_depth = TRY(convert_bit_depth_code(TRY(bit_stream.read_bits(3)))); - - reserved_bit = TRY(bit_stream.read_bit()); - FLAC_VERIFY(reserved_bit == 0, LoaderError::Category::Format, "Reserved frame header end bit"); - - // 11.22.8. CODED NUMBER - m_current_sample_or_frame = TRY(read_utf8_char(bit_stream)); - - // Conditional header variables - // 11.22.9. BLOCK SIZE INT - if (sample_count == FLAC_BLOCKSIZE_AT_END_OF_HEADER_8) { - sample_count = TRY(bit_stream.read_bits(8)) + 1; - } else if (sample_count == FLAC_BLOCKSIZE_AT_END_OF_HEADER_16) { - sample_count = TRY(bit_stream.read_bits(16)) + 1; - } - - // 11.22.10. SAMPLE RATE INT - if (frame_sample_rate == FLAC_SAMPLERATE_AT_END_OF_HEADER_8) { - frame_sample_rate = TRY(bit_stream.read_bits(8)) * 1000; - } else if (frame_sample_rate == FLAC_SAMPLERATE_AT_END_OF_HEADER_16) { - frame_sample_rate = TRY(bit_stream.read_bits(16)); - } else if (frame_sample_rate == FLAC_SAMPLERATE_AT_END_OF_HEADER_16X10) { - frame_sample_rate = TRY(bit_stream.read_bits(16)) * 10; - } - - // It does not matter whether we extract the checksum from the digest here, or extract the digest 0x00 after processing the checksum. - auto const calculated_header_checksum = header_checksum_stream->digest(); - // 11.22.11. FRAME CRC - u8 specified_header_checksum = TRY(bit_stream.read_bits(8)); - VERIFY(bit_stream.is_aligned_to_byte_boundary()); - if (specified_header_checksum != calculated_header_checksum) - dbgln("FLAC frame {}: Calculated header checksum {:02x} is different from specified checksum {:02x}", m_current_sample_or_frame, calculated_header_checksum, specified_header_checksum); - - dbgln_if(AFLACLOADER_DEBUG, "Frame: {} samples, {}bit {}Hz, channeltype {:x}, {} number {}, header checksum {:02x}{}", sample_count, bit_depth, frame_sample_rate, channel_type_num, blocking_strategy ? "sample" : "frame", m_current_sample_or_frame, specified_header_checksum, specified_header_checksum != calculated_header_checksum ? " (checksum error)"sv : ""sv); - - m_current_frame = FlacFrameHeader { - .sample_rate = frame_sample_rate, - .sample_count = static_cast(sample_count), - .sample_or_frame_index = static_cast(m_current_sample_or_frame), - .blocking_strategy = static_cast(blocking_strategy), - .channels = channel_type, - .bit_depth = bit_depth, - .checksum = specified_header_checksum, - }; - - u8 subframe_count = frame_channel_type_to_channel_count(channel_type); - TRY(m_subframe_buffers.try_resize_and_keep_capacity(subframe_count)); - - float sample_rescale = 1 / static_cast(1 << (m_current_frame->bit_depth - 1)); - dbgln_if(AFLACLOADER_DEBUG, "Samples will be rescaled from {} bits: factor {:.8f}", m_current_frame->bit_depth, sample_rescale); - - for (u8 i = 0; i < subframe_count; ++i) { - FlacSubframeHeader new_subframe = TRY(next_subframe_header(bit_stream, i)); - auto& subframe_samples = m_subframe_buffers[i]; - subframe_samples.clear_with_capacity(); - TRY(parse_subframe(subframe_samples, new_subframe, bit_stream)); - // We only verify the sample count for the common case of a constant sample rate. - if (m_sample_rate == m_current_frame->sample_rate) - VERIFY(subframe_samples.size() == m_current_frame->sample_count); - } - - // 11.2. Overview ("The audio data is composed of...") - bit_stream.align_to_byte_boundary(); - - // 11.23. FRAME_FOOTER - auto const calculated_frame_checksum = frame_checksum_stream->digest(); - auto const specified_frame_checksum = TRY(bit_stream.read_bits(16)); - if (calculated_frame_checksum != specified_frame_checksum) - dbgln("FLAC frame {}: Calculated frame checksum {:04x} is different from specified checksum {:04x}", m_current_sample_or_frame, calculated_frame_checksum, specified_frame_checksum); - dbgln_if(AFLACLOADER_DEBUG, "Subframe footer checksum: {:04x}{}", specified_frame_checksum, specified_frame_checksum != calculated_frame_checksum ? " (checksum error)"sv : ""sv); - - FixedArray samples; - - switch (channel_type) { - case FlacFrameChannelType::Mono: - case FlacFrameChannelType::Stereo: - case FlacFrameChannelType::StereoCenter: - case FlacFrameChannelType::Surround4p0: - case FlacFrameChannelType::Surround5p0: - case FlacFrameChannelType::Surround5p1: - case FlacFrameChannelType::Surround6p1: - case FlacFrameChannelType::Surround7p1: { - auto new_samples = TRY(downmix_surround_to_stereo>(m_subframe_buffers, sample_rescale)); - samples.swap(new_samples); - break; - } - case FlacFrameChannelType::LeftSideStereo: { - auto new_samples = TRY(FixedArray::create(m_current_frame->sample_count)); - samples.swap(new_samples); - // channels are left (0) and side (1) - for (size_t i = 0; i < m_current_frame->sample_count; ++i) { - // right = left - side - samples[i] = { static_cast(m_subframe_buffers[0][i]) * sample_rescale, - static_cast(m_subframe_buffers[0][i] - m_subframe_buffers[1][i]) * sample_rescale }; - } - break; - } - case FlacFrameChannelType::RightSideStereo: { - auto new_samples = TRY(FixedArray::create(m_current_frame->sample_count)); - samples.swap(new_samples); - // channels are side (0) and right (1) - for (size_t i = 0; i < m_current_frame->sample_count; ++i) { - // left = right + side - samples[i] = { static_cast(m_subframe_buffers[1][i] + m_subframe_buffers[0][i]) * sample_rescale, - static_cast(m_subframe_buffers[1][i]) * sample_rescale }; - } - break; - } - case FlacFrameChannelType::MidSideStereo: { - auto new_samples = TRY(FixedArray::create(m_current_frame->sample_count)); - samples.swap(new_samples); - // channels are mid (0) and side (1) - for (size_t i = 0; i < m_subframe_buffers[0].size(); ++i) { - i64 mid = m_subframe_buffers[0][i]; - i64 side = m_subframe_buffers[1][i]; - mid *= 2; - // prevent integer division errors - samples[i] = { static_cast(mid + side) * .5f * sample_rescale, - static_cast(mid - side) * .5f * sample_rescale }; - } - break; - } - } - - return samples; -#undef FLAC_VERIFY -} - -// 11.22.3. INTERCHANNEL SAMPLE BLOCK SIZE -ErrorOr FlacLoaderPlugin::convert_sample_count_code(u8 sample_count_code) -{ - // single codes - switch (sample_count_code) { - case 0: - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Reserved block size" }; - case 1: - return 192; - case 6: - return FLAC_BLOCKSIZE_AT_END_OF_HEADER_8; - case 7: - return FLAC_BLOCKSIZE_AT_END_OF_HEADER_16; - } - if (sample_count_code >= 2 && sample_count_code <= 5) { - return 576 * AK::exp2(sample_count_code - 2); - } - return 256 * AK::exp2(sample_count_code - 8); -} - -// 11.22.4. SAMPLE RATE -ErrorOr FlacLoaderPlugin::convert_sample_rate_code(u8 sample_rate_code) -{ - switch (sample_rate_code) { - case 0: - return m_sample_rate; - case 1: - return 88200; - case 2: - return 176400; - case 3: - return 192000; - case 4: - return 8000; - case 5: - return 16000; - case 6: - return 22050; - case 7: - return 24000; - case 8: - return 32000; - case 9: - return 44100; - case 10: - return 48000; - case 11: - return 96000; - case 12: - return FLAC_SAMPLERATE_AT_END_OF_HEADER_8; - case 13: - return FLAC_SAMPLERATE_AT_END_OF_HEADER_16; - case 14: - return FLAC_SAMPLERATE_AT_END_OF_HEADER_16X10; - default: - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Invalid sample rate code" }; - } -} - -// 11.22.6. SAMPLE SIZE -ErrorOr FlacLoaderPlugin::convert_bit_depth_code(u8 bit_depth_code) -{ - switch (bit_depth_code) { - case 0: - return m_bits_per_sample; - case 1: - return 8; - case 2: - return 12; - case 3: - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Reserved sample size" }; - case 4: - return 16; - case 5: - return 20; - case 6: - return 24; - case 7: - return 32; - default: - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), ByteString::formatted("Unsupported sample size {}", bit_depth_code) }; - } -} - -// 11.22.5. CHANNEL ASSIGNMENT -u8 frame_channel_type_to_channel_count(FlacFrameChannelType channel_type) -{ - if (channel_type <= FlacFrameChannelType::Surround7p1) - return to_underlying(channel_type) + 1; - return 2; -} - -// 11.25. SUBFRAME_HEADER -ErrorOr FlacLoaderPlugin::next_subframe_header(BigEndianInputBitStream& bit_stream, u8 channel_index) -{ - u8 bits_per_sample = m_current_frame->bit_depth; - - // For inter-channel correlation, the side channel needs an extra bit for its samples - switch (m_current_frame->channels) { - case FlacFrameChannelType::LeftSideStereo: - case FlacFrameChannelType::MidSideStereo: - if (channel_index == 1) { - ++bits_per_sample; - } - break; - case FlacFrameChannelType::RightSideStereo: - if (channel_index == 0) { - ++bits_per_sample; - } - break; - // "normal" channel types - default: - break; - } - - // zero-bit padding - if (TRY(bit_stream.read_bit()) != 0) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Zero bit padding" }; - - // 11.25.1. SUBFRAME TYPE - u8 subframe_code = TRY(bit_stream.read_bits(6)); - if ((subframe_code >= 0b000010 && subframe_code <= 0b000111) || (subframe_code > 0b001100 && subframe_code < 0b100000)) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Subframe type" }; - - FlacSubframeType subframe_type; - u8 order = 0; - // LPC has the highest bit set - if ((subframe_code & 0b100000) > 0) { - subframe_type = FlacSubframeType::LPC; - order = (subframe_code & 0b011111) + 1; - } else if ((subframe_code & 0b001000) > 0) { - // Fixed has the third-highest bit set - subframe_type = FlacSubframeType::Fixed; - order = (subframe_code & 0b000111); - } else { - subframe_type = (FlacSubframeType)subframe_code; - } - - // 11.25.2. WASTED BITS PER SAMPLE FLAG - bool has_wasted_bits = TRY(bit_stream.read_bit()); - u8 k = 0; - if (has_wasted_bits) { - bool current_k_bit = 0; - do { - current_k_bit = TRY(bit_stream.read_bit()); - ++k; - } while (current_k_bit != 1); - } - - return FlacSubframeHeader { - subframe_type, - order, - k, - bits_per_sample - }; -} - -ErrorOr FlacLoaderPlugin::parse_subframe(Vector& samples, FlacSubframeHeader& subframe_header, BigEndianInputBitStream& bit_input) -{ - TRY(samples.try_ensure_capacity(m_current_frame->sample_count)); - - switch (subframe_header.type) { - case FlacSubframeType::Constant: { - // 11.26. SUBFRAME_CONSTANT - u64 constant_value = TRY(bit_input.read_bits(subframe_header.bits_per_sample - subframe_header.wasted_bits_per_sample)); - dbgln_if(AFLACLOADER_DEBUG, " Constant subframe: {}", constant_value); - - VERIFY(subframe_header.bits_per_sample - subframe_header.wasted_bits_per_sample != 0); - i64 constant = sign_extend(static_cast(constant_value), subframe_header.bits_per_sample - subframe_header.wasted_bits_per_sample); - for (u64 i = 0; i < m_current_frame->sample_count; ++i) { - samples.unchecked_append(constant); - } - break; - } - case FlacSubframeType::Fixed: { - dbgln_if(AFLACLOADER_DEBUG, " Fixed LPC subframe order {}", subframe_header.order); - samples = TRY(decode_fixed_lpc(subframe_header, bit_input)); - break; - } - case FlacSubframeType::Verbatim: { - dbgln_if(AFLACLOADER_DEBUG, " Verbatim subframe"); - samples = TRY(decode_verbatim(subframe_header, bit_input)); - break; - } - case FlacSubframeType::LPC: { - dbgln_if(AFLACLOADER_DEBUG, " Custom LPC subframe order {}", subframe_header.order); - TRY(decode_custom_lpc(samples, subframe_header, bit_input)); - break; - } - default: - return LoaderError { LoaderError::Category::Unimplemented, static_cast(m_current_sample_or_frame), "Unhandled FLAC subframe type" }; - } - - for (size_t i = 0; i < samples.size(); ++i) { - samples[i] <<= subframe_header.wasted_bits_per_sample; - } - - // Resamplers VERIFY that the sample rate is non-zero. - if (m_current_frame->sample_rate == 0 || m_sample_rate == 0 - || m_current_frame->sample_rate == m_sample_rate) - return {}; - - ResampleHelper resampler(m_current_frame->sample_rate, m_sample_rate); - samples = resampler.resample(samples); - return {}; -} - -// 11.29. SUBFRAME_VERBATIM -// Decode a subframe that isn't actually encoded, usually seen in random data -ErrorOr, LoaderError> FlacLoaderPlugin::decode_verbatim(FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input) -{ - Vector decoded; - decoded.ensure_capacity(m_current_frame->sample_count); - - if (subframe.bits_per_sample <= subframe.wasted_bits_per_sample) { - return LoaderError { - LoaderError::Category::Format, - TRY(m_stream->tell()), - "Effective verbatim bits per sample are zero"sv, - }; - } - for (size_t i = 0; i < m_current_frame->sample_count; ++i) { - decoded.unchecked_append(sign_extend( - TRY(bit_input.read_bits(subframe.bits_per_sample - subframe.wasted_bits_per_sample)), - subframe.bits_per_sample - subframe.wasted_bits_per_sample)); - } - - return decoded; -} - -// 11.28. SUBFRAME_LPC -// Decode a subframe encoded with a custom linear predictor coding, i.e. the subframe provides the polynomial order and coefficients -ErrorOr FlacLoaderPlugin::decode_custom_lpc(Vector& decoded, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input) -{ - // LPC must provide at least as many samples as its order. - if (subframe.order > m_current_frame->sample_count) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Too small frame for LPC order" }; - - decoded.ensure_capacity(m_current_frame->sample_count); - - if (subframe.bits_per_sample <= subframe.wasted_bits_per_sample) { - return LoaderError { - LoaderError::Category::Format, - TRY(m_stream->tell()), - "Effective verbatim bits per sample are zero"sv, - }; - } - // warm-up samples - for (auto i = 0; i < subframe.order; ++i) { - decoded.unchecked_append(sign_extend( - TRY(bit_input.read_bits(subframe.bits_per_sample - subframe.wasted_bits_per_sample)), - subframe.bits_per_sample - subframe.wasted_bits_per_sample)); - } - - // precision of the coefficients - u8 lpc_precision = TRY(bit_input.read_bits(4)); - if (lpc_precision == 0b1111) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Invalid linear predictor coefficient precision" }; - lpc_precision += 1; - - // shift needed on the data (signed!) - i8 lpc_shift = static_cast(sign_extend(TRY(bit_input.read_bits(5)), 5)); - - Vector coefficients; - coefficients.ensure_capacity(subframe.order); - // read coefficients - for (auto i = 0; i < subframe.order; ++i) { - u64 raw_coefficient = TRY(bit_input.read_bits(lpc_precision)); - i64 coefficient = sign_extend(raw_coefficient, lpc_precision); - coefficients.unchecked_append(coefficient); - } - - dbgln_if(AFLACLOADER_DEBUG, " {}-bit {} shift coefficients: {}", lpc_precision, lpc_shift, coefficients); - - TRY(decode_residual(decoded, subframe, bit_input)); - - // approximate the waveform with the predictor - for (size_t i = subframe.order; i < m_current_frame->sample_count; ++i) { - // (see below) - Checked sample = 0; - for (size_t t = 0; t < subframe.order; ++t) { - // It's really important that we compute in 64-bit land here. - // Even though FLAC operates at a maximum bit depth of 32 bits, modern encoders use super-large coefficients for maximum compression. - // These will easily overflow 32 bits and cause strange white noise that abruptly stops intermittently (at the end of a frame). - // The simple fix of course is to do intermediate computations in 64 bits, but we additionally use saturating arithmetic. - // These considerations are not in the original FLAC spec, but have been added to the IETF standard: https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-03#appendix-A.3 - sample.saturating_add(Checked::saturating_mul(static_cast(coefficients[t]), static_cast(decoded[i - t - 1]))); - } - decoded[i] += lpc_shift >= 0 ? (sample.value() >> lpc_shift) : (sample.value() << -lpc_shift); - } - - return {}; -} - -// 11.27. SUBFRAME_FIXED -// Decode a subframe encoded with one of the fixed linear predictor codings -ErrorOr, LoaderError> FlacLoaderPlugin::decode_fixed_lpc(FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input) -{ - // LPC must provide at least as many samples as its order. - if (subframe.order > m_current_frame->sample_count) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Too small frame for LPC order" }; - - Vector decoded; - decoded.ensure_capacity(m_current_frame->sample_count); - - if (subframe.bits_per_sample <= subframe.wasted_bits_per_sample) { - return LoaderError { - LoaderError::Category::Format, - TRY(m_stream->tell()), - "Effective verbatim bits per sample are zero"sv, - }; - } - // warm-up samples - for (auto i = 0; i < subframe.order; ++i) { - decoded.unchecked_append(sign_extend( - TRY(bit_input.read_bits(subframe.bits_per_sample - subframe.wasted_bits_per_sample)), - subframe.bits_per_sample - subframe.wasted_bits_per_sample)); - } - - TRY(decode_residual(decoded, subframe, bit_input)); - - dbgln_if(AFLACLOADER_DEBUG, " decoded length {}, {} order predictor, now at file offset {:x}", decoded.size(), subframe.order, TRY(m_stream->tell())); - - // Skip these comments if you don't care about the neat math behind fixed LPC :^) - // These coefficients for the recursive prediction formula are the only ones that can be resolved to polynomial predictor functions. - // The order equals the degree of the polynomial - 1, so the second-order predictor has an underlying polynomial of degree 1, a straight line. - // More specifically, the closest approximation to a polynomial is used, and the degree depends on how many previous values are available. - // This makes use of a very neat property of polynomials, which is that they are entirely characterized by their finitely many derivatives. - // (Mathematically speaking, the infinite Taylor series of any polynomial equals the polynomial itself.) - // Now remember that derivation is just the slope of the function, which is the same as the difference of two close-by values. - // Therefore, with two samples we can calculate the first derivative at a sample via the difference, which gives us a polynomial of degree 1. - // With three samples, we can do the same but also calculate the second derivative via the difference in the first derivatives. - // This gives us a polynomial of degree 2, as it has two "proper" (non-constant) derivatives. - // This can be continued for higher-order derivatives when we have more coefficients, giving us higher-order polynomials. - // In essence, it's akin to a Lagrangian polynomial interpolation for every sample (but already pre-solved). - - // The coefficients for orders 0-3 originate from the SHORTEN codec: - // http://mi.eng.cam.ac.uk/reports/svr-ftp/auto-pdf/robinson_tr156.pdf page 4 - // The coefficients for order 4 are undocumented in the original FLAC specification(s), but can now be found in - // https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-03#section-10.2.5 - // FIXME: Share this code with predict_fixed_lpc(). - switch (subframe.order) { - case 0: - // s_0(t) = 0 - for (u32 i = subframe.order; i < m_current_frame->sample_count; ++i) - decoded[i] += 0; - break; - case 1: - // s_1(t) = s(t-1) - for (u32 i = subframe.order; i < m_current_frame->sample_count; ++i) - decoded[i] += decoded[i - 1]; - break; - case 2: - // s_2(t) = 2s(t-1) - s(t-2) - for (u32 i = subframe.order; i < m_current_frame->sample_count; ++i) - decoded[i] += 2 * decoded[i - 1] - decoded[i - 2]; - break; - case 3: - // s_3(t) = 3s(t-1) - 3s(t-2) + s(t-3) - for (u32 i = subframe.order; i < m_current_frame->sample_count; ++i) - decoded[i] += 3 * decoded[i - 1] - 3 * decoded[i - 2] + decoded[i - 3]; - break; - case 4: - // s_4(t) = 4s(t-1) - 6s(t-2) + 4s(t-3) - s(t-4) - for (u32 i = subframe.order; i < m_current_frame->sample_count; ++i) - decoded[i] += 4 * decoded[i - 1] - 6 * decoded[i - 2] + 4 * decoded[i - 3] - decoded[i - 4]; - break; - default: - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), ByteString::formatted("Unrecognized predictor order {}", subframe.order) }; - } - return decoded; -} - -// 11.30. RESIDUAL -// Decode the residual, the "error" between the function approximation and the actual audio data -MaybeLoaderError FlacLoaderPlugin::decode_residual(Vector& decoded, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input) -{ - // 11.30.1. RESIDUAL_CODING_METHOD - auto residual_mode = static_cast(TRY(bit_input.read_bits(2))); - u8 partition_order = TRY(bit_input.read_bits(4)); - size_t partitions = 1 << partition_order; - - dbgln_if(AFLACLOADER_DEBUG, " {}-bit Rice partitions, {} total (order {})", residual_mode == FlacResidualMode::Rice4Bit ? "4"sv : "5"sv, partitions, partition_order); - - if (partitions > m_current_frame->sample_count) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Too many Rice partitions, each partition must contain at least one sample" }; - // “The partition order MUST be such that the block size is evenly divisible by the number of partitions.” - // FIXME: Check “The partition order also MUST be such that the (block size >> partition order) is larger than the predictor order.” - if (m_current_frame->sample_count % partitions != 0) - return LoaderError { LoaderError::Category::Format, TRY(m_stream->tell()), "Block size is not evenly divisible by number of partitions" }; - - if (residual_mode == FlacResidualMode::Rice4Bit) { - // 11.30.2. RESIDUAL_CODING_METHOD_PARTITIONED_EXP_GOLOMB - // decode a single Rice partition with four bits for the order k - for (size_t i = 0; i < partitions; ++i) { - // FIXME: Write into the decode buffer directly. - auto rice_partition = TRY(decode_rice_partition(4, partitions, i, subframe, bit_input)); - decoded.extend(move(rice_partition)); - } - } else if (residual_mode == FlacResidualMode::Rice5Bit) { - // 11.30.3. RESIDUAL_CODING_METHOD_PARTITIONED_EXP_GOLOMB2 - // five bits equivalent - for (size_t i = 0; i < partitions; ++i) { - // FIXME: Write into the decode buffer directly. - auto rice_partition = TRY(decode_rice_partition(5, partitions, i, subframe, bit_input)); - decoded.extend(move(rice_partition)); - } - } else - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "Reserved residual coding method" }; - - return {}; -} - -// 11.30.2.1. EXP_GOLOMB_PARTITION and 11.30.3.1. EXP_GOLOMB2_PARTITION -// Decode a single Rice partition as part of the residual, every partition can have its own Rice parameter k -ALWAYS_INLINE ErrorOr, LoaderError> FlacLoaderPlugin::decode_rice_partition(u8 partition_type, u32 partitions, u32 partition_index, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input) -{ - // 11.30.2.2. EXP GOLOMB PARTITION ENCODING PARAMETER and 11.30.3.2. EXP-GOLOMB2 PARTITION ENCODING PARAMETER - u8 k = TRY(bit_input.read_bits(partition_type)); - - u32 residual_sample_count; - if (partitions == 0) - residual_sample_count = m_current_frame->sample_count - subframe.order; - else - residual_sample_count = m_current_frame->sample_count / partitions; - if (partition_index == 0) { - if (subframe.order > residual_sample_count) - return LoaderError { LoaderError::Category::Format, static_cast(m_current_sample_or_frame), "First Rice partition must advertise more residuals than LPC order" }; - residual_sample_count -= subframe.order; - } - - Vector rice_partition; - rice_partition.resize(residual_sample_count); - - // escape code for unencoded binary partition - if (k == (1 << partition_type) - 1) { - u8 unencoded_bps = TRY(bit_input.read_bits(5)); - if (unencoded_bps != 0) { - for (size_t r = 0; r < residual_sample_count; ++r) { - rice_partition[r] = sign_extend(TRY(bit_input.read_bits(unencoded_bps)), unencoded_bps); - } - } - } else { - for (size_t r = 0; r < residual_sample_count; ++r) { - rice_partition[r] = TRY(decode_unsigned_exp_golomb(k, bit_input)); - } - } - - return rice_partition; -} - -// Decode a single number encoded with Rice/Exponential-Golomb encoding (the unsigned variant) -ALWAYS_INLINE ErrorOr decode_unsigned_exp_golomb(u8 k, BigEndianInputBitStream& bit_input) -{ - u8 q = 0; - while (TRY(bit_input.read_bit()) == 0) - ++q; - - // least significant bits (remainder) - u32 rem = TRY(bit_input.read_bits(k)); - u32 value = q << k | rem; - - return rice_to_signed(value); -} - -ErrorOr read_utf8_char(BigEndianInputBitStream& input) -{ - u64 character; - u8 start_byte = TRY(input.read_value()); - // Signal byte is zero: ASCII character - if ((start_byte & 0b10000000) == 0) { - return start_byte; - } else if ((start_byte & 0b11000000) == 0b10000000) { - return Error::from_string_literal("Illegal continuation byte"); - } - // This algorithm supports the theoretical max 0xFF start byte, which is not part of the regular UTF-8 spec. - u8 length = 1; - while (((start_byte << length) & 0b10000000) == 0b10000000) - ++length; - - // This is technically not spec-compliant, but if we take UTF-8 to its logical extreme, - // we can say 0xFF means there's 7 following continuation bytes and no data at all in the leading character. - if (length == 8) [[unlikely]] { - character = 0; - } else { - u8 bits_from_start_byte = 8 - (length + 1); - u8 start_byte_bitmask = AK::exp2(bits_from_start_byte) - 1; - character = start_byte_bitmask & start_byte; - } - for (u8 i = length - 1; i > 0; --i) { - u8 current_byte = TRY(input.read_value()); - character = (character << 6) | (current_byte & 0b00111111); - } - return character; -} - -i64 sign_extend(u32 n, u8 size) -{ - // negative - if ((n & (1 << (size - 1))) > 0) { - return static_cast(n | (0xffffffffffffffffLL << size)); - } - // positive - return n; -} - -i32 rice_to_signed(u32 x) -{ - // positive numbers are even, negative numbers are odd - // bitmask for conditionally inverting the entire number, thereby "negating" it - i32 sign = -static_cast(x & 1); - // copies the sign's sign onto the actual magnitude of x - return static_cast(sign ^ (x >> 1)); -} -} diff --git a/Userland/Libraries/LibMedia/Audio/FlacLoader.h b/Userland/Libraries/LibMedia/Audio/FlacLoader.h deleted file mode 100644 index 99b73c40da8..00000000000 --- a/Userland/Libraries/LibMedia/Audio/FlacLoader.h +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (c) 2021, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "FlacTypes.h" -#include "Loader.h" -#include -#include -#include -#include - -namespace Audio { - -ALWAYS_INLINE u8 frame_channel_type_to_channel_count(FlacFrameChannelType channel_type); -// Sign-extend an arbitrary-size signed number to 64 bit signed -ALWAYS_INLINE i64 sign_extend(u32 n, u8 size); -// Decodes the sign representation method used in Rice coding. -// Numbers alternate between positive and negative: 0, 1, -1, 2, -2, 3, -3, 4, -4, 5, -5, ... -ALWAYS_INLINE i32 rice_to_signed(u32 x); - -// decoders -// read a UTF-8 encoded number, even if it is not a valid codepoint -ALWAYS_INLINE ErrorOr read_utf8_char(BigEndianInputBitStream& input); -// decode a single number encoded with exponential golomb encoding of the specified order -ALWAYS_INLINE ErrorOr decode_unsigned_exp_golomb(u8 order, BigEndianInputBitStream& bit_input); - -// Loader for the Free Lossless Audio Codec (FLAC) -// This loader supports all audio features of FLAC, although audio from more than two channels is discarded. -// The loader currently supports the STREAMINFO, PADDING, and SEEKTABLE metadata blocks. -// See: https://xiph.org/flac/documentation_format_overview.html -// https://xiph.org/flac/format.html (identical to IETF draft version 2) -// https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-02 (all section numbers refer to this specification) -// https://datatracker.ietf.org/doc/html/draft-ietf-cellar-flac-03 (newer IETF draft that uses incompatible numberings and names) -class FlacLoaderPlugin : public LoaderPlugin { -public: - explicit FlacLoaderPlugin(NonnullOwnPtr stream); - virtual ~FlacLoaderPlugin() override = default; - - static bool sniff(SeekableStream& stream); - static ErrorOr, LoaderError> create(NonnullOwnPtr); - - virtual ErrorOr>, LoaderError> load_chunks(size_t samples_to_read_from_input) override; - - virtual MaybeLoaderError reset() override; - virtual MaybeLoaderError seek(int sample_index) override; - - virtual int loaded_samples() override { return static_cast(m_loaded_samples); } - virtual int total_samples() override { return static_cast(m_total_samples); } - virtual u32 sample_rate() override { return m_sample_rate; } - virtual u16 num_channels() override { return m_num_channels; } - virtual ByteString format_name() override { return "FLAC (.flac)"; } - virtual PcmSampleFormat pcm_format() override { return m_sample_format; } - - bool is_fixed_blocksize_stream() const { return m_min_block_size == m_max_block_size; } - bool sample_count_unknown() const { return m_total_samples == 0; } - -private: - MaybeLoaderError initialize(); - MaybeLoaderError parse_header(); - // Either returns the metadata block or sets error message. - // Additionally, increments m_data_start_location past the read meta block. - ErrorOr next_meta_block(BigEndianInputBitStream& bit_input); - // Fetches and returns the next FLAC frame. - LoaderSamples next_frame(); - // Helper of next_frame that fetches a sub frame's header - ErrorOr next_subframe_header(BigEndianInputBitStream& bit_input, u8 channel_index); - // Helper of next_frame that decompresses a subframe - ErrorOr parse_subframe(Vector& samples, FlacSubframeHeader& subframe_header, BigEndianInputBitStream& bit_input); - // Subframe-internal data decoders (heavy lifting) - ErrorOr, LoaderError> decode_fixed_lpc(FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input); - ErrorOr, LoaderError> decode_verbatim(FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input); - ErrorOr decode_custom_lpc(Vector& decoded, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input); - MaybeLoaderError decode_residual(Vector& decoded, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input); - // decode a single rice partition that has its own rice parameter - ALWAYS_INLINE ErrorOr, LoaderError> decode_rice_partition(u8 partition_type, u32 partitions, u32 partition_index, FlacSubframeHeader& subframe, BigEndianInputBitStream& bit_input); - MaybeLoaderError load_seektable(FlacRawMetadataBlock&); - // Note that failing to read a Vorbis comment block is not treated as an error of the FLAC loader, since metadata is optional. - void load_vorbis_comment(FlacRawMetadataBlock&); - MaybeLoaderError load_picture(FlacRawMetadataBlock&); - - // Converters for special coding used in frame headers - ALWAYS_INLINE ErrorOr convert_sample_count_code(u8 sample_count_code); - ALWAYS_INLINE ErrorOr convert_sample_rate_code(u8 sample_rate_code); - ALWAYS_INLINE ErrorOr convert_bit_depth_code(u8 bit_depth_code); - - bool should_insert_seekpoint_at(u64 sample_index) const; - - // Data obtained directly from the FLAC metadata: many values have specific bit counts - u32 m_sample_rate { 0 }; // 20 bit - u8 m_num_channels { 0 }; // 3 bit - u8 m_bits_per_sample { 0 }; // 5 bits for the integer bit depth - // Externally visible format; the smallest integer format that's larger than the precise bit depth. - PcmSampleFormat m_sample_format; - // Blocks are units of decoded audio data - u16 m_min_block_size { 0 }; - u16 m_max_block_size { 0 }; - // Frames are units of encoded audio data, both of these are 24-bit - u32 m_min_frame_size { 0 }; // 24 bit - u32 m_max_frame_size { 0 }; // 24 bit - u64 m_total_samples { 0 }; // 36 bit - u8 m_md5_checksum[128 / 8]; // 128 bit (!) - size_t m_loaded_samples { 0 }; - - // keep track of the start of the data in the FLAC stream to seek back more easily - u64 m_data_start_location { 0 }; - Optional m_current_frame; - u64 m_current_sample_or_frame { 0 }; - SeekTable m_seektable; - - // Keep around a few temporary buffers whose allocated space can be reused. - // This is an empirical optimization since allocations and deallocations take a lot of time in the decoder. - mutable Vector, 2> m_subframe_buffers; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/FlacTypes.h b/Userland/Libraries/LibMedia/Audio/FlacTypes.h deleted file mode 100644 index 86a986c1444..00000000000 --- a/Userland/Libraries/LibMedia/Audio/FlacTypes.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright (c) 2021, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "SampleFormats.h" -#include -#include -#include -#include -#include -#include - -namespace Audio { - -// These are not the actual values stored in the file! They are marker constants instead, only used temporarily in the decoder. -// 11.22.3. INTERCHANNEL SAMPLE BLOCK SIZE -#define FLAC_BLOCKSIZE_AT_END_OF_HEADER_8 0xffffffff -#define FLAC_BLOCKSIZE_AT_END_OF_HEADER_16 0xfffffffe -// 11.22.4. SAMPLE RATE -#define FLAC_SAMPLERATE_AT_END_OF_HEADER_8 0xffffffff -#define FLAC_SAMPLERATE_AT_END_OF_HEADER_16 0xfffffffe -#define FLAC_SAMPLERATE_AT_END_OF_HEADER_16X10 0xfffffffd - -constexpr StringView flac_magic = "fLaC"sv; - -// 11.22.11. FRAME CRC -// The polynomial used here is known as CRC-8-CCITT. -static constexpr u8 flac_polynomial = 0x07; -using FlacFrameHeaderCRC = Crypto::Checksum::CRC8; - -// 11.23. FRAME_FOOTER -// The polynomial used here is known as CRC-16-IBM. -static constexpr u16 ibm_polynomial = 0xA001; -using IBMCRC = Crypto::Checksum::CRC16; - -static constexpr size_t flac_seekpoint_size = (64 + 64 + 16) / 8; - -// 11.8 BLOCK_TYPE (7 bits) -enum class FlacMetadataBlockType : u8 { - STREAMINFO = 0, // Important data about the audio format - PADDING = 1, // Non-data block to be ignored - APPLICATION = 2, // Ignored - SEEKTABLE = 3, // Seeking info, maybe to be used later - VORBIS_COMMENT = 4, // Ignored - CUESHEET = 5, // Ignored - PICTURE = 6, // Ignored - INVALID = 127, // Error -}; - -// 11.22.5. CHANNEL ASSIGNMENT -enum class FlacFrameChannelType : u8 { - Mono = 0, - Stereo = 1, - StereoCenter = 2, // left, right, center - Surround4p0 = 3, // front left/right, back left/right - Surround5p0 = 4, // front left/right, center, back left/right - Surround5p1 = 5, // front left/right, center, LFE, back left/right - Surround6p1 = 6, // front left/right, center, LFE, back center, side left/right - Surround7p1 = 7, // front left/right, center, LFE, back left/right, side left/right - LeftSideStereo = 8, // channel coupling: left and difference - RightSideStereo = 9, // channel coupling: difference and right - MidSideStereo = 10, // channel coupling: center and difference - // others are reserved -}; - -// 11.25.1. SUBFRAME TYPE -enum class FlacSubframeType : u8 { - Constant = 0, - Verbatim = 1, - Fixed = 0b001000, - LPC = 0b100000, - // others are reserved -}; - -// 11.30.1. RESIDUAL_CODING_METHOD -enum class FlacResidualMode : u8 { - Rice4Bit = 0, - Rice5Bit = 1, -}; - -// 11.6. METADATA_BLOCK -struct FlacRawMetadataBlock { - bool is_last_block; - FlacMetadataBlockType type; - u32 length; // 24 bits - ByteBuffer data; - - ErrorOr write_to_stream(Stream&) const; -}; - -enum class BlockingStrategy : u8 { - Fixed = 0, - Variable = 1, -}; - -// Block sample count can be stored in one of 5 ways. -enum class BlockSizeCategory : u8 { - Reserved = 0b0000, - S192 = 0b0001, - // The formula for these four is 144 * (2^x), and it appears to be an MP3 compatibility feature. - S576 = 0b0010, - S1152 = 0b0011, - S2304 = 0b0100, - S4608 = 0b0101, - // Actual size is stored later on. - Uncommon8Bits = 0b0110, - Uncommon16Bits = 0b0111, - // Formula 2^x. - S256 = 0b1000, - S512 = 0b1001, - S1024 = 0b1010, - S2048 = 0b1011, - S4096 = 0b1100, - S8192 = 0b1101, - S16384 = 0b1110, - S32768 = 0b1111, -}; - -// 11.22. FRAME_HEADER -struct FlacFrameHeader { - u32 sample_rate; - // Referred to as “block size” in the specification. - u16 sample_count; - // If blocking strategy is fixed, this encodes the frame index instead of the sample index. - u32 sample_or_frame_index; - BlockingStrategy blocking_strategy; - FlacFrameChannelType channels; - u8 bit_depth; - u8 checksum; - - ErrorOr write_to_stream(Stream&) const; -}; - -// 11.25. SUBFRAME_HEADER -struct FlacSubframeHeader { - FlacSubframeType type; - // order for fixed and LPC subframes - u8 order; - u8 wasted_bits_per_sample; - u8 bits_per_sample; -}; - -enum class FlacFixedLPC : size_t { - Zero = 0, - One = 1, - Two = 2, - Three = 3, - Four = 4, -}; - -struct FlacLPCEncodedSubframe { - Vector warm_up_samples; - Variant, FlacFixedLPC> coefficients; - Vector residuals; - size_t residual_cost_bits; - // If we’re only using one Rice partition, this is the optimal order to use. - u8 single_partition_optimal_order; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/Forward.h b/Userland/Libraries/LibMedia/Audio/Forward.h index 94a8f0d19f6..36c33b493fc 100644 --- a/Userland/Libraries/LibMedia/Audio/Forward.h +++ b/Userland/Libraries/LibMedia/Audio/Forward.h @@ -10,12 +10,7 @@ namespace Audio { class ConnectionToServer; class Loader; -struct Person; -struct Metadata; class PlaybackStream; struct Sample; -template -class ResampleHelper; - } diff --git a/Userland/Libraries/LibMedia/Audio/GenericTypes.cpp b/Userland/Libraries/LibMedia/Audio/GenericTypes.cpp deleted file mode 100644 index 407de22703d..00000000000 --- a/Userland/Libraries/LibMedia/Audio/GenericTypes.cpp +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "GenericTypes.h" -#include -#include -#include - -namespace Audio { - -size_t SeekTable::size() const -{ - return m_seek_points.size(); -} - -ReadonlySpan SeekTable::seek_points() const -{ - return m_seek_points.span(); -} - -Vector& SeekTable::seek_points() -{ - return m_seek_points; -} - -Optional SeekTable::seek_point_before(u64 sample_index) const -{ - if (m_seek_points.is_empty()) - return {}; - size_t nearby_seek_point_index = 0; - AK::binary_search(m_seek_points, sample_index, &nearby_seek_point_index, [](auto const& sample_index, auto const& seekpoint_candidate) { - // Subtraction with i64 cast may cause overflow. - if (sample_index > seekpoint_candidate.sample_index) - return 1; - if (sample_index == seekpoint_candidate.sample_index) - return 0; - return -1; - }); - // Binary search will always give us a close index, but it may be too large or too small. - // By doing the index adjustment in this order, we will always find a seek point before the given sample. - while (nearby_seek_point_index < m_seek_points.size() - 1 && m_seek_points[nearby_seek_point_index].sample_index < sample_index) - ++nearby_seek_point_index; - while (nearby_seek_point_index > 0 && m_seek_points[nearby_seek_point_index].sample_index > sample_index) - --nearby_seek_point_index; - if (m_seek_points[nearby_seek_point_index].sample_index > sample_index) - return {}; - return m_seek_points[nearby_seek_point_index]; -} - -Optional SeekTable::seek_point_sample_distance_around(u64 sample_index) const -{ - if (m_seek_points.is_empty()) - return {}; - size_t nearby_seek_point_index = 0; - AK::binary_search(m_seek_points, sample_index, &nearby_seek_point_index, [](auto const& sample_index, auto const& seekpoint_candidate) { - // Subtraction with i64 cast may cause overflow. - if (sample_index > seekpoint_candidate.sample_index) - return 1; - if (sample_index == seekpoint_candidate.sample_index) - return 0; - return -1; - }); - - while (nearby_seek_point_index < m_seek_points.size() && m_seek_points[nearby_seek_point_index].sample_index <= sample_index) - ++nearby_seek_point_index; - // There is no seek point beyond the sample index. - if (nearby_seek_point_index >= m_seek_points.size()) - return {}; - auto upper_seek_point_index = nearby_seek_point_index; - - while (nearby_seek_point_index > 0 && m_seek_points[nearby_seek_point_index].sample_index > sample_index) - --nearby_seek_point_index; - auto lower_seek_point_index = nearby_seek_point_index; - - VERIFY(upper_seek_point_index >= lower_seek_point_index); - return m_seek_points[upper_seek_point_index].sample_index - m_seek_points[lower_seek_point_index].sample_index; -} - -ErrorOr SeekTable::insert_seek_point(SeekPoint seek_point) -{ - if (auto previous_seek_point = seek_point_before(seek_point.sample_index); previous_seek_point.has_value() && previous_seek_point->sample_index == seek_point.sample_index) { - // Do not insert a duplicate seek point. - return {}; - } - - // FIXME: This could be even faster if we used binary search while finding the insertion point. - return m_seek_points.try_insert_before_matching(seek_point, [&](auto const& other_seek_point) { - return seek_point.sample_index < other_seek_point.sample_index; - }); -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/GenericTypes.h b/Userland/Libraries/LibMedia/Audio/GenericTypes.h deleted file mode 100644 index 33a344b7aaf..00000000000 --- a/Userland/Libraries/LibMedia/Audio/GenericTypes.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2022, Lucas Chollet - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include - -namespace Audio { - -// 11.20. PICTURE_TYPE (in Flac specification) -enum class ID3PictureType : u32 { - Other = 0, - FileIcon = 1, - OtherFileIcon = 2, - FrontCover = 3, - BackCover = 4, - LeafletPage = 5, - Media = 6, - LeadArtist = 7, - Artist = 8, - Conductor = 9, - Band = 10, - Composer = 11, - Lyricist = 12, - RecordingLocation = 13, - DuringRecording = 14, - DuringPerformance = 15, - MovieScreenCapture = 16, - BrightColouredFish = 17, - Illustration = 18, - BandLogoType = 19, - PublisherLogoType = 20, - // others are reserved -}; - -// Note: This was first implemented for Flac but is compatible with ID3v2 -struct PictureData { - ID3PictureType type {}; - String mime_string {}; - String description_string {}; - - u32 width {}; - u32 height {}; - u32 color_depth {}; - u32 colors {}; - - Vector data; -}; - -// A generic sample seek point within a file. -struct SeekPoint { - u64 sample_index; - u64 byte_offset; -}; - -class SeekTable { -public: - Optional seek_point_before(u64 sample_index) const; - // Returns the distance between the closest two seek points around the sample index. - // The lower seek point may be exactly at the sample index, but the upper seek point must be after the sample index. - Optional seek_point_sample_distance_around(u64 sample_index) const; - - size_t size() const; - ReadonlySpan seek_points() const; - Vector& seek_points(); - - ErrorOr insert_seek_point(SeekPoint); - -private: - // Invariant: The list of seek points is always sorted. - // This makes all operations, such as inserting and searching, faster. - Vector m_seek_points; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/Loader.cpp b/Userland/Libraries/LibMedia/Audio/Loader.cpp index dec5d53fe4c..3c350aa6d67 100644 --- a/Userland/Libraries/LibMedia/Audio/Loader.cpp +++ b/Userland/Libraries/LibMedia/Audio/Loader.cpp @@ -7,10 +7,6 @@ #include "Loader.h" #include "FFmpegLoader.h" -#include "FlacLoader.h" -#include "MP3Loader.h" -#include "QOALoader.h" -#include "WavLoader.h" #include #include @@ -32,13 +28,9 @@ struct LoaderPluginInitializer { }; static constexpr LoaderPluginInitializer s_initializers[] = { - { FlacLoaderPlugin::sniff, FlacLoaderPlugin::create }, - { QOALoaderPlugin::sniff, QOALoaderPlugin::create }, #ifdef USE_FFMPEG { FFmpegLoaderPlugin::sniff, FFmpegLoaderPlugin::create }, #endif - { WavLoaderPlugin::sniff, WavLoaderPlugin::create }, - { MP3LoaderPlugin::sniff, MP3LoaderPlugin::create }, }; ErrorOr, LoaderError> Loader::create(StringView path) diff --git a/Userland/Libraries/LibMedia/Audio/Loader.h b/Userland/Libraries/LibMedia/Audio/Loader.h index 7aceafd05cf..04093787dd6 100644 --- a/Userland/Libraries/LibMedia/Audio/Loader.h +++ b/Userland/Libraries/LibMedia/Audio/Loader.h @@ -6,9 +6,7 @@ #pragma once -#include "GenericTypes.h" #include "LoaderError.h" -#include "Metadata.h" #include "Sample.h" #include "SampleFormats.h" #include @@ -16,11 +14,9 @@ #include #include #include -#include -#include #include #include -#include +#include namespace Audio { @@ -73,14 +69,8 @@ public: virtual ByteString format_name() = 0; virtual PcmSampleFormat pcm_format() = 0; - Metadata const& metadata() const { return m_metadata; } - Vector const& pictures() const { return m_pictures; } - protected: NonnullOwnPtr m_stream; - - Vector m_pictures; - Metadata m_metadata; }; class Loader : public RefCounted { @@ -110,8 +100,6 @@ public: ByteString format_name() const { return m_plugin->format_name(); } u16 bits_per_sample() const { return pcm_bits_per_sample(m_plugin->pcm_format()); } PcmSampleFormat pcm_format() const { return m_plugin->pcm_format(); } - Metadata const& metadata() const { return m_plugin->metadata(); } - Vector const& pictures() const { return m_plugin->pictures(); } private: static ErrorOr, LoaderError> create_plugin(NonnullOwnPtr stream); diff --git a/Userland/Libraries/LibMedia/Audio/MDCT.h b/Userland/Libraries/LibMedia/Audio/MDCT.h deleted file mode 100644 index e13b3dadd68..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MDCT.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (c) 2021, Arne Elster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace DSP { - -template -requires(N % 2 == 0) class MDCT { -public: - constexpr MDCT() - { - for (size_t n = 0; n < N; n++) { - for (size_t k = 0; k < N / 2; k++) { - m_phi[n][k] = AK::cos(AK::Pi / (2 * N) * (2 * static_cast(n) + 1 + N / 2.0f) * static_cast(2 * k + 1)); - } - } - } - - void transform(ReadonlySpan data, Span output) - { - VERIFY(N == 2 * data.size()); - VERIFY(N == output.size()); - for (size_t n = 0; n < N; n++) { - output[n] = 0; - for (size_t k = 0; k < N / 2; k++) { - output[n] += data[k] * m_phi[n][k]; - } - } - } - -private: - Array, N> m_phi; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/MP3HuffmanTables.h b/Userland/Libraries/LibMedia/Audio/MP3HuffmanTables.h deleted file mode 100644 index 45ed9ed8d94..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MP3HuffmanTables.h +++ /dev/null @@ -1,1726 +0,0 @@ -/* - * Copyright (c) 2021, the SerenityOS developers. - * Copyright (c) 2021, Arne Elster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Audio::MP3::Tables::Huffman { - -template -struct HuffmanEntry { - using SymbolType = Symbol; - unsigned code; - size_t code_length; - Symbol symbol; -}; - -template -struct HuffmanNode { - int left; - int right; - unsigned code; - size_t code_length; - Symbol symbol; - bool is_leaf() const { return left == -1 && right == -1; } -}; - -template -using HuffmanEntries = Array; - -template -using HuffmanNodes = Array, Size>; - -template -consteval size_t length_of_longest_huffman_code(HuffmanEntries const& table) -{ - size_t max = 0; - for (size_t i = 0; i < table.size(); i++) { - if (table[i].code_length > max) - max = table[i].code_length; - } - return max; -} - -template -consteval int make_huffman_tree_internal(auto const& table, NodeArrayType&& nodes) -{ - size_t allocation_count = 1; - - nodes = {}; - nodes[0].left = nodes[0].right = -1; - - for (size_t i = 0; i < table.size(); i++) { - HuffmanEntry const& entry = table[i]; - int tree_pointer = 0; - - for (size_t j = 0; j < entry.code_length; j++) { - bool const bit = (entry.code >> (entry.code_length - j - 1)) & 1; - bool const end_of_code = j == entry.code_length - 1; - - int& target_index = bit ? nodes[tree_pointer].left : nodes[tree_pointer].right; - - if (target_index != -1) { - if (end_of_code) - return -1; - tree_pointer = target_index; - } else { - tree_pointer = target_index = allocation_count++; - nodes[target_index].left = nodes[target_index].right = -1; - nodes[target_index].code_length = j + 1; - if (end_of_code) { - nodes[target_index].symbol = entry.symbol; - nodes[target_index].code = entry.code; - } - } - } - } - - return allocation_count; -} - -template -consteval auto make_huffman_tree() -{ - using Symbol = typename decltype(table)::ValueType::SymbolType; - constexpr size_t size_worst_case = 1 << (length_of_longest_huffman_code(table) + 1); - constexpr int size_fitted = make_huffman_tree_internal(table, HuffmanNodes()); - static_assert(size_fitted >= 0, "Huffman tree is ill-formed"); - - HuffmanNodes nodes; - make_huffman_tree_internal(table, nodes); - - return nodes; -} - -template -struct HuffmanDecodeResult { - size_t bits_read; - Optional> code; -}; - -template -HuffmanDecodeResult huffman_decode(BigEndianInputBitStream& bitstream, ReadonlySpan> tree, size_t max_bits_to_read) -{ - HuffmanNode const* node = &tree[0]; - size_t bits_read = 0; - - while (!node->is_leaf() && max_bits_to_read-- > 0) { - auto const maybe_direction = bitstream.read_bit(); - if (maybe_direction.is_error()) - return { bits_read, {} }; - - ++bits_read; - if (maybe_direction.value()) { - if (node->left == -1) - return {}; - node = &tree[node->left]; - } else { - if (node->right == -1) - return {}; - node = &tree[node->right]; - } - } - - if (!node->is_leaf()) - return { bits_read, {} }; - return { bits_read, *node }; -} - -struct HuffmanXY { - int x; - int y; -}; - -struct HuffmanVWXY { - int v; - int w; - int x; - int y; -}; - -struct HuffmanEntryXY : public HuffmanEntry { - constexpr HuffmanEntryXY(int x, int y, size_t code_length, unsigned code) - { - symbol.x = x; - symbol.y = y; - this->code_length = code_length; - this->code = code; - } -}; - -struct HuffmanEntryVWXY : public HuffmanEntry { - constexpr HuffmanEntryVWXY(int v, int w, int x, int y, size_t code_length, unsigned code) - { - symbol.v = v; - symbol.w = w; - symbol.x = x; - symbol.y = y; - this->code_length = code_length; - this->code = code; - } -}; - -// All data taken from ISO/IEC 11172-3 (Table B.7) -constexpr HuffmanEntries TableA { { - { 0, 0, 0, 0, 1, 0b1 }, - { 0, 0, 0, 1, 4, 0b0101 }, - { 0, 0, 1, 0, 4, 0b0100 }, - { 0, 0, 1, 1, 5, 0b00101 }, - { 0, 1, 0, 0, 4, 0b0110 }, - { 0, 1, 0, 1, 6, 0b000101 }, - { 0, 1, 1, 0, 5, 0b00100 }, - { 0, 1, 1, 1, 6, 0b000100 }, - { 1, 0, 0, 0, 4, 0b0111 }, - { 1, 0, 0, 1, 5, 0b00011 }, - { 1, 0, 1, 0, 5, 0b00110 }, - { 1, 0, 1, 1, 6, 0b000000 }, - { 1, 1, 0, 0, 5, 0b00111 }, - { 1, 1, 0, 1, 6, 0b000010 }, - { 1, 1, 1, 0, 6, 0b000011 }, - { 1, 1, 1, 1, 6, 0b000001 }, -} }; - -constexpr HuffmanEntries TableB { { - { 0, 0, 0, 0, 4, 0b1111 }, - { 0, 0, 0, 1, 4, 0b1110 }, - { 0, 0, 1, 0, 4, 0b1101 }, - { 0, 0, 1, 1, 4, 0b1100 }, - { 0, 1, 0, 0, 4, 0b1011 }, - { 0, 1, 0, 1, 4, 0b1010 }, - { 0, 1, 1, 0, 4, 0b1001 }, - { 0, 1, 1, 1, 4, 0b1000 }, - { 1, 0, 0, 0, 4, 0b0111 }, - { 1, 0, 0, 1, 4, 0b0110 }, - { 1, 0, 1, 0, 4, 0b0101 }, - { 1, 0, 1, 1, 4, 0b0100 }, - { 1, 1, 0, 0, 4, 0b0011 }, - { 1, 1, 0, 1, 4, 0b0010 }, - { 1, 1, 1, 0, 4, 0b0001 }, - { 1, 1, 1, 1, 4, 0b0000 }, -} }; - -constexpr HuffmanEntries Table0 { { - { 0, 0, 0, 0b0 }, -} }; - -constexpr HuffmanEntries Table1 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 3, 0b001 }, - { 1, 0, 2, 0b01 }, - { 1, 1, 3, 0b000 }, -} }; - -constexpr HuffmanEntries Table2 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 3, 0b010 }, - { 0, 2, 6, 0b000001 }, - { 1, 0, 3, 0b011 }, - { 1, 1, 3, 0b001 }, - { 1, 2, 5, 0b00001 }, - { 2, 0, 5, 0b00011 }, - { 2, 1, 5, 0b00010 }, - { 2, 2, 6, 0b000000 }, -} }; - -constexpr HuffmanEntries Table3 { { - { 0, 0, 2, 0b11 }, - { 0, 1, 2, 0b10 }, - { 0, 2, 6, 0b000001 }, - { 1, 0, 3, 0b001 }, - { 1, 1, 2, 0b01 }, - { 1, 2, 5, 0b00001 }, - { 2, 0, 5, 0b00011 }, - { 2, 1, 5, 0b00010 }, - { 2, 2, 6, 0b000000 }, -} }; - -constexpr HuffmanEntries Table5 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 3, 0b010 }, - { 0, 2, 6, 0b000110 }, - { 0, 3, 7, 0b0000101 }, - { 1, 0, 3, 0b011 }, - { 1, 1, 3, 0b001 }, - { 1, 2, 6, 0b000100 }, - { 1, 3, 7, 0b0000100 }, - { 2, 0, 6, 0b000111 }, - { 2, 1, 6, 0b000101 }, - { 2, 2, 7, 0b0000111 }, - { 2, 3, 8, 0b00000001 }, - { 3, 0, 7, 0b0000110 }, - { 3, 1, 6, 0b000001 }, - { 3, 2, 7, 0b0000001 }, - { 3, 3, 8, 0b00000000 }, -} }; - -constexpr HuffmanEntries Table6 { { - { 0, 0, 3, 0b111 }, - { 0, 1, 3, 0b011 }, - { 0, 2, 5, 0b00101 }, - { 0, 3, 7, 0b0000001 }, - { 1, 0, 3, 0b110 }, - { 1, 1, 2, 0b10 }, - { 1, 2, 4, 0b0011 }, - { 1, 3, 5, 0b00010 }, - { 2, 0, 4, 0b0101 }, - { 2, 1, 4, 0b0100 }, - { 2, 2, 5, 0b00100 }, - { 2, 3, 6, 0b000001 }, - { 3, 0, 6, 0b000011 }, - { 3, 1, 5, 0b00011 }, - { 3, 2, 6, 0b000010 }, - { 3, 3, 7, 0b0000000 }, -} }; - -constexpr HuffmanEntries Table7 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 3, 0b010 }, - { 0, 2, 6, 0b001010 }, - { 0, 3, 8, 0b00010011 }, - { 0, 4, 8, 0b00010000 }, - { 0, 5, 9, 0b000001010 }, - { 1, 0, 3, 0b011 }, - { 1, 1, 4, 0b0011 }, - { 1, 2, 6, 0b000111 }, - { 1, 3, 7, 0b0001010 }, - { 1, 4, 7, 0b0000101 }, - { 1, 5, 8, 0b00000011 }, - { 2, 0, 6, 0b001011 }, - { 2, 1, 5, 0b00100 }, - { 2, 2, 7, 0b0001101 }, - { 2, 3, 8, 0b00010001 }, - { 2, 4, 8, 0b00001000 }, - { 2, 5, 9, 0b000000100 }, - { 3, 0, 7, 0b0001100 }, - { 3, 1, 7, 0b0001011 }, - { 3, 2, 8, 0b00010010 }, - { 3, 3, 9, 0b000001111 }, - { 3, 4, 9, 0b000001011 }, - { 3, 5, 9, 0b000000010 }, - { 4, 0, 7, 0b0000111 }, - { 4, 1, 7, 0b0000110 }, - { 4, 2, 8, 0b00001001 }, - { 4, 3, 9, 0b000001110 }, - { 4, 4, 9, 0b000000011 }, - { 4, 5, 10, 0b0000000001 }, - { 5, 0, 8, 0b00000110 }, - { 5, 1, 8, 0b00000100 }, - { 5, 2, 9, 0b000000101 }, - { 5, 3, 10, 0b0000000011 }, - { 5, 4, 10, 0b0000000010 }, - { 5, 5, 10, 0b0000000000 }, -} }; - -constexpr HuffmanEntries Table8 { { - { 0, 0, 2, 0b11 }, - { 0, 1, 3, 0b100 }, - { 0, 2, 6, 0b000110 }, - { 0, 3, 8, 0b00010010 }, - { 0, 4, 8, 0b00001100 }, - { 0, 5, 9, 0b000000101 }, - { 1, 0, 3, 0b101 }, - { 1, 1, 2, 0b01 }, - { 1, 2, 4, 0b0010 }, - { 1, 3, 8, 0b00010000 }, - { 1, 4, 8, 0b00001001 }, - { 1, 5, 8, 0b00000011 }, - { 2, 0, 6, 0b000111 }, - { 2, 1, 4, 0b0011 }, - { 2, 2, 6, 0b000101 }, - { 2, 3, 8, 0b00001110 }, - { 2, 4, 8, 0b00000111 }, - { 2, 5, 9, 0b000000011 }, - { 3, 0, 8, 0b00010011 }, - { 3, 1, 8, 0b00010001 }, - { 3, 2, 8, 0b00001111 }, - { 3, 3, 9, 0b000001101 }, - { 3, 4, 9, 0b000001010 }, - { 3, 5, 10, 0b0000000100 }, - { 4, 0, 8, 0b00001101 }, - { 4, 1, 7, 0b0000101 }, - { 4, 2, 8, 0b00001000 }, - { 4, 3, 9, 0b000001011 }, - { 4, 4, 10, 0b0000000101 }, - { 4, 5, 10, 0b0000000001 }, - { 5, 0, 9, 0b000001100 }, - { 5, 1, 8, 0b00000100 }, - { 5, 2, 9, 0b000000100 }, - { 5, 3, 9, 0b000000001 }, - { 5, 4, 11, 0b00000000001 }, - { 5, 5, 11, 0b00000000000 }, -} }; - -constexpr HuffmanEntries Table9 { { - { 0, 0, 3, 0b111 }, - { 0, 1, 3, 0b101 }, - { 0, 2, 5, 0b01001 }, - { 0, 3, 6, 0b001110 }, - { 0, 4, 8, 0b00001111 }, - { 0, 5, 9, 0b000000111 }, - { 1, 0, 3, 0b110 }, - { 1, 1, 3, 0b100 }, - { 1, 2, 4, 0b0101 }, - { 1, 3, 5, 0b00101 }, - { 1, 4, 6, 0b000110 }, - { 1, 5, 8, 0b00000111 }, - { 2, 0, 4, 0b0111 }, - { 2, 1, 4, 0b0110 }, - { 2, 2, 5, 0b01000 }, - { 2, 3, 6, 0b001000 }, - { 2, 4, 7, 0b0001000 }, - { 2, 5, 8, 0b00000101 }, - { 3, 0, 6, 0b001111 }, - { 3, 1, 5, 0b00110 }, - { 3, 2, 6, 0b001001 }, - { 3, 3, 7, 0b0001010 }, - { 3, 4, 7, 0b0000101 }, - { 3, 5, 8, 0b00000001 }, - { 4, 0, 7, 0b0001011 }, - { 4, 1, 6, 0b000111 }, - { 4, 2, 7, 0b0001001 }, - { 4, 3, 7, 0b0000110 }, - { 4, 4, 8, 0b00000100 }, - { 4, 5, 9, 0b000000001 }, - { 5, 0, 8, 0b00001110 }, - { 5, 1, 7, 0b0000100 }, - { 5, 2, 8, 0b00000110 }, - { 5, 3, 8, 0b00000010 }, - { 5, 4, 9, 0b000000110 }, - { 5, 5, 9, 0b000000000 }, -} }; - -constexpr HuffmanEntries Table10 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 3, 0b010 }, - { 0, 2, 6, 0b001010 }, - { 0, 3, 8, 0b00010111 }, - { 0, 4, 9, 0b000100011 }, - { 0, 5, 9, 0b000011110 }, - { 0, 6, 9, 0b000001100 }, - { 0, 7, 10, 0b0000010001 }, - { 1, 0, 3, 0b011 }, - { 1, 1, 4, 0b0011 }, - { 1, 2, 6, 0b001000 }, - { 1, 3, 7, 0b0001100 }, - { 1, 4, 8, 0b00010010 }, - { 1, 5, 9, 0b000010101 }, - { 1, 6, 8, 0b00001100 }, - { 1, 7, 8, 0b00000111 }, - { 2, 0, 6, 0b001011 }, - { 2, 1, 6, 0b001001 }, - { 2, 2, 7, 0b0001111 }, - { 2, 3, 8, 0b00010101 }, - { 2, 4, 9, 0b000100000 }, - { 2, 5, 10, 0b0000101000 }, - { 2, 6, 9, 0b000010011 }, - { 2, 7, 9, 0b000000110 }, - { 3, 0, 7, 0b0001110 }, - { 3, 1, 7, 0b0001101 }, - { 3, 2, 8, 0b00010110 }, - { 3, 3, 9, 0b000100010 }, - { 3, 4, 10, 0b0000101110 }, - { 3, 5, 10, 0b0000010111 }, - { 3, 6, 9, 0b000010010 }, - { 3, 7, 10, 0b0000000111 }, - { 4, 0, 8, 0b00010100 }, - { 4, 1, 8, 0b00010011 }, - { 4, 2, 9, 0b000100001 }, - { 4, 3, 10, 0b0000101111 }, - { 4, 4, 10, 0b0000011011 }, - { 4, 5, 10, 0b0000010110 }, - { 4, 6, 10, 0b0000001001 }, - { 4, 7, 10, 0b0000000011 }, - { 5, 0, 9, 0b000011111 }, - { 5, 1, 9, 0b000010110 }, - { 5, 2, 10, 0b0000101001 }, - { 5, 3, 10, 0b0000011010 }, - { 5, 4, 11, 0b00000010101 }, - { 5, 5, 11, 0b00000010100 }, - { 5, 6, 10, 0b0000000101 }, - { 5, 7, 11, 0b00000000011 }, - { 6, 0, 8, 0b00001110 }, - { 6, 1, 8, 0b00001101 }, - { 6, 2, 9, 0b000001010 }, - { 6, 3, 10, 0b0000001011 }, - { 6, 4, 10, 0b0000010000 }, - { 6, 5, 10, 0b0000000110 }, - { 6, 6, 11, 0b00000000101 }, - { 6, 7, 11, 0b00000000001 }, - { 7, 0, 9, 0b000001001 }, - { 7, 1, 8, 0b00001000 }, - { 7, 2, 9, 0b000000111 }, - { 7, 3, 10, 0b0000001000 }, - { 7, 4, 10, 0b0000000100 }, - { 7, 5, 11, 0b00000000100 }, - { 7, 6, 11, 0b00000000010 }, - { 7, 7, 11, 0b00000000000 }, -} }; - -constexpr HuffmanEntries Table11 { { - { 0, 0, 2, 0b11 }, - { 0, 1, 3, 0b100 }, - { 0, 2, 5, 0b01010 }, - { 0, 3, 7, 0b0011000 }, - { 0, 4, 8, 0b00100010 }, - { 0, 5, 9, 0b000100001 }, - { 0, 6, 8, 0b00010101 }, - { 0, 7, 9, 0b000001111 }, - { 1, 0, 3, 0b101 }, - { 1, 1, 3, 0b011 }, - { 1, 2, 4, 0b0100 }, - { 1, 3, 6, 0b001010 }, - { 1, 4, 8, 0b00100000 }, - { 1, 5, 8, 0b00010001 }, - { 1, 6, 7, 0b0001011 }, - { 1, 7, 8, 0b00001010 }, - { 2, 0, 5, 0b01011 }, - { 2, 1, 5, 0b00111 }, - { 2, 2, 6, 0b001101 }, - { 2, 3, 7, 0b0010010 }, - { 2, 4, 8, 0b00011110 }, - { 2, 5, 9, 0b000011111 }, - { 2, 6, 8, 0b00010100 }, - { 2, 7, 8, 0b00000101 }, - { 3, 0, 7, 0b0011001 }, - { 3, 1, 6, 0b001011 }, - { 3, 2, 7, 0b0010011 }, - { 3, 3, 9, 0b000111011 }, - { 3, 4, 8, 0b00011011 }, - { 3, 5, 10, 0b0000010010 }, - { 3, 6, 8, 0b00001100 }, - { 3, 7, 9, 0b000000101 }, - { 4, 0, 8, 0b00100011 }, - { 4, 1, 8, 0b00100001 }, - { 4, 2, 8, 0b00011111 }, - { 4, 3, 9, 0b000111010 }, - { 4, 4, 9, 0b000011110 }, - { 4, 5, 10, 0b0000010000 }, - { 4, 6, 9, 0b000000111 }, - { 4, 7, 10, 0b0000000101 }, - { 5, 0, 8, 0b00011100 }, - { 5, 1, 8, 0b00011010 }, - { 5, 2, 9, 0b000100000 }, - { 5, 3, 10, 0b0000010011 }, - { 5, 4, 10, 0b0000010001 }, - { 5, 5, 11, 0b00000001111 }, - { 5, 6, 10, 0b0000001000 }, - { 5, 7, 11, 0b00000001110 }, - { 6, 0, 8, 0b00001110 }, - { 6, 1, 7, 0b0001100 }, - { 6, 2, 7, 0b0001001 }, - { 6, 3, 8, 0b00001101 }, - { 6, 4, 9, 0b000001110 }, - { 6, 5, 10, 0b0000001001 }, - { 6, 6, 10, 0b0000000100 }, - { 6, 7, 10, 0b0000000001 }, - { 7, 0, 8, 0b00001011 }, - { 7, 1, 7, 0b0000100 }, - { 7, 2, 8, 0b00000110 }, - { 7, 3, 9, 0b000000110 }, - { 7, 4, 10, 0b0000000110 }, - { 7, 5, 10, 0b0000000011 }, - { 7, 6, 10, 0b0000000010 }, - { 7, 7, 10, 0b0000000000 }, -} }; - -constexpr HuffmanEntries Table12 { { - { 0, 0, 4, 0b1001 }, - { 0, 1, 3, 0b110 }, - { 0, 2, 5, 0b10000 }, - { 0, 3, 7, 0b0100001 }, - { 0, 4, 8, 0b00101001 }, - { 0, 5, 9, 0b000100111 }, - { 0, 6, 9, 0b000100110 }, - { 0, 7, 9, 0b000011010 }, - { 1, 0, 3, 0b111 }, - { 1, 1, 3, 0b101 }, - { 1, 2, 4, 0b0110 }, - { 1, 3, 5, 0b01001 }, - { 1, 4, 7, 0b0010111 }, - { 1, 5, 7, 0b0010000 }, - { 1, 6, 8, 0b00011010 }, - { 1, 7, 8, 0b00001011 }, - { 2, 0, 5, 0b10001 }, - { 2, 1, 4, 0b0111 }, - { 2, 2, 5, 0b01011 }, - { 2, 3, 6, 0b001110 }, - { 2, 4, 7, 0b0010101 }, - { 2, 5, 8, 0b00011110 }, - { 2, 6, 7, 0b0001010 }, - { 2, 7, 8, 0b00000111 }, - { 3, 0, 6, 0b010001 }, - { 3, 1, 5, 0b01010 }, - { 3, 2, 6, 0b001111 }, - { 3, 3, 6, 0b001100 }, - { 3, 4, 7, 0b0010010 }, - { 3, 5, 8, 0b00011100 }, - { 3, 6, 8, 0b00001110 }, - { 3, 7, 8, 0b00000101 }, - { 4, 0, 7, 0b0100000 }, - { 4, 1, 6, 0b001101 }, - { 4, 2, 7, 0b0010110 }, - { 4, 3, 7, 0b0010011 }, - { 4, 4, 8, 0b00010010 }, - { 4, 5, 8, 0b00010000 }, - { 4, 6, 8, 0b00001001 }, - { 4, 7, 9, 0b000000101 }, - { 5, 0, 8, 0b00101000 }, - { 5, 1, 7, 0b0010001 }, - { 5, 2, 8, 0b00011111 }, - { 5, 3, 8, 0b00011101 }, - { 5, 4, 8, 0b00010001 }, - { 5, 5, 9, 0b000001101 }, - { 5, 6, 8, 0b00000100 }, - { 5, 7, 9, 0b000000010 }, - { 6, 0, 8, 0b00011011 }, - { 6, 1, 7, 0b0001100 }, - { 6, 2, 7, 0b0001011 }, - { 6, 3, 8, 0b00001111 }, - { 6, 4, 8, 0b00001010 }, - { 6, 5, 9, 0b000000111 }, - { 6, 6, 9, 0b000000100 }, - { 6, 7, 10, 0b0000000001 }, - { 7, 0, 9, 0b000011011 }, - { 7, 1, 8, 0b00001100 }, - { 7, 2, 8, 0b00001000 }, - { 7, 3, 9, 0b000001100 }, - { 7, 4, 9, 0b000000110 }, - { 7, 5, 9, 0b000000011 }, - { 7, 6, 9, 0b000000001 }, - { 7, 7, 10, 0b0000000000 }, -} }; - -constexpr HuffmanEntries Table13 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 4, 0b0101 }, - { 0, 2, 6, 0b001110 }, - { 0, 3, 7, 0b0010101 }, - { 0, 4, 8, 0b00100010 }, - { 0, 5, 9, 0b000110011 }, - { 0, 6, 9, 0b000101110 }, - { 0, 7, 10, 0b0001000111 }, - { 0, 8, 9, 0b000101010 }, - { 0, 9, 10, 0b0000110100 }, - { 0, 10, 11, 0b00001000100 }, - { 0, 11, 11, 0b00000110100 }, - { 0, 12, 12, 0b000001000011 }, - { 0, 13, 12, 0b000000101100 }, - { 0, 14, 13, 0b0000000101011 }, - { 0, 15, 13, 0b0000000010011 }, - { 1, 0, 3, 0b011 }, - { 1, 1, 4, 0b0100 }, - { 1, 2, 6, 0b001100 }, - { 1, 3, 7, 0b0010011 }, - { 1, 4, 8, 0b00011111 }, - { 1, 5, 8, 0b00011010 }, - { 1, 6, 9, 0b000101100 }, - { 1, 7, 9, 0b000100001 }, - { 1, 8, 9, 0b000011111 }, - { 1, 9, 9, 0b000011000 }, - { 1, 10, 10, 0b0000100000 }, - { 1, 11, 10, 0b0000011000 }, - { 1, 12, 11, 0b00000011111 }, - { 1, 13, 12, 0b000000100011 }, - { 1, 14, 12, 0b000000010110 }, - { 1, 15, 12, 0b000000001110 }, - { 2, 0, 6, 0b001111 }, - { 2, 1, 6, 0b001101 }, - { 2, 2, 7, 0b0010111 }, - { 2, 3, 8, 0b00100100 }, - { 2, 4, 9, 0b000111011 }, - { 2, 5, 9, 0b000110001 }, - { 2, 6, 10, 0b0001001101 }, - { 2, 7, 10, 0b0001000001 }, - { 2, 8, 9, 0b000011101 }, - { 2, 9, 10, 0b0000101000 }, - { 2, 10, 10, 0b0000011110 }, - { 2, 11, 11, 0b00000101000 }, - { 2, 12, 11, 0b00000011011 }, - { 2, 13, 12, 0b000000100001 }, - { 2, 14, 13, 0b0000000101010 }, - { 2, 15, 13, 0b0000000010000 }, - { 3, 0, 7, 0b0010110 }, - { 3, 1, 7, 0b0010100 }, - { 3, 2, 8, 0b00100101 }, - { 3, 3, 9, 0b000111101 }, - { 3, 4, 9, 0b000111000 }, - { 3, 5, 10, 0b0001001111 }, - { 3, 6, 10, 0b0001001001 }, - { 3, 7, 10, 0b0001000000 }, - { 3, 8, 10, 0b0000101011 }, - { 3, 9, 11, 0b00001001100 }, - { 3, 10, 11, 0b00000111000 }, - { 3, 11, 11, 0b00000100101 }, - { 3, 12, 11, 0b00000011010 }, - { 3, 13, 12, 0b000000011111 }, - { 3, 14, 13, 0b0000000011001 }, - { 3, 15, 13, 0b0000000001110 }, - { 4, 0, 8, 0b00100011 }, - { 4, 1, 7, 0b0010000 }, - { 4, 2, 9, 0b000111100 }, - { 4, 3, 9, 0b000111001 }, - { 4, 4, 10, 0b0001100001 }, - { 4, 5, 10, 0b0001001011 }, - { 4, 6, 11, 0b00001110010 }, - { 4, 7, 11, 0b00001011011 }, - { 4, 8, 10, 0b0000110110 }, - { 4, 9, 11, 0b00001001001 }, - { 4, 10, 11, 0b00000110111 }, - { 4, 11, 12, 0b000000101001 }, - { 4, 12, 12, 0b000000110000 }, - { 4, 13, 13, 0b0000000110101 }, - { 4, 14, 13, 0b0000000010111 }, - { 4, 15, 14, 0b00000000011000 }, - { 5, 0, 9, 0b000111010 }, - { 5, 1, 8, 0b00011011 }, - { 5, 2, 9, 0b000110010 }, - { 5, 3, 10, 0b0001100000 }, - { 5, 4, 10, 0b0001001100 }, - { 5, 5, 10, 0b0001000110 }, - { 5, 6, 11, 0b00001011101 }, - { 5, 7, 11, 0b00001010100 }, - { 5, 8, 11, 0b00001001101 }, - { 5, 9, 11, 0b00000111010 }, - { 5, 10, 12, 0b000001001111 }, - { 5, 11, 11, 0b00000011101 }, - { 5, 12, 13, 0b0000001001010 }, - { 5, 13, 13, 0b0000000110001 }, - { 5, 14, 14, 0b00000000101001 }, - { 5, 15, 14, 0b00000000010001 }, - { 6, 0, 9, 0b000101111 }, - { 6, 1, 9, 0b000101101 }, - { 6, 2, 10, 0b0001001110 }, - { 6, 3, 10, 0b0001001010 }, - { 6, 4, 11, 0b00001110011 }, - { 6, 5, 11, 0b00001011110 }, - { 6, 6, 11, 0b00001011010 }, - { 6, 7, 11, 0b00001001111 }, - { 6, 8, 11, 0b00001000101 }, - { 6, 9, 12, 0b000001010011 }, - { 6, 10, 12, 0b000001000111 }, - { 6, 11, 12, 0b000000110010 }, - { 6, 12, 13, 0b0000000111011 }, - { 6, 13, 13, 0b0000000100110 }, - { 6, 14, 14, 0b00000000100100 }, - { 6, 15, 14, 0b00000000001111 }, - { 7, 0, 10, 0b0001001000 }, - { 7, 1, 9, 0b000100010 }, - { 7, 2, 10, 0b0000111000 }, - { 7, 3, 11, 0b00001011111 }, - { 7, 4, 11, 0b00001011100 }, - { 7, 5, 11, 0b00001010101 }, - { 7, 6, 12, 0b000001011011 }, - { 7, 7, 12, 0b000001011010 }, - { 7, 8, 12, 0b000001010110 }, - { 7, 9, 12, 0b000001001001 }, - { 7, 10, 13, 0b0000001001101 }, - { 7, 11, 13, 0b0000001000001 }, - { 7, 12, 13, 0b0000000110011 }, - { 7, 13, 14, 0b00000000101100 }, - { 7, 14, 16, 0b0000000000101011 }, - { 7, 15, 16, 0b0000000000101010 }, - { 8, 0, 9, 0b000101011 }, - { 8, 1, 8, 0b00010100 }, - { 8, 2, 9, 0b000011110 }, - { 8, 3, 10, 0b0000101100 }, - { 8, 4, 10, 0b0000110111 }, - { 8, 5, 11, 0b00001001110 }, - { 8, 6, 11, 0b00001001000 }, - { 8, 7, 12, 0b000001010111 }, - { 8, 8, 12, 0b000001001110 }, - { 8, 9, 12, 0b000000111101 }, - { 8, 10, 12, 0b000000101110 }, - { 8, 11, 13, 0b0000000110110 }, - { 8, 12, 13, 0b0000000100101 }, - { 8, 13, 14, 0b00000000011110 }, - { 8, 14, 15, 0b000000000010100 }, - { 8, 15, 15, 0b000000000010000 }, - { 9, 0, 10, 0b0000110101 }, - { 9, 1, 9, 0b000011001 }, - { 9, 2, 10, 0b0000101001 }, - { 9, 3, 10, 0b0000100101 }, - { 9, 4, 11, 0b00000101100 }, - { 9, 5, 11, 0b00000111011 }, - { 9, 6, 11, 0b00000110110 }, - { 9, 7, 13, 0b0000001010001 }, - { 9, 8, 12, 0b000001000010 }, - { 9, 9, 13, 0b0000001001100 }, - { 9, 10, 13, 0b0000000111001 }, - { 9, 11, 14, 0b00000000110110 }, - { 9, 12, 14, 0b00000000100101 }, - { 9, 13, 14, 0b00000000010010 }, - { 9, 14, 16, 0b0000000000100111 }, - { 9, 15, 15, 0b000000000001011 }, - { 10, 0, 10, 0b0000100011 }, - { 10, 1, 10, 0b0000100001 }, - { 10, 2, 10, 0b0000011111 }, - { 10, 3, 11, 0b00000111001 }, - { 10, 4, 11, 0b00000101010 }, - { 10, 5, 12, 0b000001010010 }, - { 10, 6, 12, 0b000001001000 }, - { 10, 7, 13, 0b0000001010000 }, - { 10, 8, 12, 0b000000101111 }, - { 10, 9, 13, 0b0000000111010 }, - { 10, 10, 14, 0b00000000110111 }, - { 10, 11, 13, 0b0000000010101 }, - { 10, 12, 14, 0b00000000010110 }, - { 10, 13, 15, 0b000000000011010 }, - { 10, 14, 16, 0b0000000000100110 }, - { 10, 15, 17, 0b00000000000010110 }, - { 11, 0, 11, 0b00000110101 }, - { 11, 1, 10, 0b0000011001 }, - { 11, 2, 10, 0b0000010111 }, - { 11, 3, 11, 0b00000100110 }, - { 11, 4, 12, 0b000001000110 }, - { 11, 5, 12, 0b000000111100 }, - { 11, 6, 12, 0b000000110011 }, - { 11, 7, 12, 0b000000100100 }, - { 11, 8, 13, 0b0000000110111 }, - { 11, 9, 13, 0b0000000011010 }, - { 11, 10, 13, 0b0000000100010 }, - { 11, 11, 14, 0b00000000010111 }, - { 11, 12, 15, 0b000000000011011 }, - { 11, 13, 15, 0b000000000001110 }, - { 11, 14, 15, 0b000000000001001 }, - { 11, 15, 16, 0b0000000000000111 }, - { 12, 0, 11, 0b00000100010 }, - { 12, 1, 11, 0b00000100000 }, - { 12, 2, 11, 0b00000011100 }, - { 12, 3, 12, 0b000000100111 }, - { 12, 4, 12, 0b000000110001 }, - { 12, 5, 13, 0b0000001001011 }, - { 12, 6, 12, 0b000000011110 }, - { 12, 7, 13, 0b0000000110100 }, - { 12, 8, 14, 0b00000000110000 }, - { 12, 9, 14, 0b00000000101000 }, - { 12, 10, 15, 0b000000000110100 }, - { 12, 11, 15, 0b000000000011100 }, - { 12, 12, 15, 0b000000000010010 }, - { 12, 13, 16, 0b0000000000010001 }, - { 12, 14, 16, 0b0000000000001001 }, - { 12, 15, 16, 0b0000000000000101 }, - { 13, 0, 12, 0b000000101101 }, - { 13, 1, 11, 0b00000010101 }, - { 13, 2, 12, 0b000000100010 }, - { 13, 3, 13, 0b0000001000000 }, - { 13, 4, 13, 0b0000000111000 }, - { 13, 5, 13, 0b0000000110010 }, - { 13, 6, 14, 0b00000000110001 }, - { 13, 7, 14, 0b00000000101101 }, - { 13, 8, 14, 0b00000000011111 }, - { 13, 9, 14, 0b00000000010011 }, - { 13, 10, 14, 0b00000000001100 }, - { 13, 11, 15, 0b000000000001111 }, - { 13, 12, 16, 0b0000000000001010 }, - { 13, 13, 15, 0b000000000000111 }, - { 13, 14, 16, 0b0000000000000110 }, - { 13, 15, 16, 0b0000000000000011 }, - { 14, 0, 13, 0b0000000110000 }, - { 14, 1, 12, 0b000000010111 }, - { 14, 2, 12, 0b000000010100 }, - { 14, 3, 13, 0b0000000100111 }, - { 14, 4, 13, 0b0000000100100 }, - { 14, 5, 13, 0b0000000100011 }, - { 14, 6, 15, 0b000000000110101 }, - { 14, 7, 14, 0b00000000010101 }, - { 14, 8, 14, 0b00000000010000 }, - { 14, 9, 17, 0b00000000000010111 }, - { 14, 10, 15, 0b000000000001101 }, - { 14, 11, 15, 0b000000000001010 }, - { 14, 12, 15, 0b000000000000110 }, - { 14, 13, 17, 0b00000000000000001 }, - { 14, 14, 16, 0b0000000000000100 }, - { 14, 15, 16, 0b0000000000000010 }, - { 15, 0, 12, 0b000000010000 }, - { 15, 1, 12, 0b000000001111 }, - { 15, 2, 13, 0b0000000010001 }, - { 15, 3, 14, 0b00000000011011 }, - { 15, 4, 14, 0b00000000011001 }, - { 15, 5, 14, 0b00000000010100 }, - { 15, 6, 15, 0b000000000011101 }, - { 15, 7, 14, 0b00000000001011 }, - { 15, 8, 15, 0b000000000010001 }, - { 15, 9, 15, 0b000000000001100 }, - { 15, 10, 16, 0b0000000000010000 }, - { 15, 11, 16, 0b0000000000001000 }, - { 15, 12, 19, 0b0000000000000000001 }, - { 15, 13, 18, 0b000000000000000001 }, - { 15, 14, 19, 0b0000000000000000000 }, - { 15, 15, 16, 0b0000000000000001 }, -} }; - -constexpr HuffmanEntries Table15 { { - { 0, 0, 3, 0b111 }, - { 0, 1, 4, 0b1100 }, - { 0, 2, 5, 0b10010 }, - { 0, 3, 7, 0b0110101 }, - { 0, 4, 7, 0b0101111 }, - { 0, 5, 8, 0b01001100 }, - { 0, 6, 9, 0b001111100 }, - { 0, 7, 9, 0b001101100 }, - { 0, 8, 9, 0b001011001 }, - { 0, 9, 10, 0b0001111011 }, - { 0, 10, 10, 0b0001101100 }, - { 0, 11, 11, 0b00001110111 }, - { 0, 12, 11, 0b00001101011 }, - { 0, 13, 11, 0b00001010001 }, - { 0, 14, 12, 0b000001111010 }, - { 0, 15, 13, 0b0000000111111 }, - { 1, 0, 4, 0b1101 }, - { 1, 1, 3, 0b101 }, - { 1, 2, 5, 0b10000 }, - { 1, 3, 6, 0b011011 }, - { 1, 4, 7, 0b0101110 }, - { 1, 5, 7, 0b0100100 }, - { 1, 6, 8, 0b00111101 }, - { 1, 7, 8, 0b00110011 }, - { 1, 8, 8, 0b00101010 }, - { 1, 9, 9, 0b001000110 }, - { 1, 10, 9, 0b000110100 }, - { 1, 11, 10, 0b0001010011 }, - { 1, 12, 10, 0b0001000001 }, - { 1, 13, 10, 0b0000101001 }, - { 1, 14, 11, 0b00000111011 }, - { 1, 15, 11, 0b00000100100 }, - { 2, 0, 5, 0b10011 }, - { 2, 1, 5, 0b10001 }, - { 2, 2, 5, 0b01111 }, - { 2, 3, 6, 0b011000 }, - { 2, 4, 7, 0b0101001 }, - { 2, 5, 7, 0b0100010 }, - { 2, 6, 8, 0b00111011 }, - { 2, 7, 8, 0b00110000 }, - { 2, 8, 8, 0b00101000 }, - { 2, 9, 9, 0b001000000 }, - { 2, 10, 9, 0b000110010 }, - { 2, 11, 10, 0b0001001110 }, - { 2, 12, 10, 0b0000111110 }, - { 2, 13, 11, 0b00001010000 }, - { 2, 14, 11, 0b00000111000 }, - { 2, 15, 11, 0b00000100001 }, - { 3, 0, 6, 0b011101 }, - { 3, 1, 6, 0b011100 }, - { 3, 2, 6, 0b011001 }, - { 3, 3, 7, 0b0101011 }, - { 3, 4, 7, 0b0100111 }, - { 3, 5, 8, 0b00111111 }, - { 3, 6, 8, 0b00110111 }, - { 3, 7, 9, 0b001011101 }, - { 3, 8, 9, 0b001001100 }, - { 3, 9, 9, 0b000111011 }, - { 3, 10, 10, 0b0001011101 }, - { 3, 11, 10, 0b0001001000 }, - { 3, 12, 10, 0b0000110110 }, - { 3, 13, 11, 0b00001001011 }, - { 3, 14, 11, 0b00000110010 }, - { 3, 15, 11, 0b00000011101 }, - { 4, 0, 7, 0b0110100 }, - { 4, 1, 6, 0b010110 }, - { 4, 2, 7, 0b0101010 }, - { 4, 3, 7, 0b0101000 }, - { 4, 4, 8, 0b01000011 }, - { 4, 5, 8, 0b00111001 }, - { 4, 6, 9, 0b001011111 }, - { 4, 7, 9, 0b001001111 }, - { 4, 8, 9, 0b001001000 }, - { 4, 9, 9, 0b000111001 }, - { 4, 10, 10, 0b0001011001 }, - { 4, 11, 10, 0b0001000101 }, - { 4, 12, 10, 0b0000110001 }, - { 4, 13, 11, 0b00001000010 }, - { 4, 14, 11, 0b00000101110 }, - { 4, 15, 11, 0b00000011011 }, - { 5, 0, 8, 0b01001101 }, - { 5, 1, 7, 0b0100101 }, - { 5, 2, 7, 0b0100011 }, - { 5, 3, 8, 0b01000010 }, - { 5, 4, 8, 0b00111010 }, - { 5, 5, 8, 0b00110100 }, - { 5, 6, 9, 0b001011011 }, - { 5, 7, 9, 0b001001010 }, - { 5, 8, 9, 0b000111110 }, - { 5, 9, 9, 0b000110000 }, - { 5, 10, 10, 0b0001001111 }, - { 5, 11, 10, 0b0000111111 }, - { 5, 12, 11, 0b00001011010 }, - { 5, 13, 11, 0b00000111110 }, - { 5, 14, 11, 0b00000101000 }, - { 5, 15, 12, 0b000000100110 }, - { 6, 0, 9, 0b001111101 }, - { 6, 1, 7, 0b0100000 }, - { 6, 2, 8, 0b00111100 }, - { 6, 3, 8, 0b00111000 }, - { 6, 4, 8, 0b00110010 }, - { 6, 5, 9, 0b001011100 }, - { 6, 6, 9, 0b001001110 }, - { 6, 7, 9, 0b001000001 }, - { 6, 8, 9, 0b000110111 }, - { 6, 9, 10, 0b0001010111 }, - { 6, 10, 10, 0b0001000111 }, - { 6, 11, 10, 0b0000110011 }, - { 6, 12, 11, 0b00001001001 }, - { 6, 13, 11, 0b00000110011 }, - { 6, 14, 12, 0b000001000110 }, - { 6, 15, 12, 0b000000011110 }, - { 7, 0, 9, 0b001101101 }, - { 7, 1, 8, 0b00110101 }, - { 7, 2, 8, 0b00110001 }, - { 7, 3, 9, 0b001011110 }, - { 7, 4, 9, 0b001011000 }, - { 7, 5, 9, 0b001001011 }, - { 7, 6, 9, 0b001000010 }, - { 7, 7, 10, 0b0001111010 }, - { 7, 8, 10, 0b0001011011 }, - { 7, 9, 10, 0b0001001001 }, - { 7, 10, 10, 0b0000111000 }, - { 7, 11, 10, 0b0000101010 }, - { 7, 12, 11, 0b00001000000 }, - { 7, 13, 11, 0b00000101100 }, - { 7, 14, 11, 0b00000010101 }, - { 7, 15, 12, 0b000000011001 }, - { 8, 0, 9, 0b001011010 }, - { 8, 1, 8, 0b00101011 }, - { 8, 2, 8, 0b00101001 }, - { 8, 3, 9, 0b001001101 }, - { 8, 4, 9, 0b001001001 }, - { 8, 5, 9, 0b000111111 }, - { 8, 6, 9, 0b000111000 }, - { 8, 7, 10, 0b0001011100 }, - { 8, 8, 10, 0b0001001101 }, - { 8, 9, 10, 0b0001000010 }, - { 8, 10, 10, 0b0000101111 }, - { 8, 11, 11, 0b00001000011 }, - { 8, 12, 11, 0b00000110000 }, - { 8, 13, 12, 0b000000110101 }, - { 8, 14, 12, 0b000000100100 }, - { 8, 15, 12, 0b000000010100 }, - { 9, 0, 9, 0b001000111 }, - { 9, 1, 8, 0b00100010 }, - { 9, 2, 9, 0b001000011 }, - { 9, 3, 9, 0b000111100 }, - { 9, 4, 9, 0b000111010 }, - { 9, 5, 9, 0b000110001 }, - { 9, 6, 10, 0b0001011000 }, - { 9, 7, 10, 0b0001001100 }, - { 9, 8, 10, 0b0001000011 }, - { 9, 9, 11, 0b00001101010 }, - { 9, 10, 11, 0b00001000111 }, - { 9, 11, 11, 0b00000110110 }, - { 9, 12, 11, 0b00000100110 }, - { 9, 13, 12, 0b000000100111 }, - { 9, 14, 12, 0b000000010111 }, - { 9, 15, 12, 0b000000001111 }, - { 10, 0, 10, 0b0001101101 }, - { 10, 1, 9, 0b000110101 }, - { 10, 2, 9, 0b000110011 }, - { 10, 3, 9, 0b000101111 }, - { 10, 4, 10, 0b0001011010 }, - { 10, 5, 10, 0b0001010010 }, - { 10, 6, 10, 0b0000111010 }, - { 10, 7, 10, 0b0000111001 }, - { 10, 8, 10, 0b0000110000 }, - { 10, 9, 11, 0b00001001000 }, - { 10, 10, 11, 0b00000111001 }, - { 10, 11, 11, 0b00000101001 }, - { 10, 12, 11, 0b00000010111 }, - { 10, 13, 12, 0b000000011011 }, - { 10, 14, 13, 0b0000000111110 }, - { 10, 15, 12, 0b000000001001 }, - { 11, 0, 10, 0b0001010110 }, - { 11, 1, 9, 0b000101010 }, - { 11, 2, 9, 0b000101000 }, - { 11, 3, 9, 0b000100101 }, - { 11, 4, 10, 0b0001000110 }, - { 11, 5, 10, 0b0001000000 }, - { 11, 6, 10, 0b0000110100 }, - { 11, 7, 10, 0b0000101011 }, - { 11, 8, 11, 0b00001000110 }, - { 11, 9, 11, 0b00000110111 }, - { 11, 10, 11, 0b00000101010 }, - { 11, 11, 11, 0b00000011001 }, - { 11, 12, 12, 0b000000011101 }, - { 11, 13, 12, 0b000000010010 }, - { 11, 14, 12, 0b000000001011 }, - { 11, 15, 13, 0b0000000001011 }, - { 12, 0, 11, 0b00001110110 }, - { 12, 1, 10, 0b0001000100 }, - { 12, 2, 9, 0b000011110 }, - { 12, 3, 10, 0b0000110111 }, - { 12, 4, 10, 0b0000110010 }, - { 12, 5, 10, 0b0000101110 }, - { 12, 6, 11, 0b00001001010 }, - { 12, 7, 11, 0b00001000001 }, - { 12, 8, 11, 0b00000110001 }, - { 12, 9, 11, 0b00000100111 }, - { 12, 10, 11, 0b00000011000 }, - { 12, 11, 11, 0b00000010000 }, - { 12, 12, 12, 0b000000010110 }, - { 12, 13, 12, 0b000000001101 }, - { 12, 14, 13, 0b0000000001110 }, - { 12, 15, 13, 0b0000000000111 }, - { 13, 0, 11, 0b00001011011 }, - { 13, 1, 10, 0b0000101100 }, - { 13, 2, 10, 0b0000100111 }, - { 13, 3, 10, 0b0000100110 }, - { 13, 4, 10, 0b0000100010 }, - { 13, 5, 11, 0b00000111111 }, - { 13, 6, 11, 0b00000110100 }, - { 13, 7, 11, 0b00000101101 }, - { 13, 8, 11, 0b00000011111 }, - { 13, 9, 12, 0b000000110100 }, - { 13, 10, 12, 0b000000011100 }, - { 13, 11, 12, 0b000000010011 }, - { 13, 12, 12, 0b000000001110 }, - { 13, 13, 12, 0b000000001000 }, - { 13, 14, 13, 0b0000000001001 }, - { 13, 15, 13, 0b0000000000011 }, - { 14, 0, 12, 0b000001111011 }, - { 14, 1, 11, 0b00000111100 }, - { 14, 2, 11, 0b00000111010 }, - { 14, 3, 11, 0b00000110101 }, - { 14, 4, 11, 0b00000101111 }, - { 14, 5, 11, 0b00000101011 }, - { 14, 6, 11, 0b00000100000 }, - { 14, 7, 11, 0b00000010110 }, - { 14, 8, 12, 0b000000100101 }, - { 14, 9, 12, 0b000000011000 }, - { 14, 10, 12, 0b000000010001 }, - { 14, 11, 12, 0b000000001100 }, - { 14, 12, 13, 0b0000000001111 }, - { 14, 13, 13, 0b0000000001010 }, - { 14, 14, 12, 0b000000000010 }, - { 14, 15, 13, 0b0000000000001 }, - { 15, 0, 12, 0b000001000111 }, - { 15, 1, 11, 0b00000100101 }, - { 15, 2, 11, 0b00000100010 }, - { 15, 3, 11, 0b00000011110 }, - { 15, 4, 11, 0b00000011100 }, - { 15, 5, 11, 0b00000010100 }, - { 15, 6, 11, 0b00000010001 }, - { 15, 7, 12, 0b000000011010 }, - { 15, 8, 12, 0b000000010101 }, - { 15, 9, 12, 0b000000010000 }, - { 15, 10, 12, 0b000000001010 }, - { 15, 11, 12, 0b000000000110 }, - { 15, 12, 13, 0b0000000001000 }, - { 15, 13, 13, 0b0000000000110 }, - { 15, 14, 13, 0b0000000000010 }, - { 15, 15, 13, 0b0000000000000 }, -} }; - -constexpr HuffmanEntries Table16 { { - { 0, 0, 1, 0b1 }, - { 0, 1, 4, 0b0101 }, - { 0, 2, 6, 0b001110 }, - { 0, 3, 8, 0b00101100 }, - { 0, 4, 9, 0b001001010 }, - { 0, 5, 9, 0b000111111 }, - { 0, 6, 10, 0b0001101110 }, - { 0, 7, 10, 0b0001011101 }, - { 0, 8, 11, 0b00010101100 }, - { 0, 9, 11, 0b00010010101 }, - { 0, 10, 11, 0b00010001010 }, - { 0, 11, 12, 0b000011110010 }, - { 0, 12, 12, 0b000011100001 }, - { 0, 13, 12, 0b000011000011 }, - { 0, 14, 13, 0b0000101111000 }, - { 0, 15, 9, 0b000010001 }, - { 1, 0, 3, 0b011 }, - { 1, 1, 4, 0b0100 }, - { 1, 2, 6, 0b001100 }, - { 1, 3, 7, 0b0010100 }, - { 1, 4, 8, 0b00100011 }, - { 1, 5, 9, 0b000111110 }, - { 1, 6, 9, 0b000110101 }, - { 1, 7, 9, 0b000101111 }, - { 1, 8, 10, 0b0001010011 }, - { 1, 9, 10, 0b0001001011 }, - { 1, 10, 10, 0b0001000100 }, - { 1, 11, 11, 0b00001110111 }, - { 1, 12, 12, 0b000011001001 }, - { 1, 13, 11, 0b00001101011 }, - { 1, 14, 12, 0b000011001111 }, - { 1, 15, 8, 0b00001001 }, - { 2, 0, 6, 0b001111 }, - { 2, 1, 6, 0b001101 }, - { 2, 2, 7, 0b0010111 }, - { 2, 3, 8, 0b00100110 }, - { 2, 4, 9, 0b001000011 }, - { 2, 5, 9, 0b000111010 }, - { 2, 6, 10, 0b0001100111 }, - { 2, 7, 10, 0b0001011010 }, - { 2, 8, 11, 0b00010100001 }, - { 2, 9, 10, 0b0001001000 }, - { 2, 10, 11, 0b00001111111 }, - { 2, 11, 11, 0b00001110101 }, - { 2, 12, 11, 0b00001101110 }, - { 2, 13, 12, 0b000011010001 }, - { 2, 14, 12, 0b000011001110 }, - { 2, 15, 9, 0b000010000 }, - { 3, 0, 8, 0b00101101 }, - { 3, 1, 7, 0b0010101 }, - { 3, 2, 8, 0b00100111 }, - { 3, 3, 9, 0b001000101 }, - { 3, 4, 9, 0b001000000 }, - { 3, 5, 10, 0b0001110010 }, - { 3, 6, 10, 0b0001100011 }, - { 3, 7, 10, 0b0001010111 }, - { 3, 8, 11, 0b00010011110 }, - { 3, 9, 11, 0b00010001100 }, - { 3, 10, 12, 0b000011111100 }, - { 3, 11, 12, 0b000011010100 }, - { 3, 12, 12, 0b000011000111 }, - { 3, 13, 13, 0b0000110000011 }, - { 3, 14, 13, 0b0000101101101 }, - { 3, 15, 10, 0b0000011010 }, - { 4, 0, 9, 0b001001011 }, - { 4, 1, 8, 0b00100100 }, - { 4, 2, 9, 0b001000100 }, - { 4, 3, 9, 0b001000001 }, - { 4, 4, 10, 0b0001110011 }, - { 4, 5, 10, 0b0001100101 }, - { 4, 6, 11, 0b00010110011 }, - { 4, 7, 11, 0b00010100100 }, - { 4, 8, 11, 0b00010011011 }, - { 4, 9, 12, 0b000100001000 }, - { 4, 10, 12, 0b000011110110 }, - { 4, 11, 12, 0b000011100010 }, - { 4, 12, 13, 0b0000110001011 }, - { 4, 13, 13, 0b0000101111110 }, - { 4, 14, 13, 0b0000101101010 }, - { 4, 15, 9, 0b000001001 }, - { 5, 0, 9, 0b001000010 }, - { 5, 1, 8, 0b00011110 }, - { 5, 2, 9, 0b000111011 }, - { 5, 3, 9, 0b000111000 }, - { 5, 4, 10, 0b0001100110 }, - { 5, 5, 11, 0b00010111001 }, - { 5, 6, 11, 0b00010101101 }, - { 5, 7, 12, 0b000100001001 }, - { 5, 8, 11, 0b00010001110 }, - { 5, 9, 12, 0b000011111101 }, - { 5, 10, 12, 0b000011101000 }, - { 5, 11, 13, 0b0000110010000 }, - { 5, 12, 13, 0b0000110000100 }, - { 5, 13, 13, 0b0000101111010 }, - { 5, 14, 14, 0b00000110111101 }, - { 5, 15, 10, 0b0000010000 }, - { 6, 0, 10, 0b0001101111 }, - { 6, 1, 9, 0b000110110 }, - { 6, 2, 9, 0b000110100 }, - { 6, 3, 10, 0b0001100100 }, - { 6, 4, 11, 0b00010111000 }, - { 6, 5, 11, 0b00010110010 }, - { 6, 6, 11, 0b00010100000 }, - { 6, 7, 11, 0b00010000101 }, - { 6, 8, 12, 0b000100000001 }, - { 6, 9, 12, 0b000011110100 }, - { 6, 10, 12, 0b000011100100 }, - { 6, 11, 12, 0b000011011001 }, - { 6, 12, 13, 0b0000110000001 }, - { 6, 13, 13, 0b0000101101110 }, - { 6, 14, 14, 0b00001011001011 }, - { 6, 15, 10, 0b0000001010 }, - { 7, 0, 10, 0b0001100010 }, - { 7, 1, 9, 0b000110000 }, - { 7, 2, 10, 0b0001011011 }, - { 7, 3, 10, 0b0001011000 }, - { 7, 4, 11, 0b00010100101 }, - { 7, 5, 11, 0b00010011101 }, - { 7, 6, 11, 0b00010010100 }, - { 7, 7, 12, 0b000100000101 }, - { 7, 8, 12, 0b000011111000 }, - { 7, 9, 13, 0b0000110010111 }, - { 7, 10, 13, 0b0000110001101 }, - { 7, 11, 13, 0b0000101110100 }, - { 7, 12, 13, 0b0000101111100 }, - { 7, 13, 15, 0b000001101111001 }, - { 7, 14, 15, 0b000001101110100 }, - { 7, 15, 10, 0b0000001000 }, - { 8, 0, 10, 0b0001010101 }, - { 8, 1, 10, 0b0001010100 }, - { 8, 2, 10, 0b0001010001 }, - { 8, 3, 11, 0b00010011111 }, - { 8, 4, 11, 0b00010011100 }, - { 8, 5, 11, 0b00010001111 }, - { 8, 6, 12, 0b000100000100 }, - { 8, 7, 12, 0b000011111001 }, - { 8, 8, 13, 0b0000110101011 }, - { 8, 9, 13, 0b0000110010001 }, - { 8, 10, 13, 0b0000110001000 }, - { 8, 11, 13, 0b0000101111111 }, - { 8, 12, 14, 0b00001011010111 }, - { 8, 13, 14, 0b00001011001001 }, - { 8, 14, 14, 0b00001011000100 }, - { 8, 15, 10, 0b0000000111 }, - { 9, 0, 11, 0b00010011010 }, - { 9, 1, 10, 0b0001001100 }, - { 9, 2, 10, 0b0001001001 }, - { 9, 3, 11, 0b00010001101 }, - { 9, 4, 11, 0b00010000011 }, - { 9, 5, 12, 0b000100000000 }, - { 9, 6, 12, 0b000011110101 }, - { 9, 7, 13, 0b0000110101010 }, - { 9, 8, 13, 0b0000110010110 }, - { 9, 9, 13, 0b0000110001010 }, - { 9, 10, 13, 0b0000110000000 }, - { 9, 11, 14, 0b00001011011111 }, - { 9, 12, 13, 0b0000101100111 }, - { 9, 13, 14, 0b00001011000110 }, - { 9, 14, 13, 0b0000101100000 }, - { 9, 15, 11, 0b00000001011 }, - { 10, 0, 11, 0b00010001011 }, - { 10, 1, 11, 0b00010000001 }, - { 10, 2, 10, 0b0001000011 }, - { 10, 3, 11, 0b00001111101 }, - { 10, 4, 12, 0b000011110111 }, - { 10, 5, 12, 0b000011101001 }, - { 10, 6, 12, 0b000011100101 }, - { 10, 7, 12, 0b000011011011 }, - { 10, 8, 13, 0b0000110001001 }, - { 10, 9, 14, 0b00001011100111 }, - { 10, 10, 14, 0b00001011100001 }, - { 10, 11, 14, 0b00001011010000 }, - { 10, 12, 15, 0b000001101110101 }, - { 10, 13, 15, 0b000001101110010 }, - { 10, 14, 14, 0b00000110110111 }, - { 10, 15, 10, 0b0000000100 }, - { 11, 0, 12, 0b000011110011 }, - { 11, 1, 11, 0b00001111000 }, - { 11, 2, 11, 0b00001110110 }, - { 11, 3, 11, 0b00001110011 }, - { 11, 4, 12, 0b000011100011 }, - { 11, 5, 12, 0b000011011111 }, - { 11, 6, 13, 0b0000110001100 }, - { 11, 7, 14, 0b00001011101010 }, - { 11, 8, 14, 0b00001011100110 }, - { 11, 9, 14, 0b00001011100000 }, - { 11, 10, 14, 0b00001011010001 }, - { 11, 11, 14, 0b00001011001000 }, - { 11, 12, 14, 0b00001011000010 }, - { 11, 13, 13, 0b0000011011111 }, - { 11, 14, 14, 0b00000110110100 }, - { 11, 15, 11, 0b00000000110 }, - { 12, 0, 12, 0b000011001010 }, - { 12, 1, 12, 0b000011100000 }, - { 12, 2, 12, 0b000011011110 }, - { 12, 3, 12, 0b000011011010 }, - { 12, 4, 12, 0b000011011000 }, - { 12, 5, 13, 0b0000110000101 }, - { 12, 6, 13, 0b0000110000010 }, - { 12, 7, 13, 0b0000101111101 }, - { 12, 8, 13, 0b0000101101100 }, - { 12, 9, 15, 0b000001101111000 }, - { 12, 10, 14, 0b00000110111011 }, - { 12, 11, 14, 0b00001011000011 }, - { 12, 12, 14, 0b00000110111000 }, - { 12, 13, 14, 0b00000110110101 }, - { 12, 14, 16, 0b0000011011000000 }, - { 12, 15, 11, 0b00000000100 }, - { 13, 0, 14, 0b00001011101011 }, - { 13, 1, 12, 0b000011010011 }, - { 13, 2, 12, 0b000011010010 }, - { 13, 3, 12, 0b000011010000 }, - { 13, 4, 13, 0b0000101110010 }, - { 13, 5, 13, 0b0000101111011 }, - { 13, 6, 14, 0b00001011011110 }, - { 13, 7, 14, 0b00001011010011 }, - { 13, 8, 14, 0b00001011001010 }, - { 13, 9, 16, 0b0000011011000111 }, - { 13, 10, 15, 0b000001101110011 }, - { 13, 11, 15, 0b000001101101101 }, - { 13, 12, 15, 0b000001101101100 }, - { 13, 13, 17, 0b00000110110000011 }, - { 13, 14, 15, 0b000001101100001 }, - { 13, 15, 11, 0b00000000010 }, - { 14, 0, 13, 0b0000101111001 }, - { 14, 1, 13, 0b0000101110001 }, - { 14, 2, 11, 0b00001100110 }, - { 14, 3, 12, 0b000010111011 }, - { 14, 4, 14, 0b00001011010110 }, - { 14, 5, 14, 0b00001011010010 }, - { 14, 6, 13, 0b0000101100110 }, - { 14, 7, 14, 0b00001011000111 }, - { 14, 8, 14, 0b00001011000101 }, - { 14, 9, 15, 0b000001101100010 }, - { 14, 10, 16, 0b0000011011000110 }, - { 14, 11, 15, 0b000001101100111 }, - { 14, 12, 17, 0b00000110110000010 }, - { 14, 13, 15, 0b000001101100110 }, - { 14, 14, 14, 0b00000110110010 }, - { 14, 15, 11, 0b00000000000 }, - { 15, 0, 9, 0b000001100 }, - { 15, 1, 8, 0b00001010 }, - { 15, 2, 8, 0b00000111 }, - { 15, 3, 9, 0b000001011 }, - { 15, 4, 9, 0b000001010 }, - { 15, 5, 10, 0b0000010001 }, - { 15, 6, 10, 0b0000001011 }, - { 15, 7, 10, 0b0000001001 }, - { 15, 8, 11, 0b00000001101 }, - { 15, 9, 11, 0b00000001100 }, - { 15, 10, 11, 0b00000001010 }, - { 15, 11, 11, 0b00000000111 }, - { 15, 12, 11, 0b00000000101 }, - { 15, 13, 11, 0b00000000011 }, - { 15, 14, 11, 0b00000000001 }, - { 15, 15, 8, 0b00000011 }, -} }; - -constexpr HuffmanEntries Table17 { Table16 }; -constexpr HuffmanEntries Table18 { Table16 }; -constexpr HuffmanEntries Table19 { Table16 }; -constexpr HuffmanEntries Table20 { Table16 }; -constexpr HuffmanEntries Table21 { Table16 }; -constexpr HuffmanEntries Table22 { Table16 }; -constexpr HuffmanEntries Table23 { Table16 }; - -constexpr HuffmanEntries Table24 { { - { 0, 0, 4, 0b1111 }, - { 0, 1, 4, 0b1101 }, - { 0, 2, 6, 0b101110 }, - { 0, 3, 7, 0b1010000 }, - { 0, 4, 8, 0b10010010 }, - { 0, 5, 9, 0b100000110 }, - { 0, 6, 9, 0b011111000 }, - { 0, 7, 10, 0b0110110010 }, - { 0, 8, 10, 0b0110101010 }, - { 0, 9, 11, 0b01010011101 }, - { 0, 10, 11, 0b01010001101 }, - { 0, 11, 11, 0b01010001001 }, - { 0, 12, 11, 0b01001101101 }, - { 0, 13, 11, 0b01000000101 }, - { 0, 14, 12, 0b010000001000 }, - { 0, 15, 9, 0b001011000 }, - { 1, 0, 4, 0b1110 }, - { 1, 1, 4, 0b1100 }, - { 1, 2, 5, 0b10101 }, - { 1, 3, 6, 0b100110 }, - { 1, 4, 7, 0b1000111 }, - { 1, 5, 8, 0b10000010 }, - { 1, 6, 8, 0b01111010 }, - { 1, 7, 9, 0b011011000 }, - { 1, 8, 9, 0b011010001 }, - { 1, 9, 9, 0b011000110 }, - { 1, 10, 10, 0b0101000111 }, - { 1, 11, 10, 0b0101011001 }, - { 1, 12, 10, 0b0100111111 }, - { 1, 13, 10, 0b0100101001 }, - { 1, 14, 10, 0b0100010111 }, - { 1, 15, 8, 0b00101010 }, - { 2, 0, 6, 0b101111 }, - { 2, 1, 5, 0b10110 }, - { 2, 2, 6, 0b101001 }, - { 2, 3, 7, 0b1001010 }, - { 2, 4, 7, 0b1000100 }, - { 2, 5, 8, 0b10000000 }, - { 2, 6, 8, 0b01111000 }, - { 2, 7, 9, 0b011011101 }, - { 2, 8, 9, 0b011001111 }, - { 2, 9, 9, 0b011000010 }, - { 2, 10, 9, 0b010110110 }, - { 2, 11, 10, 0b0101010100 }, - { 2, 12, 10, 0b0100111011 }, - { 2, 13, 10, 0b0100100111 }, - { 2, 14, 11, 0b01000011101 }, - { 2, 15, 7, 0b0010010 }, - { 3, 0, 7, 0b1010001 }, - { 3, 1, 6, 0b100111 }, - { 3, 2, 7, 0b1001011 }, - { 3, 3, 7, 0b1000110 }, - { 3, 4, 8, 0b10000110 }, - { 3, 5, 8, 0b01111101 }, - { 3, 6, 8, 0b01110100 }, - { 3, 7, 9, 0b011011100 }, - { 3, 8, 9, 0b011001100 }, - { 3, 9, 9, 0b010111110 }, - { 3, 10, 9, 0b010110010 }, - { 3, 11, 10, 0b0101000101 }, - { 3, 12, 10, 0b0100110111 }, - { 3, 13, 10, 0b0100100101 }, - { 3, 14, 10, 0b0100001111 }, - { 3, 15, 7, 0b0010000 }, - { 4, 0, 8, 0b10010011 }, - { 4, 1, 7, 0b1001000 }, - { 4, 2, 7, 0b1000101 }, - { 4, 3, 8, 0b10000111 }, - { 4, 4, 8, 0b01111111 }, - { 4, 5, 8, 0b01110110 }, - { 4, 6, 8, 0b01110000 }, - { 4, 7, 9, 0b011010010 }, - { 4, 8, 9, 0b011001000 }, - { 4, 9, 9, 0b010111100 }, - { 4, 10, 10, 0b0101100000 }, - { 4, 11, 10, 0b0101000011 }, - { 4, 12, 10, 0b0100110010 }, - { 4, 13, 10, 0b0100011101 }, - { 4, 14, 11, 0b01000011100 }, - { 4, 15, 7, 0b0001110 }, - { 5, 0, 9, 0b100000111 }, - { 5, 1, 7, 0b1000010 }, - { 5, 2, 8, 0b10000001 }, - { 5, 3, 8, 0b01111110 }, - { 5, 4, 8, 0b01110111 }, - { 5, 5, 8, 0b01110010 }, - { 5, 6, 9, 0b011010110 }, - { 5, 7, 9, 0b011001010 }, - { 5, 8, 9, 0b011000000 }, - { 5, 9, 9, 0b010110100 }, - { 5, 10, 10, 0b0101010101 }, - { 5, 11, 10, 0b0100111101 }, - { 5, 12, 10, 0b0100101101 }, - { 5, 13, 10, 0b0100011001 }, - { 5, 14, 10, 0b0100000110 }, - { 5, 15, 7, 0b0001100 }, - { 6, 0, 9, 0b011111001 }, - { 6, 1, 8, 0b01111011 }, - { 6, 2, 8, 0b01111001 }, - { 6, 3, 8, 0b01110101 }, - { 6, 4, 8, 0b01110001 }, - { 6, 5, 9, 0b011010111 }, - { 6, 6, 9, 0b011001110 }, - { 6, 7, 9, 0b011000011 }, - { 6, 8, 9, 0b010111001 }, - { 6, 9, 10, 0b0101011011 }, - { 6, 10, 10, 0b0101001010 }, - { 6, 11, 10, 0b0100110100 }, - { 6, 12, 10, 0b0100100011 }, - { 6, 13, 10, 0b0100010000 }, - { 6, 14, 11, 0b01000001000 }, - { 6, 15, 7, 0b0001010 }, - { 7, 0, 10, 0b0110110011 }, - { 7, 1, 8, 0b01110011 }, - { 7, 2, 8, 0b01101111 }, - { 7, 3, 8, 0b01101101 }, - { 7, 4, 9, 0b011010011 }, - { 7, 5, 9, 0b011001011 }, - { 7, 6, 9, 0b011000100 }, - { 7, 7, 9, 0b010111011 }, - { 7, 8, 10, 0b0101100001 }, - { 7, 9, 10, 0b0101001100 }, - { 7, 10, 10, 0b0100111001 }, - { 7, 11, 10, 0b0100101010 }, - { 7, 12, 10, 0b0100011011 }, - { 7, 13, 11, 0b01000010011 }, - { 7, 14, 11, 0b00101111101 }, - { 7, 15, 8, 0b00010001 }, - { 8, 0, 10, 0b0110101011 }, - { 8, 1, 9, 0b011010100 }, - { 8, 2, 9, 0b011010000 }, - { 8, 3, 9, 0b011001101 }, - { 8, 4, 9, 0b011001001 }, - { 8, 5, 9, 0b011000001 }, - { 8, 6, 9, 0b010111010 }, - { 8, 7, 9, 0b010110001 }, - { 8, 8, 9, 0b010101001 }, - { 8, 9, 10, 0b0101000000 }, - { 8, 10, 10, 0b0100101111 }, - { 8, 11, 10, 0b0100011110 }, - { 8, 12, 10, 0b0100001100 }, - { 8, 13, 11, 0b01000000010 }, - { 8, 14, 11, 0b00101111001 }, - { 8, 15, 8, 0b00010000 }, - { 9, 0, 10, 0b0101001111 }, - { 9, 1, 9, 0b011000111 }, - { 9, 2, 9, 0b011000101 }, - { 9, 3, 9, 0b010111111 }, - { 9, 4, 9, 0b010111101 }, - { 9, 5, 9, 0b010110101 }, - { 9, 6, 9, 0b010101110 }, - { 9, 7, 10, 0b0101001101 }, - { 9, 8, 10, 0b0101000001 }, - { 9, 9, 10, 0b0100110001 }, - { 9, 10, 10, 0b0100100001 }, - { 9, 11, 10, 0b0100010011 }, - { 9, 12, 11, 0b01000001001 }, - { 9, 13, 11, 0b00101111011 }, - { 9, 14, 11, 0b00101110011 }, - { 9, 15, 8, 0b00001011 }, - { 10, 0, 11, 0b01010011100 }, - { 10, 1, 9, 0b010111000 }, - { 10, 2, 9, 0b010110111 }, - { 10, 3, 9, 0b010110011 }, - { 10, 4, 9, 0b010101111 }, - { 10, 5, 10, 0b0101011000 }, - { 10, 6, 10, 0b0101001011 }, - { 10, 7, 10, 0b0100111010 }, - { 10, 8, 10, 0b0100110000 }, - { 10, 9, 10, 0b0100100010 }, - { 10, 10, 10, 0b0100010101 }, - { 10, 11, 11, 0b01000010010 }, - { 10, 12, 11, 0b00101111111 }, - { 10, 13, 11, 0b00101110101 }, - { 10, 14, 11, 0b00101101110 }, - { 10, 15, 8, 0b00001010 }, - { 11, 0, 11, 0b01010001100 }, - { 11, 1, 10, 0b0101011010 }, - { 11, 2, 9, 0b010101011 }, - { 11, 3, 9, 0b010101000 }, - { 11, 4, 9, 0b010100100 }, - { 11, 5, 10, 0b0100111110 }, - { 11, 6, 10, 0b0100110101 }, - { 11, 7, 10, 0b0100101011 }, - { 11, 8, 10, 0b0100011111 }, - { 11, 9, 10, 0b0100010100 }, - { 11, 10, 10, 0b0100000111 }, - { 11, 11, 11, 0b01000000001 }, - { 11, 12, 11, 0b00101110111 }, - { 11, 13, 11, 0b00101110000 }, - { 11, 14, 11, 0b00101101010 }, - { 11, 15, 8, 0b00000110 }, - { 12, 0, 11, 0b01010001000 }, - { 12, 1, 10, 0b0101000010 }, - { 12, 2, 10, 0b0100111100 }, - { 12, 3, 10, 0b0100111000 }, - { 12, 4, 10, 0b0100110011 }, - { 12, 5, 10, 0b0100101110 }, - { 12, 6, 10, 0b0100100100 }, - { 12, 7, 10, 0b0100011100 }, - { 12, 8, 10, 0b0100001101 }, - { 12, 9, 10, 0b0100000101 }, - { 12, 10, 11, 0b01000000000 }, - { 12, 11, 11, 0b00101111000 }, - { 12, 12, 11, 0b00101110010 }, - { 12, 13, 11, 0b00101101100 }, - { 12, 14, 11, 0b00101100111 }, - { 12, 15, 8, 0b00000100 }, - { 13, 0, 11, 0b01001101100 }, - { 13, 1, 10, 0b0100101100 }, - { 13, 2, 10, 0b0100101000 }, - { 13, 3, 10, 0b0100100110 }, - { 13, 4, 10, 0b0100100000 }, - { 13, 5, 10, 0b0100011010 }, - { 13, 6, 10, 0b0100010001 }, - { 13, 7, 10, 0b0100001010 }, - { 13, 8, 11, 0b01000000011 }, - { 13, 9, 11, 0b00101111100 }, - { 13, 10, 11, 0b00101110110 }, - { 13, 11, 11, 0b00101110001 }, - { 13, 12, 11, 0b00101101101 }, - { 13, 13, 11, 0b00101101001 }, - { 13, 14, 11, 0b00101100101 }, - { 13, 15, 8, 0b00000010 }, - { 14, 0, 12, 0b010000001001 }, - { 14, 1, 10, 0b0100011000 }, - { 14, 2, 10, 0b0100010110 }, - { 14, 3, 10, 0b0100010010 }, - { 14, 4, 10, 0b0100001011 }, - { 14, 5, 10, 0b0100001000 }, - { 14, 6, 10, 0b0100000011 }, - { 14, 7, 11, 0b00101111110 }, - { 14, 8, 11, 0b00101111010 }, - { 14, 9, 11, 0b00101110100 }, - { 14, 10, 11, 0b00101101111 }, - { 14, 11, 11, 0b00101101011 }, - { 14, 12, 11, 0b00101101000 }, - { 14, 13, 11, 0b00101100110 }, - { 14, 14, 11, 0b00101100100 }, - { 14, 15, 8, 0b00000000 }, - { 15, 0, 8, 0b00101011 }, - { 15, 1, 7, 0b0010100 }, - { 15, 2, 7, 0b0010011 }, - { 15, 3, 7, 0b0010001 }, - { 15, 4, 7, 0b0001111 }, - { 15, 5, 7, 0b0001101 }, - { 15, 6, 7, 0b0001011 }, - { 15, 7, 7, 0b0001001 }, - { 15, 8, 7, 0b0000111 }, - { 15, 9, 7, 0b0000110 }, - { 15, 10, 7, 0b0000100 }, - { 15, 11, 8, 0b00000111 }, - { 15, 12, 8, 0b00000101 }, - { 15, 13, 8, 0b00000011 }, - { 15, 14, 8, 0b00000001 }, - { 15, 15, 4, 0b0011 }, -} }; - -constexpr HuffmanEntries Table25 { Table24 }; -constexpr HuffmanEntries Table26 { Table24 }; -constexpr HuffmanEntries Table27 { Table24 }; -constexpr HuffmanEntries Table28 { Table24 }; -constexpr HuffmanEntries Table29 { Table24 }; -constexpr HuffmanEntries Table30 { Table24 }; -constexpr HuffmanEntries Table31 { Table24 }; - -constexpr auto TreeA = make_huffman_tree(); -constexpr auto TreeB = make_huffman_tree(); - -constexpr auto Tree0 = make_huffman_tree(); -constexpr auto Tree1 = make_huffman_tree(); -constexpr auto Tree2 = make_huffman_tree(); -constexpr auto Tree3 = make_huffman_tree(); -constexpr auto Tree5 = make_huffman_tree(); -constexpr auto Tree6 = make_huffman_tree(); -constexpr auto Tree7 = make_huffman_tree(); -constexpr auto Tree8 = make_huffman_tree(); -constexpr auto Tree9 = make_huffman_tree(); -constexpr auto Tree10 = make_huffman_tree(); -constexpr auto Tree11 = make_huffman_tree(); -constexpr auto Tree12 = make_huffman_tree(); -constexpr auto Tree13 = make_huffman_tree(); -constexpr auto Tree15 = make_huffman_tree(); -constexpr auto Tree16 = make_huffman_tree(); -constexpr auto Tree17 = make_huffman_tree(); -constexpr auto Tree18 = make_huffman_tree(); -constexpr auto Tree19 = make_huffman_tree(); -constexpr auto Tree20 = make_huffman_tree(); -constexpr auto Tree21 = make_huffman_tree(); -constexpr auto Tree22 = make_huffman_tree(); -constexpr auto Tree23 = make_huffman_tree(); -constexpr auto Tree24 = make_huffman_tree(); -constexpr auto Tree25 = make_huffman_tree(); -constexpr auto Tree26 = make_huffman_tree(); -constexpr auto Tree27 = make_huffman_tree(); -constexpr auto Tree28 = make_huffman_tree(); -constexpr auto Tree29 = make_huffman_tree(); -constexpr auto Tree30 = make_huffman_tree(); -constexpr auto Tree31 = make_huffman_tree(); - -struct HuffmanTreeXY { - ReadonlySpan> nodes; - int linbits; -}; - -Array HuffmanTreesXY { { - { Tree0, 0 }, - { Tree1, 0 }, - { Tree2, 0 }, - { Tree3, 0 }, - { {}, 0 }, - { Tree5, 0 }, - { Tree6, 0 }, - { Tree7, 0 }, - { Tree8, 0 }, - { Tree9, 0 }, - { Tree10, 0 }, - { Tree11, 0 }, - { Tree12, 0 }, - { Tree13, 0 }, - { {}, 0 }, - { Tree15, 0 }, - { Tree16, 1 }, - { Tree17, 2 }, - { Tree18, 3 }, - { Tree19, 4 }, - { Tree20, 6 }, - { Tree21, 8 }, - { Tree22, 10 }, - { Tree23, 13 }, - { Tree24, 4 }, - { Tree25, 5 }, - { Tree26, 6 }, - { Tree27, 7 }, - { Tree28, 8 }, - { Tree29, 9 }, - { Tree30, 11 }, - { Tree31, 13 }, -} }; - -} diff --git a/Userland/Libraries/LibMedia/Audio/MP3Loader.cpp b/Userland/Libraries/LibMedia/Audio/MP3Loader.cpp deleted file mode 100644 index 9cf321d5f57..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MP3Loader.cpp +++ /dev/null @@ -1,895 +0,0 @@ -/* - * Copyright (c) 2021, Arne Elster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "MP3Loader.h" -#include "MP3HuffmanTables.h" -#include "MP3Tables.h" -#include "MP3Types.h" -#include -#include -#include - -namespace Audio { - -DSP::MDCT<12> MP3LoaderPlugin::s_mdct_12; -DSP::MDCT<36> MP3LoaderPlugin::s_mdct_36; - -MP3LoaderPlugin::MP3LoaderPlugin(NonnullOwnPtr stream) - : LoaderPlugin(move(stream)) -{ -} - -MaybeLoaderError MP3LoaderPlugin::skip_id3(SeekableStream& stream) -{ - // FIXME: This is a bit of a hack until we have a proper ID3 reader and MP3 demuxer. - // Based on https://mutagen-specs.readthedocs.io/en/latest/id3/id3v2.2.html - char identifier_buffer[3] = { 0, 0, 0 }; - auto read_identifier = StringView(TRY(stream.read_some({ &identifier_buffer[0], sizeof(identifier_buffer) }))); - if (read_identifier == "ID3"sv) { - [[maybe_unused]] auto version = TRY(stream.read_value()); - [[maybe_unused]] auto revision = TRY(stream.read_value()); - [[maybe_unused]] auto flags = TRY(stream.read_value()); - auto size = 0; - for (auto i = 0; i < 4; i++) { - // Each byte has a zeroed most significant bit to prevent it from looking like a sync code. - auto byte = TRY(stream.read_value()); - size <<= 7; - size |= byte & 0x7F; - } - TRY(stream.seek(size, SeekMode::FromCurrentPosition)); - } else if (read_identifier != "TAG"sv) { - MUST(stream.seek(-static_cast(read_identifier.length()), SeekMode::FromCurrentPosition)); - } - return {}; -} - -bool MP3LoaderPlugin::sniff(SeekableStream& stream) -{ - auto skip_id3_result = skip_id3(stream); - if (skip_id3_result.is_error()) - return false; - return !synchronize_and_read_header(stream, 0).is_error(); -} - -ErrorOr, LoaderError> MP3LoaderPlugin::create(NonnullOwnPtr stream) -{ - auto loader = make(move(stream)); - TRY(loader->initialize()); - return loader; -} - -MaybeLoaderError MP3LoaderPlugin::initialize() -{ - TRY(build_seek_table()); - - TRY(seek(0)); - auto header = TRY(synchronize_and_read_header()); - - m_sample_rate = header.samplerate; - m_num_channels = header.channel_count(); - m_loaded_samples = 0; - - TRY(seek(0)); - - return {}; -} - -MaybeLoaderError MP3LoaderPlugin::reset() -{ - TRY(seek(0)); - m_synthesis_buffer = {}; - m_loaded_samples = 0; - TRY(m_bit_reservoir.discard(m_bit_reservoir.used_buffer_size())); - return {}; -} - -MaybeLoaderError MP3LoaderPlugin::seek(int const position) -{ - auto seek_entry = m_seek_table.seek_point_before(position); - if (seek_entry.has_value()) { - TRY(m_stream->seek(seek_entry->byte_offset, SeekMode::SetPosition)); - m_loaded_samples = seek_entry->sample_index; - } - m_synthesis_buffer = {}; - TRY(m_bit_reservoir.discard(m_bit_reservoir.used_buffer_size())); - return {}; -} - -ErrorOr>, LoaderError> MP3LoaderPlugin::load_chunks(size_t samples_to_read_from_input) -{ - int samples_to_read = samples_to_read_from_input; - Vector> frames; - while (samples_to_read > 0) { - FixedArray samples = TRY(FixedArray::create(MP3::frame_size)); - - auto maybe_frame = read_next_frame(); - if (maybe_frame.is_error()) { - if (m_stream->is_eof()) - return Vector> {}; - return maybe_frame.release_error(); - } - auto frame = maybe_frame.release_value(); - - bool const is_stereo = frame.header.channel_count() == 2; - size_t current_frame_read = 0; - for (; current_frame_read < MP3::granule_size; current_frame_read++) { - auto const left_sample = frame.channels[0].granules[0].pcm[current_frame_read / 32][current_frame_read % 32]; - auto const right_sample = is_stereo ? frame.channels[1].granules[0].pcm[current_frame_read / 32][current_frame_read % 32] : left_sample; - samples[current_frame_read] = Sample { left_sample, right_sample }; - samples_to_read--; - } - for (; current_frame_read < MP3::frame_size; current_frame_read++) { - auto const left_sample = frame.channels[0].granules[1].pcm[(current_frame_read - MP3::granule_size) / 32][(current_frame_read - MP3::granule_size) % 32]; - auto const right_sample = is_stereo ? frame.channels[1].granules[1].pcm[(current_frame_read - MP3::granule_size) / 32][(current_frame_read - MP3::granule_size) % 32] : left_sample; - samples[current_frame_read] = Sample { left_sample, right_sample }; - samples_to_read--; - } - m_loaded_samples += samples.size(); - TRY(frames.try_append(move(samples))); - } - - return frames; -} - -MaybeLoaderError MP3LoaderPlugin::build_seek_table() -{ - VERIFY(MUST(m_stream->tell()) == 0); - TRY(skip_id3(*m_stream)); - - int sample_count = 0; - size_t frame_count = 0; - m_seek_table = {}; - - while (true) { - auto error_or_header = synchronize_and_read_header(); - if (error_or_header.is_error()) - break; - - if (frame_count % 10 == 0) { - auto frame_pos = TRY(m_stream->tell()) - error_or_header.value().header_size; - TRY(m_seek_table.insert_seek_point({ static_cast(sample_count), frame_pos })); - } - - frame_count++; - sample_count += MP3::frame_size; - - TRY(m_stream->seek(error_or_header.value().frame_size - error_or_header.value().header_size, SeekMode::FromCurrentPosition)); - } - m_total_samples = sample_count; - return {}; -} - -ErrorOr MP3LoaderPlugin::read_header(SeekableStream& stream, size_t sample_index) -{ - auto bitstream = BigEndianInputBitStream(MaybeOwned(stream)); - if (TRY(bitstream.read_bits(4)) != 0xF) - return LoaderError { LoaderError::Category::Format, sample_index, "Frame header did not start with sync code." }; - MP3::Header header; - header.id = TRY(bitstream.read_bit()); - header.layer = MP3::Tables::LayerNumberLookup[TRY(bitstream.read_bits(2))]; - if (header.layer <= 0) - return LoaderError { LoaderError::Category::Format, sample_index, "Frame header contains invalid layer number." }; - header.protection_bit = TRY(bitstream.read_bit()); - header.bitrate = MP3::Tables::BitratesPerLayerLookup[header.layer - 1][TRY(bitstream.read_bits(4))]; - if (header.bitrate <= 0) - return LoaderError { LoaderError::Category::Format, sample_index, "Frame header contains invalid bitrate." }; - header.samplerate = MP3::Tables::SampleratesLookup[TRY(bitstream.read_bits(2))]; - if (header.samplerate <= 0) - return LoaderError { LoaderError::Category::Format, sample_index, "Frame header contains invalid samplerate." }; - header.padding_bit = TRY(bitstream.read_bit()); - header.private_bit = TRY(bitstream.read_bit()); - header.mode = static_cast(TRY(bitstream.read_bits(2))); - header.mode_extension = static_cast(TRY(bitstream.read_bits(2))); - header.copyright_bit = TRY(bitstream.read_bit()); - header.original_bit = TRY(bitstream.read_bit()); - header.emphasis = static_cast(TRY(bitstream.read_bits(2))); - header.header_size = 4; - if (!header.protection_bit) { - header.crc16 = TRY(bitstream.read_bits(16)); - header.header_size += 2; - } - header.frame_size = 144 * header.bitrate * 1000 / header.samplerate + header.padding_bit; - header.slot_count = header.frame_size - ((header.channel_count() == 2 ? 32 : 17) + header.header_size); - return header; -} - -ErrorOr MP3LoaderPlugin::synchronize_and_read_header(SeekableStream& stream, size_t sample_index) -{ - while (!stream.is_eof()) { - bool last_was_all_set = false; - - while (!stream.is_eof()) { - u8 byte = TRY(stream.read_value()); - if (last_was_all_set && (byte & 0xF0) == 0xF0) { - // Seek back, since there is still data we have not consumed within the current byte. - // read_header() will consume and check these 4 bits itself and then continue reading - // the rest of the data from there. - TRY(stream.seek(-1, SeekMode::FromCurrentPosition)); - break; - } - last_was_all_set = byte == 0xFF; - } - - auto header_start = TRY(stream.tell()); - auto header_result = read_header(stream, sample_index); - if (header_result.is_error() || header_result.value().id != 1 || header_result.value().layer != 3) { - TRY(stream.seek(header_start, SeekMode::SetPosition)); - continue; - } - return header_result.value(); - } - return LoaderError { LoaderError::Category::Format, sample_index, "Failed to synchronize." }; -} - -ErrorOr MP3LoaderPlugin::synchronize_and_read_header() -{ - return MP3LoaderPlugin::synchronize_and_read_header(*m_stream, m_loaded_samples); -} - -ErrorOr MP3LoaderPlugin::read_next_frame() -{ - return read_frame_data(TRY(synchronize_and_read_header())); -} - -ErrorOr MP3LoaderPlugin::read_frame_data(MP3::Header const& header) -{ - MP3::MP3Frame frame { header }; - - TRY(read_side_information(frame)); - - auto maybe_buffer = ByteBuffer::create_uninitialized(header.slot_count); - if (maybe_buffer.is_error()) - return LoaderError { LoaderError::Category::IO, m_loaded_samples, "Out of memory" }; - auto& buffer = maybe_buffer.value(); - - size_t old_reservoir_size = m_bit_reservoir.used_buffer_size(); - TRY(m_stream->read_until_filled(buffer)); - TRY(m_bit_reservoir.write_until_depleted(buffer)); - - // If we don't have enough data in the reservoir to process this frame, skip it (but keep the data). - if (old_reservoir_size < static_cast(frame.main_data_begin)) - return frame; - - TRY(m_bit_reservoir.discard(old_reservoir_size - frame.main_data_begin)); - - BigEndianInputBitStream reservoir_stream { MaybeOwned(m_bit_reservoir) }; - - for (size_t granule_index = 0; granule_index < 2; granule_index++) { - for (size_t channel_index = 0; channel_index < header.channel_count(); channel_index++) { - size_t scale_factor_size = TRY(read_scale_factors(frame, reservoir_stream, granule_index, channel_index)); - TRY(read_huffman_data(frame, reservoir_stream, granule_index, channel_index, scale_factor_size)); - if (frame.channels[channel_index].granules[granule_index].block_type == MP3::BlockType::Short) { - reorder_samples(frame.channels[channel_index].granules[granule_index], frame.header.samplerate); - - // Only reduce alias for lowest 2 bands as they're long. - // Afaik this is not mentioned in the ISO spec, but it is addressed in the - // changelog for the ISO compliance tests. - if (frame.channels[channel_index].granules[granule_index].mixed_block_flag) - reduce_alias(frame.channels[channel_index].granules[granule_index], 36); - } else { - reduce_alias(frame.channels[channel_index].granules[granule_index]); - } - } - - if (header.mode == MP3::Mode::JointStereo) { - process_stereo(frame, granule_index); - } - } - - for (size_t granule_index = 0; granule_index < 2; granule_index++) { - for (size_t channel_index = 0; channel_index < header.channel_count(); channel_index++) { - auto& granule = frame.channels[channel_index].granules[granule_index]; - - for (size_t i = 0; i < MP3::granule_size; i += 18) { - MP3::BlockType block_type = granule.block_type; - if (i < 36 && granule.mixed_block_flag) { - // ISO/IEC 11172-3: if mixed_block_flag is set, the lowest two subbands are transformed with normal window. - block_type = MP3::BlockType::Normal; - } - - Array output; - transform_samples_to_time(granule.samples, i, output, block_type); - - int const subband_index = i / 18; - for (size_t sample_index = 0; sample_index < 18; sample_index++) { - // overlap add - granule.filter_bank_input[subband_index][sample_index] = output[sample_index] + m_last_values[channel_index][subband_index][sample_index]; - m_last_values[channel_index][subband_index][sample_index] = output[sample_index + 18]; - - // frequency inversion - if (subband_index % 2 == 1 && sample_index % 2 == 1) - granule.filter_bank_input[subband_index][sample_index] *= -1; - } - } - } - } - - Array in_samples; - for (size_t channel_index = 0; channel_index < frame.header.channel_count(); channel_index++) { - for (size_t granule_index = 0; granule_index < 2; granule_index++) { - auto& granule = frame.channels[channel_index].granules[granule_index]; - for (size_t sample_index = 0; sample_index < 18; sample_index++) { - for (size_t band_index = 0; band_index < 32; band_index++) { - in_samples[band_index] = granule.filter_bank_input[band_index][sample_index]; - } - synthesis(m_synthesis_buffer[channel_index], in_samples, granule.pcm[sample_index]); - } - } - } - - return frame; -} - -MaybeLoaderError MP3LoaderPlugin::read_side_information(MP3::MP3Frame& frame) -{ - auto bitstream = BigEndianInputBitStream(MaybeOwned(*m_stream)); - - frame.main_data_begin = TRY(bitstream.read_bits(9)); - - if (frame.header.channel_count() == 1) { - frame.private_bits = TRY(bitstream.read_bits(5)); - } else { - frame.private_bits = TRY(bitstream.read_bits(3)); - } - - for (size_t channel_index = 0; channel_index < frame.header.channel_count(); channel_index++) { - for (size_t scale_factor_selection_info_band = 0; scale_factor_selection_info_band < 4; scale_factor_selection_info_band++) { - frame.channels[channel_index].scale_factor_selection_info[scale_factor_selection_info_band] = TRY(bitstream.read_bit()); - } - } - - for (size_t granule_index = 0; granule_index < 2; granule_index++) { - for (size_t channel_index = 0; channel_index < frame.header.channel_count(); channel_index++) { - auto& granule = frame.channels[channel_index].granules[granule_index]; - granule.part_2_3_length = TRY(bitstream.read_bits(12)); - granule.big_values = TRY(bitstream.read_bits(9)); - granule.global_gain = TRY(bitstream.read_bits(8)); - granule.scalefac_compress = TRY(bitstream.read_bits(4)); - granule.window_switching_flag = TRY(bitstream.read_bit()); - if (granule.window_switching_flag) { - granule.block_type = static_cast(TRY(bitstream.read_bits(2))); - granule.mixed_block_flag = TRY(bitstream.read_bit()); - for (size_t region = 0; region < 2; region++) - granule.table_select[region] = TRY(bitstream.read_bits(5)); - for (size_t window = 0; window < 3; window++) - granule.sub_block_gain[window] = TRY(bitstream.read_bits(3)); - granule.region0_count = (granule.block_type == MP3::BlockType::Short && !granule.mixed_block_flag) ? 8 : 7; - granule.region1_count = 36; - } else { - for (size_t region = 0; region < 3; region++) - granule.table_select[region] = TRY(bitstream.read_bits(5)); - granule.region0_count = TRY(bitstream.read_bits(4)); - granule.region1_count = TRY(bitstream.read_bits(3)); - } - granule.preflag = TRY(bitstream.read_bit()); - granule.scalefac_scale = TRY(bitstream.read_bit()); - granule.count1table_select = TRY(bitstream.read_bit()); - } - } - return {}; -} - -// From ISO/IEC 11172-3 (2.4.3.4.7.1) -Array MP3LoaderPlugin::calculate_frame_exponents(MP3::MP3Frame const& frame, size_t granule_index, size_t channel_index) -{ - Array exponents; - - auto fill_band = [&exponents](float exponent, size_t start, size_t end) { - for (size_t j = start; j <= end; j++) { - exponents[j] = exponent; - } - }; - - auto const& channel = frame.channels[channel_index]; - auto const& granule = frame.channels[channel_index].granules[granule_index]; - - auto const scale_factor_bands = get_scalefactor_bands(granule, frame.header.samplerate); - float const scale_factor_multiplier = granule.scalefac_scale ? 1 : 0.5; - int const gain = granule.global_gain - 210; - - if (granule.block_type != MP3::BlockType::Short) { - for (size_t band_index = 0; band_index < 22; band_index++) { - float const exponent = gain / 4.0f - (scale_factor_multiplier * (channel.scale_factors[band_index] + granule.preflag * MP3::Tables::Pretab[band_index])); - fill_band(AK::pow(2.0, exponent), scale_factor_bands[band_index].start, scale_factor_bands[band_index].end); - } - } else { - size_t band_index = 0; - size_t sample_count = 0; - - if (granule.mixed_block_flag) { - while (sample_count < 36) { - float const exponent = gain / 4.0f - (scale_factor_multiplier * (channel.scale_factors[band_index] + granule.preflag * MP3::Tables::Pretab[band_index])); - fill_band(AK::pow(2.0, exponent), scale_factor_bands[band_index].start, scale_factor_bands[band_index].end); - sample_count += scale_factor_bands[band_index].width; - band_index++; - } - } - - float const gain0 = (gain - 8 * granule.sub_block_gain[0]) / 4.0; - float const gain1 = (gain - 8 * granule.sub_block_gain[1]) / 4.0; - float const gain2 = (gain - 8 * granule.sub_block_gain[2]) / 4.0; - - while (sample_count < MP3::granule_size && band_index < scale_factor_bands.size()) { - float const exponent0 = gain0 - (scale_factor_multiplier * channel.scale_factors[band_index + 0]); - float const exponent1 = gain1 - (scale_factor_multiplier * channel.scale_factors[band_index + 1]); - float const exponent2 = gain2 - (scale_factor_multiplier * channel.scale_factors[band_index + 2]); - - fill_band(AK::pow(2.0, exponent0), scale_factor_bands[band_index + 0].start, scale_factor_bands[band_index + 0].end); - sample_count += scale_factor_bands[band_index + 0].width; - fill_band(AK::pow(2.0, exponent1), scale_factor_bands[band_index + 1].start, scale_factor_bands[band_index + 1].end); - sample_count += scale_factor_bands[band_index + 1].width; - fill_band(AK::pow(2.0, exponent2), scale_factor_bands[band_index + 2].start, scale_factor_bands[band_index + 2].end); - sample_count += scale_factor_bands[band_index + 2].width; - - band_index += 3; - } - - while (sample_count < MP3::granule_size) - exponents[sample_count++] = 0; - } - return exponents; -} - -ErrorOr MP3LoaderPlugin::read_scale_factors(MP3::MP3Frame& frame, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index) -{ - auto& channel = frame.channels[channel_index]; - auto const& granule = channel.granules[granule_index]; - size_t band_index = 0; - size_t bits_read = 0; - - if (granule.window_switching_flag && granule.block_type == MP3::BlockType::Short) { - if (granule.mixed_block_flag) { - for (size_t i = 0; i < 8; i++) { - auto const bits = MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress]; - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - bits_read += bits; - } - for (size_t i = 3; i < 12; i++) { - auto const bits = i <= 5 ? MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress] : MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - bits_read += 3 * bits; - } - } else { - for (size_t i = 0; i < 12; i++) { - auto const bits = i <= 5 ? MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress] : MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - channel.scale_factors[band_index++] = TRY(reservoir.read_bits(bits)); - bits_read += 3 * bits; - } - } - channel.scale_factors[band_index++] = 0; - channel.scale_factors[band_index++] = 0; - channel.scale_factors[band_index++] = 0; - } else { - if ((channel.scale_factor_selection_info[0] == 0) || (granule_index == 0)) { - for (band_index = 0; band_index < 6; band_index++) { - auto const bits = MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress]; - channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); - bits_read += bits; - } - } - if ((channel.scale_factor_selection_info[1] == 0) || (granule_index == 0)) { - for (band_index = 6; band_index < 11; band_index++) { - auto const bits = MP3::Tables::ScalefacCompressSlen1[granule.scalefac_compress]; - channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); - bits_read += bits; - } - } - if ((channel.scale_factor_selection_info[2] == 0) || (granule_index == 0)) { - for (band_index = 11; band_index < 16; band_index++) { - auto const bits = MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; - channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); - bits_read += bits; - } - } - if ((channel.scale_factor_selection_info[3] == 0) || (granule_index == 0)) { - for (band_index = 16; band_index < 21; band_index++) { - auto const bits = MP3::Tables::ScalefacCompressSlen2[granule.scalefac_compress]; - channel.scale_factors[band_index] = TRY(reservoir.read_bits(bits)); - bits_read += bits; - } - } - channel.scale_factors[21] = 0; - } - - return bits_read; -} - -MaybeLoaderError MP3LoaderPlugin::read_huffman_data(MP3::MP3Frame& frame, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index, size_t granule_bits_read) -{ - auto const exponents = calculate_frame_exponents(frame, granule_index, channel_index); - auto& granule = frame.channels[channel_index].granules[granule_index]; - - auto const scale_factor_bands = get_scalefactor_bands(granule, frame.header.samplerate); - size_t const scale_factor_band_index1 = granule.region0_count + 1; - size_t const scale_factor_band_index2 = min(scale_factor_bands.size() - 1, scale_factor_band_index1 + granule.region1_count + 1); - - bool const is_short_granule = granule.window_switching_flag && granule.block_type == MP3::BlockType::Short; - size_t const region1_start = is_short_granule ? 36 : scale_factor_bands[scale_factor_band_index1].start; - size_t const region2_start = is_short_granule ? MP3::granule_size : scale_factor_bands[scale_factor_band_index2].start; - - auto requantize = [](int const sample, float const exponent) -> float { - int const sign = sample < 0 ? -1 : 1; - int const magnitude = AK::abs(sample); - return sign * AK::pow(static_cast(magnitude), 4 / 3.0) * exponent; - }; - - size_t count = 0; - - // 2.4.3.4.6: "Decoding is done until all Huffman code bits have been decoded - // or until quantized values representing 576 frequency lines have been decoded, - // whichever comes first." - auto max_count = min(granule.big_values * 2, MP3::granule_size); - - for (; count < max_count; count += 2) { - MP3::Tables::Huffman::HuffmanTreeXY const* tree = nullptr; - - if (count < region1_start) { - tree = &MP3::Tables::Huffman::HuffmanTreesXY[granule.table_select[0]]; - } else if (count < region2_start) { - tree = &MP3::Tables::Huffman::HuffmanTreesXY[granule.table_select[1]]; - } else { - tree = &MP3::Tables::Huffman::HuffmanTreesXY[granule.table_select[2]]; - } - - if (!tree || tree->nodes.is_empty()) { - return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Frame references invalid huffman table." }; - } - - // Assumption: There's enough bits to read. 32 is just a placeholder for "unlimited". - // There are no 32 bit long huffman codes in the tables. - auto const entry = MP3::Tables::Huffman::huffman_decode(reservoir, tree->nodes, 32); - granule_bits_read += entry.bits_read; - if (!entry.code.has_value()) - return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Frame contains invalid huffman data." }; - int x = entry.code->symbol.x; - int y = entry.code->symbol.y; - - if (x == 15 && tree->linbits > 0) { - x += TRY(reservoir.read_bits(tree->linbits)); - granule_bits_read += tree->linbits; - } - if (x != 0) { - if (TRY(reservoir.read_bit())) - x = -x; - granule_bits_read++; - } - - if (y == 15 && tree->linbits > 0) { - y += TRY(reservoir.read_bits(tree->linbits)); - granule_bits_read += tree->linbits; - } - if (y != 0) { - if (TRY(reservoir.read_bit())) - y = -y; - granule_bits_read++; - } - - granule.samples[count + 0] = requantize(x, exponents[count + 0]); - granule.samples[count + 1] = requantize(y, exponents[count + 1]); - } - - ReadonlySpan> count1table = granule.count1table_select ? MP3::Tables::Huffman::TreeB : MP3::Tables::Huffman::TreeA; - - // count1 is not known. We have to read huffman encoded values - // until we've exhausted the granule's bits. We know the size of - // the granule from part2_3_length, which is the number of bits - // used for scalefactors and huffman data (in the granule). - while (granule_bits_read < granule.part_2_3_length && count <= MP3::granule_size - 4) { - auto const entry = MP3::Tables::Huffman::huffman_decode(reservoir, count1table, granule.part_2_3_length - granule_bits_read); - granule_bits_read += entry.bits_read; - if (!entry.code.has_value()) - return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Frame contains invalid huffman data." }; - int v = entry.code->symbol.v; - if (v != 0) { - if (granule_bits_read >= granule.part_2_3_length) - break; - if (TRY(reservoir.read_bit())) - v = -v; - granule_bits_read++; - } - int w = entry.code->symbol.w; - if (w != 0) { - if (granule_bits_read >= granule.part_2_3_length) - break; - if (TRY(reservoir.read_bit())) - w = -w; - granule_bits_read++; - } - int x = entry.code->symbol.x; - if (x != 0) { - if (granule_bits_read >= granule.part_2_3_length) - break; - if (TRY(reservoir.read_bit())) - x = -x; - granule_bits_read++; - } - int y = entry.code->symbol.y; - if (y != 0) { - if (granule_bits_read >= granule.part_2_3_length) - break; - if (TRY(reservoir.read_bit())) - y = -y; - granule_bits_read++; - } - - granule.samples[count + 0] = requantize(v, exponents[count + 0]); - granule.samples[count + 1] = requantize(w, exponents[count + 1]); - granule.samples[count + 2] = requantize(x, exponents[count + 2]); - granule.samples[count + 3] = requantize(y, exponents[count + 3]); - - count += 4; - } - - if (granule_bits_read > granule.part_2_3_length) { - return LoaderError { LoaderError::Category::Format, m_loaded_samples, "Read too many bits from bit reservoir." }; - } - - // 2.4.3.4.6: "If there are more Huffman code bits than necessary to decode 576 values - // they are regarded as stuffing bits and discarded." - for (size_t i = granule_bits_read; i < granule.part_2_3_length; i++) { - TRY(reservoir.read_bit()); - } - - return {}; -} - -void MP3LoaderPlugin::reorder_samples(MP3::Granule& granule, u32 sample_rate) -{ - float tmp[MP3::granule_size] = {}; - size_t band_index = 0; - size_t subband_index = 0; - - auto scale_factor_bands = get_scalefactor_bands(granule, sample_rate); - - if (granule.mixed_block_flag) { - while (subband_index < 36) { - for (size_t frequency_line_index = 0; frequency_line_index < scale_factor_bands[band_index].width; frequency_line_index++) { - tmp[subband_index] = granule.samples[subband_index]; - subband_index++; - } - band_index++; - } - } - - while (subband_index < MP3::granule_size && band_index <= 36) { - for (size_t frequency_line_index = 0; frequency_line_index < scale_factor_bands[band_index].width; frequency_line_index++) { - tmp[subband_index++] = granule.samples[scale_factor_bands[band_index + 0].start + frequency_line_index]; - tmp[subband_index++] = granule.samples[scale_factor_bands[band_index + 1].start + frequency_line_index]; - tmp[subband_index++] = granule.samples[scale_factor_bands[band_index + 2].start + frequency_line_index]; - } - band_index += 3; - } - - for (size_t i = 0; i < MP3::granule_size; i++) - granule.samples[i] = tmp[i]; -} - -void MP3LoaderPlugin::reduce_alias(MP3::Granule& granule, size_t max_subband_index) -{ - for (size_t subband = 0; subband < max_subband_index - 18; subband += 18) { - for (size_t i = 0; i < 8; i++) { - size_t const idx1 = subband + 17 - i; - size_t const idx2 = subband + 18 + i; - auto const d1 = granule.samples[idx1]; - auto const d2 = granule.samples[idx2]; - granule.samples[idx1] = d1 * MP3::Tables::AliasReductionCs[i] - d2 * MP3::Tables::AliasReductionCa[i]; - granule.samples[idx2] = d2 * MP3::Tables::AliasReductionCs[i] + d1 * MP3::Tables::AliasReductionCa[i]; - } - } -} - -void MP3LoaderPlugin::process_stereo(MP3::MP3Frame& frame, size_t granule_index) -{ - size_t band_index_ms_start = 0; - size_t band_index_ms_end = 0; - size_t band_index_intensity_start = 0; - size_t band_index_intensity_end = 0; - auto& granule_left = frame.channels[0].granules[granule_index]; - auto& granule_right = frame.channels[1].granules[granule_index]; - - auto get_last_nonempty_band = [](Span samples, ReadonlySpan bands) -> size_t { - size_t last_nonempty_band = 0; - - for (size_t i = 0; i < bands.size(); i++) { - bool is_empty = true; - for (size_t l = bands[i].start; l < bands[i].end; l++) { - if (samples[l] != 0) { - is_empty = false; - break; - } - } - if (!is_empty) - last_nonempty_band = i; - } - - return last_nonempty_band; - }; - - auto process_ms_stereo = [&](MP3::Tables::ScaleFactorBand const& band) { - float const SQRT_2 = AK::sqrt(2.0); - for (size_t i = band.start; i <= band.end; i++) { - float const m = granule_left.samples[i]; - float const s = granule_right.samples[i]; - granule_left.samples[i] = (m + s) / SQRT_2; - granule_right.samples[i] = (m - s) / SQRT_2; - } - }; - - auto process_intensity_stereo = [&](MP3::Tables::ScaleFactorBand const& band, float intensity_stereo_ratio) { - for (size_t i = band.start; i <= band.end; i++) { - // Superflous empty scale factor band. - if (i >= MP3::granule_size) - continue; - float const sample_left = granule_left.samples[i]; - float const coeff_l = intensity_stereo_ratio / (1 + intensity_stereo_ratio); - float const coeff_r = 1 / (1 + intensity_stereo_ratio); - granule_left.samples[i] = sample_left * coeff_l; - granule_right.samples[i] = sample_left * coeff_r; - } - }; - - auto scale_factor_bands = get_scalefactor_bands(granule_right, frame.header.samplerate); - - if (has_flag(frame.header.mode_extension, MP3::ModeExtension::MsStereo)) { - band_index_ms_start = 0; - band_index_ms_end = scale_factor_bands.size(); - } - - if (has_flag(frame.header.mode_extension, MP3::ModeExtension::IntensityStereo)) { - band_index_intensity_start = get_last_nonempty_band(granule_right.samples, scale_factor_bands); - band_index_intensity_end = scale_factor_bands.size(); - band_index_ms_end = band_index_intensity_start; - } - - for (size_t band_index = band_index_ms_start; band_index < band_index_ms_end; band_index++) { - process_ms_stereo(scale_factor_bands[band_index]); - } - - for (size_t band_index = band_index_intensity_start; band_index < band_index_intensity_end; band_index++) { - auto const intensity_stereo_position = frame.channels[1].scale_factors[band_index]; - if (intensity_stereo_position == 7) { - if (has_flag(frame.header.mode_extension, MP3::ModeExtension::MsStereo)) - process_ms_stereo(scale_factor_bands[band_index]); - continue; - } - float const intensity_stereo_ratio = AK::tan(intensity_stereo_position * AK::Pi / 12); - process_intensity_stereo(scale_factor_bands[band_index], intensity_stereo_ratio); - } -} - -void MP3LoaderPlugin::transform_samples_to_time(Array const& input, size_t input_offset, Array& output, MP3::BlockType block_type) -{ - if (block_type == MP3::BlockType::Short) { - size_t const N = 12; - Array temp_out; - Array temp_in; - - for (size_t k = 0; k < N / 2; k++) - temp_in[k] = input[input_offset + 3 * k + 0]; - s_mdct_12.transform(temp_in, Span(temp_out).slice(0, N)); - for (size_t i = 0; i < N; i++) - temp_out[i + 0] *= MP3::Tables::WindowBlockTypeShort[i]; - - for (size_t k = 0; k < N / 2; k++) - temp_in[k] = input[input_offset + 3 * k + 1]; - s_mdct_12.transform(temp_in, Span(temp_out).slice(12, N)); - for (size_t i = 0; i < N; i++) - temp_out[i + 12] *= MP3::Tables::WindowBlockTypeShort[i]; - - for (size_t k = 0; k < N / 2; k++) - temp_in[k] = input[input_offset + 3 * k + 2]; - s_mdct_12.transform(temp_in, Span(temp_out).slice(24, N)); - for (size_t i = 0; i < N; i++) - temp_out[i + 24] *= MP3::Tables::WindowBlockTypeShort[i]; - - Span idmct1 = Span(temp_out).slice(0, 12); - Span idmct2 = Span(temp_out).slice(12, 12); - Span idmct3 = Span(temp_out).slice(24, 12); - for (size_t i = 0; i < 6; i++) - output[i] = 0; - for (size_t i = 6; i < 12; i++) - output[i] = idmct1[i - 6]; - for (size_t i = 12; i < 18; i++) - output[i] = idmct1[i - 6] + idmct2[i - 12]; - for (size_t i = 18; i < 24; i++) - output[i] = idmct2[i - 12] + idmct3[i - 18]; - for (size_t i = 24; i < 30; i++) - output[i] = idmct3[i - 18]; - for (size_t i = 30; i < 36; i++) - output[i] = 0; - - } else { - s_mdct_36.transform(ReadonlySpan(input).slice(input_offset, 18), output); - for (size_t i = 0; i < 36; i++) { - switch (block_type) { - case MP3::BlockType::Normal: - output[i] *= MP3::Tables::WindowBlockTypeNormal[i]; - break; - case MP3::BlockType::Start: - output[i] *= MP3::Tables::WindowBlockTypeStart[i]; - break; - case MP3::BlockType::End: - output[i] *= MP3::Tables::WindowBlockTypeEnd[i]; - break; - case MP3::BlockType::Short: - VERIFY_NOT_REACHED(); - break; - } - } - } -} - -// ISO/IEC 11172-3 (Figure A.2) -void MP3LoaderPlugin::synthesis(Array& V, Array& samples, Array& result) -{ - for (size_t i = 1023; i >= 64; i--) { - V[i] = V[i - 64]; - } - - for (size_t i = 0; i < 64; i++) { - V[i] = 0; - for (size_t k = 0; k < 32; k++) { - float const N = MP3::Tables::SynthesisSubbandFilterCoefficients[i][k]; - V[i] += N * samples[k]; - } - } - - Array U; - for (size_t i = 0; i < 8; i++) { - for (size_t j = 0; j < 32; j++) { - U[i * 64 + j] = V[i * 128 + j]; - U[i * 64 + 32 + j] = V[i * 128 + 96 + j]; - } - } - - Array W; - for (size_t i = 0; i < 512; i++) { - W[i] = U[i] * MP3::Tables::WindowSynthesis[i]; - } - - for (size_t j = 0; j < 32; j++) { - result[j] = 0; - for (size_t k = 0; k < 16; k++) { - result[j] += W[j + 32 * k]; - } - } -} - -ReadonlySpan MP3LoaderPlugin::get_scalefactor_bands(MP3::Granule const& granule, int samplerate) -{ - switch (granule.block_type) { - case MP3::BlockType::Short: - switch (samplerate) { - case 32000: - return granule.mixed_block_flag ? MP3::Tables::ScaleFactorBandMixed32000 : MP3::Tables::ScaleFactorBandShort32000; - case 44100: - return granule.mixed_block_flag ? MP3::Tables::ScaleFactorBandMixed44100 : MP3::Tables::ScaleFactorBandShort44100; - case 48000: - return granule.mixed_block_flag ? MP3::Tables::ScaleFactorBandMixed48000 : MP3::Tables::ScaleFactorBandShort48000; - } - break; - case MP3::BlockType::Normal: - [[fallthrough]]; - case MP3::BlockType::Start: - [[fallthrough]]; - case MP3::BlockType::End: - switch (samplerate) { - case 32000: - return MP3::Tables::ScaleFactorBandLong32000; - case 44100: - return MP3::Tables::ScaleFactorBandLong44100; - case 48000: - return MP3::Tables::ScaleFactorBandLong48000; - } - } - VERIFY_NOT_REACHED(); -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/MP3Loader.h b/Userland/Libraries/LibMedia/Audio/MP3Loader.h deleted file mode 100644 index 5e7b88c94cb..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MP3Loader.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2021, Arne Elster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Loader.h" -#include "MDCT.h" -#include "MP3Types.h" -#include -#include - -namespace Audio { - -namespace MP3::Tables { -struct ScaleFactorBand; -} - -class MP3LoaderPlugin : public LoaderPlugin { -public: - explicit MP3LoaderPlugin(NonnullOwnPtr stream); - virtual ~MP3LoaderPlugin() = default; - - static bool sniff(SeekableStream& stream); - static ErrorOr, LoaderError> create(NonnullOwnPtr); - - virtual ErrorOr>, LoaderError> load_chunks(size_t samples_to_read_from_input) override; - - virtual MaybeLoaderError reset() override; - virtual MaybeLoaderError seek(int const position) override; - - virtual int loaded_samples() override { return m_loaded_samples; } - virtual int total_samples() override { return m_total_samples; } - virtual u32 sample_rate() override { return m_sample_rate; } - virtual u16 num_channels() override { return m_num_channels; } - virtual PcmSampleFormat pcm_format() override { return m_sample_format; } - virtual ByteString format_name() override { return "MP3 (.mp3)"; } - -private: - MaybeLoaderError initialize(); - static MaybeLoaderError skip_id3(SeekableStream& stream); - static MaybeLoaderError synchronize(SeekableStream& stream, size_t sample_index); - static ErrorOr read_header(SeekableStream& stream, size_t sample_index); - static ErrorOr synchronize_and_read_header(SeekableStream& stream, size_t sample_index); - ErrorOr synchronize_and_read_header(); - MaybeLoaderError build_seek_table(); - ErrorOr read_next_frame(); - ErrorOr read_frame_data(MP3::Header const&); - MaybeLoaderError read_side_information(MP3::MP3Frame&); - ErrorOr read_scale_factors(MP3::MP3Frame&, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index); - MaybeLoaderError read_huffman_data(MP3::MP3Frame&, BigEndianInputBitStream& reservoir, size_t granule_index, size_t channel_index, size_t granule_bits_read); - static AK::Array calculate_frame_exponents(MP3::MP3Frame const&, size_t granule_index, size_t channel_index); - static void reorder_samples(MP3::Granule&, u32 sample_rate); - static void reduce_alias(MP3::Granule&, size_t max_subband_index = 576); - static void process_stereo(MP3::MP3Frame&, size_t granule_index); - static void transform_samples_to_time(Array const& input, size_t input_offset, Array& output, MP3::BlockType block_type); - static void synthesis(Array& V, Array& samples, Array& result); - static ReadonlySpan get_scalefactor_bands(MP3::Granule const&, int samplerate); - - SeekTable m_seek_table; - AK::Array, 32>, 2> m_last_values {}; - AK::Array, 2> m_synthesis_buffer {}; - static DSP::MDCT<36> s_mdct_36; - static DSP::MDCT<12> s_mdct_12; - - u32 m_sample_rate { 0 }; - u8 m_num_channels { 0 }; - PcmSampleFormat m_sample_format { PcmSampleFormat::Int16 }; - int m_total_samples { 0 }; - size_t m_loaded_samples { 0 }; - - AllocatingMemoryStream m_bit_reservoir; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/MP3Tables.h b/Userland/Libraries/LibMedia/Audio/MP3Tables.h deleted file mode 100644 index f1389466368..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MP3Tables.h +++ /dev/null @@ -1,447 +0,0 @@ -/* - * Copyright (c) 2021, Arne Elster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Audio::MP3::Tables { - -// ISO/IEC 11172-3 (2.4.2.3) -Array LayerNumberLookup { -1, 3, 2, 1 }; - -// ISO/IEC 11172-3 (2.4.2.3) -Array, 3> BitratesPerLayerLookup { { - { 0, 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, -1 }, // Layer I - { 0, 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, -1 }, // Layer II - { 0, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, -1 } // Layer III -} }; - -// ISO/IEC 11172-3 (2.4.2.3) -Array SampleratesLookup { { 44100, 48000, 32000, -1 } }; - -// ISO/IEC 11172-3 (2.4.2.7) -Array ScalefacCompressSlen1 { { 0, 0, 0, 0, 3, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4 } }; -Array ScalefacCompressSlen2 { { 0, 1, 2, 3, 0, 1, 2, 3, 1, 2, 3, 1, 2, 3, 2, 3 } }; - -// ISO/IEC 11172-3 (Table B.6) -Array Pretab { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 3, 3, 3, 2, 0 } }; - -// ISO/IEC 11172-3 (Table B.9) -Array AliasReductionCoefficients { - -0.6, - -0.535, - -0.33, - -0.185, - -0.095, - -0.041, - -0.0142, - -0.0032 -}; - -// This is using the cs[i] formula taken from ISO/IEC 11172-3 (below Table B.9) -Array AliasReductionCs { { - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[0], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[1], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[2], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[3], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[4], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[5], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[6], 2.0)), - 1.0f / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[7], 2.0)), -} }; - -// This is using the ca[i] formula taken from ISO/IEC 11172-3 (below Table B.9) -Array AliasReductionCa { { - AliasReductionCoefficients[0] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[0], 2.0)), - AliasReductionCoefficients[1] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[1], 2.0)), - AliasReductionCoefficients[2] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[2], 2.0)), - AliasReductionCoefficients[3] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[3], 2.0)), - AliasReductionCoefficients[4] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[4], 2.0)), - AliasReductionCoefficients[5] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[5], 2.0)), - AliasReductionCoefficients[6] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[6], 2.0)), - AliasReductionCoefficients[7] / AK::sqrt(1 + AK::pow(AliasReductionCoefficients[7], 2.0)), -} }; - -struct ScaleFactorBand { - size_t width; - size_t start; - size_t end; -}; - -template -constexpr auto MakeShortScaleFactorBandArray() -{ - constexpr size_t N = sizes.size(); - Array result {}; - size_t start = offset; - - for (size_t i = 0; i < N; i++) { - result[3 * i + 0] = { sizes[i], start, start + sizes[i] - 1 }; - start += sizes[i]; - result[3 * i + 1] = { sizes[i], start, start + sizes[i] - 1 }; - start += sizes[i]; - result[3 * i + 2] = { sizes[i], start, start + sizes[i] - 1 }; - start += sizes[i]; - } - - return result; -} - -template -constexpr auto MakeLongScaleFactorBandArray() -{ - constexpr size_t N = sizes.size(); - Array result {}; - size_t start = 0; - - for (size_t i = 0; i < N; i++) { - result[i] = { sizes[i], start, start + sizes[i] - 1 }; - start += sizes[i]; - } - - return result; -} - -template -constexpr auto MakeMixedScaleFactorBandArray() -{ - constexpr size_t N = sizes_long.size() + sizes_short.size() * 3 + 1; - Array result {}; - - constexpr auto long_bands = MakeLongScaleFactorBandArray(); - constexpr auto short_bands = MakeShortScaleFactorBandArray(); - - for (size_t i = 0; i < long_bands.size(); i++) { - result[i] = long_bands[i]; - } - - for (size_t i = 0; i < short_bands.size(); i++) { - result[i + long_bands.size()] = short_bands[i]; - } - - for (size_t i = long_bands.size() + short_bands.size(); i < N; i++) { - result[i] = { 0, 576, 576 }; - } - - return result; -} - -// ISO/IEC 11172-3 (Table B.8) -constexpr auto ScaleFactorBandShort32000 = MakeShortScaleFactorBandArray { 4, 4, 4, 4, 6, 8, 12, 16, 20, 26, 34, 42, 12 }>(); -constexpr auto ScaleFactorBandShort44100 = MakeShortScaleFactorBandArray { 4, 4, 4, 4, 6, 8, 10, 12, 14, 18, 22, 30, 56 }>(); -constexpr auto ScaleFactorBandShort48000 = MakeShortScaleFactorBandArray { 4, 4, 4, 4, 6, 6, 10, 12, 14, 16, 20, 26, 66 }>(); - -constexpr auto ScaleFactorBandMixed32000 = MakeMixedScaleFactorBandArray { 4, 4, 4, 4, 4, 4, 6, 6 }, Array { 4, 6, 8, 12, 16, 20, 26, 34, 42, 12 }>(); -constexpr auto ScaleFactorBandMixed44100 = MakeMixedScaleFactorBandArray { 4, 4, 4, 4, 4, 4, 6, 6 }, Array { 4, 6, 8, 10, 12, 14, 18, 22, 30, 56 }>(); -constexpr auto ScaleFactorBandMixed48000 = MakeMixedScaleFactorBandArray { 4, 4, 4, 4, 4, 4, 6, 6 }, Array { 4, 6, 6, 10, 12, 14, 16, 20, 26, 66 }>(); - -constexpr auto ScaleFactorBandLong32000 = MakeLongScaleFactorBandArray { 4, 4, 4, 4, 4, 4, 6, 6, 8, 10, 12, 16, 20, 24, 30, 38, 46, 56, 68, 84, 102, 26, 0 }>(); -constexpr auto ScaleFactorBandLong44100 = MakeLongScaleFactorBandArray { 4, 4, 4, 4, 4, 4, 6, 6, 8, 8, 10, 12, 16, 20, 24, 28, 34, 42, 50, 54, 76, 158, 0 }>(); -constexpr auto ScaleFactorBandLong48000 = MakeLongScaleFactorBandArray { 4, 4, 4, 4, 4, 4, 6, 6, 6, 8, 10, 12, 16, 18, 22, 28, 34, 40, 46, 54, 54, 192, 0 }>(); - -// ISO/IEC 11172-3 (2.4.3.4.10.3 a) -Array WindowBlockTypeNormal { { - AK::sin(AK::Pi / 36 * (0 + 0.5f)), - AK::sin(AK::Pi / 36 * (1 + 0.5f)), - AK::sin(AK::Pi / 36 * (2 + 0.5f)), - AK::sin(AK::Pi / 36 * (3 + 0.5f)), - AK::sin(AK::Pi / 36 * (4 + 0.5f)), - AK::sin(AK::Pi / 36 * (5 + 0.5f)), - AK::sin(AK::Pi / 36 * (6 + 0.5f)), - AK::sin(AK::Pi / 36 * (7 + 0.5f)), - AK::sin(AK::Pi / 36 * (8 + 0.5f)), - AK::sin(AK::Pi / 36 * (9 + 0.5f)), - AK::sin(AK::Pi / 36 * (10 + 0.5f)), - AK::sin(AK::Pi / 36 * (11 + 0.5f)), - AK::sin(AK::Pi / 36 * (12 + 0.5f)), - AK::sin(AK::Pi / 36 * (13 + 0.5f)), - AK::sin(AK::Pi / 36 * (14 + 0.5f)), - AK::sin(AK::Pi / 36 * (15 + 0.5f)), - AK::sin(AK::Pi / 36 * (16 + 0.5f)), - AK::sin(AK::Pi / 36 * (17 + 0.5f)), - AK::sin(AK::Pi / 36 * (18 + 0.5f)), - AK::sin(AK::Pi / 36 * (19 + 0.5f)), - AK::sin(AK::Pi / 36 * (20 + 0.5f)), - AK::sin(AK::Pi / 36 * (21 + 0.5f)), - AK::sin(AK::Pi / 36 * (22 + 0.5f)), - AK::sin(AK::Pi / 36 * (23 + 0.5f)), - AK::sin(AK::Pi / 36 * (24 + 0.5f)), - AK::sin(AK::Pi / 36 * (25 + 0.5f)), - AK::sin(AK::Pi / 36 * (26 + 0.5f)), - AK::sin(AK::Pi / 36 * (27 + 0.5f)), - AK::sin(AK::Pi / 36 * (28 + 0.5f)), - AK::sin(AK::Pi / 36 * (29 + 0.5f)), - AK::sin(AK::Pi / 36 * (30 + 0.5f)), - AK::sin(AK::Pi / 36 * (31 + 0.5f)), - AK::sin(AK::Pi / 36 * (32 + 0.5f)), - AK::sin(AK::Pi / 36 * (33 + 0.5f)), - AK::sin(AK::Pi / 36 * (34 + 0.5f)), - AK::sin(AK::Pi / 36 * (35 + 0.5f)), -} }; - -// ISO/IEC 11172-3 (2.4.3.4.10.3 b) -AK::Array WindowBlockTypeStart { { - AK::sin(AK::Pi / 36 * (0 + 0.5f)), - AK::sin(AK::Pi / 36 * (1 + 0.5f)), - AK::sin(AK::Pi / 36 * (2 + 0.5f)), - AK::sin(AK::Pi / 36 * (3 + 0.5f)), - AK::sin(AK::Pi / 36 * (4 + 0.5f)), - AK::sin(AK::Pi / 36 * (5 + 0.5f)), - AK::sin(AK::Pi / 36 * (6 + 0.5f)), - AK::sin(AK::Pi / 36 * (7 + 0.5f)), - AK::sin(AK::Pi / 36 * (8 + 0.5f)), - AK::sin(AK::Pi / 36 * (9 + 0.5f)), - AK::sin(AK::Pi / 36 * (10 + 0.5f)), - AK::sin(AK::Pi / 36 * (11 + 0.5f)), - AK::sin(AK::Pi / 36 * (12 + 0.5f)), - AK::sin(AK::Pi / 36 * (13 + 0.5f)), - AK::sin(AK::Pi / 36 * (14 + 0.5f)), - AK::sin(AK::Pi / 36 * (15 + 0.5f)), - AK::sin(AK::Pi / 36 * (16 + 0.5f)), - AK::sin(AK::Pi / 36 * (17 + 0.5f)), - 1, - 1, - 1, - 1, - 1, - 1, - AK::sin(AK::Pi / 12 * (24 - 18 + 0.5f)), - AK::sin(AK::Pi / 12 * (25 - 18 + 0.5f)), - AK::sin(AK::Pi / 12 * (26 - 18 + 0.5f)), - AK::sin(AK::Pi / 12 * (27 - 18 + 0.5f)), - AK::sin(AK::Pi / 12 * (28 - 18 + 0.5f)), - AK::sin(AK::Pi / 12 * (29 - 18 + 0.5f)), - 0, - 0, - 0, - 0, - 0, - 0, -} }; - -// ISO/IEC 11172-3 (2.4.3.4.10.3 d) -AK::Array WindowBlockTypeShort { { - AK::sin(AK::Pi / 12 * (0 + 0.5f)), - AK::sin(AK::Pi / 12 * (1 + 0.5f)), - AK::sin(AK::Pi / 12 * (2 + 0.5f)), - AK::sin(AK::Pi / 12 * (3 + 0.5f)), - AK::sin(AK::Pi / 12 * (4 + 0.5f)), - AK::sin(AK::Pi / 12 * (5 + 0.5f)), - AK::sin(AK::Pi / 12 * (6 + 0.5f)), - AK::sin(AK::Pi / 12 * (7 + 0.5f)), - AK::sin(AK::Pi / 12 * (8 + 0.5f)), - AK::sin(AK::Pi / 12 * (9 + 0.5f)), - AK::sin(AK::Pi / 12 * (10 + 0.5f)), - AK::sin(AK::Pi / 12 * (11 + 0.5f)), - - AK::sin(AK::Pi / 12 * (0 + 0.5f)), - AK::sin(AK::Pi / 12 * (1 + 0.5f)), - AK::sin(AK::Pi / 12 * (2 + 0.5f)), - AK::sin(AK::Pi / 12 * (3 + 0.5f)), - AK::sin(AK::Pi / 12 * (4 + 0.5f)), - AK::sin(AK::Pi / 12 * (5 + 0.5f)), - AK::sin(AK::Pi / 12 * (6 + 0.5f)), - AK::sin(AK::Pi / 12 * (7 + 0.5f)), - AK::sin(AK::Pi / 12 * (8 + 0.5f)), - AK::sin(AK::Pi / 12 * (9 + 0.5f)), - AK::sin(AK::Pi / 12 * (10 + 0.5f)), - AK::sin(AK::Pi / 12 * (11 + 0.5f)), - - AK::sin(AK::Pi / 12 * (0 + 0.5f)), - AK::sin(AK::Pi / 12 * (1 + 0.5f)), - AK::sin(AK::Pi / 12 * (2 + 0.5f)), - AK::sin(AK::Pi / 12 * (3 + 0.5f)), - AK::sin(AK::Pi / 12 * (4 + 0.5f)), - AK::sin(AK::Pi / 12 * (5 + 0.5f)), - AK::sin(AK::Pi / 12 * (6 + 0.5f)), - AK::sin(AK::Pi / 12 * (7 + 0.5f)), - AK::sin(AK::Pi / 12 * (8 + 0.5f)), - AK::sin(AK::Pi / 12 * (9 + 0.5f)), - AK::sin(AK::Pi / 12 * (10 + 0.5f)), - AK::sin(AK::Pi / 12 * (11 + 0.5f)), -} }; - -// ISO/IEC 11172-3 (2.4.3.4.10.3 c) -AK::Array WindowBlockTypeEnd { { - 0, - 0, - 0, - 0, - 0, - 0, - AK::sin(AK::Pi / 12 * (6 - 6 + 0.5f)), - AK::sin(AK::Pi / 12 * (7 - 6 + 0.5f)), - AK::sin(AK::Pi / 12 * (8 - 6 + 0.5f)), - AK::sin(AK::Pi / 12 * (9 - 6 + 0.5f)), - AK::sin(AK::Pi / 12 * (10 - 6 + 0.5f)), - AK::sin(AK::Pi / 12 * (11 - 6 + 0.5f)), - 1, - 1, - 1, - 1, - 1, - 1, - AK::sin(AK::Pi / 36 * (18 + 0.5f)), - AK::sin(AK::Pi / 36 * (19 + 0.5f)), - AK::sin(AK::Pi / 36 * (20 + 0.5f)), - AK::sin(AK::Pi / 36 * (21 + 0.5f)), - AK::sin(AK::Pi / 36 * (22 + 0.5f)), - AK::sin(AK::Pi / 36 * (23 + 0.5f)), - AK::sin(AK::Pi / 36 * (24 + 0.5f)), - AK::sin(AK::Pi / 36 * (25 + 0.5f)), - AK::sin(AK::Pi / 36 * (26 + 0.5f)), - AK::sin(AK::Pi / 36 * (27 + 0.5f)), - AK::sin(AK::Pi / 36 * (28 + 0.5f)), - AK::sin(AK::Pi / 36 * (29 + 0.5f)), - AK::sin(AK::Pi / 36 * (30 + 0.5f)), - AK::sin(AK::Pi / 36 * (31 + 0.5f)), - AK::sin(AK::Pi / 36 * (32 + 0.5f)), - AK::sin(AK::Pi / 36 * (33 + 0.5f)), - AK::sin(AK::Pi / 36 * (34 + 0.5f)), - AK::sin(AK::Pi / 36 * (35 + 0.5f)), -} }; - -// ISO/IEC 11172-3 (Table B.3) -AK::Array WindowSynthesis { - 0.000000000, -0.000015259, -0.000015259, -0.000015259, -0.000015259, -0.000015259, -0.000015259, -0.000030518, - -0.000030518, -0.000030518, -0.000030518, -0.000045776, -0.000045776, -0.000061035, -0.000061035, -0.000076294, - -0.000076294, -0.000091553, -0.000106812, -0.000106812, -0.000122070, -0.000137329, -0.000152588, -0.000167847, - -0.000198364, -0.000213623, -0.000244141, -0.000259399, -0.000289917, -0.000320435, -0.000366211, -0.000396729, - -0.000442505, -0.000473022, -0.000534058, -0.000579834, -0.000625610, -0.000686646, -0.000747681, -0.000808716, - -0.000885010, -0.000961304, -0.001037598, -0.001113892, -0.001205444, -0.001296997, -0.001388550, -0.001480103, - -0.001586914, -0.001693726, -0.001785278, -0.001907349, -0.002014160, -0.002120972, -0.002243042, -0.002349854, - -0.002456665, -0.002578735, -0.002685547, -0.002792358, -0.002899170, -0.002990723, -0.003082275, -0.003173828, - 0.003250122, 0.003326416, 0.003387451, 0.003433228, 0.003463745, 0.003479004, 0.003479004, 0.003463745, - 0.003417969, 0.003372192, 0.003280640, 0.003173828, 0.003051758, 0.002883911, 0.002700806, 0.002487183, - 0.002227783, 0.001937866, 0.001617432, 0.001266479, 0.000869751, 0.000442505, -0.000030518, -0.000549316, - -0.001098633, -0.001693726, -0.002334595, -0.003005981, -0.003723145, -0.004486084, -0.005294800, -0.006118774, - -0.007003784, -0.007919312, -0.008865356, -0.009841919, -0.010848999, -0.011886597, -0.012939453, -0.014022827, - -0.015121460, -0.016235352, -0.017349243, -0.018463135, -0.019577026, -0.020690918, -0.021789551, -0.022857666, - -0.023910522, -0.024932861, -0.025909424, -0.026840210, -0.027725220, -0.028533936, -0.029281616, -0.029937744, - -0.030532837, -0.031005859, -0.031387329, -0.031661987, -0.031814575, -0.031845093, -0.031738281, -0.031478882, - 0.031082153, 0.030517578, 0.029785156, 0.028884888, 0.027801514, 0.026535034, 0.025085449, 0.023422241, - 0.021575928, 0.019531250, 0.017257690, 0.014801025, 0.012115479, 0.009231567, 0.006134033, 0.002822876, - -0.000686646, -0.004394531, -0.008316040, -0.012420654, -0.016708374, -0.021179199, -0.025817871, -0.030609131, - -0.035552979, -0.040634155, -0.045837402, -0.051132202, -0.056533813, -0.061996460, -0.067520142, -0.073059082, - -0.078628540, -0.084182739, -0.089706421, -0.095169067, -0.100540161, -0.105819702, -0.110946655, -0.115921021, - -0.120697021, -0.125259399, -0.129562378, -0.133590698, -0.137298584, -0.140670776, -0.143676758, -0.146255493, - -0.148422241, -0.150115967, -0.151306152, -0.151962280, -0.152069092, -0.151596069, -0.150497437, -0.148773193, - -0.146362305, -0.143264771, -0.139450073, -0.134887695, -0.129577637, -0.123474121, -0.116577148, -0.108856201, - 0.100311279, 0.090927124, 0.080688477, 0.069595337, 0.057617187, 0.044784546, 0.031082153, 0.016510010, - 0.001068115, -0.015228271, -0.032379150, -0.050354004, -0.069168091, -0.088775635, -0.109161377, -0.130310059, - -0.152206421, -0.174789429, -0.198059082, -0.221984863, -0.246505737, -0.271591187, -0.297210693, -0.323318481, - -0.349868774, -0.376800537, -0.404083252, -0.431655884, -0.459472656, -0.487472534, -0.515609741, -0.543823242, - -0.572036743, -0.600219727, -0.628295898, -0.656219482, -0.683914185, -0.711318970, -0.738372803, -0.765029907, - -0.791213989, -0.816864014, -0.841949463, -0.866363525, -0.890090942, -0.913055420, -0.935195923, -0.956481934, - -0.976852417, -0.996246338, -1.014617920, -1.031936646, -1.048156738, -1.063217163, -1.077117920, -1.089782715, - -1.101211548, -1.111373901, -1.120223999, -1.127746582, -1.133926392, -1.138763428, -1.142211914, -1.144287109, - 1.144989014, 1.144287109, 1.142211914, 1.138763428, 1.133926392, 1.127746582, 1.120223999, 1.111373901, - 1.101211548, 1.089782715, 1.077117920, 1.063217163, 1.048156738, 1.031936646, 1.014617920, 0.996246338, - 0.976852417, 0.956481934, 0.935195923, 0.913055420, 0.890090942, 0.866363525, 0.841949463, 0.816864014, - 0.791213989, 0.765029907, 0.738372803, 0.711318970, 0.683914185, 0.656219482, 0.628295898, 0.600219727, - 0.572036743, 0.543823242, 0.515609741, 0.487472534, 0.459472656, 0.431655884, 0.404083252, 0.376800537, - 0.349868774, 0.323318481, 0.297210693, 0.271591187, 0.246505737, 0.221984863, 0.198059082, 0.174789429, - 0.152206421, 0.130310059, 0.109161377, 0.088775635, 0.069168091, 0.050354004, 0.032379150, 0.015228271, - -0.001068115, -0.016510010, -0.031082153, -0.044784546, -0.057617187, -0.069595337, -0.080688477, -0.090927124, - 0.100311279, 0.108856201, 0.116577148, 0.123474121, 0.129577637, 0.134887695, 0.139450073, 0.143264771, - 0.146362305, 0.148773193, 0.150497437, 0.151596069, 0.152069092, 0.151962280, 0.151306152, 0.150115967, - 0.148422241, 0.146255493, 0.143676758, 0.140670776, 0.137298584, 0.133590698, 0.129562378, 0.125259399, - 0.120697021, 0.115921021, 0.110946655, 0.105819702, 0.100540161, 0.095169067, 0.089706421, 0.084182739, - 0.078628540, 0.073059082, 0.067520142, 0.061996460, 0.056533813, 0.051132202, 0.045837402, 0.040634155, - 0.035552979, 0.030609131, 0.025817871, 0.021179199, 0.016708374, 0.012420654, 0.008316040, 0.004394531, - 0.000686646, -0.002822876, -0.006134033, -0.009231567, -0.012115479, -0.014801025, -0.017257690, -0.019531250, - -0.021575928, -0.023422241, -0.025085449, -0.026535034, -0.027801514, -0.028884888, -0.029785156, -0.030517578, - 0.031082153, 0.031478882, 0.031738281, 0.031845093, 0.031814575, 0.031661987, 0.031387329, 0.031005859, - 0.030532837, 0.029937744, 0.029281616, 0.028533936, 0.027725220, 0.026840210, 0.025909424, 0.024932861, - 0.023910522, 0.022857666, 0.021789551, 0.020690918, 0.019577026, 0.018463135, 0.017349243, 0.016235352, - 0.015121460, 0.014022827, 0.012939453, 0.011886597, 0.010848999, 0.009841919, 0.008865356, 0.007919312, - 0.007003784, 0.006118774, 0.005294800, 0.004486084, 0.003723145, 0.003005981, 0.002334595, 0.001693726, - 0.001098633, 0.000549316, 0.000030518, -0.000442505, -0.000869751, -0.001266479, -0.001617432, -0.001937866, - -0.002227783, -0.002487183, -0.002700806, -0.002883911, -0.003051758, -0.003173828, -0.003280640, -0.003372192, - -0.003417969, -0.003463745, -0.003479004, -0.003479004, -0.003463745, -0.003433228, -0.003387451, -0.003326416, - 0.003250122, 0.003173828, 0.003082275, 0.002990723, 0.002899170, 0.002792358, 0.002685547, 0.002578735, - 0.002456665, 0.002349854, 0.002243042, 0.002120972, 0.002014160, 0.001907349, 0.001785278, 0.001693726, - 0.001586914, 0.001480103, 0.001388550, 0.001296997, 0.001205444, 0.001113892, 0.001037598, 0.000961304, - 0.000885010, 0.000808716, 0.000747681, 0.000686646, 0.000625610, 0.000579834, 0.000534058, 0.000473022, - 0.000442505, 0.000396729, 0.000366211, 0.000320435, 0.000289917, 0.000259399, 0.000244141, 0.000213623, - 0.000198364, 0.000167847, 0.000152588, 0.000137329, 0.000122070, 0.000106812, 0.000106812, 0.000091553, - 0.000076294, 0.000076294, 0.000061035, 0.000061035, 0.000045776, 0.000045776, 0.000030518, 0.000030518, - 0.000030518, 0.000030518, 0.000015259, 0.000015259, 0.000015259, 0.000015259, 0.000015259, 0.000015259 -}; - -// ISO/IEC 11172-3 (2.4.3.2.2) -// cos((16 + i) * (2 * k + 1) * pi / 64.0), k=0..31, i=0..63 -Array, 64> SynthesisSubbandFilterCoefficients = { - Array { { 0.7071067811865476, -0.7071067811865475, -0.7071067811865477, 0.7071067811865474, 0.7071067811865477, -0.7071067811865467, -0.7071067811865471, 0.7071067811865466, 0.7071067811865472, -0.7071067811865465, -0.7071067811865474, 0.7071067811865464, 0.7071067811865475, -0.7071067811865464, -0.7071067811865476, 0.7071067811865462, 0.7071067811865476, -0.7071067811865461, -0.7071067811865477, 0.707106781186546, 0.7071067811865503, -0.707106781186546, -0.7071067811865479, 0.7071067811865483, 0.7071067811865505, -0.7071067811865458, -0.707106781186548, 0.7071067811865482, 0.7071067811865507, -0.7071067811865456, -0.7071067811865482, 0.707106781186548 } }, - Array { { 0.6715589548470183, -0.8032075314806448, -0.5141027441932218, 0.9039892931234431, 0.33688985339222005, -0.9700312531945441, -0.14673047445536166, 0.9987954562051724, -0.04906767432741729, -0.9891765099647811, 0.24298017990326243, 0.9415440651830208, -0.42755509343028003, -0.8577286100002726, 0.5956993044924337, 0.7409511253549602, -0.7409511253549589, -0.5956993044924354, 0.8577286100002715, 0.4275550934302851, -0.9415440651830214, -0.24298017990326443, 0.9891765099647806, 0.04906767432742292, -0.9987954562051724, 0.1467304744553596, 0.9700312531945451, -0.3368898533922206, -0.903989293123444, 0.5141027441932186, 0.8032075314806442, -0.6715589548470177 } }, - Array { { 0.6343932841636455, -0.8819212643483549, -0.29028467725446244, 0.9951847266721969, -0.09801714032955997, -0.9569403357322087, 0.47139673682599736, 0.7730104533627377, -0.773010453362737, -0.4713967368259983, 0.9569403357322089, 0.09801714032956282, -0.995184726672197, 0.2902846772544622, 0.8819212643483563, -0.6343932841636443, -0.6343932841636459, 0.8819212643483553, 0.29028467725446433, -0.9951847266721968, 0.09801714032956063, 0.9569403357322086, -0.47139673682599326, -0.7730104533627394, 0.7730104533627351, 0.4713967368259993, -0.9569403357322086, -0.09801714032956038, 0.9951847266721968, -0.2902846772544578, -0.8819212643483568, 0.6343932841636434 } }, - Array { { 0.5956993044924335, -0.9415440651830207, -0.04906767432741803, 0.9700312531945441, -0.5141027441932214, -0.6715589548470181, 0.903989293123443, 0.1467304744553618, -0.9891765099647811, 0.42755509343028014, 0.7409511253549601, -0.8577286100002717, -0.24298017990326395, 0.9987954562051724, -0.33688985339221794, -0.8032075314806458, 0.8032075314806444, 0.33688985339222016, -0.9987954562051723, 0.24298017990326515, 0.8577286100002729, -0.7409511253549561, -0.4275550934302822, 0.9891765099647806, -0.146730474455363, -0.903989293123444, 0.6715589548470151, 0.5141027441932219, -0.9700312531945433, 0.04906767432741926, 0.9415440651830214, -0.5956993044924298 } }, - Array { { 0.5555702330196023, -0.9807852804032304, 0.1950903220161283, 0.8314696123025455, -0.8314696123025451, -0.19509032201612803, 0.9807852804032307, -0.5555702330196015, -0.5555702330196026, 0.9807852804032304, -0.19509032201612858, -0.8314696123025449, 0.8314696123025438, 0.19509032201613036, -0.9807852804032308, 0.5555702330196011, 0.5555702330196061, -0.9807852804032297, 0.19509032201612447, 0.8314696123025471, -0.8314696123025435, -0.19509032201613097, 0.9807852804032309, -0.5555702330196005, -0.5555702330196036, 0.9807852804032302, -0.19509032201612736, -0.8314696123025456, 0.8314696123025451, 0.19509032201612808, -0.9807852804032303, 0.555570233019603 } }, - Array { { 0.5141027441932217, -0.9987954562051724, 0.42755509343028214, 0.5956993044924332, -0.989176509964781, 0.3368898533922202, 0.6715589548470182, -0.9700312531945441, 0.24298017990326243, 0.7409511253549601, -0.9415440651830203, 0.14673047445536033, 0.8032075314806457, -0.9039892931234428, 0.04906767432741668, 0.8577286100002728, -0.8577286100002696, -0.04906767432741925, 0.9039892931234453, -0.8032075314806442, -0.1467304744553664, 0.9415440651830211, -0.740951125354956, -0.24298017990326493, 0.9700312531945451, -0.6715589548470177, -0.3368898533922243, 0.9891765099647811, -0.5956993044924298, -0.42755509343028286, 0.9987954562051726, -0.5141027441932149 } }, - Array { { 0.4713967368259978, -0.9951847266721969, 0.6343932841636456, 0.29028467725446255, -0.9569403357322087, 0.773010453362737, 0.09801714032956081, -0.8819212643483562, 0.8819212643483555, -0.09801714032956124, -0.7730104533627368, 0.9569403357322088, -0.2902846772544621, -0.6343932841636459, 0.9951847266721968, -0.4713967368259935, -0.47139673682599587, 0.9951847266721967, -0.6343932841636466, -0.2902846772544613, 0.9569403357322086, -0.7730104533627373, -0.09801714032956038, 0.881921264348355, -0.8819212643483548, 0.0980171403295599, 0.7730104533627375, -0.9569403357322085, 0.29028467725446083, 0.634393284163647, -0.9951847266721959, 0.47139673682598915 } }, - Array { { 0.4275550934302822, -0.970031253194544, 0.803207531480645, -0.04906767432741754, -0.7409511253549599, 0.989176509964781, -0.5141027441932212, -0.33688985339221955, 0.9415440651830208, -0.8577286100002717, 0.14673047445536033, 0.6715589548470199, -0.9987954562051723, 0.5956993044924335, 0.24298017990326776, -0.9039892931234438, 0.9039892931234441, -0.2429801799032616, -0.5956993044924329, 0.9987954562051726, -0.6715589548470179, -0.14673047445536663, 0.8577286100002731, -0.941544065183021, 0.33688985339221694, 0.5141027441932221, -0.9891765099647817, 0.740951125354958, 0.04906767432741681, -0.8032075314806467, 0.9700312531945422, -0.42755509343028464 } }, - Array { { 0.38268343236508984, -0.9238795325112868, 0.9238795325112865, -0.3826834323650899, -0.38268343236509056, 0.9238795325112867, -0.9238795325112864, 0.38268343236508956, 0.3826834323650909, -0.9238795325112876, 0.9238795325112868, -0.3826834323650892, -0.3826834323650912, 0.9238795325112877, -0.9238795325112854, 0.38268343236508556, 0.3826834323650883, -0.9238795325112865, 0.9238795325112866, -0.3826834323650885, -0.38268343236509195, 0.9238795325112881, -0.9238795325112851, 0.3826834323650849, 0.382683432365089, -0.9238795325112868, 0.9238795325112863, -0.3826834323650813, -0.3826834323650926, 0.9238795325112856, -0.9238795325112849, 0.3826834323650908 } }, - Array { { 0.33688985339222005, -0.8577286100002721, 0.9891765099647809, -0.6715589548470177, 0.04906767432741742, 0.5956993044924335, -0.9700312531945443, 0.9039892931234429, -0.42755509343028003, -0.24298017990326395, 0.8032075314806457, -0.9987954562051723, 0.7409511253549588, -0.1467304744553635, -0.5141027441932244, 0.941544065183021, -0.9415440651830213, 0.5141027441932188, 0.146730474455363, -0.7409511253549584, 0.9987954562051726, -0.8032075314806439, 0.24298017990326443, 0.42755509343028597, -0.9039892931234442, 0.9700312531945441, -0.5956993044924352, -0.04906767432742757, 0.6715589548470239, -0.9891765099647817, 0.8577286100002706, -0.33688985339221944 } }, - Array { { 0.29028467725446233, -0.7730104533627371, 0.9951847266721969, -0.8819212643483548, 0.47139673682599736, 0.09801714032956081, -0.6343932841636456, 0.9569403357322094, -0.9569403357322089, 0.6343932841636444, -0.09801714032956099, -0.47139673682599875, 0.8819212643483564, -0.9951847266721968, 0.7730104533627352, -0.2902846772544582, -0.2902846772544613, 0.7730104533627373, -0.9951847266721972, 0.8819212643483533, -0.4713967368259928, -0.09801714032956063, 0.6343932841636468, -0.9569403357322098, 0.9569403357322074, -0.6343932841636404, 0.09801714032955235, 0.47139673682599387, -0.8819212643483538, 0.9951847266721969, -0.7730104533627365, 0.2902846772544601 } }, - Array { { 0.24298017990326398, -0.6715589548470187, 0.9415440651830209, -0.989176509964781, 0.8032075314806448, -0.4275550934302818, -0.04906767432741852, 0.5141027441932239, -0.8577286100002726, 0.9987954562051724, -0.9039892931234428, 0.5956993044924335, -0.1467304744553635, -0.3368898533922236, 0.7409511253549605, -0.9700312531945442, 0.9700312531945442, -0.740951125354956, 0.33688985339221716, 0.14673047445536325, -0.5956993044924334, 0.9039892931234457, -0.9987954562051722, 0.8577286100002709, -0.5141027441932149, 0.049067674327418764, 0.4275550934302864, -0.8032075314806426, 0.9891765099647812, -0.9415440651830184, 0.6715589548470194, -0.24298017990325993 } }, - Array { { 0.19509032201612833, -0.5555702330196022, 0.8314696123025455, -0.9807852804032307, 0.9807852804032304, -0.831469612302545, 0.5555702330196015, -0.19509032201612858, -0.19509032201613025, 0.5555702330196028, -0.831469612302545, 0.9807852804032309, -0.9807852804032297, 0.8314696123025456, -0.5555702330196007, 0.19509032201612425, 0.1950903220161276, -0.5555702330196036, 0.8314696123025475, -0.9807852804032303, 0.9807852804032301, -0.8314696123025431, 0.555570233019603, -0.1950903220161269, -0.19509032201612497, 0.5555702330196073, -0.8314696123025459, 0.9807852804032298, -0.9807852804032293, 0.8314696123025446, -0.5555702330196052, 0.19509032201612256 } }, - Array { { 0.14673047445536175, -0.4275550934302825, 0.6715589548470188, -0.8577286100002723, 0.9700312531945443, -0.9987954562051724, 0.9415440651830204, -0.8032075314806446, 0.5956993044924337, -0.33688985339221794, 0.04906767432741668, 0.24298017990326776, -0.5141027441932244, 0.7409511253549605, -0.9039892931234439, 0.989176509964781, -0.989176509964781, 0.9039892931234439, -0.7409511253549558, 0.5141027441932183, -0.24298017990326087, -0.04906767432742023, 0.33688985339222133, -0.5956993044924337, 0.8032075314806446, -0.9415440651830204, 0.9987954562051723, -0.9700312531945448, 0.8577286100002668, -0.6715589548470114, 0.4275550934302745, -0.14673047445535428 } }, - Array { { 0.09801714032956077, -0.29028467725446244, 0.471396736825998, -0.6343932841636454, 0.7730104533627377, -0.8819212643483562, 0.9569403357322094, -0.995184726672197, 0.9951847266721968, -0.9569403357322088, 0.8819212643483553, -0.7730104533627375, 0.6343932841636439, -0.47139673682599326, 0.2902846772544615, -0.09801714032955673, -0.09801714032956038, 0.29028467725446505, -0.4713967368259965, 0.6343932841636468, -0.7730104533627399, 0.8819212643483553, -0.9569403357322078, 0.9951847266721968, -0.9951847266721966, 0.9569403357322073, -0.881921264348351, 0.7730104533627387, -0.6343932841636453, 0.47139673682599476, -0.29028467725445634, 0.09801714032955137 } }, - Array { { 0.049067674327418126, -0.1467304744553623, 0.24298017990326423, -0.336889853392221, 0.4275550934302828, -0.5141027441932238, 0.595699304492435, -0.6715589548470199, 0.7409511253549602, -0.8032075314806458, 0.8577286100002728, -0.9039892931234438, 0.941544065183021, -0.9700312531945442, 0.989176509964781, -0.9987954562051724, 0.9987954562051724, -0.989176509964781, 0.9700312531945441, -0.941544065183021, 0.9039892931234437, -0.8577286100002726, 0.8032075314806414, -0.7409511253549601, 0.6715589548470144, -0.5956993044924349, 0.5141027441932174, -0.4275550934302842, 0.3368898533922158, -0.2429801799032666, 0.14673047445535767, -0.049067674327421214 } }, - Array { { 6.123233995736766e-17, -1.8369701987210297e-16, 3.061616997868383e-16, -4.286263797015736e-16, 5.51091059616309e-16, -2.4499125789312946e-15, -9.803364199544708e-16, -2.6948419387607653e-15, -7.354070601250002e-16, -2.939771298590236e-15, -4.904777002955296e-16, -3.1847006584197066e-15, -2.45548340466059e-16, -3.4296300182491773e-15, -6.189806365883577e-19, -3.674559378078648e-15, 2.443103791928823e-16, -3.919488737908119e-15, 4.892397390223529e-16, -4.164418097737589e-15, 7.839596456452825e-15, -4.40934745756706e-15, 9.790984586812941e-16, 2.4511505402044715e-15, 8.329455176111767e-15, -4.899206177226001e-15, 1.4689571783402355e-15, 1.96129182054553e-15, 8.819313895770708e-15, -5.389064896884942e-15, 1.9588158979991767e-15, 1.471433100886589e-15 } }, - Array { { -0.04906767432741801, 0.14673047445536194, -0.2429801799032628, 0.3368898533922202, -0.4275550934302818, 0.5141027441932227, -0.5956993044924338, 0.6715589548470184, -0.7409511253549589, 0.8032075314806444, -0.8577286100002696, 0.9039892931234441, -0.9415440651830213, 0.9700312531945442, -0.989176509964781, 0.9987954562051724, -0.9987954562051724, 0.9891765099647811, -0.9700312531945443, 0.9415440651830214, -0.9039892931234473, 0.8577286100002698, -0.8032075314806426, 0.7409511253549568, -0.6715589548470162, 0.5956993044924314, -0.51410274419322, 0.42755509343028064, -0.336889853392219, 0.24298017990326326, -0.14673047445536155, 0.04906767432741827 } }, - Array { { -0.09801714032956065, 0.29028467725446205, -0.4713967368259975, 0.6343932841636447, -0.773010453362737, 0.8819212643483555, -0.9569403357322089, 0.9951847266721968, -0.995184726672197, 0.9569403357322095, -0.8819212643483565, 0.7730104533627371, -0.634393284163649, 0.4713967368259993, -0.2902846772544615, 0.09801714032956405, 0.0980171403295599, -0.29028467725445756, 0.47139673682599564, -0.6343932841636404, 0.773010453362739, -0.8819212643483545, 0.9569403357322073, -0.9951847266721959, 0.9951847266721969, -0.9569403357322102, 0.8819212643483592, -0.7730104533627362, 0.6343932841636479, -0.47139673682600425, 0.2902846772544601, -0.09801714032956259 } }, - Array { { -0.14673047445536164, 0.42755509343028214, -0.6715589548470177, 0.8577286100002719, -0.9700312531945441, 0.9987954562051724, -0.9415440651830209, 0.8032075314806457, -0.5956993044924354, 0.33688985339222016, -0.04906767432741925, -0.2429801799032616, 0.5141027441932188, -0.740951125354956, 0.9039892931234439, -0.989176509964781, 0.9891765099647811, -0.9039892931234442, 0.7409511253549612, -0.5141027441932254, 0.2429801799032623, 0.04906767432741142, -0.33688985339221944, 0.5956993044924263, -0.8032075314806432, 0.9415440651830218, -0.9987954562051722, 0.9700312531945438, -0.8577286100002759, 0.6715589548470194, -0.42755509343029086, 0.14673047445536544 } }, - Array { { -0.1950903220161282, 0.5555702330196018, -0.8314696123025451, 0.9807852804032304, -0.9807852804032307, 0.8314696123025448, -0.5555702330196027, 0.19509032201613036, 0.19509032201612822, -0.555570233019601, 0.8314696123025456, -0.9807852804032295, 0.9807852804032309, -0.8314696123025455, 0.5555702330196066, -0.19509032201613144, -0.19509032201612714, 0.555570233019603, -0.8314696123025429, 0.9807852804032301, -0.9807852804032304, 0.831469612302544, -0.5555702330196105, 0.19509032201613602, 0.19509032201612256, -0.5555702330195991, 0.8314696123025443, -0.9807852804032305, 0.98078528040323, -0.8314696123025506, 0.5555702330196085, -0.1950903220161336 } }, - Array { { -0.24298017990326387, 0.6715589548470183, -0.9415440651830205, 0.9891765099647811, -0.8032075314806455, 0.4275550934302814, 0.049067674327416926, -0.5141027441932223, 0.8577286100002715, -0.9987954562051723, 0.9039892931234453, -0.5956993044924329, 0.146730474455363, 0.33688985339221716, -0.7409511253549558, 0.9700312531945441, -0.9700312531945443, 0.7409511253549612, -0.33688985339221805, -0.14673047445536205, 0.5956993044924321, -0.9039892931234419, 0.9987954562051726, -0.8577286100002757, 0.5141027441932292, -0.04906767432742855, -0.42755509343028375, 0.8032075314806449, -0.9891765099647807, 0.941544065183022, -0.6715589548470223, 0.24298017990327087 } }, - Array { { -0.29028467725446216, 0.7730104533627367, -0.9951847266721969, 0.8819212643483553, -0.4713967368259983, -0.09801714032956124, 0.6343932841636444, -0.9569403357322088, 0.9569403357322095, -0.6343932841636489, 0.09801714032956356, 0.47139673682599625, -0.8819212643483549, 0.9951847266721968, -0.7730104533627398, 0.2902846772544653, 0.29028467725446083, -0.7730104533627368, 0.9951847266721963, -0.8819212643483538, 0.47139673682600036, 0.09801714032955186, -0.6343932841636453, 0.9569403357322072, -0.9569403357322082, 0.6343932841636479, -0.09801714032956942, -0.47139673682599736, 0.8819212643483522, -0.9951847266721966, 0.773010453362739, -0.2902846772544709 } }, - Array { { -0.33688985339221994, 0.857728610000272, -0.9891765099647811, 0.6715589548470182, -0.04906767432741852, -0.5956993044924338, 0.9700312531945435, -0.9039892931234437, 0.4275550934302851, 0.24298017990326515, -0.8032075314806442, 0.9987954562051726, -0.7409511253549584, 0.14673047445536325, 0.5141027441932183, -0.941544065183021, 0.9415440651830214, -0.5141027441932254, -0.14673047445536205, 0.7409511253549529, -0.9987954562051722, 0.8032075314806449, -0.24298017990327322, -0.4275550934302776, 0.9039892931234431, -0.9700312531945464, 0.5956993044924377, 0.0490676743274173, -0.6715589548470108, 0.9891765099647801, -0.8577286100002726, 0.33688985339223004 } }, - Array { { -0.3826834323650897, 0.9238795325112865, -0.9238795325112867, 0.38268343236509067, 0.38268343236508956, -0.923879532511287, 0.9238795325112876, -0.3826834323650912, -0.382683432365089, 0.9238795325112867, -0.9238795325112865, 0.3826834323650885, 0.3826834323650851, -0.9238795325112851, 0.9238795325112881, -0.3826834323650924, -0.3826834323650813, 0.9238795325112835, -0.9238795325112897, 0.3826834323650962, 0.382683432365084, -0.9238795325112846, 0.9238795325112886, -0.3826834323650935, -0.38268343236508673, 0.9238795325112857, -0.9238795325112874, 0.3826834323650908, 0.38268343236508945, -0.9238795325112868, 0.9238795325112863, -0.38268343236508806 } }, - Array { { -0.42755509343028186, 0.970031253194544, -0.8032075314806454, 0.0490676743274184, 0.7409511253549591, -0.9891765099647809, 0.5141027441932241, 0.33688985339221783, -0.9415440651830214, 0.8577286100002729, -0.1467304744553664, -0.6715589548470179, 0.9987954562051726, -0.5956993044924334, -0.24298017990326087, 0.9039892931234437, -0.9039892931234473, 0.2429801799032623, 0.5956993044924321, -0.9987954562051722, 0.6715589548470242, 0.14673047445536494, -0.8577286100002721, 0.9415440651830218, -0.33688985339222594, -0.5141027441932137, 0.9891765099647812, -0.7409511253549601, -0.04906767432741338, 0.8032075314806403, -0.9700312531945466, 0.427555093430282 } }, - Array { { -0.4713967368259977, 0.9951847266721969, -0.6343932841636454, -0.29028467725446255, 0.9569403357322089, -0.7730104533627368, -0.09801714032956099, 0.8819212643483553, -0.8819212643483565, 0.09801714032956356, 0.7730104533627351, -0.9569403357322097, 0.29028467725446505, 0.6343932841636434, -0.9951847266721972, 0.4713967368259999, 0.47139673682598915, -0.9951847266721966, 0.6343932841636528, 0.2902846772544601, -0.9569403357322062, 0.7730104533627383, 0.09801714032955137, -0.881921264348354, 0.8819212643483594, -0.09801714032956259, -0.7730104533627312, 0.9569403357322094, -0.2902846772544709, -0.6343932841636442, 0.9951847266721977, -0.47139673682601163 } }, - Array { { -0.5141027441932217, 0.9987954562051724, -0.4275550934302827, -0.5956993044924326, 0.9891765099647809, -0.33688985339221983, -0.6715589548470184, 0.9700312531945441, -0.24298017990326443, -0.7409511253549561, 0.9415440651830211, -0.14673047445536663, -0.8032075314806439, 0.9039892931234457, -0.04906767432742023, -0.8577286100002726, 0.8577286100002698, 0.04906767432741142, -0.9039892931234419, 0.8032075314806449, 0.14673047445536494, -0.9415440651830181, 0.7409511253549621, 0.2429801799032628, -0.9700312531945445, 0.6715589548470249, 0.33688985339221483, -0.9891765099647807, 0.5956993044924325, 0.42755509343027315, -0.9987954562051727, 0.5141027441932245 } }, - Array { { -0.555570233019602, 0.9807852804032304, -0.19509032201612803, -0.831469612302545, 0.8314696123025448, 0.19509032201612844, -0.9807852804032303, 0.5555702330196061, 0.5555702330196038, -0.9807852804032302, 0.1950903220161276, 0.8314696123025452, -0.8314696123025456, -0.19509032201612714, 0.9807852804032301, -0.5555702330196102, -0.5555702330196056, 0.9807852804032298, -0.19509032201612544, -0.8314696123025465, 0.8314696123025443, 0.1950903220161293, -0.9807852804032305, 0.5555702330196024, 0.5555702330196015, -0.9807852804032308, 0.19509032201613025, 0.8314696123025438, -0.831469612302547, -0.19509032201612447, 0.9807852804032268, -0.5555702330196183 } }, - Array { { -0.5956993044924334, 0.9415440651830209, 0.04906767432741742, -0.9700312531945441, 0.5141027441932239, 0.6715589548470184, -0.9039892931234437, -0.1467304744553635, 0.9891765099647806, -0.4275550934302822, -0.740951125354956, 0.8577286100002731, 0.24298017990326443, -0.9987954562051722, 0.33688985339222133, 0.8032075314806414, -0.8032075314806426, -0.33688985339221944, 0.9987954562051726, -0.24298017990327322, -0.8577286100002721, 0.7409511253549621, 0.42755509343027404, -0.9891765099647809, 0.14673047445536544, 0.9039892931234398, -0.6715589548470173, -0.5141027441932191, 0.9700312531945459, -0.04906767432741582, -0.9415440651830153, 0.5956993044924388 } }, - Array { { -0.6343932841636454, 0.881921264348355, 0.29028467725446266, -0.9951847266721969, 0.09801714032956282, 0.9569403357322088, -0.47139673682599875, -0.7730104533627375, 0.7730104533627371, 0.47139673682599625, -0.9569403357322097, -0.09801714032955648, 0.9951847266721964, -0.290284677254462, -0.8819212643483513, 0.6343932841636472, 0.6343932841636483, -0.8819212643483573, -0.2902846772544634, 0.9951847266721976, -0.09801714032956209, -0.956940335732206, 0.47139673682600125, 0.7730104533627381, -0.7730104533627412, -0.4713967368259969, 0.9569403357322115, 0.09801714032955722, -0.9951847266721972, 0.2902846772544681, 0.8819212643483483, -0.6343932841636412 } }, - Array { { -0.6715589548470184, 0.8032075314806453, 0.5141027441932213, -0.9039892931234434, -0.33688985339221816, 0.970031253194544, 0.1467304744553601, -0.9987954562051724, 0.04906767432742292, 0.9891765099647806, -0.24298017990326493, -0.941544065183021, 0.42755509343028597, 0.8577286100002709, -0.5956993044924337, -0.7409511253549601, 0.7409511253549568, 0.5956993044924263, -0.8577286100002757, -0.4275550934302776, 0.9415440651830218, 0.2429801799032628, -0.9891765099647809, -0.04906767432742072, 0.998795456205172, -0.1467304744553693, -0.9700312531945426, 0.3368898533922236, 0.9039892931234365, -0.5141027441932339, -0.8032075314806376, 0.671558954847026 } }, - Array { { -0.7071067811865475, 0.7071067811865477, 0.7071067811865466, -0.7071067811865474, -0.7071067811865464, 0.7071067811865476, 0.707106781186546, -0.7071067811865479, -0.7071067811865458, 0.7071067811865507, 0.707106781186548, -0.7071067811865483, -0.7071067811865452, 0.7071067811865511, 0.7071067811865425, -0.7071067811865539, -0.7071067811865498, 0.7071067811865467, 0.707106781186547, -0.7071067811865495, -0.7071067811865442, 0.7071067811865522, 0.7071067811865415, -0.707106781186555, -0.7071067811865487, 0.7071067811865477, 0.707106781186546, -0.7071067811865606, -0.7071067811865432, 0.7071067811865432, 0.7071067811865405, -0.707106781186546 } }, - Array { { -0.7409511253549589, 0.5956993044924332, 0.8577286100002719, -0.4275550934302813, -0.9415440651830203, 0.2429801799032641, 0.9891765099647806, -0.04906767432741925, -0.9987954562051724, -0.146730474455363, 0.9700312531945451, 0.33688985339221694, -0.9039892931234442, -0.5141027441932149, 0.8032075314806446, 0.6715589548470144, -0.6715589548470162, -0.8032075314806432, 0.5141027441932292, 0.9039892931234431, -0.33688985339222594, -0.9700312531945445, 0.14673047445536544, 0.998795456205172, 0.04906767432741681, -0.989176509964782, -0.24298017990326515, 0.9415440651830271, 0.4275550934302855, -0.8577286100002731, -0.595699304492427, 0.7409511253549683 } }, - Array { { -0.773010453362737, 0.471396736825998, 0.9569403357322085, -0.0980171403295627, -0.995184726672197, -0.2902846772544621, 0.8819212643483564, 0.6343932841636439, -0.634393284163649, -0.8819212643483549, 0.29028467725446505, 0.9951847266721964, 0.09801714032955966, -0.9569403357322078, -0.47139673682599215, 0.7730104533627381, 0.7730104533627387, -0.47139673682600386, -0.9569403357322082, 0.09801714032955867, 0.9951847266721977, 0.29028467725445917, -0.8819212643483545, -0.6343932841636388, 0.6343932841636487, 0.8819212643483552, -0.2902846772544578, -0.995184726672195, -0.098017140329546, 0.9569403357322118, 0.4713967368259926, -0.7730104533627378 } }, - Array { { -0.8032075314806448, 0.33688985339222005, 0.9987954562051724, 0.24298017990326243, -0.8577286100002726, -0.7409511253549589, 0.4275550934302851, 0.9891765099647806, 0.1467304744553596, -0.903989293123444, -0.6715589548470177, 0.5141027441932221, 0.9700312531945441, 0.049067674327418764, -0.9415440651830204, -0.5956993044924349, 0.5956993044924314, 0.9415440651830218, -0.04906767432742855, -0.9700312531945464, -0.5141027441932137, 0.6715589548470249, 0.9039892931234398, -0.1467304744553693, -0.989176509964782, -0.42755509343027626, 0.7409511253549631, 0.857728610000262, -0.24298017990326848, -0.9987954562051733, -0.3368898533922167, 0.8032075314806552 } }, - Array { { -0.8314696123025453, 0.19509032201612878, 0.9807852804032307, 0.5555702330196015, -0.5555702330196027, -0.9807852804032303, -0.19509032201612808, 0.8314696123025471, 0.8314696123025455, -0.19509032201613122, -0.9807852804032303, -0.5555702330196002, 0.5555702330196071, 0.9807852804032301, 0.19509032201612303, -0.83146961230255, -0.8314696123025465, 0.19509032201612928, 0.9807852804032313, 0.5555702330195958, -0.5555702330196114, -0.9807852804032304, -0.19509032201612497, 0.8314696123025489, 0.8314696123025397, -0.1950903220161413, -0.9807852804032337, -0.5555702330196093, 0.5555702330195978, 0.9807852804032309, 0.1950903220161269, -0.8314696123025479 } }, - Array { { -0.857728610000272, 0.049067674327418154, 0.9039892931234434, 0.8032075314806447, -0.14673047445536216, -0.9415440651830209, -0.7409511253549563, 0.242980179903268, 0.9700312531945451, 0.6715589548470151, -0.3368898533922243, -0.9891765099647817, -0.5956993044924352, 0.4275550934302864, 0.9987954562051723, 0.5141027441932174, -0.51410274419322, -0.9987954562051722, -0.42755509343028375, 0.5956993044924377, 0.9891765099647812, 0.33688985339221483, -0.6715589548470173, -0.9700312531945426, -0.24298017990326515, 0.7409511253549631, 0.9415440651830211, 0.1467304744553698, -0.8032075314806528, -0.9039892931234407, -0.049067674327418764, 0.8577286100002681 } }, - Array { { -0.8819212643483549, -0.09801714032955997, 0.7730104533627377, 0.9569403357322089, 0.2902846772544622, -0.6343932841636459, -0.9951847266721968, -0.47139673682599326, 0.4713967368259993, 0.9951847266721968, 0.6343932841636434, -0.290284677254462, -0.9569403357322078, -0.7730104533627321, 0.09801714032956502, 0.8819212643483556, 0.8819212643483558, 0.09801714032955137, -0.7730104533627409, -0.9569403357322079, -0.29028467725446244, 0.634393284163654, 0.9951847266721962, 0.4713967368259935, -0.47139673682601163, -0.9951847266721967, -0.634393284163638, 0.29028467725445495, 0.9569403357322098, 0.7730104533627278, -0.0980171403295577, -0.8819212643483589 } }, - Array { { -0.9039892931234433, -0.2429801799032628, 0.5956993044924335, 0.9987954562051724, 0.6715589548470184, -0.14673047445536241, -0.857728610000271, -0.9415440651830213, -0.3368898533922206, 0.5141027441932219, 0.9891765099647811, 0.740951125354958, -0.04906767432742757, -0.8032075314806426, -0.9700312531945448, -0.4275550934302842, 0.42755509343028064, 0.9700312531945438, 0.8032075314806449, 0.0490676743274173, -0.7409511253549601, -0.9891765099647807, -0.5141027441932191, 0.3368898533922236, 0.9415440651830271, 0.857728610000262, 0.1467304744553698, -0.6715589548470129, -0.9987954562051727, -0.595699304492438, 0.24298017990325896, 0.9039892931234415 } }, - Array { { -0.9238795325112867, -0.3826834323650899, 0.38268343236509067, 0.9238795325112875, 0.9238795325112868, 0.3826834323650891, -0.38268343236509145, -0.9238795325112865, -0.9238795325112852, -0.3826834323650883, 0.382683432365089, 0.9238795325112882, 0.9238795325112835, 0.3826834323650908, -0.38268343236509306, -0.9238795325112898, -0.9238795325112873, -0.38268343236508673, 0.3826834323650971, 0.9238795325112862, 0.9238795325112856, 0.3826834323650826, -0.38268343236508806, -0.9238795325112878, -0.9238795325112893, -0.38268343236507857, 0.38268343236509217, 0.9238795325112841, 0.9238795325112822, 0.3826834323650876, -0.38268343236508306, -0.9238795325112912 } }, - Array { { -0.9415440651830207, -0.5141027441932214, 0.1467304744553618, 0.7409511253549601, 0.9987954562051724, 0.8032075314806444, 0.24298017990326515, -0.4275550934302822, -0.903989293123444, -0.9700312531945433, -0.5956993044924298, 0.04906767432741681, 0.6715589548470239, 0.9891765099647812, 0.8577286100002668, 0.3368898533922158, -0.336889853392219, -0.8577286100002759, -0.9891765099647807, -0.6715589548470108, -0.04906767432741338, 0.5956993044924325, 0.9700312531945459, 0.9039892931234365, 0.4275550934302855, -0.24298017990326848, -0.8032075314806528, -0.9987954562051727, -0.7409511253549578, -0.14673047445535137, 0.5141027441932381, 0.9415440651830205 } }, - Array { { -0.9569403357322088, -0.6343932841636448, -0.09801714032955972, 0.4713967368259984, 0.8819212643483563, 0.9951847266721968, 0.7730104533627352, 0.2902846772544615, -0.2902846772544615, -0.7730104533627398, -0.9951847266721972, -0.8819212643483513, -0.47139673682599215, 0.09801714032956502, 0.6343932841636476, 0.9569403357322092, 0.9569403357322092, 0.6343932841636476, 0.09801714032955088, -0.4713967368260047, -0.8819212643483579, -0.9951847266721965, -0.7730104533627352, -0.2902846772544615, 0.2902846772544615, 0.7730104533627352, 0.9951847266721965, 0.8819212643483579, 0.47139673682597966, -0.09801714032957916, -0.6343932841636586, -0.9569403357322133 } }, - Array { { -0.970031253194544, -0.7409511253549593, -0.3368898533922201, 0.14673047445536203, 0.5956993044924352, 0.9039892931234438, 0.9987954562051724, 0.8577286100002712, 0.5141027441932186, 0.04906767432741926, -0.42755509343028286, -0.8032075314806467, -0.9891765099647817, -0.9415440651830184, -0.6715589548470114, -0.2429801799032666, 0.24298017990326326, 0.6715589548470194, 0.941544065183022, 0.9891765099647801, 0.8032075314806403, 0.42755509343027315, -0.04906767432741582, -0.5141027441932339, -0.8577286100002731, -0.9987954562051733, -0.9039892931234407, -0.595699304492438, -0.14673047445535137, 0.33688985339221855, 0.740951125354969, 0.9700312531945446 } }, - Array { { -0.9807852804032304, -0.8314696123025451, -0.5555702330196015, -0.19509032201612858, 0.19509032201613036, 0.5555702330196061, 0.8314696123025471, 0.9807852804032309, 0.9807852804032302, 0.8314696123025451, 0.555570233019603, 0.19509032201613025, -0.19509032201613216, -0.5555702330196105, -0.8314696123025462, -0.980785280403232, -0.9807852804032305, -0.8314696123025421, -0.5555702330196044, -0.19509032201612497, 0.19509032201613746, 0.5555702330196032, 0.8314696123025413, 0.9807852804032302, 0.9807852804032294, 0.8314696123025391, 0.5555702330195881, 0.1950903220161336, -0.1950903220161288, -0.5555702330196076, -0.8314696123025522, -0.9807852804032341 } }, - Array { { -0.989176509964781, -0.9039892931234431, -0.7409511253549592, -0.5141027441932225, -0.24298017990326207, 0.04906767432742268, 0.3368898533922204, 0.5956993044924359, 0.8032075314806442, 0.9415440651830214, 0.9987954562051726, 0.9700312531945422, 0.8577286100002706, 0.6715589548470194, 0.4275550934302745, 0.14673047445535767, -0.14673047445536155, -0.42755509343029086, -0.6715589548470223, -0.8577286100002726, -0.9700312531945466, -0.9987954562051727, -0.9415440651830153, -0.8032075314806376, -0.595699304492427, -0.3368898533922167, -0.049067674327418764, 0.24298017990325896, 0.5141027441932381, 0.740951125354969, 0.9039892931234478, 0.9891765099647819 } }, - Array { { -0.9951847266721968, -0.9569403357322085, -0.8819212643483547, -0.7730104533627357, -0.6343932841636443, -0.4713967368259935, -0.2902846772544582, -0.09801714032955673, 0.09801714032956405, 0.2902846772544653, 0.4713967368259999, 0.6343932841636472, 0.7730104533627381, 0.8819212643483556, 0.9569403357322092, 0.9951847266721969, 0.9951847266721969, 0.9569403357322089, 0.8819212643483554, 0.7730104533627378, 0.6343932841636468, 0.47139673682599953, 0.29028467725445123, 0.09801714032956356, -0.09801714032957136, -0.2902846772544587, -0.4713967368260064, -0.6343932841636418, -0.7730104533627428, -0.8819212643483524, -0.9569403357322113, -0.9951847266721963 } }, - Array { { -0.9987954562051724, -0.989176509964781, -0.9700312531945441, -0.9415440651830203, -0.9039892931234428, -0.8577286100002696, -0.8032075314806442, -0.740951125354956, -0.6715589548470177, -0.5956993044924298, -0.5141027441932149, -0.42755509343028464, -0.33688985339221944, -0.24298017990325993, -0.14673047445535428, -0.049067674327421214, 0.04906767432741827, 0.14673047445536544, 0.24298017990327087, 0.33688985339223004, 0.427555093430282, 0.5141027441932245, 0.5956993044924388, 0.671558954847026, 0.7409511253549683, 0.8032075314806552, 0.8577286100002681, 0.9039892931234415, 0.9415440651830205, 0.9700312531945446, 0.9891765099647819, 0.9987954562051728 } }, - Array { { -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0 } }, - Array { { -0.9987954562051724, -0.9891765099647811, -0.9700312531945443, -0.9415440651830209, -0.9039892931234437, -0.857728610000271, -0.803207531480646, -0.7409511253549584, -0.6715589548470208, -0.5956993044924335, -0.5141027441932254, -0.4275550934302833, -0.33688985339221855, -0.24298017990327322, -0.14673047445536833, -0.0490676743274217, 0.0490676743274173, 0.14673047445536397, 0.24298017990325518, 0.3368898533922144, 0.42755509343027936, 0.5141027441932094, 0.5956993044924357, 0.6715589548470122, 0.7409511253549459, 0.8032075314806435, 0.857728610000265, 0.9039892931234449, 0.9415440651830181, 0.9700312531945394, 0.9891765099647807, 0.9987954562051717 } }, - Array { { -0.9951847266721969, -0.9569403357322087, -0.8819212643483562, -0.7730104533627368, -0.6343932841636459, -0.47139673682599587, -0.2902846772544613, -0.09801714032956038, 0.0980171403295599, 0.29028467725446083, 0.47139673682598915, 0.6343932841636483, 0.7730104533627387, 0.8819212643483558, 0.9569403357322092, 0.9951847266721969, 0.9951847266721969, 0.9569403357322094, 0.8819212643483564, 0.7730104533627393, 0.63439328416366, 0.47139673682599, 0.29028467725445495, 0.0980171403295538, -0.09801714032956649, -0.29028467725446716, -0.47139673682600125, -0.6343932841636479, -0.7730104533627383, -0.8819212643483556, -0.9569403357322089, -0.9951847266721968 } }, - Array { { -0.989176509964781, -0.9039892931234433, -0.74095112535496, -0.514102744193224, -0.2429801799032642, 0.049067674327419986, 0.3368898533922174, 0.5956993044924329, 0.8032075314806417, 0.9415440651830198, 0.9987954562051724, 0.9700312531945453, 0.8577286100002701, 0.6715589548470191, 0.4275550934302873, 0.1467304744553722, -0.14673047445536058, -0.4275550934302767, -0.6715589548470104, -0.857728610000264, -0.9700312531945425, -0.9987954562051722, -0.9415440651830261, -0.8032075314806487, -0.5956993044924309, -0.33688985339223515, -0.049067674327424635, 0.2429801799032666, 0.5141027441932078, 0.7409511253549544, 0.9039892931234444, 0.9891765099647786 } }, - Array { { -0.9807852804032304, -0.8314696123025456, -0.5555702330196026, -0.19509032201613025, 0.19509032201612822, 0.5555702330196038, 0.8314696123025455, 0.9807852804032302, 0.980785280403231, 0.8314696123025477, 0.5555702330196073, 0.1950903220161288, -0.1950903220161192, -0.5555702330195991, -0.8314696123025462, -0.9807852804032291, -0.9807852804032308, -0.8314696123025509, -0.5555702330196061, -0.1950903220161413, 0.19509032201613458, 0.5555702330196003, 0.8314696123025391, 0.9807852804032267, 0.9807852804032304, 0.83146961230255, 0.5555702330196166, 0.19509032201612592, -0.1950903220161221, -0.5555702330195897, -0.8314696123025479, -0.9807852804032297 } }, - Array { { -0.970031253194544, -0.7409511253549599, -0.33688985339221955, 0.14673047445536033, 0.5956993044924335, 0.9039892931234441, 0.9987954562051726, 0.8577286100002731, 0.5141027441932221, 0.04906767432741681, -0.42755509343028464, -0.8032075314806391, -0.9891765099647798, -0.9415440651830229, -0.671558954847022, -0.24298017990326706, 0.2429801799032623, 0.6715589548470184, 0.9415440651830214, 0.9891765099647826, 0.8032075314806505, 0.4275550934302891, -0.049067674327411916, -0.5141027441932179, -0.8577286100002706, -0.9987954562051723, -0.9039892931234431, -0.5956993044924317, -0.14673047445535817, 0.336889853392225, 0.7409511253549447, 0.9700312531945392 } }, - Array { { -0.9569403357322089, -0.6343932841636454, -0.0980171403295627, 0.4713967368259969, 0.8819212643483553, 0.9951847266721967, 0.7730104533627373, 0.29028467725446505, -0.29028467725445756, -0.7730104533627368, -0.9951847266721966, -0.8819212643483573, -0.47139673682600386, 0.09801714032955137, 0.6343932841636476, 0.9569403357322089, 0.9569403357322094, 0.6343932841636487, 0.09801714032956697, -0.47139673682599, -0.8819212643483566, -0.9951847266721981, -0.7730104533627378, -0.2902846772544793, 0.29028467725445684, 0.7730104533627409, 0.9951847266721959, 0.8819212643483543, 0.47139673682601074, -0.0980171403295577, -0.6343932841636305, -0.9569403357322067 } }, - Array { { -0.9415440651830208, -0.514102744193222, 0.14673047445536058, 0.7409511253549589, 0.9987954562051723, 0.8032075314806439, 0.24298017990326823, -0.4275550934302789, -0.9039892931234422, -0.9700312531945444, -0.5956993044924396, 0.04906767432741828, 0.671558954847014, 0.9891765099647812, 0.8577286100002741, 0.3368898533922296, -0.33688985339221805, -0.8577286100002678, -0.989176509964781, -0.6715589548470231, -0.049067674327430505, 0.5956993044924184, 0.9700312531945449, 0.9039892931234444, 0.42755509343028997, -0.24298017990324947, -0.8032075314806324, -0.9987954562051723, -0.7409511253549624, -0.1467304744553727, 0.514102744193207, 0.9415440651830225 } }, - Array { { -0.9238795325112868, -0.38268343236509056, 0.38268343236508956, 0.9238795325112868, 0.9238795325112877, 0.3826834323650883, -0.3826834323650885, -0.9238795325112851, -0.9238795325112868, -0.3826834323650926, 0.3826834323650908, 0.9238795325112833, 0.9238795325112886, 0.38268343236509034, -0.3826834323650799, -0.9238795325112843, -0.9238795325112876, -0.38268343236508806, 0.3826834323650822, 0.9238795325112852, 0.9238795325112867, 0.3826834323650858, -0.38268343236507135, -0.9238795325112807, -0.9238795325112912, -0.38268343236509667, 0.38268343236508673, 0.9238795325112871, 0.9238795325112849, 0.38268343236510755, -0.38268343236507585, -0.9238795325112826 } }, - Array { { -0.9039892931234434, -0.24298017990326348, 0.5956993044924339, 0.9987954562051723, 0.6715589548470174, -0.14673047445536325, -0.8577286100002693, -0.9415440651830225, -0.33688985339222455, 0.5141027441932179, 0.9891765099647803, 0.7409511253549618, -0.04906767432741436, -0.8032075314806429, -0.9700312531945448, -0.42755509343028464, 0.4275550934302798, 0.9700312531945434, 0.8032075314806546, 0.04906767432741974, -0.7409511253549486, -0.9891765099647811, -0.5141027441932347, 0.33688985339221944, 0.9415440651830159, 0.8577286100002721, 0.1467304744553756, -0.6715589548470188, -0.9987954562051731, -0.5956993044924325, 0.24298017990325138, 0.903989293123444 } }, - Array { { -0.881921264348355, -0.09801714032956069, 0.7730104533627358, 0.9569403357322095, 0.29028467725446433, -0.6343932841636466, -0.9951847266721972, -0.4713967368259965, 0.47139673682599564, 0.9951847266721963, 0.6343932841636528, -0.2902846772544634, -0.9569403357322082, -0.7730104533627409, 0.09801714032955088, 0.8819212643483554, 0.8819212643483564, 0.09801714032956697, -0.7730104533627397, -0.9569403357322087, -0.2902846772544653, 0.6343932841636404, 0.9951847266721979, 0.4713967368260099, -0.4713967368259822, -0.9951847266721948, -0.6343932841636426, 0.29028467725446244, 0.9569403357322078, 0.7730104533627414, -0.0980171403295499, -0.8819212643483483 } }, - Array { { -0.8577286100002721, 0.04906767432741742, 0.9039892931234429, 0.8032075314806457, -0.1467304744553635, -0.9415440651830213, -0.7409511253549584, 0.24298017990326443, 0.9700312531945441, 0.6715589548470239, -0.33688985339221944, -0.9891765099647798, -0.5956993044924345, 0.42755509343027404, 0.9987954562051723, 0.5141027441932301, -0.5141027441932191, -0.998795456205173, -0.4275550934302855, 0.5956993044924357, 0.9891765099647838, 0.33688985339223143, -0.6715589548470144, -0.9700312531945436, -0.2429801799032837, 0.7409511253549499, 0.9415440651830231, 0.14673047445536203, -0.8032075314806318, -0.9039892931234499, -0.04906767432742659, 0.8577286100002711 } }, - Array { { -0.8314696123025455, 0.1950903220161272, 0.9807852804032304, 0.5555702330196028, -0.555570233019601, -0.9807852804032302, -0.19509032201613122, 0.8314696123025451, 0.8314696123025477, -0.19509032201611967, -0.9807852804032293, -0.5555702330196048, 0.555570233019602, 0.98078528040323, 0.195090322016137, -0.8314696123025419, -0.831469612302547, 0.19509032201612786, 0.9807852804032281, 0.5555702330195978, -0.5555702330195971, -0.9807852804032339, -0.1950903220161288, 0.8314696123025386, 0.8314696123025425, -0.1950903220161221, -0.980785280403227, -0.5555702330196027, 0.5555702330195922, 0.9807852804032294, 0.19509032201613458, -0.8314696123025354 } }, - Array { { -0.8032075314806449, 0.3368898533922202, 0.9987954562051724, 0.2429801799032641, -0.8577286100002696, -0.7409511253549583, 0.4275550934302822, 0.9891765099647811, 0.14673047445537077, -0.903989293123445, -0.6715589548470162, 0.5141027441932233, 0.9700312531945438, 0.04906767432741827, -0.9415440651830204, -0.5956993044924352, 0.5956993044924306, 0.9415440651830271, -0.0490676743274266, -0.9700312531945459, -0.5141027441932162, 0.6715589548470224, 0.9039892931234415, -0.14673047445536494, -0.9891765099647812, -0.4275550934302811, 0.7409511253549591, 0.8577286100002726, -0.24298017990326182, -0.9987954562051722, -0.33688985339222405, 0.8032075314806417 } }, - Array { { -0.7730104533627371, 0.47139673682599736, 0.9569403357322094, -0.09801714032956099, -0.9951847266721968, -0.2902846772544613, 0.8819212643483533, 0.6343932841636468, -0.6343932841636404, -0.8819212643483538, 0.2902846772544601, 0.9951847266721976, 0.09801714032955867, -0.9569403357322079, -0.4713967368260047, 0.7730104533627378, 0.7730104533627393, -0.47139673682599, -0.9569403357322087, 0.0980171403295421, 0.9951847266721959, 0.29028467725446244, -0.881921264348346, -0.6343932841636533, 0.6343932841636449, 0.8819212643483644, -0.2902846772544521, -0.995184726672197, -0.09801714032958111, 0.9569403357322056, 0.47139673682599953, -0.7730104533627234 } }, - Array { { -0.7409511253549591, 0.5956993044924327, 0.8577286100002725, -0.4275550934302798, -0.9415440651830222, 0.24298017990326493, 0.9891765099647811, -0.049067674327415586, -0.9987954562051722, -0.14673047445536058, 0.9700312531945421, 0.3368898533922222, -0.9039892931234447, -0.5141027441932267, 0.8032075314806446, 0.6715589548470253, -0.6715589548470154, -0.803207531480644, 0.5141027441932153, 0.9039892931234503, -0.33688985339222316, -0.9700312531945453, 0.1467304744553475, 0.9987954562051722, 0.0490676743274217, -0.9891765099647791, -0.24298017990328463, 0.9415440651830201, 0.42755509343029174, -0.857728610000262, -0.5956993044924334, 0.7409511253549532 } }, -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/MP3Types.h b/Userland/Libraries/LibMedia/Audio/MP3Types.h deleted file mode 100644 index bf3d25db564..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MP3Types.h +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2021, Arne Elster - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Audio::MP3 { - -constexpr size_t const frame_size = 1152; -// 576 samples. -constexpr size_t const granule_size = frame_size / 2; - -enum class Mode { - Stereo = 0, - JointStereo = 1, - DualChannel = 2, - SingleChannel = 3, -}; - -enum class ModeExtension { - Stereo = 0, - IntensityStereo = 1, - MsStereo = 2, -}; -AK_ENUM_BITWISE_OPERATORS(ModeExtension) - -enum class Emphasis { - None = 0, - Microseconds_50_15 = 1, - Reserved = 2, - CCITT_J17 = 3, -}; - -enum class BlockType { - Normal = 0, - Start = 1, - Short = 2, - End = 3, -}; - -struct Header { - i32 id { 0 }; - i32 layer { 0 }; - bool protection_bit { false }; - i32 bitrate { 0 }; - i32 samplerate { 0 }; - bool padding_bit { false }; - bool private_bit { false }; - Mode mode { Mode::Stereo }; - ModeExtension mode_extension { ModeExtension::Stereo }; - bool copyright_bit { false }; - bool original_bit { false }; - Emphasis emphasis { Emphasis::None }; - u16 crc16 { 0 }; - size_t header_size { 0 }; - size_t frame_size { 0 }; - size_t slot_count { 0 }; - - size_t channel_count() const { return mode == Mode::SingleChannel ? 1 : 2; } -}; - -struct Granule { - Array samples; - Array, 32> filter_bank_input; - Array, 18> pcm; - u32 part_2_3_length { 0 }; - u32 big_values { 0 }; - u32 global_gain { 0 }; - u32 scalefac_compress { 0 }; - bool window_switching_flag { false }; - BlockType block_type { BlockType::Normal }; - bool mixed_block_flag { false }; - Array table_select; - Array sub_block_gain; - u32 region0_count { 0 }; - u32 region1_count { 0 }; - bool preflag { false }; - bool scalefac_scale { false }; - bool count1table_select { false }; -}; - -struct Channel { - Array granules; - Array scale_factors; - Array scale_factor_selection_info; -}; - -struct MP3Frame { - Header header; - FixedArray channels; - off_t main_data_begin { 0 }; - u32 private_bits { 0 }; - - MP3Frame(Header header) - : header(header) - , channels(FixedArray::must_create_but_fixme_should_propagate_errors(header.channel_count())) - { - } -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/Metadata.cpp b/Userland/Libraries/LibMedia/Audio/Metadata.cpp deleted file mode 100644 index 920a6e53325..00000000000 --- a/Userland/Libraries/LibMedia/Audio/Metadata.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "Metadata.h" -#include -#include - -namespace Audio { - -bool Person::is_artist() const -{ - return role == Person::Role::Artist - || role == Person::Role::Composer - || role == Person::Role::Conductor - || role == Person::Role::Lyricist - || role == Person::Role::Performer; -} - -Optional Person::name_for_role() const -{ - switch (role) { - case Role::Artist: - case Role::Performer: - return {}; - case Role::Lyricist: - return "Lyricist"sv; - case Role::Conductor: - return "Conductor"sv; - case Role::Publisher: - return "Publisher"sv; - case Role::Engineer: - return "Engineer"sv; - case Role::Composer: - return "Composer"sv; - } - VERIFY_NOT_REACHED(); -} - -Optional Metadata::first_artist() const -{ - auto artist = people.find_if([](auto const& person) { return person.is_artist(); }); - if (artist.is_end()) - return {}; - return artist->name; -} - -ErrorOr> Metadata::all_artists(StringView concatenate_with) const -{ - // FIXME: This entire function could be similar to TRY(TRY(people.filter(...).try_map(...)).join(concatenate_with)) if these functional iterator transformers existed :^) - Vector artist_texts; - TRY(artist_texts.try_ensure_capacity(people.size())); - for (auto const& person : people) { - if (!person.is_artist()) - continue; - if (auto role_name = person.name_for_role(); role_name.has_value()) - artist_texts.unchecked_append(TRY(String::formatted("{} ({})", person.name, role_name.release_value()))); - else - artist_texts.unchecked_append(person.name); - } - if (artist_texts.is_empty()) - return Optional {}; - return String::join(concatenate_with, artist_texts); -} - -ErrorOr Metadata::add_miscellaneous(String const& field, String value) -{ - // FIXME: Since try_ensure does not return a reference to the contained value, we have to retrieve it separately. - // This is a try_ensure bug that should be fixed. - (void)TRY(miscellaneous.try_ensure(field, []() { return Vector {}; })); - auto& values_for_field = miscellaneous.get(field).release_value(); - return values_for_field.try_append(move(value)); -} - -ErrorOr Metadata::add_person(Person::Role role, String name) -{ - return people.try_append(Person { role, move(name) }); -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/Metadata.h b/Userland/Libraries/LibMedia/Audio/Metadata.h deleted file mode 100644 index bbb2c6c8c4a..00000000000 --- a/Userland/Libraries/LibMedia/Audio/Metadata.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace Audio { - -struct Person { - enum class Role { - Artist, - Performer, - Lyricist, - Conductor, - Publisher, - Engineer, - Composer, - }; - Role role; - String name; - - // Whether this person has creative involvement with the song (so not only Role::Artist!). - // This list is subjective and is intended to keep the artist display text in applications relevant. - // It is used for first_artist and all_artists in Metadata. - bool is_artist() const; - - Optional name_for_role() const; -}; - -// Audio metadata of the original format must be equivalently reconstructible from this struct. -// That means, (if the format allows it) fields can appear in a different order, but all fields must be present with the original values, -// including duplicate fields where allowed by the format. -struct Metadata { - using Year = unsigned; - - ErrorOr add_miscellaneous(String const& field, String value); - ErrorOr add_person(Person::Role role, String name); - Optional first_artist() const; - ErrorOr> all_artists(StringView concatenate_with = ", "sv) const; - - Optional title; - Optional subtitle; - Optional track_number; - Optional album; - Optional genre; - Optional comment; - Optional isrc; - Optional encoder; - Optional copyright; - Optional bpm; - // FIXME: Until the time data structure situation is solved in a good way, we don't parse ISO 8601 time specifications. - Optional unparsed_time; - Vector people; - - // Any other metadata, using the format-specific field names. This ensures reproducibility. - HashMap> miscellaneous; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/MultiChannel.h b/Userland/Libraries/LibMedia/Audio/MultiChannel.h deleted file mode 100644 index fdcb4d889d4..00000000000 --- a/Userland/Libraries/LibMedia/Audio/MultiChannel.h +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Sample.h" -#include -#include - -namespace Audio { - -// Downmixes any number of channels to stereo, under the assumption that standard channel layout is followed: -// 1 channel = mono -// 2 channels = stereo (left, right) -// 3 channels = left, right, center -// 4 channels = front left/right, back left/right -// 5 channels = front left/right, center, back left/right -// 6 channels = front left/right, center, LFE, back left/right -// 7 channels = front left/right, center, LFE, back center, side left/right -// 8 channels = front left/right, center, LFE, back left/right, side left/right -// Additionally, performs sample rescaling to go from integer samples to floating-point samples. -template ChannelType, ArrayLike InputType> -ErrorOr> downmix_surround_to_stereo(InputType const& input, float sample_scale_factor) -{ - if (input.size() == 0) - return Error::from_string_literal("Cannot resample from 0 channels"); - - auto channel_count = input.size(); - auto sample_count = input[0].size(); - - FixedArray output = TRY(FixedArray::create(sample_count)); - - // FIXME: We could figure out a better way to mix the channels, possibly spatially, but for now: - // - Center and LFE channels are added to both left and right. - // - All left channels are added together on the left, all right channels are added together on the right. - switch (channel_count) { - case 1: - for (auto i = 0u; i < sample_count; ++i) - output[i] = Sample { input[0][i] * sample_scale_factor }; - break; - case 2: - for (auto i = 0u; i < sample_count; ++i) - output[i] = Sample { - input[0][i] * sample_scale_factor, - input[1][i] * sample_scale_factor - }; - break; - case 3: - for (auto i = 0u; i < sample_count; ++i) - output[i] = Sample { - input[0][i] * sample_scale_factor + input[2][i] * sample_scale_factor, - input[1][i] * sample_scale_factor + input[2][i] * sample_scale_factor - }; - break; - case 4: - for (auto i = 0u; i < sample_count; ++i) - output[i] = Sample { - input[0][i] * sample_scale_factor + input[2][i] * sample_scale_factor, - input[1][i] * sample_scale_factor + input[3][i] * sample_scale_factor - }; - break; - case 5: - for (auto i = 0u; i < sample_count; ++i) - output[i] = Sample { - input[0][i] * sample_scale_factor + input[3][i] * sample_scale_factor + input[2][i] * sample_scale_factor, - input[1][i] * sample_scale_factor + input[4][i] * sample_scale_factor + input[2][i] * sample_scale_factor - }; - break; - case 6: - for (auto i = 0u; i < sample_count; ++i) { - output[i] = Sample { - input[0][i] * sample_scale_factor + input[4][i] * sample_scale_factor + input[2][i] * sample_scale_factor + input[3][i] * sample_scale_factor, - input[1][i] * sample_scale_factor + input[5][i] * sample_scale_factor + input[2][i] * sample_scale_factor + input[3][i] * sample_scale_factor - }; - } - break; - case 7: - for (auto i = 0u; i < sample_count; ++i) { - output[i] = Sample { - input[0][i] * sample_scale_factor + input[5][i] * sample_scale_factor + input[2][i] * sample_scale_factor + input[3][i] * sample_scale_factor + input[4][i] * sample_scale_factor, - input[1][i] * sample_scale_factor + input[6][i] * sample_scale_factor + input[2][i] * sample_scale_factor + input[3][i] * sample_scale_factor + input[4][i] * sample_scale_factor - }; - } - break; - case 8: - for (auto i = 0u; i < sample_count; ++i) { - output[i] = Sample { - input[0][i] * sample_scale_factor + input[4][i] * sample_scale_factor + input[6][i] * sample_scale_factor + input[2][i] * sample_scale_factor + input[3][i] * sample_scale_factor, - input[1][i] * sample_scale_factor + input[5][i] * sample_scale_factor + input[7][i] * sample_scale_factor + input[2][i] * sample_scale_factor + input[3][i] * sample_scale_factor - }; - } - break; - default: - return Error::from_string_literal("Invalid number of channels greater than 8"); - } - - return output; -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/QOALoader.cpp b/Userland/Libraries/LibMedia/Audio/QOALoader.cpp deleted file mode 100644 index e07a82a8f0d..00000000000 --- a/Userland/Libraries/LibMedia/Audio/QOALoader.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "QOALoader.h" -#include "Loader.h" -#include "LoaderError.h" -#include "QOATypes.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace Audio { - -QOALoaderPlugin::QOALoaderPlugin(NonnullOwnPtr stream) - : LoaderPlugin(move(stream)) -{ -} - -bool QOALoaderPlugin::sniff(SeekableStream& stream) -{ - auto maybe_qoa = stream.read_value>(); - return !maybe_qoa.is_error() && maybe_qoa.value() == QOA::magic; -} - -ErrorOr, LoaderError> QOALoaderPlugin::create(NonnullOwnPtr stream) -{ - auto loader = make(move(stream)); - TRY(loader->initialize()); - return loader; -} - -MaybeLoaderError QOALoaderPlugin::initialize() -{ - TRY(parse_header()); - TRY(reset()); - return {}; -} - -MaybeLoaderError QOALoaderPlugin::parse_header() -{ - u32 header_magic = TRY(m_stream->read_value>()); - if (header_magic != QOA::magic) - return LoaderError { LoaderError::Category::Format, 0, "QOA header: Magic number must be 'qoaf'" }; - - m_total_samples = TRY(m_stream->read_value>()); - - return {}; -} - -MaybeLoaderError QOALoaderPlugin::load_one_frame(Span& target, IsFirstFrame is_first_frame) -{ - QOA::FrameHeader header = TRY(m_stream->read_value()); - - if (header.num_channels > 8) - dbgln("QOALoader: Warning: QOA frame at {} has more than 8 channels ({}), this is not supported by the reference implementation.", TRY(m_stream->tell()) - sizeof(QOA::FrameHeader), header.num_channels); - if (header.num_channels == 0) - return LoaderError { LoaderError::Category::Format, TRY(m_stream->tell()), "QOA frame: Number of channels must be greater than 0" }; - if (header.sample_count > QOA::max_frame_samples) - return LoaderError { LoaderError::Category::Format, TRY(m_stream->tell()), "QOA frame: Too many samples in frame" }; - - // We weren't given a large enough buffer; signal that we didn't write anything and return. - if (header.sample_count > target.size()) { - target = target.trim(0); - TRY(m_stream->seek(-sizeof(QOA::frame_header_size), AK::SeekMode::FromCurrentPosition)); - return {}; - } - - target = target.trim(header.sample_count); - - auto lms_states = TRY(FixedArray::create(header.num_channels)); - for (size_t channel = 0; channel < header.num_channels; ++channel) { - auto history_packed = TRY(m_stream->read_value>()); - auto weights_packed = TRY(m_stream->read_value>()); - lms_states[channel] = { history_packed, weights_packed }; - } - - // We pre-allocate very large arrays here, but that's the last allocation of the QOA loader! - // Everything else is just shuffling data around. - // (We will also be using all of the arrays in every frame but the last one.) - auto channels = TRY((FixedArray>::create(header.num_channels))); - - // There's usually (and at maximum) 256 slices per channel, but less at the very end. - // If the final slice would be partial, we still need to decode it; integer division would tell us that this final slice doesn't exist. - auto const slice_count = static_cast(ceil(static_cast(header.sample_count) / static_cast(QOA::slice_samples))); - VERIFY(slice_count <= QOA::max_slices_per_frame); - - // Observe the loop nesting: Slices are channel-interleaved. - for (size_t slice = 0; slice < slice_count; ++slice) { - for (size_t channel = 0; channel < header.num_channels; ++channel) { - auto slice_samples = channels[channel].span().slice(slice * QOA::slice_samples, QOA::slice_samples); - TRY(read_one_slice(lms_states[channel], slice_samples)); - } - } - - if (is_first_frame == IsFirstFrame::Yes) { - m_num_channels = header.num_channels; - m_sample_rate = header.sample_rate; - } else { - if (m_sample_rate != header.sample_rate) - return LoaderError { LoaderError::Category::Unimplemented, TRY(m_stream->tell()), "QOA: Differing sample rate in non-initial frame" }; - if (m_num_channels != header.num_channels) - m_has_uniform_channel_count = false; - } - - switch (header.num_channels) { - case 1: - for (size_t sample = 0; sample < header.sample_count; ++sample) - target[sample] = Sample { static_cast(channels[0][sample]) / static_cast(NumericLimits::max()) }; - break; - // FIXME: Combine surround channels sensibly, FlacLoader has the same simplification at the moment. - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - case 8: - default: - for (size_t sample = 0; sample < header.sample_count; ++sample) { - target[sample] = { - static_cast(channels[0][sample]) / static_cast(NumericLimits::max()), - static_cast(channels[1][sample]) / static_cast(NumericLimits::max()), - }; - } - break; - } - - return {}; -} - -ErrorOr>, LoaderError> QOALoaderPlugin::load_chunks(size_t samples_to_read_from_input) -{ - ssize_t const remaining_samples = static_cast(m_total_samples - m_loaded_samples); - if (remaining_samples <= 0) - return Vector> {}; - size_t const samples_to_read = min(samples_to_read_from_input, remaining_samples); - auto is_first_frame = m_loaded_samples == 0 ? IsFirstFrame::Yes : IsFirstFrame::No; - - Vector> frames; - size_t current_loaded_samples = 0; - - while (current_loaded_samples < samples_to_read) { - auto samples = TRY(FixedArray::create(QOA::max_frame_samples)); - auto slice_to_load_into = samples.span(); - TRY(this->load_one_frame(slice_to_load_into, is_first_frame)); - is_first_frame = IsFirstFrame::No; - VERIFY(slice_to_load_into.size() <= QOA::max_frame_samples); - current_loaded_samples += slice_to_load_into.size(); - if (slice_to_load_into.size() != samples.size()) { - auto smaller_samples = TRY(FixedArray::create(slice_to_load_into)); - samples.swap(smaller_samples); - } - TRY(frames.try_append(move(samples))); - - if (slice_to_load_into.size() != samples.size()) - break; - } - m_loaded_samples += current_loaded_samples; - - return frames; -} - -MaybeLoaderError QOALoaderPlugin::reset() -{ - TRY(m_stream->seek(QOA::header_size, AK::SeekMode::SetPosition)); - m_loaded_samples = 0; - // Read the first frame, then seek back to the beginning. This is necessary since the first frame contains the sample rate and channel count. - auto frame_samples = TRY(FixedArray::create(QOA::max_frame_samples)); - auto span = frame_samples.span(); - TRY(load_one_frame(span, IsFirstFrame::Yes)); - - TRY(m_stream->seek(QOA::header_size, AK::SeekMode::SetPosition)); - m_loaded_samples = 0; - return {}; -} - -MaybeLoaderError QOALoaderPlugin::seek(int sample_index) -{ - if (sample_index == 0 && m_loaded_samples == 0) - return {}; - // A QOA file consists of 8 bytes header followed by a number of usually fixed-size frames. - // This fixed bitrate allows us to seek in constant time. - if (!m_has_uniform_channel_count) - return LoaderError { LoaderError::Category::Unimplemented, TRY(m_stream->tell()), "QOA with non-uniform channel count is currently not seekable"sv }; - /// FIXME: Change the Loader API to use size_t. - VERIFY(sample_index >= 0); - // We seek to the frame "before"; i.e. the frame that contains that sample. - auto const frame_of_sample = static_cast(AK::floor(static_cast(sample_index) / static_cast(QOA::max_frame_samples))); - auto const frame_size = QOA::frame_header_size + m_num_channels * (QOA::lms_state_size + sizeof(QOA::PackedSlice) * QOA::max_slices_per_frame); - auto const byte_index = QOA::header_size + frame_of_sample * frame_size; - TRY(m_stream->seek(byte_index, AK::SeekMode::SetPosition)); - m_loaded_samples = frame_of_sample * QOA::max_frame_samples; - return {}; -} - -MaybeLoaderError QOALoaderPlugin::read_one_slice(QOA::LMSState& lms_state, Span& samples) -{ - VERIFY(samples.size() == QOA::slice_samples); - - auto packed_slice = TRY(m_stream->read_value>()); - auto unpacked_slice = unpack_slice(packed_slice); - - for (size_t i = 0; i < QOA::slice_samples; ++i) { - auto const residual = unpacked_slice.residuals[i]; - auto const predicted = lms_state.predict(); - auto const dequantized = QOA::dequantization_table[unpacked_slice.scale_factor_index][residual]; - auto const reconstructed = clamp(predicted + dequantized, QOA::sample_minimum, QOA::sample_maximum); - samples[i] = static_cast(reconstructed); - lms_state.update(reconstructed, dequantized); - } - - return {}; -} - -QOA::UnpackedSlice QOALoaderPlugin::unpack_slice(QOA::PackedSlice packed_slice) -{ - size_t const scale_factor_index = (packed_slice >> 60) & 0b1111; - Array residuals = {}; - auto shifted_slice = packed_slice << 4; - - for (size_t i = 0; i < QOA::slice_samples; ++i) { - residuals[i] = static_cast((shifted_slice >> 61) & 0b111); - shifted_slice <<= 3; - } - - return { - .scale_factor_index = scale_factor_index, - .residuals = residuals, - }; -} - -i16 QOALoaderPlugin::qoa_divide(i16 value, i16 scale_factor) -{ - auto const reciprocal = QOA::reciprocal_table[scale_factor]; - auto const n = (value * reciprocal + (1 << 15)) >> 16; - // Rounding away from zero gives better quantization for small values. - auto const n_rounded = n + (static_cast(value > 0) - static_cast(value < 0)) - (static_cast(n > 0) - static_cast(n < 0)); - return static_cast(n_rounded); -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/QOALoader.h b/Userland/Libraries/LibMedia/Audio/QOALoader.h deleted file mode 100644 index 772ba9c5922..00000000000 --- a/Userland/Libraries/LibMedia/Audio/QOALoader.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Loader.h" -#include "QOATypes.h" -#include "SampleFormats.h" -#include -#include -#include -#include - -namespace Audio { - -// Decoder for the Quite Okay Audio (QOA) format. -// NOTE: The QOA format is not finalized yet and this decoder might not be fully spec-compliant as of 2023-02-02. -// -// https://github.com/phoboslab/qoa/blob/master/qoa.h -class QOALoaderPlugin : public LoaderPlugin { -public: - explicit QOALoaderPlugin(NonnullOwnPtr stream); - virtual ~QOALoaderPlugin() override = default; - - static bool sniff(SeekableStream& stream); - static ErrorOr, LoaderError> create(NonnullOwnPtr); - - virtual ErrorOr>, LoaderError> load_chunks(size_t samples_to_read_from_input) override; - - virtual MaybeLoaderError reset() override; - virtual MaybeLoaderError seek(int sample_index) override; - - virtual int loaded_samples() override { return static_cast(m_loaded_samples); } - virtual int total_samples() override { return static_cast(m_total_samples); } - virtual u32 sample_rate() override { return m_sample_rate; } - virtual u16 num_channels() override { return m_num_channels; } - virtual ByteString format_name() override { return "Quite Okay Audio (.qoa)"; } - virtual PcmSampleFormat pcm_format() override { return PcmSampleFormat::Int16; } - -private: - enum class IsFirstFrame : bool { - Yes = true, - No = false, - }; - - MaybeLoaderError initialize(); - MaybeLoaderError parse_header(); - - MaybeLoaderError load_one_frame(Span& target, IsFirstFrame is_first_frame = IsFirstFrame::No); - // Updates predictor values in lms_state so the next slice can reuse the same state. - MaybeLoaderError read_one_slice(QOA::LMSState& lms_state, Span& samples); - static ALWAYS_INLINE QOA::UnpackedSlice unpack_slice(QOA::PackedSlice packed_slice); - - // QOA's division routine for scaling residuals before final quantization. - static ALWAYS_INLINE i16 qoa_divide(i16 value, i16 scale_factor); - - // Because QOA has dynamic sample rate and channel count, we only use the sample rate and channel count from the first frame. - u32 m_sample_rate { 0 }; - u8 m_num_channels { 0 }; - // If this is the case (the reference encoder even enforces it at the moment) - bool m_has_uniform_channel_count { true }; - - size_t m_loaded_samples { 0 }; - size_t m_total_samples { 0 }; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/QOATypes.cpp b/Userland/Libraries/LibMedia/Audio/QOATypes.cpp deleted file mode 100644 index eb239ddf1ba..00000000000 --- a/Userland/Libraries/LibMedia/Audio/QOATypes.cpp +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "QOATypes.h" -#include -#include - -namespace Audio::QOA { - -ErrorOr FrameHeader::read_from_stream(Stream& stream) -{ - FrameHeader header; - header.num_channels = TRY(stream.read_value()); - u8 sample_rate[3]; - // Enforce the order of the reads here, since the order of expression evaluations further down is implementation-defined. - sample_rate[0] = TRY(stream.read_value()); - sample_rate[1] = TRY(stream.read_value()); - sample_rate[2] = TRY(stream.read_value()); - header.sample_rate = (sample_rate[0] << 16) | (sample_rate[1] << 8) | sample_rate[2]; - header.sample_count = TRY(stream.read_value>()); - header.frame_size = TRY(stream.read_value>()); - return header; -} - -LMSState::LMSState(u64 history_packed, u64 weights_packed) -{ - for (size_t i = 0; i < lms_history; ++i) { - // The casts ensure proper sign extension. - history[i] = static_cast(history_packed >> 48); - history_packed <<= 16; - weights[i] = static_cast(weights_packed >> 48); - weights_packed <<= 16; - } -} - -i32 LMSState::predict() const -{ - // The spec specifies that overflows are not allowed, but we do a safe thing anyways. - Checked prediction = 0; - for (size_t i = 0; i < lms_history; ++i) - prediction.saturating_add(Checked::saturating_mul(history[i], weights[i])); - return prediction.value() >> 13; -} - -void LMSState::update(i32 sample, i32 residual) -{ - i32 delta = residual >> 4; - for (size_t i = 0; i < lms_history; ++i) - weights[i] += history[i] < 0 ? -delta : delta; - - for (size_t i = 0; i < lms_history - 1; ++i) - history[i] = history[i + 1]; - history[lms_history - 1] = sample; -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/QOATypes.h b/Userland/Libraries/LibMedia/Audio/QOATypes.h deleted file mode 100644 index aeefb5f98be..00000000000 --- a/Userland/Libraries/LibMedia/Audio/QOATypes.h +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include -#include -#include - -namespace Audio::QOA { - -// 'qoaf' -static constexpr u32 const magic = 0x716f6166; - -static constexpr size_t const header_size = sizeof(u64); - -struct FrameHeader { - u8 num_channels; - u32 sample_rate; // 24 bits - u16 sample_count; - // TODO: might be removed and/or replaced - u16 frame_size; - - static ErrorOr read_from_stream(Stream& stream); -}; - -static constexpr size_t const frame_header_size = sizeof(u64); - -// Least mean squares (LMS) predictor FIR filter size. -static constexpr size_t const lms_history = 4; - -static constexpr size_t const lms_state_size = 2 * lms_history * sizeof(u16); - -// Only used for internal purposes; intermediate LMS states can be beyond 16 bits. -struct LMSState { - i32 history[lms_history] { 0, 0, 0, 0 }; - i32 weights[lms_history] { 0, 0, 0, 0 }; - - LMSState() = default; - LMSState(u64 history_packed, u64 weights_packed); - - i32 predict() const; - void update(i32 sample, i32 residual); -}; - -using PackedSlice = u64; - -// A QOA slice in a more directly readable format, unpacked from the stored 64-bit format. -struct UnpackedSlice { - size_t scale_factor_index; // 4 bits packed - Array residuals; // 3 bits packed -}; - -// Samples within a 64-bit slice. -static constexpr size_t const slice_samples = 20; -static constexpr size_t const max_slices_per_frame = 256; -static constexpr size_t const max_frame_samples = slice_samples * max_slices_per_frame; - -// Defined as clamping limits by the spec. -static constexpr i32 const sample_minimum = -32768; -static constexpr i32 const sample_maximum = 32767; - -// Quantization and scale factor tables computed from formulas given in qoa.h - -constexpr Array generate_scale_factor_table() -{ - Array scalefactor_table; - for (size_t s = 0; s < 17; ++s) - scalefactor_table[s] = static_cast(AK::round(AK::pow(static_cast(s + 1), 2.75))); - - return scalefactor_table; -} - -// FIXME: Get rid of the literal table once Clang understands our constexpr pow() and round() implementations. -#if defined(AK_COMPILER_CLANG) -static constexpr Array scale_factor_table = { - 1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048 -}; -#else -static constexpr Array scale_factor_table = generate_scale_factor_table(); -#endif - -constexpr Array generate_reciprocal_table() -{ - Array reciprocal_table; - for (size_t s = 0; s < 17; ++s) { - reciprocal_table[s] = ((1 << 16) + scale_factor_table[s] - 1) / scale_factor_table[s]; - } - return reciprocal_table; -} - -constexpr Array, 16> generate_dequantization_table() -{ - Array, 16> dequantization_table; - constexpr Array float_dequantization_table = { 0.75, -0.75, 2.5, -2.5, 4.5, -4.5, 7, -7 }; - for (size_t scale = 0; scale < 16; ++scale) { - for (size_t quantization = 0; quantization < 8; ++quantization) - dequantization_table[scale][quantization] = static_cast(AK::round( - static_cast(scale_factor_table[scale]) * float_dequantization_table[quantization])); - } - return dequantization_table; -} - -#if defined(AK_COMPILER_CLANG) -static constexpr Array reciprocal_table = { - 65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32 -}; -static constexpr Array, 16> dequantization_table = { - Array { 1, -1, 3, -3, 5, -5, 7, -7 }, - { 5, -5, 18, -18, 32, -32, 49, -49 }, - { 16, -16, 53, -53, 95, -95, 147, -147 }, - { 34, -34, 113, -113, 203, -203, 315, -315 }, - { 63, -63, 210, -210, 378, -378, 588, -588 }, - { 104, -104, 345, -345, 621, -621, 966, -966 }, - { 158, -158, 528, -528, 950, -950, 1477, -1477 }, - { 228, -228, 760, -760, 1368, -1368, 2128, -2128 }, - { 316, -316, 1053, -1053, 1895, -1895, 2947, -2947 }, - { 422, -422, 1405, -1405, 2529, -2529, 3934, -3934 }, - { 548, -548, 1828, -1828, 3290, -3290, 5117, -5117 }, - { 696, -696, 2320, -2320, 4176, -4176, 6496, -6496 }, - { 868, -868, 2893, -2893, 5207, -5207, 8099, -8099 }, - { 1064, -1064, 3548, -3548, 6386, -6386, 9933, -9933 }, - { 1286, -1286, 4288, -4288, 7718, -7718, 12005, -12005 }, - { 1536, -1536, 5120, -5120, 9216, -9216, 14336, -14336 }, -}; -#else -static constexpr Array reciprocal_table = generate_reciprocal_table(); -static constexpr Array, 16> dequantization_table = generate_dequantization_table(); -#endif - -static constexpr Array quantization_table = { - 7, 7, 7, 5, 5, 3, 3, 1, // -8 ..-1 - 0, // 0 - 0, 2, 2, 4, 4, 6, 6, 6 // 1 .. 8 -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/Resampler.h b/Userland/Libraries/LibMedia/Audio/Resampler.h deleted file mode 100644 index 81640420483..00000000000 --- a/Userland/Libraries/LibMedia/Audio/Resampler.h +++ /dev/null @@ -1,100 +0,0 @@ -/* - * Copyright (c) 2022, kleines Filmröllchen . - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include -#include -#include - -namespace Audio { - -// Small helper to resample from one playback rate to another -// This isn't really "smart", in that we just insert (or drop) samples. -// Should do better... -template -class ResampleHelper { -public: - ResampleHelper(u32 source, u32 target) - : m_source(source) - , m_target(target) - { - VERIFY(source > 0); - VERIFY(target > 0); - } - - // To be used as follows: - // while the resampler doesn't need a new sample, read_sample(current) and store the resulting samples. - // as long as the resampler needs a new sample, process_sample(current) - - // Stores a new sample - void process_sample(SampleType sample_l, SampleType sample_r) - { - m_last_sample_l = sample_l; - m_last_sample_r = sample_r; - m_current_ratio += m_target; - } - - // Assigns the given sample to its correct value and returns false if there is a new sample required - bool read_sample(SampleType& next_l, SampleType& next_r) - { - if (m_current_ratio >= m_source) { - m_current_ratio -= m_source; - next_l = m_last_sample_l; - next_r = m_last_sample_r; - return true; - } - - return false; - } - - template Samples> - ErrorOr> try_resample(Samples&& to_resample) - { - Vector resampled; - TRY(try_resample_into_end(resampled, forward(to_resample))); - return resampled; - } - - template Samples, size_t vector_inline_capacity = 0> - ErrorOr try_resample_into_end(Vector& destination, Samples&& to_resample) - { - float ratio = (m_source > m_target) ? static_cast(m_source) / m_target : static_cast(m_target) / m_source; - TRY(destination.try_ensure_capacity(destination.size() + to_resample.size() * ratio)); - for (auto sample : to_resample) { - process_sample(sample, sample); - - while (read_sample(sample, sample)) - destination.unchecked_append(sample); - } - return {}; - } - - template Samples> - Vector resample(Samples&& to_resample) - { - return MUST(try_resample(forward(to_resample))); - } - - void reset() - { - m_current_ratio = 0; - m_last_sample_l = {}; - m_last_sample_r = {}; - } - - u32 source() const { return m_source; } - u32 target() const { return m_target; } - -private: - u32 const m_source; - u32 const m_target; - u32 m_current_ratio { 0 }; - SampleType m_last_sample_l {}; - SampleType m_last_sample_r {}; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/SampleFormats.cpp b/Userland/Libraries/LibMedia/Audio/SampleFormats.cpp index 3f750e61349..f346e33e3fd 100644 --- a/Userland/Libraries/LibMedia/Audio/SampleFormats.cpp +++ b/Userland/Libraries/LibMedia/Audio/SampleFormats.cpp @@ -27,31 +27,4 @@ u16 pcm_bits_per_sample(PcmSampleFormat format) } } -bool is_integer_format(PcmSampleFormat format) -{ - return format == PcmSampleFormat::Uint8 || format == PcmSampleFormat::Int16 || format == PcmSampleFormat::Int24 || format == PcmSampleFormat::Int32; -} - -Optional integer_sample_format_for(u16 bits_per_sample) -{ - switch (bits_per_sample) { - case 8: - return PcmSampleFormat::Uint8; - case 16: - return PcmSampleFormat::Int16; - case 24: - return PcmSampleFormat::Int24; - case 32: - return PcmSampleFormat::Int32; - default: - return {}; - } -} - -ByteString sample_format_name(PcmSampleFormat format) -{ - bool is_float = format == PcmSampleFormat::Float32 || format == PcmSampleFormat::Float64; - return ByteString::formatted("PCM {}bit {}", pcm_bits_per_sample(format), is_float ? "Float" : "LE"); -} - } diff --git a/Userland/Libraries/LibMedia/Audio/SampleFormats.h b/Userland/Libraries/LibMedia/Audio/SampleFormats.h index 918a43e49a1..a6801a5727e 100644 --- a/Userland/Libraries/LibMedia/Audio/SampleFormats.h +++ b/Userland/Libraries/LibMedia/Audio/SampleFormats.h @@ -23,7 +23,5 @@ enum class PcmSampleFormat : u8 { // Most of the read code only cares about how many bits to read or write u16 pcm_bits_per_sample(PcmSampleFormat format); -bool is_integer_format(PcmSampleFormat format); -Optional integer_sample_format_for(u16 bits_per_sample); -ByteString sample_format_name(PcmSampleFormat format); + } diff --git a/Userland/Libraries/LibMedia/Audio/VorbisComment.cpp b/Userland/Libraries/LibMedia/Audio/VorbisComment.cpp deleted file mode 100644 index 91f54f4f452..00000000000 --- a/Userland/Libraries/LibMedia/Audio/VorbisComment.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "VorbisComment.h" -#include -#include -#include -#include - -namespace Audio { - -static StringView vorbis_field_for_role(Person::Role role) -{ - static HashMap role_map { - { Person::Role::Artist, "ARTIST"sv }, - { Person::Role::Performer, "PERFORMER"sv }, - { Person::Role::Lyricist, "LYRICIST"sv }, - { Person::Role::Conductor, "CONDUCTOR"sv }, - { Person::Role::Publisher, "PUBLISHER"sv }, - { Person::Role::Engineer, "ENCODED-BY"sv }, - { Person::Role::Composer, "COMPOSER"sv }, - }; - return role_map.get(role).value(); -} - -// "Content vector format" -static ErrorOr read_vorbis_field(Metadata& metadata_to_write_into, String const& unparsed_user_comment) -{ - // Technically the field name has to be ASCII, but we just accept all UTF-8. - auto field_name_and_contents = TRY(unparsed_user_comment.split_limit('=', 2)); - - if (field_name_and_contents.size() != 2) - return Error::from_string_literal("User comment does not contain '='"); - auto contents = field_name_and_contents.take_last(); - auto field_name = TRY(field_name_and_contents.take_first().to_uppercase()); - - // Some of these are taken from https://age.hobba.nl/audio/tag_frame_reference.html - if (field_name == "TITLE"sv) { - if (metadata_to_write_into.title.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.title = contents; - } else if (field_name == "VERSION"sv) { - if (metadata_to_write_into.subtitle.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.subtitle = contents; - } else if (field_name == "ALBUM"sv) { - if (metadata_to_write_into.album.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.album = contents; - } else if (field_name == "COPYRIGHT"sv) { - if (metadata_to_write_into.copyright.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.copyright = contents; - } else if (field_name == "ISRC"sv) { - if (metadata_to_write_into.isrc.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.isrc = contents; - } else if (field_name == "GENRE"sv) { - if (metadata_to_write_into.genre.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.genre = contents; - } else if (field_name == "COMMENT"sv) { - if (metadata_to_write_into.comment.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.comment = contents; - } else if (field_name == "TRACKNUMBER"sv) { - if (metadata_to_write_into.track_number.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else if (auto maybe_number = contents.to_number(); maybe_number.has_value()) - metadata_to_write_into.track_number = maybe_number.release_value(); - else - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - } else if (field_name == "DATE"sv) { - if (metadata_to_write_into.unparsed_time.has_value()) - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - else - metadata_to_write_into.unparsed_time = contents; - } else if (field_name == vorbis_field_for_role(Person::Role::Performer)) { - TRY(metadata_to_write_into.add_person(Person::Role::Performer, contents)); - } else if (field_name == vorbis_field_for_role(Person::Role::Artist)) { - TRY(metadata_to_write_into.add_person(Person::Role::Artist, contents)); - } else if (field_name == vorbis_field_for_role(Person::Role::Composer)) { - TRY(metadata_to_write_into.add_person(Person::Role::Composer, contents)); - } else if (field_name == vorbis_field_for_role(Person::Role::Conductor)) { - TRY(metadata_to_write_into.add_person(Person::Role::Conductor, contents)); - } else if (field_name == vorbis_field_for_role(Person::Role::Lyricist)) { - TRY(metadata_to_write_into.add_person(Person::Role::Lyricist, contents)); - } else if (field_name == "ORGANIZATION"sv) { - TRY(metadata_to_write_into.add_person(Person::Role::Publisher, contents)); - } else if (field_name == vorbis_field_for_role(Person::Role::Publisher)) { - TRY(metadata_to_write_into.add_person(Person::Role::Publisher, contents)); - } else if (field_name == vorbis_field_for_role(Person::Role::Engineer)) { - TRY(metadata_to_write_into.add_person(Person::Role::Engineer, contents)); - } else { - TRY(metadata_to_write_into.add_miscellaneous(field_name, contents)); - } - - return {}; -} - -ErrorOr load_vorbis_comment(ByteBuffer const& vorbis_comment) -{ - FixedMemoryStream stream { vorbis_comment }; - auto vendor_length = TRY(stream.read_value>()); - Vector raw_vendor_string; - TRY(raw_vendor_string.try_resize(vendor_length)); - TRY(stream.read_until_filled(raw_vendor_string)); - auto vendor_string = TRY(String::from_utf8(StringView { raw_vendor_string.span() })); - - Metadata metadata; - metadata.encoder = move(vendor_string); - - auto user_comment_count = TRY(stream.read_value>()); - for (size_t i = 0; i < user_comment_count; ++i) { - auto user_comment_length = TRY(stream.read_value>()); - Vector raw_user_comment; - TRY(raw_user_comment.try_resize(user_comment_length)); - TRY(stream.read_until_filled(raw_user_comment)); - auto unparsed_user_comment = TRY(String::from_utf8(StringView { raw_user_comment.span() })); - TRY(read_vorbis_field(metadata, unparsed_user_comment)); - } - - return metadata; -} - -struct VorbisCommentPair { - String field_name; - String contents; -}; - -static ErrorOr> make_vorbis_user_comments(Metadata const& metadata) -{ - Vector user_comments; - - auto add_if_present = [&](auto field_name, auto const& value) -> ErrorOr { - if (value.has_value()) - TRY(user_comments.try_append(VorbisCommentPair { field_name, TRY(String::formatted("{}", value.value())) })); - return {}; - }; - - TRY(add_if_present("TITLE"_string, metadata.title)); - TRY(add_if_present("VERSION"_string, metadata.subtitle)); - TRY(add_if_present("ALBUM"_string, metadata.album)); - TRY(add_if_present("COPYRIGHT"_string, metadata.copyright)); - TRY(add_if_present("ISRC"_string, metadata.isrc)); - TRY(add_if_present("GENRE"_string, metadata.genre)); - TRY(add_if_present("COMMENT"_string, metadata.comment)); - TRY(add_if_present("TRACKNUMBER"_string, metadata.track_number)); - TRY(add_if_present("DATE"_string, metadata.unparsed_time)); - - for (auto const& person : metadata.people) - TRY(user_comments.try_append(VorbisCommentPair { TRY(String::from_utf8(vorbis_field_for_role(person.role))), person.name })); - - for (auto const& field : metadata.miscellaneous) { - for (auto const& value : field.value) - TRY(user_comments.try_append(VorbisCommentPair { field.key, value })); - } - - return user_comments; -} - -ErrorOr write_vorbis_comment(Metadata const& metadata, Stream& target) -{ - auto encoder = metadata.encoder.value_or({}).bytes(); - TRY(target.write_value>(encoder.size())); - TRY(target.write_until_depleted(encoder)); - - auto vorbis_user_comments = TRY(make_vorbis_user_comments(metadata)); - TRY(target.write_value>(vorbis_user_comments.size())); - for (auto const& field : vorbis_user_comments) { - auto const serialized_field = TRY(String::formatted("{}={}", field.field_name, field.contents)); - TRY(target.write_value>(serialized_field.bytes().size())); - TRY(target.write_until_depleted(serialized_field.bytes())); - } - - return {}; -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/VorbisComment.h b/Userland/Libraries/LibMedia/Audio/VorbisComment.h deleted file mode 100644 index d4ac57b63e2..00000000000 --- a/Userland/Libraries/LibMedia/Audio/VorbisComment.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright (c) 2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "LoaderError.h" -#include "Metadata.h" -#include - -namespace Audio { - -// https://www.xiph.org/vorbis/doc/v-comment.html -ErrorOr load_vorbis_comment(ByteBuffer const& vorbis_comment); -ErrorOr write_vorbis_comment(Metadata const& metadata, Stream& target); - -} diff --git a/Userland/Libraries/LibMedia/Audio/WavLoader.cpp b/Userland/Libraries/LibMedia/Audio/WavLoader.cpp deleted file mode 100644 index 57fed364d66..00000000000 --- a/Userland/Libraries/LibMedia/Audio/WavLoader.cpp +++ /dev/null @@ -1,337 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2021-2023, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#include "WavLoader.h" -#include "LoaderError.h" -#include "WavTypes.h" -#include -#include -#include -#include -#include -#include -#include - -namespace Audio { - -WavLoaderPlugin::WavLoaderPlugin(NonnullOwnPtr stream) - : LoaderPlugin(move(stream)) -{ -} - -bool WavLoaderPlugin::sniff(SeekableStream& stream) -{ - auto riff = stream.read_value(); - if (riff.is_error()) - return false; - if (riff.value() != RIFF::riff_magic) - return false; - - auto size = stream.read_value>(); - if (size.is_error()) - return false; - - auto wave = stream.read_value(); - return !wave.is_error() && wave.value() == Wav::wave_subformat_id; -} - -ErrorOr, LoaderError> WavLoaderPlugin::create(NonnullOwnPtr stream) -{ - auto loader = make(move(stream)); - TRY(loader->parse_header()); - return loader; -} - -template -MaybeLoaderError WavLoaderPlugin::read_samples_from_stream(Stream& stream, SampleReader read_sample, FixedArray& samples) const -{ - switch (m_num_channels) { - case 1: - for (auto& sample : samples) - sample = Sample(TRY(read_sample(stream))); - break; - case 2: - for (auto& sample : samples) { - auto left_channel_sample = TRY(read_sample(stream)); - auto right_channel_sample = TRY(read_sample(stream)); - sample = Sample(left_channel_sample, right_channel_sample); - } - break; - default: - VERIFY_NOT_REACHED(); - } - return {}; -} - -// There's no i24 type + we need to do the endianness conversion manually anyways. -static ErrorOr read_sample_int24(Stream& stream) -{ - i32 sample1 = TRY(stream.read_value()); - i32 sample2 = TRY(stream.read_value()); - i32 sample3 = TRY(stream.read_value()); - - i32 value = 0; - value = sample1; - value |= sample2 << 8; - value |= sample3 << 16; - // Sign extend the value, as it can currently not have the correct sign. - value = (value << 8) >> 8; - // Range of value is now -2^23 to 2^23-1 and we can rescale normally. - return static_cast(value) / static_cast((1 << 23) - 1); -} - -template -static ErrorOr read_sample(Stream& stream) -{ - T sample { 0 }; - TRY(stream.read_until_filled(Bytes { &sample, sizeof(T) })); - // Remap integer samples to normalized floating-point range of -1 to 1. - if constexpr (IsIntegral) { - if constexpr (NumericLimits::is_signed()) { - // Signed integer samples are centered around zero, so this division is enough. - return static_cast(AK::convert_between_host_and_little_endian(sample)) / static_cast(NumericLimits::max()); - } else { - // Unsigned integer samples, on the other hand, need to be shifted to center them around zero. - // The first division therefore remaps to the range 0 to 2. - return static_cast(AK::convert_between_host_and_little_endian(sample)) / (static_cast(NumericLimits::max()) / 2.0) - 1.0; - } - } else { - return static_cast(AK::convert_between_host_and_little_endian(sample)); - } -} - -LoaderSamples WavLoaderPlugin::samples_from_pcm_data(ReadonlyBytes data, size_t samples_to_read) const -{ - FixedArray samples = TRY(FixedArray::create(samples_to_read)); - FixedMemoryStream stream { data }; - - switch (m_sample_format) { - case PcmSampleFormat::Uint8: - TRY(read_samples_from_stream(stream, read_sample, samples)); - break; - case PcmSampleFormat::Int16: - TRY(read_samples_from_stream(stream, read_sample, samples)); - break; - case PcmSampleFormat::Int24: - TRY(read_samples_from_stream(stream, read_sample_int24, samples)); - break; - case PcmSampleFormat::Float32: - TRY(read_samples_from_stream(stream, read_sample, samples)); - break; - case PcmSampleFormat::Float64: - TRY(read_samples_from_stream(stream, read_sample, samples)); - break; - default: - VERIFY_NOT_REACHED(); - } - - return samples; -} - -ErrorOr>, LoaderError> WavLoaderPlugin::load_chunks(size_t samples_to_read_from_input) -{ - auto remaining_samples = m_total_samples - m_loaded_samples; - if (remaining_samples <= 0) - return Vector> {}; - - // One "sample" contains data from all channels. - // In the Wave spec, this is also called a block. - size_t bytes_per_sample - = m_num_channels * pcm_bits_per_sample(m_sample_format) / 8; - - auto samples_to_read = min(samples_to_read_from_input, remaining_samples); - auto bytes_to_read = samples_to_read * bytes_per_sample; - - dbgln_if(AWAVLOADER_DEBUG, "Read {} bytes WAV with num_channels {} sample rate {}, " - "bits per sample {}, sample format {}", - bytes_to_read, m_num_channels, m_sample_rate, - pcm_bits_per_sample(m_sample_format), sample_format_name(m_sample_format)); - - auto sample_data = TRY(ByteBuffer::create_zeroed(bytes_to_read)); - TRY(m_stream->read_until_filled(sample_data.bytes())); - - // m_loaded_samples should contain the amount of actually loaded samples - m_loaded_samples += samples_to_read; - Vector> samples; - TRY(samples.try_append(TRY(samples_from_pcm_data(sample_data.bytes(), samples_to_read)))); - return samples; -} - -MaybeLoaderError WavLoaderPlugin::seek(int sample_index) -{ - dbgln_if(AWAVLOADER_DEBUG, "seek sample_index {}", sample_index); - if (sample_index < 0 || sample_index >= static_cast(m_total_samples)) - return LoaderError { LoaderError::Category::Internal, m_loaded_samples, "Seek outside the sample range" }; - - size_t sample_offset = m_byte_offset_of_data_samples + static_cast(sample_index * m_num_channels * (pcm_bits_per_sample(m_sample_format) / 8)); - - TRY(m_stream->seek(sample_offset, SeekMode::SetPosition)); - - m_loaded_samples = sample_index; - return {}; -} - -// Specification reference: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html -MaybeLoaderError WavLoaderPlugin::parse_header() -{ -#define CHECK(check, category, msg) \ - do { \ - if (!(check)) { \ - return LoaderError { category, static_cast(TRY(m_stream->tell())), ByteString::formatted("WAV header: {}", msg) }; \ - } \ - } while (0) - - auto file_header = TRY(m_stream->read_value()); - CHECK(file_header.magic() == RIFF::riff_magic, LoaderError::Category::Format, "RIFF header magic invalid"); - CHECK(file_header.subformat == Wav::wave_subformat_id, LoaderError::Category::Format, "WAVE subformat id invalid"); - - auto format_chunk = TRY(m_stream->read_value()); - CHECK(format_chunk.id().as_ascii_string() == Wav::format_chunk_id, LoaderError::Category::Format, "FMT chunk id invalid"); - - auto format_stream = format_chunk.data_stream(); - u16 audio_format = TRY(format_stream.read_value>()); - CHECK(audio_format == to_underlying(Wav::WaveFormat::Pcm) || audio_format == to_underlying(Wav::WaveFormat::IEEEFloat) || audio_format == to_underlying(Wav::WaveFormat::Extensible), - LoaderError::Category::Unimplemented, "Audio format not supported"); - - m_num_channels = TRY(format_stream.read_value>()); - CHECK(m_num_channels == 1 || m_num_channels == 2, LoaderError::Category::Unimplemented, "Channel count"); - - m_sample_rate = TRY(format_stream.read_value>()); - // Data rate; can be ignored. - TRY(format_stream.read_value>()); - u16 block_size_bytes = TRY(format_stream.read_value>()); - - u16 bits_per_sample = TRY(format_stream.read_value>()); - - if (audio_format == to_underlying(Wav::WaveFormat::Extensible)) { - CHECK(format_chunk.size() == 40, LoaderError::Category::Format, "Extensible fmt size is not 40 bytes"); - - // Discard everything until the GUID. - // We've already read 16 bytes from the stream. The GUID starts in another 8 bytes. - TRY(format_stream.read_value>()); - - // Get the underlying audio format from the first two bytes of GUID - u16 guid_subformat = TRY(format_stream.read_value>()); - CHECK(guid_subformat == to_underlying(Wav::WaveFormat::Pcm) || guid_subformat == to_underlying(Wav::WaveFormat::IEEEFloat), LoaderError::Category::Unimplemented, "GUID SubFormat not supported"); - - audio_format = guid_subformat; - } - - if (audio_format == to_underlying(Wav::WaveFormat::Pcm)) { - CHECK(bits_per_sample == 8 || bits_per_sample == 16 || bits_per_sample == 24, LoaderError::Category::Unimplemented, "PCM bits per sample not supported"); - - // We only support 8-24 bit audio right now because other formats are uncommon - if (bits_per_sample == 8) { - m_sample_format = PcmSampleFormat::Uint8; - } else if (bits_per_sample == 16) { - m_sample_format = PcmSampleFormat::Int16; - } else if (bits_per_sample == 24) { - m_sample_format = PcmSampleFormat::Int24; - } - } else if (audio_format == to_underlying(Wav::WaveFormat::IEEEFloat)) { - CHECK(bits_per_sample == 32 || bits_per_sample == 64, LoaderError::Category::Unimplemented, "Float bits per sample not supported"); - - // Again, only the common 32 and 64 bit - if (bits_per_sample == 32) { - m_sample_format = PcmSampleFormat::Float32; - } else if (bits_per_sample == 64) { - m_sample_format = PcmSampleFormat::Float64; - } - } - - CHECK(block_size_bytes == (m_num_channels * (bits_per_sample / 8)), LoaderError::Category::Format, "Block size invalid"); - - dbgln_if(AWAVLOADER_DEBUG, "WAV format {} at {} bit, {} channels, rate {}Hz ", - sample_format_name(m_sample_format), pcm_bits_per_sample(m_sample_format), m_num_channels, m_sample_rate); - - // Read all chunks before DATA. - bool found_data = false; - while (!found_data) { - auto chunk_header = TRY(m_stream->read_value()); - if (chunk_header == Wav::data_chunk_id) { - found_data = true; - } else { - TRY(m_stream->seek(-RIFF::chunk_id_size, SeekMode::FromCurrentPosition)); - auto chunk = TRY(m_stream->read_value()); - if (chunk.id() == RIFF::list_chunk_id) { - auto maybe_list = chunk.data_stream().read_value(); - if (maybe_list.is_error()) { - dbgln("WAV Warning: LIST chunk invalid, error: {}", maybe_list.release_error()); - continue; - } - - auto list = maybe_list.release_value(); - if (list.type == Wav::info_chunk_id) { - auto maybe_error = load_wav_info_block(move(list.chunks)); - if (maybe_error.is_error()) - dbgln("WAV Warning: INFO chunk invalid, error: {}", maybe_error.release_error()); - - } else { - dbgln("Unhandled WAV list of type {} with {} subchunks", list.type.as_ascii_string(), list.chunks.size()); - } - } else { - dbgln_if(AWAVLOADER_DEBUG, "Unhandled WAV chunk of type {}, size {} bytes", chunk.id().as_ascii_string(), chunk.size()); - } - } - } - - u32 data_size = TRY(m_stream->read_value>()); - CHECK(found_data, LoaderError::Category::Format, "Found no data chunk"); - - m_total_samples = data_size / block_size_bytes; - - dbgln_if(AWAVLOADER_DEBUG, "WAV data size {}, bytes per sample {}, total samples {}", - data_size, - block_size_bytes, - m_total_samples); - - m_byte_offset_of_data_samples = TRY(m_stream->tell()); - return {}; -} - -// http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/Docs/riffmci.pdf page 23 (LIST type) -// We only recognize the relevant official metadata types; types added in later errata of RIFF are not relevant for audio. -MaybeLoaderError WavLoaderPlugin::load_wav_info_block(Vector info_chunks) -{ - for (auto const& chunk : info_chunks) { - auto chunk_id = chunk.id(); - auto metadata_name = chunk_id.as_ascii_string(); - // Chunk contents are zero-terminated strings "ZSTR", so we just drop the null terminator. - StringView metadata_text { chunk.data().trim(chunk.size() - 1) }; - // Note that we assume chunks to be unique, since that seems to almost always be the case. - // Worst case we just drop some metadata. - if (metadata_name == "IART"sv) { - // Artists are combined together with semicolons, at least when you edit them in Windows File Explorer. - auto artists = metadata_text.split_view(";"sv); - for (auto artist : artists) - TRY(m_metadata.add_person(Person::Role::Artist, TRY(String::from_utf8(artist)))); - } else if (metadata_name == "ICMT"sv) { - m_metadata.comment = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "ICOP"sv) { - m_metadata.copyright = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "ICRD"sv) { - m_metadata.unparsed_time = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "IENG"sv) { - TRY(m_metadata.add_person(Person::Role::Engineer, TRY(String::from_utf8(metadata_text)))); - } else if (metadata_name == "IGNR"sv) { - m_metadata.genre = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "INAM"sv) { - m_metadata.title = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "IPRD"sv) { - m_metadata.album = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "ISFT"sv) { - m_metadata.encoder = TRY(String::from_utf8(metadata_text)); - } else if (metadata_name == "ISRC"sv) { - TRY(m_metadata.add_person(Person::Role::Publisher, TRY(String::from_utf8(metadata_text)))); - } else { - TRY(m_metadata.add_miscellaneous(TRY(String::from_utf8(metadata_name)), TRY(String::from_utf8(metadata_text)))); - } - } - return {}; -} - -} diff --git a/Userland/Libraries/LibMedia/Audio/WavLoader.h b/Userland/Libraries/LibMedia/Audio/WavLoader.h deleted file mode 100644 index 08e4afcb397..00000000000 --- a/Userland/Libraries/LibMedia/Audio/WavLoader.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling - * Copyright (c) 2021, kleines Filmröllchen - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include "Loader.h" -#include -#include -#include -#include -#include -#include -#include - -namespace Audio { - -// Loader for the WAVE (file extension .wav) uncompressed audio file format. -// WAVE uses the Microsoft RIFF container. -// Original RIFF Spec, without later extensions: https://www.aelius.com/njh/wavemetatools/doc/riffmci.pdf -// More concise WAVE information plus various spec links: http://www-mmsp.ece.mcgill.ca/Documents/AudioFormats/WAVE/WAVE.html -class WavLoaderPlugin : public LoaderPlugin { -public: - explicit WavLoaderPlugin(NonnullOwnPtr stream); - - static bool sniff(SeekableStream& stream); - static ErrorOr, LoaderError> create(NonnullOwnPtr); - - virtual ErrorOr>, LoaderError> load_chunks(size_t samples_to_read_from_input) override; - - virtual MaybeLoaderError reset() override { return seek(0); } - - // sample_index 0 is the start of the raw audio sample data - // within the file/stream. - virtual MaybeLoaderError seek(int sample_index) override; - - virtual int loaded_samples() override { return static_cast(m_loaded_samples); } - virtual int total_samples() override { return static_cast(m_total_samples); } - virtual u32 sample_rate() override { return m_sample_rate; } - virtual u16 num_channels() override { return m_num_channels; } - virtual ByteString format_name() override { return "RIFF WAVE (.wav)"; } - virtual PcmSampleFormat pcm_format() override { return m_sample_format; } - -private: - MaybeLoaderError parse_header(); - MaybeLoaderError load_wav_info_block(Vector info_chunks); - - LoaderSamples samples_from_pcm_data(ReadonlyBytes data, size_t samples_to_read) const; - template - MaybeLoaderError read_samples_from_stream(Stream& stream, SampleReader read_sample, FixedArray& samples) const; - - u32 m_sample_rate { 0 }; - u16 m_num_channels { 0 }; - PcmSampleFormat m_sample_format; - size_t m_byte_offset_of_data_samples { 0 }; - - size_t m_loaded_samples { 0 }; - size_t m_total_samples { 0 }; -}; - -} diff --git a/Userland/Libraries/LibMedia/Audio/WavTypes.h b/Userland/Libraries/LibMedia/Audio/WavTypes.h deleted file mode 100644 index cdef7371082..00000000000 --- a/Userland/Libraries/LibMedia/Audio/WavTypes.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (c) 2023, the SerenityOS developers. - * - * SPDX-License-Identifier: BSD-2-Clause - */ - -#pragma once - -#include - -namespace Audio::Wav { - -static constexpr StringView const wave_subformat_id = "WAVE"sv; -static constexpr StringView const data_chunk_id = "data"sv; -static constexpr StringView const info_chunk_id = "INFO"sv; -static constexpr StringView const format_chunk_id = "fmt "sv; - -// Constants for handling WAVE header data. -enum class WaveFormat : u32 { - Pcm = 0x0001, // WAVE_FORMAT_PCM - IEEEFloat = 0x0003, // WAVE_FORMAT_IEEE_FLOAT - ALaw = 0x0006, // 8-bit ITU-T G.711 A-law - MuLaw = 0x0007, // 8-bit ITU-T G.711 µ-law - Extensible = 0xFFFE, // Determined by SubFormat -}; - -} diff --git a/Userland/Libraries/LibMedia/CMakeLists.txt b/Userland/Libraries/LibMedia/CMakeLists.txt index c4fa64050b6..77820cab211 100644 --- a/Userland/Libraries/LibMedia/CMakeLists.txt +++ b/Userland/Libraries/LibMedia/CMakeLists.txt @@ -1,17 +1,9 @@ include(ffmpeg) set(SOURCES - Audio/GenericTypes.cpp - Audio/SampleFormats.cpp Audio/Loader.cpp - Audio/WavLoader.cpp - Audio/FlacLoader.cpp - Audio/Metadata.cpp - Audio/MP3Loader.cpp Audio/PlaybackStream.cpp - Audio/QOALoader.cpp - Audio/QOATypes.cpp - Audio/VorbisComment.cpp + Audio/SampleFormats.cpp Color/ColorConverter.cpp Color/ColorPrimaries.cpp Color/TransferCharacteristics.cpp diff --git a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp index 211a618b688..b6271705b8b 100644 --- a/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp +++ b/Userland/Libraries/LibWeb/HTML/HTMLMediaElement.cpp @@ -195,20 +195,17 @@ Bindings::CanPlayTypeResult HTMLMediaElement::can_play_type(StringView type) con } if (mime_type.has_value() && mime_type->type() == "audio"sv) { + if (mime_type->subtype() == "flac"sv) + return Bindings::CanPlayTypeResult::Probably; + if (mime_type->subtype() == "mp3"sv) + return Bindings::CanPlayTypeResult::Probably; // "Maybe" because we support mp3, but "mpeg" can also refer to MP1 and MP2. if (mime_type->subtype() == "mpeg"sv) return Bindings::CanPlayTypeResult::Maybe; - if (mime_type->subtype() == "mp3"sv) + if (mime_type->subtype() == "ogg"sv) return Bindings::CanPlayTypeResult::Probably; if (mime_type->subtype() == "wav"sv) return Bindings::CanPlayTypeResult::Probably; - if (mime_type->subtype() == "flac"sv) - return Bindings::CanPlayTypeResult::Probably; - // "Maybe" because we support Ogg Vorbis, but "ogg" can contain other codecs - if (mime_type->subtype() == "ogg"sv) - return Bindings::CanPlayTypeResult::Maybe; - if (mime_type->subtype() == "qoa"sv) - return Bindings::CanPlayTypeResult::Probably; return Bindings::CanPlayTypeResult::Maybe; } diff --git a/Userland/Libraries/LibWeb/Platform/AudioCodecPlugin.cpp b/Userland/Libraries/LibWeb/Platform/AudioCodecPlugin.cpp index 9e300a87672..c58de962438 100644 --- a/Userland/Libraries/LibWeb/Platform/AudioCodecPlugin.cpp +++ b/Userland/Libraries/LibWeb/Platform/AudioCodecPlugin.cpp @@ -4,8 +4,8 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include -#include #include #include diff --git a/Userland/Libraries/LibWeb/Platform/AudioCodecPluginAgnostic.cpp b/Userland/Libraries/LibWeb/Platform/AudioCodecPluginAgnostic.cpp index dc06e831837..cd680416ae4 100644 --- a/Userland/Libraries/LibWeb/Platform/AudioCodecPluginAgnostic.cpp +++ b/Userland/Libraries/LibWeb/Platform/AudioCodecPluginAgnostic.cpp @@ -5,6 +5,7 @@ */ #include +#include #include #include #include