// name: DISORIENTED_CLUB_GEN // author: Ryan Smith (smithrt@stanford.edu), Ge Wang (gewang@stanford.edu) // *assignment was adapted from code provided by Ge Wang // quarter note duration 550::ms => dur Q; 1000/((Q/44.1/4.5::samp)*16) => float lfo_freq; // control bank float controls[8]; // custom Event class MachEvent extends Event { // measure counter 0 => int measure; // where we are in the cycle 0 => int n; // max (free free to change this up, but make sure to update code that assume 16) 16 => int max; // this can be set to tell shreds to stop 1 => int keepGoing; // advance fun void next() { n++; if( n >= max ) { 0 => n; measure++; } } } // the event MachEvent boom; 0 => int flip; // reverb NRev rL => dac.left; NRev rR => dac.right; .025 => rL.mix => rR.mix; NRev both => dac; .0027 => both.mix; // sound bank SndBuf bank[32]; // Pan bank Pan2 pan[bank.size()]; // snares // (0 is no sound) me.dir() + "data/snares/808-Snare01.wav" => bank[1].read; me.dir() + "data/snares/808-Snare02.wav" => bank[2].read; me.dir() + "data/snares/808-Snare03.wav" => bank[3].read; me.dir() + "data/kicks/808-Kicks01.wav" => bank[5].read; me.dir() + "data/kicks/808-Kicks02.wav" => bank[6].read; me.dir() + "data/kicks/808-Kicks03.wav" => bank[7].read; me.dir() + "data/hihats/808-HiHats01.wav" => bank[10].read; me.dir() + "data/hihats/808-HiHats02.wav" => bank[11].read; me.dir() + "data/hihats/808-HiHats03.wav" => bank[12].read; me.dir() + "data/hihats/808-OpenHiHats01.wav" => bank[13].read; me.dir() + "data/hihats/808-OpenHiHats02.wav" => bank[14].read; me.dir() + "data/percussion/808-Clave1.wav" => bank[15].read; me.dir() + "data/percussion/808-Clave3.wav" => bank[16].read; me.dir() + "data/percussion/808-Cowbell1.wav" => bank[17].read; me.dir() + "data/percussion/808-Cowbell2.wav" => bank[18].read; me.dir() + "data/percussion/808-Cowbell3.wav" => bank[19].read; me.dir() + "data/mine/IQ_JC_Jersey_Kick_03.wav" => bank[20].read; me.dir() + "data/mine/IQ_JC_Clap___Snare_12.wav" => bank[21].read; me.dir() + "data/mine/Vocal C3 Ahh.wav" => bank[22].read; me.dir() + "data/mine/tones1.wav" => bank[23].read; me.dir() + "data/mine/metals1_1.wav" => bank[24].read; me.dir() + "data/mine/metals2_1.wav" => bank[25].read; me.dir() + "data/mine/metals3_1.wav" => bank[26].read; me.dir() + "data/mine/zip1.wav" => bank[27].read; // connect for( int i; i < bank.size(); i++ ) { // not sound 0 => bank[i].gain; // connect bank[i] => both; } // play: sound, velocity fun void play( int n, float v ) { play( n, v, Math.random2f(1,1 ) ); } // play: sound, velocity, rate fun void play( int n, float v, float r ) { if( n < 0 || n >= bank.size() ) { <<< "WARNING: out of bound BANK INDEX:", n >>>; return; } play( bank[n], v, r, 0::second ); } // play: sound, velocity, rate, duration to wait fun void play( SndBuf @ snd, float velocity, float rate, dur T ) { // start at beginning 0 => snd.pos; // set velocity if (snd == bank[20]) { velocity * 0.55 => snd.gain; } else { velocity => snd.gain; } // set rate rate => snd.rate; // wait if( T > 0::second ) T => now; } class Pattern { // pattern sound (NOTE: can set this to silence/ramp a pattern) 1 => float volume; // play velocity (NOTE: could be other lengths! different meters! etc) float vels[16]; int notes[16]; // NOTE: could be more arrays here for other data float patterns[8][16]; int sounds[4]; int map[16]; } class DrumPattern extends Pattern { // what sound int sound; //default, rate = 1 1.0 => float rate; // go N is number of booms (N < 0 means infinite loop) fun void run( int N ) { int n; // go for N time while( N != 0 && boom.keepGoing ) { // decrement if( N > 0 ) N--; // wait on the boom boom => now; // get the place in the measure boom.n => n; // logic if( vels[n] > 0 ) { play( bank[sound], vels[n] * volume, rate, 0::second ); //play( sound, vels[n] * volume ); } } } } class PitchPattern extends Pattern { int sound; // go N is number of booms (N < 0 means infinite loop) fun void run( int N ) { int n; // go for N time while( N != 0 && boom.keepGoing ) { // decrement if( N > 0 ) N--; // wait on the boom boom => now; // get the place in the measure boom.n => n; // logic if( notes[n] > 0 ) { bank[sound] => SndBuf buf; 0 => buf.pos; notes[n] => buf.rate; 0.6 => buf.gain; } } } } [ 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> float zeros[]; /// DrumPattern kick; 1 => kick.volume; [20, 5, 6, 7] @=> kick.sounds; zeros @=> kick.patterns[0]; [ 1.0, 0, 0, 0, 0.9, 0, 0, 0, 1, 0, 0, 0.8, 0, 0, 0.7, 0 ] @=> kick.patterns[1]; [ 1.0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, .8, 0.9, 0.7 ] @=> kick.patterns[2]; [ 1.0, 0, 0, 0, 0, 0, 0.9, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> kick.patterns[3]; [ 1.0, 0, 0, 0.8, 0, 0, 0.8, 0, 0, 0, 0, 0, 0, 0, 0.7, 0 ] @=> kick.patterns[4]; [ 1.0, 0, 0, 0, 0, 0, 0.9, 0, 0, 0, 1, 0, 0, 1, 0.9, 0.5 ] @=> kick.patterns[5]; /// DrumPattern clhat; 0.4 => clhat.volume; [10, 11, 12, 13, 14] @=> clhat.sounds; zeros @=> clhat.patterns[0]; [ 0.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0.8, 0.9, 0.7 ] @=> clhat.patterns[1]; [ 1.0, .2, 1, .2, 1, .2, 1, .2, 1, .2, 1, .2, 1, .2, 1, .2 ] @=> clhat.patterns[2]; [ 1.0, 0, .5, .6, 0, 0, 0, 0, 1.0, 0, .5, .6, 0, 0, 0, 0 ] @=> clhat.patterns[3]; [ 0.0, 0, 1, 0, 0, 0, 0.9, 0, 0, 0, 1, 0, 0, 0, 0.9, 0 ] @=> clhat.patterns[4]; [ 1.0, .9, .8, 0, 0, 0, .9, 0, 1, .9, .9, 0, 0, 0, .8, 0 ] @=> clhat.patterns[5]; [ 1.0, 0.7, 0.5, 0.4, 0.3, 0.2, 0.1, 0, 1.0, 0.7, 0.5, 0.4, 0.3, 0.2, 0.1, 0 ] @=> clhat.patterns[6]; /// DrumPattern kick2; 0.25 => kick2.volume; 21 => kick2.sound; [0, 0, 0, 0, 1, 2, 1, 1] @=> kick2.map; zeros @=> kick2.patterns[0]; [ .0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> kick2.patterns[1]; [ .0, 0, 0, 0, 1, 0, 0, .1, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> kick2.patterns[2]; /// DrumPattern vocal; 0.1 => vocal.volume; 22 => vocal.sound; 0.3 => vocal.rate; [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] @=> vocal.map; zeros @=> vocal.patterns[0]; [ 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> vocal.patterns[1]; /// DrumPattern beep; 0.4 => beep.volume; 23 => beep.sound; [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0] @=> beep.map; zeros @=> beep.patterns[0]; [ 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> beep.patterns[1]; /// DrumPattern metal; 0.3 => metal.volume; [24, 25, 26, 27] @=> metal.sounds; 0.7 => metal.rate; [0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0] @=> metal.map; zeros @=> metal.patterns[0]; [ 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] @=> metal.patterns[1]; spork ~ disorientationdrone(); spork ~ rise(); (Q/4.5)*16*4*2 => now; spork ~ kick.run( -1 ); // -1 to run indefinitely spork ~ clhat.run( -1 ); spork ~ kick2.run( -1 ); spork ~ vocal.run( -1 ); spork ~ beep.run( -1 ); spork ~ metal.run( -1 ); // be nice, give children shred a chance to wait on event me.yield(); // timing loop while( true ) { kick2.patterns[kick2.map[boom.measure % 8]] @=> kick2.vels; vocal.patterns[vocal.map[boom.measure % 16]] @=> vocal.vels; beep.patterns[beep.map[boom.measure % 16]] @=> beep.vels; metal.patterns[metal.map[boom.measure % 16]] @=> metal.vels; if(boom.measure % 4 == 0 && boom.n == 0) { kick.sounds[Math.random2(0, 3)] => kick.sound; clhat.sounds[Math.random2(0, 4)] => clhat.sound; metal.sounds[Math.random2(0, 2)] => metal.sound; kick.patterns[Math.random2(0, 5)] @=> kick.vels; clhat.patterns[Math.random2(0, 6)] @=> clhat.vels; } if((boom.measure + 1) % 4 == 0 && boom.n == 0 ) { -1 => int temp; if (clhat.vels == zeros) { Math.random2(1, 5) => temp; } else { Math.random2(0, 5) => temp; } clhat.patterns[temp] @=> clhat.vels; } boom.broadcast(); // wait for 16th Q/4.5 => now; // advance boom accounting boom.next(); // TEST: this can be used to break out of shred loops // if( boom.measure == 5 ) 0 => boom.keepGoing; } fun void disorientationdrone() { PulseOsc sqr1 => NRev rev => LPF lpf => Gain g => Pan2 p => Gain g2 => dac; PulseOsc sqr2 => rev => lpf => g => dac; SinOsc lfo => blackhole; SinOsc lfo2 => blackhole; 5000 => lpf.freq; 0.002 => g.gain; 0 => sqr1.phase => sqr2.phase => lfo.phase; Std.mtof(66) => sqr1.freq; Std.mtof(66) => sqr2.freq; 0.5 => sqr1.width; lfo_freq => lfo.freq; lfo_freq => lfo2.freq; 0.15 => rev.mix; SinOsc lfo3 => blackhole; 0.75 => lfo3.phase; lfo_freq/16 => lfo3.freq; while (20::ms => now) { (((lfo.last() + 1 ) / 2) / 10) + 0.45 => sqr1.width => sqr2.width; ((lfo.last() + 1 ) / 2) * 12 + Std.mtof(66.03) => sqr1.freq; ((lfo.last() + 1 ) / 2) * 12 + Std.mtof(65.97) => sqr2.freq; lfo2.last() * 0.4 => p.pan; (lfo3.last() + 1) / 2 => g2.gain; <<<(lfo3.last() + 1) / 2>>>; } } fun void rise() { SqrOsc s1 => Gain r_g => HPF r_hpf => NRev r_rev => Pan2 pan => dac; SqrOsc s2 => r_g => r_hpf => r_rev; 0 => s1.gain => s2.gain; 0.015 => r_g.gain; 500 => r_hpf.freq; 0.1 => r_rev.mix; Std.mtof(54.50) => s1.freq; Std.mtof(53.50) => s2.freq; SinOsc lfo4 => blackhole; SinOsc lfo5 => blackhole; lfo_freq/8 => lfo4.freq; 0.75 => lfo4.phase; lfo_freq*16 => lfo5.freq; -1 => float last_pos; while(5::ms => now) { ((lfo4.last() + 1) / 2) => float lfo_pos; if (lfo_pos < 1 && last_pos < lfo_pos) { lfo_pos * 0.25 => s1.gain => s2.gain; } else { 0 => s1.gain => s2.gain; } lfo_pos => last_pos; lfo5.last() *0.4 => pan.pan; } }