[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;
  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/


More information about the chuck-users mailing list