On Sat, Nov 27, 2010 at 8:41 PM, Tom Lieber
2010/11/27 Kassen
: 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; ADSR env; // 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/