/* * 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 { // Experimentally determined to be a decent buffer size on i686: // 4K (the default) is slightly worse, and 64K is much worse. // At sufficiently large buffer sizes, the advantage of infrequent read() calls is outweighed by the memmove() overhead. // There was no intensive fine-tuning done to determine this value, so improvements may definitely be possible. constexpr size_t FLAC_BUFFER_SIZE = 8 * KiB; 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 Result, LoaderError> create(StringView path); static Result, LoaderError> create(Bytes buffer); virtual LoaderSamples get_more_samples(size_t max_bytes_to_read_from_input = 128 * KiB) 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 DeprecatedString 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 writes the next FLAC frame MaybeLoaderError next_frame(Span); // 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, LoaderError> parse_subframe(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, LoaderError> decode_custom_lpc(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&); 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); // 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 PcmSampleFormat m_sample_format; // 5 bits for the integer bit depth // 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; // Whatever the last get_more_samples() call couldn't return gets stored here. Vector m_unread_data; u64 m_current_sample_or_frame { 0 }; Vector m_seektable; }; }