gearmulator

Emulation of classic VA synths of the late 90s/2000s that are based on Motorola 56300 family DSPs
Log | Files | Refs | Submodules | README | LICENSE

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 }