dac.h (2314B)
1 #pragma once 2 3 #include <cmath> 4 #include <cstdint> 5 6 #include "dsp56kEmu/types.h" 7 #include "dsp56kEmu/utils.h" 8 9 namespace juce 10 { 11 class Process; 12 } 13 14 namespace synthLib 15 { 16 struct DacState 17 { 18 uint32_t randomValue = 56362; 19 }; 20 21 namespace dacHelper 22 { 23 inline uint32_t lcg(uint32_t& _state) 24 { 25 // https://en.wikipedia.org/wiki/Linear_congruential_generator 26 constexpr uint32_t a = 1664525; 27 constexpr uint32_t c = 1013904223; 28 constexpr uint32_t m = 0xffffffff; 29 30 _state = (a * (_state) + c) & m; 31 32 return _state; 33 } 34 } 35 36 template<uint32_t OutputBits, uint32_t NoiseBits> class DacProcessor 37 { 38 public: 39 static constexpr uint32_t InBits = 24; 40 41 // first noise bit is 0.5 bits so add one to the output bits 42 static constexpr uint32_t OutBits = NoiseBits > 0 ? (OutputBits + 1) : OutputBits; 43 44 static_assert(OutputBits > 0, "OutputBits must be > 0"); 45 static_assert(NoiseBits < OutBits, "NoiseBits must be <= OutputBits"); 46 47 static constexpr float FloatToIntScale = static_cast<float>(1 << (OutputBits-1)); // 1 bit sign 48 static constexpr float IntToFloatScale = 1.0f / FloatToIntScale; 49 50 static float processSample(DacState& _dacState, const dsp56k::TWord _in) 51 { 52 int32_t v = dsp56k::signextend<int32_t,24>(static_cast<int32_t>(_in)); 53 54 if constexpr (OutBits > InBits) 55 { 56 v <<= (OutBits - InBits); 57 } 58 else if constexpr (OutBits < InBits) 59 { 60 constexpr int32_t rounder = (1<<(InBits - OutBits-1)) - 1; 61 v += rounder; 62 v >>= (InBits - OutBits); 63 } 64 65 // v = 0; 66 67 if constexpr (NoiseBits > 0) 68 { 69 constexpr int32_t rounder = (1<<(NoiseBits-1)) - 1; 70 71 _dacState.randomValue = dacHelper::lcg(_dacState.randomValue); 72 73 const int32_t randomValue = _dacState.randomValue >> (32u - NoiseBits); 74 v += (randomValue-rounder); 75 76 v >>= 1; 77 } 78 79 return static_cast<float>(v) * IntToFloatScale; 80 } 81 }; 82 83 class Dac 84 { 85 public: 86 Dac(); 87 88 using ProcessFunc = float(*)(DacState&, dsp56k::TWord); 89 90 bool configure(uint32_t _outputBits, uint32_t _noiseBits); 91 92 float processSample(const dsp56k::TWord _in) 93 { 94 return m_processFunc(m_state, _in); 95 } 96 97 private: 98 static ProcessFunc findProcessFunc(uint32_t _outputBits, uint32_t _noiseBits); 99 100 ProcessFunc m_processFunc; 101 DacState m_state; 102 uint32_t m_outputBits = 24; 103 uint32_t m_noiseBits = 1; 104 }; 105 }