// ===== 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; // ===== SOUNDS!!! ===== // gain parameters float g_target, g_inc; 0.0 => g_target; 0.0 => g_inc; JCRev rev; 0.1 => rev.mix; Gain g; 0.0 => g.gain; // use 3 LiSa buffers to prevent clicking (will rotate) LiSa l[3]; 5::second => dur bufferlen; 0 => int recbuf; 2 => int playbuf; // LiSa params for( 0 => int i; i < 3; i++ ) { l[i].duration( bufferlen ); l[i].maxVoices( 3 ); l[i].clear( ); l[i].gain( 0.6 ); l[i].feedback( 0.9 ); l[i].recRamp( 10::ms ); l[i].record( 0 ); adc => l[i] => rev => g => dac; } [ 0.0625, 0.125, 0.5, 1.0, 1.5, 2.0 ] @=> float rates[ ]; // 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); 0 => int counter; // create grains and rotate the record and play bufs when needed // as long as grainlen < bufferlen, we will not click fun void loopForever( ) { while( true ) { now + bufferlen => time later; while( now < later ) { // Std.rand2f( 0.2, 2.0 ) => float newrate; // rates[Std.rand2( 0, 5 )] => float newrate; rates[Std.rand2(0, 5)]*x => float newrate; // Std.rand2f( 250.0, 600.0 ) * 1::ms => dur newdur; Std.rand2f( 3000.0, 9000.0 ) * 1::ms => dur newdur; // get new buffer position based on sine map Math.sin(r*x) => x; // set buffer sample pos Math.fabs(x) * bufferlen => dur pos; spork ~ getgrain( playbuf, newdur, 20::ms, 20::ms, newrate, pos ); // freqmod.last( ) * 400.0 + 800.0 => s.freq; ((Math.fabs(x)*100.0)+10)::ms => now; } // rotate the record and play bufs // turn off current recording buf l[recbuf].record(0); // increment and wrap the rec buf recbuf++; if( recbuf == 3 ) 0 => recbuf; // turn on recording for the new recording buf l[recbuf].record(1); // increment and wrap the play buf playbuf++; if( playbuf == 3 ) 0 => playbuf; // stop buffer recording after we've recorded into each of // the lisa buffers so that we can play with just feedback if( counter == 3 ) { adc =< l[0]; adc =< l[1]; adc =< l[2]; <<< "stopped adc recording" >>>; } // 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++; } } fun void getgrain( int which, dur grainlen, dur rampup, dur rampdown, float rate, dur pos ) { l[which].getVoice( ) => int newvoice; // i think this is checking that the buffer has been recorded into if( newvoice > -1 ) { // and set panning for here // Std.rand2f(-1.0, 1.0 ) => p[which].pan; 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 ) ) { // use slider to control gain if( msg.data1 == 176 && msg.data2 == 1 ) { <<< "fade in" >>>; msg.data3 / 127.0 => g_target; } // 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 >>>; } } } } // interpolate gain fun void fade( ) { .02 => float slew; while (1) { (g_target - g_inc) * slew + g_inc => g_inc => g.gain; 0.01 :: 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; } } // where everything happens // <<< "audio input starting to record!" >>>; // l[recbuf].record( 1 ); spork ~ getMIDI( ); spork ~ loopForever( ); spork ~ fade( ); spork ~ interp_r( ); while( true ) 50::second => now;