123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142 |
- /*
- * Copyright (c) 2023, kleines Filmröllchen <filmroellchen@serenityos.org>
- *
- * SPDX-License-Identifier: BSD-2-Clause
- */
- #pragma once
- #include <AK/Array.h>
- #include <AK/Forward.h>
- #include <AK/Math.h>
- #include <AK/Types.h>
- #include <math.h>
- 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<FrameHeader> 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<u8, 20> 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<int, 17> generate_scale_factor_table()
- {
- Array<int, 17> scalefactor_table;
- for (size_t s = 0; s < 17; ++s)
- scalefactor_table[s] = static_cast<int>(AK::round<double>(AK::pow<double>(static_cast<double>(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<int, 17> scale_factor_table = {
- 1, 7, 21, 45, 84, 138, 211, 304, 421, 562, 731, 928, 1157, 1419, 1715, 2048
- };
- #else
- static constexpr Array<int, 17> scale_factor_table = generate_scale_factor_table();
- #endif
- constexpr Array<int, 17> generate_reciprocal_table()
- {
- Array<int, 17> 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<Array<int, 8>, 16> generate_dequantization_table()
- {
- Array<Array<int, 8>, 16> dequantization_table;
- constexpr Array<double, 8> 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<int>(AK::round<double>(
- static_cast<double>(scale_factor_table[scale]) * float_dequantization_table[quantization]));
- }
- return dequantization_table;
- }
- #if defined(AK_COMPILER_CLANG)
- static constexpr Array<int, 17> reciprocal_table = {
- 65536, 9363, 3121, 1457, 781, 475, 311, 216, 156, 117, 90, 71, 57, 47, 39, 32
- };
- static constexpr Array<Array<int, 8>, 16> dequantization_table = {
- Array<int, 8> { 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<int, 17> reciprocal_table = generate_reciprocal_table();
- static constexpr Array<Array<int, 8>, 16> dequantization_table = generate_dequantization_table();
- #endif
- static constexpr Array<int, 17> quantization_table = {
- 7, 7, 7, 5, 5, 3, 3, 1, // -8 ..-1
- 0, // 0
- 0, 2, 2, 4, 4, 6, 6, 6 // 1 .. 8
- };
- }
|