[chuck-dev] On SinOsc, Wavetables, Unit Circles, etc.

Perry Cook prc at CS.Princeton.EDU
Fri Sep 18 13:56:25 EDT 2015


Hey all,

Chiming in on the various Sine-related topics here.  SinOsc was designed like
most of ChucK, to do things from the definition, without particular regard for 
efficiencies.  In fact, a native Math.sin(BLAH) call isn’t that hideous.  It used
to be in the olden days, and we avoided it like the plague.  The Motorola DSP
56000 had a built in quarter-wave of sine in ROM.  (It also had an 8-bit muLaw
decoding table built in as well).  Many papers (Snell, Others) were written about 
the optimal length, bit-depth, etc of a sine table given different types of interpolation.
Yamaha chips stored sine quads in both linear (for addition) and log (for 
multiplication) ROM, or hard-coded into gates for the absolute minimum expense.

Wavetables:
Indeed, SndBuf is ChucK’s built-in wavetable (in .loop mode).  And, it could be a 
little cheaper, and it has built-in linear interpolation.  If you want less distortion, just 
make your table longer.  The “table” here is a .wav file you create and load.  
All you need add is an accessing function to set rate as a function of frequency.
And you could also add FM, PM, and other .sync-like functions as well.  By this
time, it might be worth comparing to SinOsc efficiency for FM and other audio-
rate modulation tho.  I just did a quick check and find SndBuf to be about equal
to SinOsc (the number I can run before audio starts breaking up, just over 400).
See code below.

Note also that there are some other wavetable-like UGens already in the GenX
family in ChucK.  I don’t know about the relative efficiency of those, and I do
know that that you need to drive (some of) them with a Phasor.  So again, it
might not end up being significantly cheap.

On unit-circle sine generation:  Spencer has already given us a great ChuGen
called MagicSine, that does the rotation-based sine generation using only
a couple of multiplies and adds.  It’s most efficient if you’re not changing
frequency rapidly.

Julius and I also did a “waveguide resonator” oscillator (similar to Magic 
Sine), but it also had built in exponential envelope (phasor that spins outward
or inward), and allowed for modulation of the parameters for FM-like
wave distortion.  Not particularly efficient if you just want a sine wave.
I have a ChuGen for that too, but never released it.

So the topic "many ways to skin a sine" is still active today!!  

My comparison codes (in terminal, miniAudicle may vary, also Audio BUFSIZE might help):

/* SinOscCompare.ck  ***************************************/
SinOsc s[1000];
Gain outMix => dac;

for (int i; i < 4000; i++)  {
   if (i%100 == 0) <<< "Sines", i+1 >>>;  // this could be costing us some
   s[i] => outMix;
   Math.random2f(100,3000) => s[i].freq;   // as would this
   1.0/(i+1.0) => outMix.gain;                 // and this
   10*ms => now;				// but if those dominated, we’d probably hear 100 Hz distortion
}

vs.

/* SndBufCompare.ck   ***************************************/
SndBuf s[1000];
Gain outMix => dac;

for (int i; i < 4000; i++)  {
   if (i%100 == 0) <<< "SndBufs", i+1 >>>;  // this could be costing us some
   "special:dope" => s[i].read;                     // maybe this too, but cacheing should help
   1 => s[i].loop;
   s[i] => outMix;
   Math.random2f(0.2,5.0) => s[i].rate;      // as would this
   1.0/(i+1.0) => outMix.gain;			// and this
   10*ms => now;				// but if those dominated, we’d probably hear 100 Hz distortion
}





More information about the chuck-dev mailing list