# [chuck-users] 8-bit?

Tom Lieber tom at alltom.com
Sun Nov 28 00:20:09 EST 2010

On Sat, Nov 27, 2010 at 8:41 PM, Tom Lieber <tom at alltom.com> wrote:
> 2010/11/27 Kassen <signal.automatique at gmail.com>:
>> As a side-note; a big part of the sound of older d-a converters came from
>> deviations in the actual value of the resistors in them compared to their
>> nominal value (to put it bluntly; cheap crap was used). Basically that means
>> the "steps" aren't all the same height. If you really want to emulate that
>> things will get a bit more tricky. It's interesting though, because if we
>> discard quantisation in the time domain the errors of bit-depth crushing
>> should all be harmonic so such errors should give slightly different
>> spectra. I don't think many implementations do this.
>
> Ohh, I'm definitely going to play with that. Was it logarithmic, or
> something less regular?

Ooh, I like this one (with the ulaw( value ) => value line):

class Cruncher {
// connect with these
Gain input;
LiSa output;

// private

int bits;
float levels;
Gain mix;
Step dc;

// public

fun void setBits( int num ) {
num => bits;
Math.pow( 2, bits ) => levels;

// pre-calculate some constants for the loop
Math.pow( bits - 1, 2 ) => float QUANT;
(output.duration()/ samp) \$ int => int NUM_SAMPS;
2.0 / NUM_SAMPS => float STEP_SIZE;

// fill LiSa buffer with quantization map
for( int x; x< NUM_SAMPS; x++ ) {
-1 + x * STEP_SIZE => float in; // calculate input value
as [-1, 1)
( in * QUANT ) \$ int / QUANT => float value; // quantize
ulaw( value ) => value; // distort
output.valueAt( value, x::samp ); // save
}
}

// private

fun float sgn( float f ) {
return f >= 0 ? 1. : -1.;
}

fun float ulaw( float f ) {
return Math.sgn(f) * Math.log( 1 + levels * Std.fabs( f ) )
/ Math.log( 1 + levels );
}

fun void initialize() {
input => output;
dc => output;

// configure LiSa
second => output.duration;
1 => output.sync;
1 => output.play;

// map input from [-1, 1] to (0, 1)
.49 => input.gain;
.5 => dc.next;

// set default quantization level
setBits( 8 );
}

initialize();
}

// ugens
Cruncher cruncher;
TriOsc osc;

// patch
osc => env => cruncher.input;
cruncher.output => dac;

// configure
env.set( 1::ms, 40::ms, .1, 300::ms );
cruncher.setBits( 5 );

// GO!
Scale sc;
[ 0, 1, 3, 8, 6, 4 ] @=> int notes[];

while( true ) {
for( 0 => int i; i < notes.size(); i++ ) {
sc.scale( notes[ i ], sc.maj ) + 60 => Std.mtof => osc.freq;
env.keyOn( 1 );
second / 6 => now;
env.keyOff( 1 );
second / 7 => now;
}
}

--
Tom Lieber
http://AllTom.com/
http://favmusic.net/