// ==== Directions ==== // NOTE THIS INCLUDES BWG !!!! PARAMETERS ARE DIFFERENT!!!! // run the shred, control parameters MPD26 // pad corresponds to selecting sound file // first two sliders (F1, F2) for gain // first 2 knobs for r and x adjustments // change the sound file "data/dustpond.wav" to what you wang // select keys // 36 -> whatever // this sounds good together too // vox, airrush, bass0, bass1, synthpad, synthpad reverebed, bwgs // website/week7/sexybell1.wav:36:0.8:0.6:0 // website/week7/mainkkit0.wav:37:1.0:1.0:1 // load rnb.ck // website/week7/CalvinLead0.wav:36:0.8:1:0 // website/week7/AirRush0.wav:37:1.0:1:0 // website/week7/Bassline0.wav:38:1.0:0.8:1:0 // website/week7/Bassline1.wav:39:1.0:0.8:1:0 // website/week7/Bassline2.wav:40:1.0:0.8:1:0 // website/week7/Bassline3.wav:41:1.0:0.8:1:0 // website/week7/DelaySynthPad0.wav:42:1.0:1:0 // website/week7/DelaySynthPadReverebed0.wav:43:1.0:1:0 // maybe? // website/week7/vocalsSinceyoureSinceyoure.wav:36:1.0:0.7:1 // loadrnb2.ck // website/week7/vox.wav:36:0.8:0.7:0 // website/week7/hats1.wav:37:0.7:2:1 // data/pianonew.wav:38:1.5:1:1 // website/week7/CalvinLead0.wav:39:0.8:1:0 // data/dropitonme.wav:36:0.8:1:0 // data/pianonew.wav:37:1.5:1:1 // data/icingnicely.wav:38:1.5:1:1 // data/oceanscut.wav:39:0.8:1:1 // data/bwg0.wav:40:0.8:1:1 // data/bwg1.wav:41:0.8:1:1 // data/bwg2.wav:42:0.8:1:1 // data/bwg3.wav:43:0.8:1:1 // data/bwg4.wav:44:0.8:1:1 // data/bwgs.wav:45:0.8:1:1 me.arg(0) => string thefile; Std.atoi(me.arg(1)) => int selectKey; Std.atof(me.arg(2)) => float thegain; Std.atof(me.arg(3)) => float therate; Std.atof(me.arg(4)) => float selectRate; Std.atof(me.arg(5)) => float theFeedback; <<< "therate", therate >>>; <<< "selectRate", selectRate>>>; 0 => int selected; // ===== PREPARE MIDI ===== // device to open 0 => int device; MidiIn min; MidiMsg msg; // try to open MIDI port, exit if we cannot if( !min.open( device ) ) me.exit( ); // print out the device that we opened <<< "MIDI device:", min.num( ), " -> ", min.name( ) >>>; // ==== SINE MAP THINGS ==== // usual values: 0.0 < r < 4.0 (noise) 1.0 => float r; // usual values: -pi/2 < x < pi/2 pi/4.0 => float x; // r parameters for interpolating float r_target, r_inc; // feedback fm and chaos // ==== SOUND MAKING THINGS ==== SndBuf buf; // set buffer parameters 1024 => buf.chunks; thefile => buf.read; buf.gain(thegain); Envelope e; // buf => e => X.in; e.time(2); Gain g; Pan2 p; // use three buffers (removes clipping sounds) LiSa l[3]; // buffer length in seconds length buffers buf.length( ) => dur bufferlen; // record from 0th buffer and play from 2nd buffer 0 => int recbuf; 2 => int playbuf; // LiSa parameters for(0 => int i; i < 3; i++) { l[i].duration(bufferlen); l[i].maxVoices(2); l[i].clear(); l[i].gain(0.99); l[i].feedback(0.0); // ramp recording so there's no clipping l[i].recRamp(20::ms); // turn recording off l[i].record(0); buf => l[i] => g => p; } // 0.999 => g.gain; // gain parameters float g_target, g_inc; 0.0 => g.gain; // panning stuff 0.0 => p.pan; p.left => X.inL; p.right => X.inR; 0.0 => float p_target; 0.0 => float p_inc; // write another LiSa buffer that holds what actually comes out // this may be like microphone output later on. // we'll use this as kind of a feedback mechanism LiSa output => blackhole; 5::second => output.duration; l[playbuf] => output; output.feedback(0.9); output.record(1); // start reading controls from the keyboard spork ~ fade( ); spork ~ interp_r( ); spork ~ interp_pan( ); spork ~ playBuf( ); spork ~ getMIDI( ); // start recording from record buf l[recbuf].record(1); [-0.05, -0.1, -0.2, -0.4, 0.4, 0.2, 0.1, 0.05] @=> float rates[ ]; [-1.0, 1.0] @=> float rates1[ ]; [-0.5, -0.5, -0.7, -0.7, -1.0, -1.0] @=> float rates2[ ]; 0 => int counter; 1 => float sliderDur; // create grains, rotate record and play bufs as needed // shouldn't click as long as the grainlen < bufferlen while( true ) { // calculate the time to keep creating grains for // this is the time when one buffer is getting recorded into now + bufferlen => time later; // toss some grains while ( now < later) { // get a new semi-random rate of playback // Std.rand2f(0.5, 2.5) => float newrate; float newrate; if( selectRate == 0 ) { therate*rates[Std.rand2(0, rates.size( )-1)] => newrate; } else if( selectRate == 1 ) { therate*rates1[Std.rand2(0, rates1.size( )-1)] => newrate; } else if( selectRate == 2 ) { therate*rates2[Std.rand2(0, rates2.size( )-1)] => newrate; } // get a new semi-random duration // Std.rand2f(250, 600) * 1::ms => dur newdur; // Std.rand2f(250, 350) * 1::ms => dur newdur; (100+(3000*sliderDur))::ms => dur newdur; // get new position for buffer based on sin map Math.sin(r*x) => x; // set buffer sample position Math.fabs( x ) * bufferlen => dur pos; // get new position for buffer // Std.rand2f(0., 1.) * bufferlen => dur pos; // get a grain with the duration and rate we just got // put the grain in our play buffer spork ~ getgrain(playbuf, newdur, 20::ms, 20::ms, newrate, pos); // advance time 100::ms => now; // 500 Hz } // rotate the record and playbufs l[recbuf++].record(0); if(recbuf == 3) 0 => recbuf; l[recbuf].record(1); playbuf++; if(playbuf == 3) 0 => playbuf; // <<< "poop" >>>; // stop buffer recording after we've recorded into each of // the lisa buffers so that we can play with just feedback /* if( counter == 3 ) { buf => blackhole; buf =< l[0]; buf =< l[1]; buf =< l[2]; <<< "stopped buffer recording" >>>; } else if( counter < 3 ) {*/ 0 => buf.pos; //} // now record what's being played into the output buffer /*l[playbuf] => output; g => output; // put this output into the recbuf output => Gain g2 => l[recbuf]; l[recbuf].record(1); 0.6 => g2.gain; counter++;*/ } // function to get next grain with paramaters as arguments fun void getgrain(int which, dur grainlen, dur rampup, dur rampdown, float rate, dur pos) { // get the next available voice l[which].getVoice() => int newvoice; // <<>>; if(newvoice > -1) { l[which].rate(newvoice, rate); l[which].playPos(newvoice, pos); l[which].rampUp(newvoice, rampup); (grainlen - (rampup + rampdown)) => now; l[which].rampDown(newvoice, rampdown); rampdown => now; } } // respond to keyboard events fun void getMIDI( ) { while( true ) { // wait on event min => now; // get one or more messages while( min.recv( msg ) ) { // pad + midi note to choose file (maybe slider later) if( msg.data1 == 144 ) { if( msg.data2 == selectKey ) { if( selected == 0 ) { 1 => selected; <<< thefile, " is selected" >>>; } else { 0 => selected; <<< thefile, " is unselected" >>>; } } } // if it's selected if( selected == 1 ) { // use slider to control gain if( msg.data1 == 176 && msg.data2 == 1 ) { <<< "fade in" >>>; msg.data3 / 127.0 => g_target; } // use 2nd slider to control duration if( msg.data1 == 176 && msg.data2 == 2 ) { // uhh why do i even need this?? <<< "sliderDur", sliderDur >>>; 2*(msg.data3 / 127.0) => sliderDur; } // use knobs to control x and r if( msg.data1 == 176 && msg.data2 == 11 ) { // adjust x (pi/2 -(-pi/2))*( msg.data3 / 127.0 ) + -pi/2 => x; <<< "x: ", x >>>; } if( msg.data1 == 176 && msg.data2 == 13 ) { // adjust r // allow for r to go beyond stated boundaries (5.0 - (-1.0))*( msg.data3 / 127.0 ) + (-1.0) => r_target; <<< "r: ", r >>>; } // last knob for panning! if( msg.data1 == 176 && msg.data2 == 15 ) { // adjust r // allow for r to go beyond stated boundaries 2*( msg.data3 / 127.0 ) - 1.0 => p_target; <<< "pan: ", p.pan( ) >>>; } } } } } // interpolate gain fun void fade( ) { .02 => float slew; while (1) { (g_target - g_inc) * slew + g_inc => g_inc => g.gain; 0.1 :: second => now; } } // interpolate r fun void interp_r( ) { 0.05 => float slew; while (1) { (r_target - r_inc) * slew + r_inc => r_inc => r; 10 :: ms => now; } } // interpolate panning // interpolate r fun void interp_pan( ) { 0.02 => float slew; while (1) { (p_target - p_inc) * slew + p_inc => p_inc => p.pan; 10 :: ms => now; } } // play the buffer fun void playBuf( ) { e.keyOn( ); (buf.samples( )/2)::samp => now; e.keyOff( ); 2::second => now; 0 => buf.pos; }