// ==== Directions ==== // run the shred, control parameters on keyboard with: // l to increase x // j to decrease x // i to increase r in a big step // k to decrease r in a big step // 8 to increase r in a small step // 9 to decrease r in a small step // change the sound file "data/dustpond.wav" to what you wang // select keys // 81: Q // 87: W // 69: E // 82: R // 84: T // 89: Y // 85: U "data/dropitonme.wav" => string thefile; 81 => float selectKey; 0.99 => float thegain; 0 => int selected; // ==== keyboard things ==== Hid hi; HidMsg msg; // which keyboard 0 => int device; // open keyboard (get device number from command line) if( !hi.openKeyboard( device ) ) me.exit(); <<< "keyboard '" + hi.name() + "' ready", "" >>>; // ==== 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; // ==== sound making things ==== SndBuf buf; // set buffer parameters thefile => buf.read; buf.gain(0.999); Gain g; // 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(30); l[i].clear(); l[i].gain(0.99); l[i].feedback(0.9); // ramp recording so there's no clipping l[i].recRamp(20::ms); // turn recording off l[i].record(0); buf => l[i] => g => dac; } // 0.999 => g.gain; // gain parameters float g_target, g_inc; 0.0 => g.gain; // 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 ~ key( ); spork ~ fade( ); // 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[ ]; 0 => int counter; // 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; rates[Std.rand2(0, 7)] => float newrate; // get a new semi-random duration // Std.rand2f(250, 600) * 1::ms => dur newdur; Std.rand2f(250, 350) * 1::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 1::ms => now; } // 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; dac => output; // put this output into the recbuf output => Gain g2 => l[recbuf]; l[recbuf].record(1); 0.9 => 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 key( ) { while( true ) { // wait on event hi => now; // get one or more messages while( hi.recv( msg ) ) { // check for action type if( msg.isButtonDown() ) { if( msg.ascii == selectKey ) { if( selected == 0 ) { 1 => selected; <<< thefile, " is selected" >>>; } else { 0 => selected; <<< thefile, " is unselected" >>>; } } if( selected == 1 ) { if( msg.ascii == 49 ) { <<< "fade in" >>>; thegain => g_target; } if( msg.ascii == 50 ) { <<< "fade out">>>; 0.0 => g_target; } if( msg.ascii == 76 ) { // increase x x + pi/16.0 => x; <<< "x: ", x >>>; } if( msg.ascii == 74 ) { // decrease x x - pi/16.0 => x; <<< "x: ", x >>>; } if( msg.ascii == 73 ) { // increase r // allow for r to go beyond stated boundaries r + 0.1 => r; <<< "r: ", r >>>; } if( msg.ascii == 75 ) { // decrease r // allow for r to go beyond above stated boundaries r - 0.1 => r; <<< "r: ", r >>>; } if( msg.ascii == 56) { // increase r by a little bit if( r < 4.0 ) { r + 0.001 => r; } <<< "r: ", r >>>; } if( msg.ascii == 57) { if( r > -4.0 ) { r + 0.001 => r; } <<< "r: ", r >>>; } } } } } } // 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; } }