The Csound Blog by Jacob Joaquin email jacobjoaquin@gmail.com web www.thumbuki.com/csound/blog (C)2007 Jacob Joaquin Licensed under Creative Commons (see below) 2007.01.22 Oscillator Arrays and Multi-Band Spatializers How does one casually write technical jargon? That's what I'm still trying to figure out. These Csound blogs aren't suppose to be full articles or tutorials, though I'm finding it difficult not to explain every nuance. I did my best to narrow down this entry to the key issues and give just enough info for those interested to start using the discussed techniques. Layered Voices The synth instrument is a monophonic combination of three different types of voices, spanning multiple registers for a full, rich sound. The first voice is an additive synthesizer, utilizing eight oscillators with frequencies chosen using the harmonic tree method.[1] The second voice is a subtractive-like detuned bass that uses the gbuzz opcode. The third voice is filtered, pitched-noise, which helps fill in the gaps of the sonic field. Synchronized Phase-Offset Oscillator Array The amplitudes of the audio oscillators for the additive voice are modulated with a synchronized phase-offset oscillator array. A master lfo[2] is generated with the phasor opcode. The master lfo is then duplicated eight times to read through a stored sine table, with the phase of each copy being offset by 45 degrees, or 0.125 of a cycle. Each individual LFO is then biased[3] and rescaled to pre-defined harmonic strengths. The amount of modulation for each LFO is then set. Since each LFO peaks at a different time, a subtle cyclic melody is generated as part of the sound. Those who have studied Jean-Claude Risset's[4] "Endless Glissando"[5] are most likely familiar with the synchronized phase-offset oscillator array concept. Though I've never seen the code, I would bet this technique is used in James Tenney's[6] piece "For Ann (rising)"[7], as well. Multi-Band Spatializer The multi-band spatializer is based off the classic graphic equalizer. Instead of changing the gain of each band, each band is placed into a stereo field. I wrote a custom opcode called Band, which is a bandpass filter created from the Butterworth highpass and lowpass filters. From this, I created a 10-band spatializer. The odd bands are hard-panned to the left, while the even bands are hard-panned to the right. As a monophonic audio stream passes through the spatializer, the sound becomes stereo-ized. Oscillator Array Modulated Multi-Band Panner The multi-band panner is a modified version of the multi-band spatializer that allows each band to be panned dynamically. This effects processor uses a synchronized phase-offset array to modulate the pan positions of each individual band. Since there are ten bands, the phase difference between each lfo is set to 0.1, or 36 degrees. The overall effect is a spatial swirl, as the different registers of the audio stream gently glide back and forth in the stereo field. Other Possibilities I will most likely revisit the topics discussed here, as they can certainly be applied to many other synth techniques. For example, one could easily adapt these effects processors to make a multi-band chorus, flange, or rhythmic delay. References [1] Harmonic Trees - Jacob Joaquin http://www.csounds.com/ezine/trees/ [2] Exploring Analogue Synth Techniques v2 - Jacob Joaquin http://www.thumbuki.com/csound/articles/east/stepsequencer.html#MasterClock [3] Exploring Analogue Synth Techniques v2 - Jacob Joaquin http://www.thumbuki.com/csound/articles/east/bias.html [4] Jean-Claude Risset http://en.wikipedia.org/wiki/Jean-Claude_Risset [5] Risset's Endless Glissando - Jean-Claude Risset http://csounds.com/catalogfrom/risset/endless.orc [6] James Tenney http://en.wikipedia.org/wiki/James_Tenney [7] For Ann (rising) - James Tenney http://www.allmusic.com/cg/amg.dll?p=amg&sql=42:477209~T1 Permalink http://www.thumbuki.com/20070122/oscillator-arrays-and-multi-band-spatializers.html License (cc) Creative Commons Attribution-ShareAlike 2.5 You are free: * to Share -- to copy, distribute, display, and perform the work * to Remix -- to make derivative works Under the following conditions: * Attribution. You must attribute the work in the manner specified by the author or licensor. * Share Alike. If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one. * For any reuse or distribution, you must make clear to others the license terms of this work. * Any of these conditions can be waived if you get permission from the copyright holder. http://creativecommons.org/licenses/by-sa/2.5/ sr = 44100 kr = 4410 ksmps = 10 nchnls = 2 ; opcode band Bandpass( asig, klowfreq, khighfreq ) ; instr 10 Layered Three Voice Synth ; instr 100 Mono ; instr 111 10-Band Spatializer ; instr 112 10-Band Panner ; instr 200 Master Mixer ; instr 300 Clear Zak Channels ; Master Volume #define VOLUME #5000# ; Zak Busses # define ZACHANNELS #3# # define ZKCHANNELS #1# zakinit $ZACHANNELS, $ZKCHANNELS ; a-rate zak channels # define ZMIXERMONO #1# # define ZMIXERLEFT #2# # define ZMIXERRIGHT #3# ; k-rate zak channels ; none ; ---- Bandpass ---- opcode Band, a, akk ; asig signal input ; klowfreq lowest frequency ; khighfreq highest frequency asig, klowfreq, khighfreq xin asig butterhp asig, klowfreq asig butterlp asig, khighfreq xout asig endop ; ---- Layered Three Voice Synth ---- instr 10 idur = p3 iamp = p4 ipch = cpspch( p5 ) ; Additive Voice ih1 = 1 ih2 = ih1 * 2 ih3 = ih2 * 3 / 2 ih4 = ih3 * 3 / 2 ih5 = ih4 * 6 / 5 ih6 = ih5 * 9 / 8 ih7 = ih6 * 4 / 3 ih8 = ih7 * 3 / 2 iv1 = 1 iv2 = 0.9 iv3 = 0.8 iv4 = 0.7 iv5 = 0.6 iv6 = 0.5 iv7 = 0.4 iv8 = 0.3 kenv linseg 0, idur * 0.2, 0, 0, 6, idur * 0.8, 3 klfo oscil 1, kenv, 1, -1 klfo = ( klfo + 1 ) * 0.5 klfo = klfo * 0.015 kenv2 expseg ipch, idur * 0.3, ipch, idur * 0.7, ipch * 1.041 kenv3 expseg ipch, idur * 0.3, ipch, idur * 0.7, ipch * 0.989 kf1 = kenv2 * ih1 kf2 = kenv3 * ih2 kf3 = kenv2 * ih3 kf4 = kenv3 * ih4 kf5 = kenv2 * ih5 kf6 = kenv3 * ih6 kf7 = kenv2 * ih7 kf8 = kenv3 * ih8 iwave = 1 ilength = ftlen( iwave ) kmlfo phasor -1.333, -1 klfo1 table ( kmlfo + 0.0 ) * ilength, iwave, 0, 0, 1 klfo2 table ( kmlfo + 0.125 ) * ilength, iwave, 0, 0, 1 klfo3 table ( kmlfo + 0.25 ) * ilength, iwave, 0, 0, 1 klfo4 table ( kmlfo + 0.375 ) * ilength, iwave, 0, 0, 1 klfo5 table ( kmlfo + 0.5 ) * ilength, iwave, 0, 0, 1 klfo6 table ( kmlfo + 0.625 ) * ilength, iwave, 0, 0, 1 klfo7 table ( kmlfo + 0.75 ) * ilength, iwave, 0, 0, 1 klfo8 table ( kmlfo + 0.875 ) * ilength, iwave, 0, 0, 1 klfo1 = ( klfo1 + 1 ) * 0.5 * iv1 + iv1 * 0.3 klfo2 = ( klfo2 + 1 ) * 0.5 * iv2 + iv2 * 0.3 klfo3 = ( klfo3 + 1 ) * 0.5 * iv3 + iv3 * 0.2 klfo4 = ( klfo4 + 1 ) * 0.5 * iv4 + iv4 * 0.2 klfo5 = ( klfo5 + 1 ) * 0.5 * iv5 + iv5 * 0.1 klfo6 = ( klfo6 + 1 ) * 0.5 * iv6 + iv6 * 0.1 klfo7 = ( klfo7 + 1 ) * 0.5 * iv7 + iv7 * 0.1 klfo8 = ( klfo8 + 1 ) * 0.5 * iv8 + iv8 * 0.1 aosc1 oscil klfo1, kf1 + ( kf1 * klfo ), 1, -1 aosc2 oscil klfo2, kf2 + ( kf2 * klfo ), 1, -1 aosc3 oscil klfo3, kf3 + ( kf3 * klfo ), 1, -1 aosc4 oscil klfo4, kf4 + ( kf4 * klfo ), 1, -1 aosc5 oscil klfo5, kf5 + ( kf5 * klfo ), 1, -1 aosc6 oscil klfo6, kf6 + ( kf6 * klfo ), 1, -1 aosc7 oscil klfo7, kf7 + ( kf7 * klfo ), 1, -1 aosc8 oscil klfo8, kf8 + ( kf8 * klfo ), 1, -1 aadditive = aosc1 + aosc2 + aosc3 + aosc4 + aosc5 + aosc6 + aosc7 + aosc8 aenv expseg 1, 0.01, 2, 0.05, 1.6, idur * 0.94, 1 aenv = aenv - 1 aadditive = aadditive * aenv ; Buzz Voice ipch2 = ipch * 0.25 abuzz1 gbuzz 1, ipch2, sr / 2 / ipch2, 1, 0.6, 4 abuzz2 gbuzz 1, ipch2 - ( ipch2 * 0.0125 ), sr / 2 / ipch2, 1, 0.6, 4 abuzzmix = abuzz1 + abuzz2 kenv expseg ipch2 * 16, idur, ipch2 * 8 abuzzmix butterlp abuzzmix, kenv aenv2 linseg 0, 0.01, 1, idur - 0.01, 0 abuzzmix = abuzzmix * aenv2 ; Noise Voice aflutter oscil 1, ipch * 0.25, 5 kenv4 expseg ipch * 1.25, idur, ipch * 1.666 aflutter Band aflutter, ipch * 0.125, kenv4 ilp = cpspch( 10.00 ) aflutter butterlp aflutter, ilp aflutter = aflutter * aenv2 ; Mix Voices and Send to Master Mixer amix = abuzzmix + aadditive * 1.2 + aflutter * 10 zawm amix, $ZMIXERMONO endin ; ---- Mono ---- instr 100 amono zar $ZMIXERMONO zawm amono, $ZMIXERLEFT zawm amono, $ZMIXERRIGHT endin ; ---- 10-Band Spatializer ---- instr 111 amono zar $ZMIXERMONO a1 Band amono, 20, 40 a2 Band amono, 40, 80 a3 Band amono, 80, 160 a4 Band amono, 160, 320 a5 Band amono, 320, 640 a6 Band amono, 640, 1280 a7 Band amono, 1280, 2560 a8 Band amono, 2560, 5120 a9 Band amono, 5120, 10240 aA Band amono, 10240, 22050 aleft = ( a1 + a3 + a5 + a7 + a9 ) * 2 aright = ( a2 + a4 + a6 + a8 + aA ) * -2 zawm aleft, $ZMIXERLEFT zawm aright, $ZMIXERRIGHT endin ; ---- 10-Band Panner ---- instr 112 amono zar $ZMIXERMONO a1 Band amono, 20, 40 a2 Band amono, 40, 80 a3 Band amono, 80, 160 a4 Band amono, 160, 320 a5 Band amono, 320, 640 a6 Band amono, 640, 1280 a7 Band amono, 1280, 2560 a8 Band amono, 2560, 5120 a9 Band amono, 5120, 10240 aA Band amono, 10240, 20000 iwave = 1 ilength = ftlen( iwave ) klfo phasor 0.333, -1 klfo1 table ( klfo + 0.0 ) * ilength, iwave, 0, 0, 1 klfo2 table ( klfo + 0.1 ) * ilength, iwave, 0, 0, 1 klfo3 table ( klfo + 0.2 ) * ilength, iwave, 0, 0, 1 klfo4 table ( klfo + 0.3 ) * ilength, iwave, 0, 0, 1 klfo5 table ( klfo + 0.4 ) * ilength, iwave, 0, 0, 1 klfo6 table ( klfo + 0.5 ) * ilength, iwave, 0, 0, 1 klfo7 table ( klfo + 0.6 ) * ilength, iwave, 0, 0, 1 klfo8 table ( klfo + 0.7 ) * ilength, iwave, 0, 0, 1 klfo9 table ( klfo + 0.8 ) * ilength, iwave, 0, 0, 1 klfoA table ( klfo + 0.9 ) * ilength, iwave, 0, 0, 1 klfo1 = ( klfo1 + 1 ) * 0.5 klfo2 = ( klfo2 + 1 ) * 0.5 klfo3 = ( klfo3 + 1 ) * 0.5 klfo4 = ( klfo4 + 1 ) * 0.5 klfo5 = ( klfo5 + 1 ) * 0.5 klfo6 = ( klfo6 + 1 ) * 0.5 klfo7 = ( klfo7 + 1 ) * 0.5 klfo8 = ( klfo8 + 1 ) * 0.5 klfo9 = ( klfo9 + 1 ) * 0.5 klfoA = ( klfoA + 1 ) * 0.5 a1l = a1 * sqrt( klfo1 ) a1r = a1 * sqrt( 1 - klfo1 ) a2l = a2 * sqrt( klfo2 ) a2r = a2 * sqrt( 1 - klfo2 ) a3l = a3 * sqrt( klfo3 ) a3r = a3 * sqrt( 1 - klfo3 ) a4l = a4 * sqrt( klfo4 ) a4r = a4 * sqrt( 1 - klfo4 ) a5l = a5 * sqrt( klfo5 ) a5r = a5 * sqrt( 1 - klfo5 ) a6l = a6 * sqrt( klfo6 ) a6r = a6 * sqrt( 1 - klfo6 ) a7l = a7 * sqrt( klfo7 ) a7r = a7 * sqrt( 1 - klfo7 ) a8l = a8 * sqrt( klfo8 ) a8r = a8 * sqrt( 1 - klfo8 ) a9l = a9 * sqrt( klfo9 ) a9r = a9 * sqrt( 1 - klfo9 ) aAl = aA * sqrt( klfoA ) aAr = aA * sqrt( 1 - klfoA ) aleft = ( a1l + a2l + a3l + a4l + a5l + a6l + a7l + a8l + a9l + aAl ) * 2 aright = ( a1r + a2r + a3r + a4r + a5r + a6r + a7r + a8r + a9r + aAr ) * -2 zawm aleft, $ZMIXERLEFT zawm aright, $ZMIXERRIGHT endin ; ---- Master Mixer ---- instr 200 aleft zar $ZMIXERLEFT aright zar $ZMIXERRIGHT outs aleft * $VOLUME, aright * $VOLUME endin ; ---- Clear Zak Channels ---- instr 300 zacl 0, 3 endin f1 0 65536 10 1 f2 0 8192 -7 -1 4096 1 4096 -1 f3 0 8192 -7 -1 8192 1 f4 0 65536 11 1 f5 0 128 21 6 1 ; ---- Layered Three Voice Synth in Mono ---- t 0 60 i100 0 20 i200 0 20 i300 0 20 i10 0 4 1 7.00 i10 + . 1 8.00 i10 + . 1 8.07 i10 + 8 1 7.00 s f0 1 s ; ---- Multi-Band Spatializer ---- t 0 60 i111 0 20 i200 0 20 i300 0 20 i10 0 4 1 7.00 i10 + . 1 8.00 i10 + . 1 8.07 i10 + 8 1 7.00 s f0 1 s ; ---- Oscillator Array Modulated Multi-Band Panner ---- t 0 60 i112 0 20 i200 0 20 i300 0 20 i10 0 4 1 7.00 i10 + . 1 8.00 i10 + . 1 8.07 i10 + 8 1 7.00 e