//HW 4- Performance Code //Ryan Landron- Music 220a Binaural4 b4; 6 => int nInsts; FMFS fm[6]; for (int i; i < 6; ++i) { 0.0 => fm[i].out.gain; } fm[0].out => b4.input[3]; fm[1].out => b4.input[1]; fm[2].out => b4.input[2]; fm[3].out => b4.input[3]; fm[4].out => b4.input[0]; fm[5].out => b4.input[1]; [90.0, 95.0, 85.0, 98, 95, 87] @=> float loud[]; [1.0, 1.0, 1.0, 1, 1, 1] @=> float tran[]; [0, 1, 2, 1, 3, 1] @=> int chan[]; [4.0, 10.0, 2.5, 1.5, 1.0, 1] @=> float fmIndex[]; [4.0, 2.0, 3.0, 2.0, 4.0, 5.0] @=> float fmRatio[]; [0.0, 0.0,0.0, 0.0, 0.0,0.0] @=> float skew[]; 1000::ms => dur duration; 500::ms => dur ioi; 10::ms => dur minIoi; 100::ms => dur minDur; 0 => int p; 0 => int i; 7 => int nPitches; int keyn[nPitches]; // ----------------------------------------------------------- // section 1 300::ms =>ioi; [ 30, 32, 34, 35, 37, 39, 31] @=> keyn; 30::second + now => time endOfSection1; while (now < endOfSection1) { chout <= "PITCH = " <= p <= "\t\t"; chout <= "INST. = " <= i <= IO.newline(); Std.mtof(keyn[p]) * tran[i] => float tmp; fm[i].setPitch(tmp); fm[i].out.gain(Math.dbtorms(loud[i])); fm[i].setIndex(fmIndex[i]); fm[i].setRatio(fmRatio[i]); fm[i].setSkew(skew[i]); fm[i].attack(400::ms); duration => now; fm[i].release(2000::ms); p++; i++; nPitches %=> p; nInsts %=> i; ioi => now; ioi * 0.8 => ioi; duration * .95 => duration; if (ioi < minIoi) { minIoi => ioi; } if (duration < minDur){ minDur => duration; } } // ----------------------------------------------------------- // section 2 [90.0, 80.0, 95.0, 85, 95, 90] @=> loud; [2.0, 1.0, 2.0, 4.0, 1.0, 2.0] @=> tran; [0, 1,2, 3, 1, 2] @=> chan; [3.0, 4.0, 7.5, 8.5, 4.0, 5] @=> fmIndex; [4.0, 2.0, 10.0, 2.0, 4.0, 5.0] @=> fmRatio; [0.0, 0.1,0.1 , 0.0, 0.1,0.1] @=> skew; [ 45, 47, 48, 50, 52, 53, 54,55, 56, 45, 47, 48, 50, 52, 53, 54] @=> keyn; [150.0, 705.0, 400.0, 275.0, 500.0, 1000.0] @=> float release[]; [10.0, 20.0, 30.0, 40.0, 50.0, 60.0] @=> float attack[]; 16 @=> nPitches; 10::second + now => time endOfSection2; 1::ms => minIoi; 500::ms =>ioi; fm[0].out => b4.input[1]; fm[1].out => b4.input[1]; fm[2].out => b4.input[2]; fm[3].out => b4.input[3]; fm[4].out => b4.input[2]; fm[5].out => b4.input[1]; while (now < endOfSection2) { chout <= "PITCH = " <= p <= "\t\t"; chout <= "INST. = " <= i <= IO.newline(); Std.mtof(keyn[p]) * tran[i] => float tmp; fm[i].setPitch(tmp); fm[i].out.gain(Math.dbtorms(loud[i])); fm[i].setIndex(fmIndex[i]); fm[i].setRatio(fmRatio[i]); fm[i].setSkew(skew[i]); fm[i].attack(attack[i]::ms); duration => now; fm[i].release(release[i]::ms); p++; i++; nPitches %=> p; nInsts %=> i; ioi => now; ioi * 0.65 => ioi; if (ioi < minIoi) { minIoi => ioi; } duration * 1.011=> duration; } // ------------------------------------------------------------- // @class FMFS fm implementation from scratch with envelopes // @author Chris Chafe (cc@ccrma) class FMFS { // modulator with index envelope and carrier with // amplitude envelope SinOsc mod => Gain ind => ADSR indEnv => SinOsc car; car => ADSR ampEnv => Gain out => blackhole; // generate detailed pitch contour with skew, periodic // vibrato and random jitter // unity constant for center pitch of event Step unity => Gain pit; // add in skew offset controlled by simple Envelope Step skew => Envelope skewEnv => pit; // add in vibrato controlled by ADSR Envelope SinOsc perVib => ADSR vibEnv => pit; // add in some low-frequency randomness Noise ranVib => ResonZ lpf => pit; // apply pitch everywhere that depends on it pit => car; pit => Gain rat => mod; pit => ind; // configure modes of above UG's // config oscillator for fm input (see SinOsc class) 2 => car.sync; // freq is controlled by input only 0.0 => car.freq; // config oscillator for fm input 2 => mod.sync; // freq is controlled by input only 0.0 => mod.freq; // config gain to multiply inputs (see UG class) 3 => ind.op; // initial values setPitch(440.0); setIndex(1.0); setRatio(1.0); // set A, D, S, and R all at once ampEnv.set (20::ms, 10::ms, 0.5, 100::ms); indEnv.set (50::ms, 50::ms, 1, 100::ms); skewEnv.duration (100::ms); vibEnv.set (50::ms, 500::ms, 0.4, 100::ms); // skew in semitones setSkew(1.0); // vibrato frequency, excursion in semitones setVib(6.5, 1.0); // randomness frequency, excursion in semitones setJit(6.5, 1.0); // setPitch() fun void setPitch(float pitch) { pit.gain(pitch); } // setIndex() fun void setIndex(float index) { mod.gain(index); } // setRatio() fun void setRatio(float ratio) { rat.gain(ratio); } // setSkew() fun void setSkew(float semitones) { // units are equal-tempered semitones (Math.pow(2.0, semitones/12.0) - 1.0) => float skewAmt; skew.next( skewAmt ); } // setVib() fun void setVib(float f, float semitones) { perVib.freq(f); // scale it to equal-tempered quartertones // in each direction Math.pow(2.0, semitones/24.0) - 1.0 => float jitAmt; perVib.gain( jitAmt ); } // setJit() fun void setJit(float f, float semitones) { lpf.freq(f); // bandwidth of low-frequency filter resonance, // ok as a constant lpf.Q(1.0); // scale it to equal-tempered quartertones // in each direction Math.pow(2.0, semitones/24.0) - 1.0 => float jitAmt; // empirically scaled up to where it's noticeable 12.0 *=> jitAmt; ranVib.gain(jitAmt); } // attack(): sculpt a note using envelopes fun void attack(dur attack) { // rise time of ADSR ampEnv.attackTime(attack); indEnv.attackTime(attack); vibEnv.attackTime(attack); // duration of simple Envelope skewEnv.duration(attack); // trigger ADSR ampEnv.keyOn(); indEnv.keyOn(); vibEnv.keyOn(); // kind of counterintuitive, but skew from skewAmt // to 0 for attack skewEnv.keyOff(); } // release() fun void release(dur release) { // release time of ADSR ampEnv.releaseTime(release); indEnv.releaseTime(release); vibEnv.releaseTime(release); // duration of simple Envelope skewEnv.duration(release); // trigger ADSR release ampEnv.keyOff(); indEnv.keyOff(); vibEnv.keyOff(); // also counterintuitive, but skew from 0 // to skewAmt during note off skewEnv.keyOn(); } } // END OF CLASS: FMFS