Fix some dither clipping issues

custom
jacqueline 1 year ago
parent 2ccaaf5724
commit d4a0085753
  1. 5
      src/codecs/include/sample.hpp
  2. 16
      src/codecs/sample.cpp
  3. 3
      src/drivers/i2s_dac.cpp

@ -28,12 +28,11 @@ constexpr auto Clip(int64_t v) -> Sample {
return std::clamp<int64_t>(v, INT16_MIN, INT16_MAX); return std::clamp<int64_t>(v, INT16_MIN, INT16_MAX);
} }
auto applyDither(int64_t src, uint_fast8_t bits) -> int32_t; auto shiftWithDither(int64_t src, uint_fast8_t bits) -> Sample;
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 shiftWithDither(src, bits - 16);
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);
} }

@ -5,6 +5,7 @@
*/ */
#include "sample.hpp" #include "sample.hpp"
#include <stdint.h>
#include <cstdint> #include <cstdint>
@ -15,11 +16,16 @@ namespace sample {
static uint64_t sSeed1{0}; static uint64_t sSeed1{0};
static uint64_t sSeed2{0}; static uint64_t sSeed2{0};
auto applyDither(int64_t src, uint_fast8_t bits) -> int32_t { auto shiftWithDither(int64_t src, uint_fast8_t bits) -> Sample {
uint64_t mask = 0xFFFFFFFF; // 32 ones // Generate `bits` random bits
mask >>= 32 - bits; // `bits` ones uint64_t mask = 0xFFFFFFFF;
uint64_t noise = komirand(&sSeed1, &sSeed2) & mask; // `bits` random noise mask >>= 32 - bits;
return std::clamp<int64_t>(src + noise, INT32_MIN, INT32_MAX); int64_t noise = static_cast<int32_t>(komirand(&sSeed1, &sSeed2) & mask);
// Centre the noise around 0.
noise -= (mask >> 1);
// Apply to the sample, then clip and shift to 16 bit.
Sample clipped = Clip((src + noise) >> bits);
return clipped;
} }
} // namespace sample } // namespace sample

@ -97,6 +97,9 @@ I2SDac::I2SDac(IGpios& gpio, i2s_chan_handle_t i2s_handle)
wm8523::WriteRegister(wm8523::Register::kReset, 1); wm8523::WriteRegister(wm8523::Register::kReset, 1);
vTaskDelay(pdMS_TO_TICKS(10)); vTaskDelay(pdMS_TO_TICKS(10));
wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0); wm8523::WriteRegister(wm8523::Register::kPsCtrl, 0b0);
// Ramp volume changes
wm8523::WriteRegister(wm8523::Register::kDacCtrl, 0b11);
} }
I2SDac::~I2SDac() { I2SDac::~I2SDac() {

Loading…
Cancel
Save