Emulating vintage DACs with bitcrusher & μ-law compression
-
following up on yesterday's thread I wanted to post the results here, so anyone can find them should they need them. Those are great to emulate a vintage DAC of old drum machines and 8 bit samplers, just the way Tal DAC or Decimort would do it.
Why prefer this over regular bitcrusher? μ-law has a higher dynamic range and much better SNR (signal to noise ratio) which means more values are spread among quieter levels, and less values among peak values. This massively improves artifacting while still giving the nice retro 8-bit crunch and sizzle we love.
This is the c++ code:
void process(float* samples, int numSamples) { for (int i = 0; i < numSamples; ++i) { float val = samples[i]; int max = 255; // μ-law compression float valmu = sgn(val) * log( 1.0f + max * abs(val) ) / log( 1.0f + max); // bit reduction float valmu8 = valmu - fmodf(valmu, 1.0f / max); // μ-law expansion float valex = sgn(valmu8) * (1.0f / max) * ( pow(max + 1.0f, abs(valmu8)) - 1.0f ); } }
there is also a faust version Stephane Letz over at faust Discord made
import("stdfaust.lib"); mulaw_bitcrusher(mu,nbits,x) = x : muLawCompress(mu) : ba.bitcrusher(nbits) : muLawExpand(mu) with { // μ-law compression muLawCompress(mu, x) = ma.signum(x) * log(1 + mu * abs(x)) / log(1 + mu); // μ-law expansion (decompression) muLawExpand(mu, x) = ma.signum(x) * (pow(1 + mu, abs(x)) - 1) / mu; }; process = mulaw_bitcrusher(255,8),mulaw_bitcrusher(255,8);
this has also been added to basics.lib so in the future you will simply be able to use ba.mulaw_bitcrusher
The same expansion formula/technique can be used to read μ-law compressed wav files or eprom binaries made using μ-law, which are probably most of them if not all.
-
@Morphoice said in Emulating vintage DACs with bitcrusher & μ-law compression:
https://instagram.com/morphoice - 80s inspired Synthwave Music, Arcade & Gameboy homebrew!
interesting - sort of... Here's a slightly more friendly-to-HISE faust version, tho I cant seem to get it to behave correctly above 8 bits... so I probably dont understand what nBits is here...I foolishly assumed it was the number of bits - and I'm pretty certain 12-bit doesnt sound this clean...and 2-bit wouldnt sound like this at all...
import("stdfaust.lib"); nBits = hslider("Bits", 8, 2, 16, 1); mulaw_bitcrusher(mu,nbits,x) = x : muLawCompress(mu) : ba.bitcrusher(nbits) : muLawExpand(mu) with { // μ-law compression muLawCompress(mu, x) = ma.signum(x) * log(1 + mu * abs(x)) / log(1 + mu); // μ-law expansion (decompression) muLawExpand(mu, x) = ma.signum(x) * (pow(1 + mu, abs(x)) - 1) / mu; }; process = mulaw_bitcrusher(255,nBits),mulaw_bitcrusher(255,nBits);
-
@Lindon probably mu needs to be bigger than 255 if you go above 8bits. I haven’t tried to be honest, I’ll check in a bit.
-
@Morphoice yeah I tried 512 but no difference.
-
@Lindon it should work fine, just above around 10 bits the difference is not really audible anymore with average audio
try this in faust IDE, it renders a very low sine wave, which makes the artifacts clearly audible even if you go above 8 bit you can hear the them gradually disappearing
import("stdfaust.lib"); nBits = hslider("Bits", 8, 2, 16, 1); mulaw_bitcrusher(mu,nbits,x) = x : muLawCompress(mu) : ba.bitcrusher(nbits) : muLawExpand(mu) with { // μ-law compression muLawCompress(mu, x) = ma.signum(x) * log(1 + mu * abs(x)) / log(1 + mu); // μ-law expansion (decompression) muLawExpand(mu, x) = ma.signum(x) * (pow(1 + mu, abs(x)) - 1) / mu; }; test = os.sinwaveform(8192) : mulaw_bitcrusher(255,nBits); process = test,test;
8 Bit steps are clearly visible
10 bit barely visible stepping at the peakI can hear artifacts up to 13 bit, as of 14 it is gone
-
@Lindon said in Emulating vintage DACs with bitcrusher & μ-law compression:
@Morphoice yeah I tried 512 but no difference.
Since the mu law is a weighted repartition of a signal, the ratio oscillate between linear at mu=0 toward logarithmic for higher values. So the higher mu the less impact on higher signals. All that to say the difference lies in the tiny signals like reverb trails, etc... So you can keep crushing higher signals like falling fire from hell on a nursery while enjoying delicate small signals with a warm latte