Add dither when requantising >16 bit samples

custom
jacqueline 1 year ago
parent 8a260dad05
commit 2ccaaf5724
  1. 5
      src/codecs/CMakeLists.txt
  2. 21
      src/codecs/include/sample.hpp
  3. 3
      src/codecs/miniflac.cpp
  4. 25
      src/codecs/sample.cpp

@ -4,8 +4,9 @@
idf_component_register( idf_component_register(
SRCS "codec.cpp" "mad.cpp" "miniflac.cpp" "opus.cpp" "vorbis.cpp" SRCS "codec.cpp" "mad.cpp" "miniflac.cpp" "opus.cpp" "vorbis.cpp"
"source_buffer.cpp" "source_buffer.cpp" "sample.cpp"
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
REQUIRES "result" "span" "libmad" "miniflac" "tremor" "opusfile" "memory") REQUIRES "result" "span" "libmad" "miniflac" "tremor" "opusfile" "memory"
"komihash")
target_compile_options("${COMPONENT_LIB}" PRIVATE ${EXTRA_WARNINGS}) target_compile_options("${COMPONENT_LIB}" PRIVATE ${EXTRA_WARNINGS})

@ -25,15 +25,14 @@ namespace sample {
typedef int16_t Sample; typedef int16_t Sample;
constexpr auto Clip(int64_t v) -> Sample { constexpr auto Clip(int64_t v) -> Sample {
if (v > INT16_MAX) return std::clamp<int64_t>(v, INT16_MIN, INT16_MAX);
return INT16_MAX;
if (v < INT16_MIN)
return INT16_MIN;
return v;
} }
auto applyDither(int64_t src, uint_fast8_t bits) -> int32_t;
constexpr auto FromSigned(int32_t src, uint_fast8_t bits) -> Sample { constexpr auto FromSigned(int32_t src, uint_fast8_t bits) -> Sample {
if (bits > 16) { if (bits > 16) {
src = applyDither(src, bits - 16);
return src >> (bits - sizeof(Sample) * 8); return src >> (bits - sizeof(Sample) * 8);
} else if (bits < 16) { } else if (bits < 16) {
return src << (sizeof(Sample) * 8 - bits); return src << (sizeof(Sample) * 8 - bits);
@ -48,16 +47,20 @@ constexpr auto FromUnsigned(uint32_t src, uint_fast8_t bits) -> Sample {
} }
constexpr auto FromFloat(float src) -> Sample { constexpr auto FromFloat(float src) -> Sample {
return std::clamp<float>(src, -1.0f, 1.0f) * static_cast<float>(INT16_MAX); int32_t quantised =
std::clamp<float>(src, -1.0f, 1.0f) * static_cast<float>(INT32_MAX);
return FromSigned(quantised, 32);
} }
constexpr auto FromDouble(double src) -> Sample { constexpr auto FromDouble(double src) -> Sample {
return std::clamp<double>(src, -1.0, 1.0) * static_cast<double>(INT16_MAX); int32_t quantised =
std::clamp<double>(src, -1.0, 1.0) * static_cast<double>(INT32_MAX);
return FromSigned(quantised, 32);
} }
constexpr auto FromMad(mad_fixed_t src) -> Sample { constexpr auto FromMad(mad_fixed_t src) -> Sample {
// Round the bottom bits. // Round the bottom bits.
src += (1L << (MAD_F_FRACBITS - 16)); src += (1L << (MAD_F_FRACBITS - 24));
// Clip the leftover bits to within range. // Clip the leftover bits to within range.
if (src >= MAD_F_ONE) if (src >= MAD_F_ONE)
@ -66,7 +69,7 @@ constexpr auto FromMad(mad_fixed_t src) -> Sample {
src = -MAD_F_ONE; src = -MAD_F_ONE;
// Quantize. // Quantize.
return FromSigned(src >> (MAD_F_FRACBITS + 1 - 16), 16); return FromSigned(src >> (MAD_F_FRACBITS + 1 - 24), 24);
} }
static constexpr float kFactor = 1.0f / static_cast<float>(INT16_MAX); static constexpr float kFactor = 1.0f / static_cast<float>(INT16_MAX);

@ -5,9 +5,8 @@
*/ */
#include "miniflac.hpp" #include "miniflac.hpp"
#include <stdint.h>
#include <sys/_stdint.h>
#include <cstdint>
#include <cstdlib> #include <cstdlib>
#include "esp_heap_caps.h" #include "esp_heap_caps.h"

@ -0,0 +1,25 @@
/*
* Copyright 2023 jacqueline <me@jacqueline.id.au>
*
* SPDX-License-Identifier: GPL-3.0-only
*/
#include "sample.hpp"
#include <cstdint>
#include "komihash.h"
namespace sample {
static uint64_t sSeed1{0};
static uint64_t sSeed2{0};
auto applyDither(int64_t src, uint_fast8_t bits) -> int32_t {
uint64_t mask = 0xFFFFFFFF; // 32 ones
mask >>= 32 - bits; // `bits` ones
uint64_t noise = komirand(&sSeed1, &sSeed2) & mask; // `bits` random noise
return std::clamp<int64_t>(src + noise, INT32_MIN, INT32_MAX);
}
} // namespace sample
Loading…
Cancel
Save