Example 6

From CSWiki
Revision as of 18:37, 17 February 2013 by Narveson (talk | contribs) (Created page with "The ChucK code here is from Dan Trueman, and is a simple version of the kind of re-settable metronomes that sometimes appear in his music – below that is the SuperCollider tra...")

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

The ChucK code here is from Dan Trueman, and is a simple version of the kind of re-settable metronomes that sometimes appear in his music – below that is the SuperCollider translation I made.

the ChucK code

 /* want to keep track of time to next click, so we can schedule things mid-click--like reverse delays... */

Impulse imp => dac;

//tempo
120 => float bpm;
1::minute/bpm => dur metrotime;
<<<"metrotime = ", metrotime/1::ms>>>;

//timeToNext is constantly updated, so we know when the next click will happen at any moment....
metrotime => dur timeToNext;

//spork a shred!! this sets the function metroreset() running, and then moves on
//so metroset() will be running in parallel with our main metro loop below.
spork ~ metroreset();

while(true) {
    
    if(timeToNext <= 0::ms) { //click now!
        
        //click
        1 => imp.next;
        
        //reset metronome
        metrotime => timeToNext;
        
    }
    
    1::ms => now;
    timeToNext - 1::ms => timeToNext;  

}

//need a function to listen for metronome resets (use the spacebar for now)
fun void metroreset() {
    
    Hid hi;
    HidMsg msg;
    
    1 => int device; //builtin keyboard is usually device 0, but maybe not!; can address by name as well
    
    if( hi.openKeyboard( device ) == 0) { //fail!
        
        <<<"unable to open device ", device>>>;
        me.exit();
        
    }
    
    //success!
    <<<"keyboard " + hi.name() + " ready">>>;
    
    //make a loop that listens for the keyboard
    while ( true ) {
        
        //wait for an event from hi
        hi => now;
        
        while( hi.recv (msg) ) {
             
            if(msg.isButtonDown() ) {
                
                <<<"down: ", msg.ascii>>>;
                if(msg.ascii == 32) metrotime => timeToNext; //reset metronome!
                else if(msg.ascii == 79) {
                    if(imp.gain() > 0.) 0. => imp.gain;
                    else 1. => imp.gain;
                }
                
            } else {
                
                <<<"up: ", msg.ascii >>>;
                
            }
        }
    }
}
                    

the SuperCollider version

 (
// run this first
SynthDef("imp", {
	var sig, ender;
	sig = Impulse.ar(freq: 1);
	DetectSilence.ar(in: sig, amp: 0.001, time: 0.01, doneAction: 2);
	sig = Pan2.ar(in: sig, pos: 0);
	Out.ar(bus: 0, channelsArray: sig);
}).add;
)

(
// run this second
var create_clock, win, clock;

create_clock = {

	if(clock.notNil, {clock.clear});

	clock = TempoClock.new(tempo: 2);  // as in: "2 beat per second"

	/* clocks can schedule functions in time, and if these functions end with a number, then that number is the number of beats in the future to re-schedule the functions.  This makes it easy to create cyclic behavior. */

	clock.schedAbs(clock.beats.ceil, { // schedule starting on the next whole beat
		Synth("imp"); // play the implulse
		1; // wait one beat then repeat
	});
};

win = Window.new(name: "press space-bar to set/reset metronome", bounds: 400@200);
win.alwaysOnTop=true;
win.front;

win.view.keyDownAction = {|view, char|
	if(char==$ , {
		create_clock.value;
	})
};

win.onClose = {if(clock.notNil, {clock.clear})}; // kill the clock if you close the window

)