Difference between revisions of "SLOrk/Instruments/Intervalis"

From CCRMA Wiki
Jump to: navigation, search
(arguments explained)
(Delete the section)
Line 81: Line 81:
 
|Right SHIFT|| Interval note
 
|Right SHIFT|| Interval note
 
|}
 
|}
 
== Advanced users ==
 
 
=== ChucK Code ===
 
 
If you just want to look at the code, here it is:
 
 
<pre>
 
// filename: intervalis.ck
 
// INTERVALIS - Play intervals
 
//
 
// MUSIC 128 - HW1
 
// By: Jorge Herrera
 
//
 
 
/************************************
 
* MAIN CONTROL PARAMETERS
 
*************************************/
 
10 => int _init_harmonics; // Control over the intial timbre
 
1 => float _init_spin_freq; // LeSLOrklie initial speed [Hz]
 
2 => int numChan; // LeSLOrklie is implemented over this many channels
 
440 => float _a440; // frequency associated to the A key
 
0 => int _init_quality;          // Initial quality of the interval (0 -> Major, 1 -> minor)
 
5 => int _init_interval;        // Initial interval
 
0.15 => float _tilt_threshold;  // [0 - 1): threshold for silence (mute) level
 
 
 
 
/************************************
 
* THE CODE
 
*************************************/
 
 
// safety checks
 
if(_tilt_threshold >= 1) 0.999 => _tilt_threshold;
 
 
 
// The synthesis
 
Blit tonic => PitShift choir => JCRev rev => PoleZero mainOut;
 
Blit interval => choir;
 
mainOut.blockZero(0.99);
 
 
 
// Synth. initialization
 
_a440 => tonic.freq;
 
_init_harmonics => tonic.harmonics => interval.harmonics;
 
0 => tonic.gain => interval.gain;
 
0.12 => rev.mix;
 
1.0 => choir.shift;
 
0.2 => choir.mix;
 
 
 
// Interval definition array:
 
int intervals[2][8];
 
 
// Major&Perfect intervals (defined in semitones)
 
0 => intervals[0][0];
 
2 => intervals[0][1];
 
4 => intervals[0][2];
 
5 => intervals[0][3];
 
7 => intervals[0][4];
 
9 => intervals[0][5];
 
11 => intervals[0][6];
 
12 => intervals[0][7];
 
 
// Minor&Tritone intervals (defined in semitones)
 
0 => intervals[1][0];
 
1 => intervals[1][1];
 
3 => intervals[1][2];
 
5 => intervals[1][3];
 
6 => intervals[1][4]; /* m5 == tritone */
 
8 => intervals[1][5];
 
10 => intervals[1][6];
 
12 => intervals[1][7];
 
 
// Interval initialization
 
0 => float tonicTarget;
 
_init_quality => int gQuality; /* 0 = major, 1 = minor */
 
_init_interval - 1 => int gInterval => float intervalTarget;
 
updateInterval(gQuality, gInterval);
 
 
// Flags to determine if the sounds are muted
 
0 => int tonicMuted => int intervalMuted;
 
 
 
/**********************
 
*      FUNCTIONS
 
*
 
* HANDLE WITH CARE!!!
 
***********************
 
 
/**************************
 
* The "LeSLOrklie"
 
**************************/
 
_init_spin_freq => float spinFreq;
 
Gain outGains[numChan];
 
 
fun void spin() {
 
    for(0 => int i; i<numChan; i++)
 
    {
 
        mainOut => outGains[i] => dac.chan(i);
 
    }
 
    0 => float angle;
 
    0.001 => float step;      // must be in seconds
 
    while(step::second => now)
 
    {
 
        2.0*Math.PI*spinFreq*step +=> angle;
 
        for(0 => int i; i<numChan; i++) {
 
            (Math.sin(angle + (2*Math.PI*i)$float/numChan) +
 
            1.0)/2.0 => outGains[i].gain;
 
        }
 
    }   
 
}
 
 
 
/**************************
 
* GET MOTION INPUT
 
**************************/
 
 
// infinite while loop
 
fun void getMotion()
 
{
 
    // instantiate a HidIn object
 
    Hid accel;
 
    HidMsg movementMsg;
 
   
 
    // open tilt sensor
 
    if( !accel.openTiltSensor() ) {
 
        <<< "", "tilt sensor unavailable", "" >>>;
 
        me.exit();
 
    }
 
   
 
    // print
 
    <<< "", "tilt sensor ready", "" >>>;
 
   
 
    while( true )
 
    {
 
        // poll the tilt sensor, expect to get back 3 element array of
 
        // (9 for now means accelerometer, 0 selects 0th accelerometer)
 
        accel.read( 9, 0, movementMsg );
 
        if( !tonicMuted ) {
 
            //<<< movementMsg.x, movementMsg.y, movementMsg.z >>>;
 
            if(Math.fabs(movementMsg.y$float/300.0) < _tilt_threshold) 0 => tonicTarget;
 
        else (Math.fabs(movementMsg.y$float/300.0) - _tilt_threshold)/(1 - _tilt_threshold) => tonicTarget;
 
}
 
 
if( !intervalMuted ) {
 
    if(Math.fabs(movementMsg.x$float/300.0) < _tilt_threshold) 0 => intervalTarget;
 
else (Math.fabs(movementMsg.x$float/300.0) - _tilt_threshold)/(1 - _tilt_threshold) => intervalTarget;
 
}
 
// advance time
 
50::ms => now;
 
}
 
}
 
 
// Smooth gain changes
 
fun void rampGains()
 
{
 
    .5 => float slew;
 
    while(20::ms => now) {
 
        (tonicTarget - tonic.gain())*slew + tonic.gain() => tonic.gain;
 
        (intervalTarget - interval.gain())*slew + interval.gain() =>
 
        interval.gain;
 
    }
 
}
 
 
 
/**************************
 
* GET KEYBOARD INPUT
 
**************************/
 
 
// infinite event loop
 
fun void getKeys()
 
{   
 
    Hid hiKbd;
 
    HidMsg msgKbd;
 
   
 
    // which keyboard
 
    0 => int device;
 
    // get from command line
 
    if( me.args() ) me.arg(0) => Std.atoi => device;
 
   
 
    // open keyboard (get device number from command line)
 
    if( !hiKbd.openKeyboard( device ) ) me.exit();
 
    <<< "", "keyboard '" + hiKbd.name() + "' ready", "" >>>;
 
   
 
    0 => int gRegister;
 
   
 
    while( true )
 
    {
 
        // wait on event
 
        hiKbd => now;
 
        // get one or more messages
 
        while( hiKbd.recv( msgKbd ) )
 
        {
 
            // check for action type
 
            if( msgKbd.isButtonDown() )
 
            {
 
                //<<< "", "down:", msgKbd.which, "(code)", msgKbd.key, "(usb key)", msgKbd.ascii, "(ascii)" >>>;
 
                //<<< "", "down:", msgKbd.which >>>;
 
               
 
                // Effect keys
 
               
 
                // Spin frequency control
 
                if(msgKbd.which == 79) {
 
                    0.2 +=> spinFreq;
 
                }
 
                if(msgKbd.which == 80 && spinFreq > 0.0000000001) {
 
                    0.2 -=> spinFreq;
 
                }
 
               
 
                // Harmonics control
 
                if(msgKbd.which == 81 && tonic.harmonics() > 0) {
 
                    tonic.harmonics() - 1 => tonic.harmonics;
 
                    interval.harmonics() - 1 => interval.harmonics;
 
                    if(tonic.harmonics() < 5) {
 
                        <<< "***** ", tonic.harmonics(), " harmonics  *****" >>>;
 
                    }
 
                }
 
                if(msgKbd.which == 82) {
 
                    tonic.harmonics() + 1 => tonic.harmonics;
 
                    interval.harmonics() + 1 => interval.harmonics;
 
                    if(tonic.harmonics() < 5) {
 
                        <<< "***** ", tonic.harmonics(), " harmonics  *****" >>>;
 
                    }
 
                }
 
               
 
                // PitShift
 
                if(msgKbd.which == 38 && choir.shift() > 0.8) {
 
                    choir.shift() - 0.01 => choir.shift;
 
                    if(choir.shift() == 1.0)
 
                        <<< "***** IN TUNE  *****" >>>;
 
                }
 
                if(msgKbd.which == 39 && choir.shift() < 1.2) {
 
                    choir.shift() + 0.01 => choir.shift;
 
                    if(choir.shift() == 1.0)
 
                        <<< "***** IN TUNE  *****" >>>;
 
                }
 
               
 
                // Interval selection
 
                if(msgKbd.which >= 30 && msgKbd.which <= 37) {
 
                    msgKbd.which - 30 => gInterval;
 
                }
 
               
 
                // Octave change
 
                // ","
 
                if(msgKbd.which == 54) {
 
                    2 /=> _a440;
 
                    tonic.freq()/2 => tonic.freq;
 
                    gRegister - 1 => gRegister;
 
                    <<< "Register: ", gRegister >>>;
 
                }
 
                // "."
 
                if(msgKbd.which == 55) {
 
                    2 *=> _a440;
 
                    tonic.freq()*2 => tonic.freq;
 
                    gRegister + 1 => gRegister;
 
                    <<< "Register: ", gRegister >>>;
 
                }
 
               
 
               
 
                // Base pitch selection
 
                if(msgKbd.which == 43) { // tab = F#
 
                    _a440*Math.pow(2,-3/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 57) { // CAPS = G
 
                    _a440*Math.pow(2,-2/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 20) { // Q = G#
 
                    _a440*Math.pow(2,-1/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 4) {
 
                    _a440*Math.pow(2,0/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 26) {
 
                    _a440*Math.pow(2,1/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 22) {
 
                    _a440*Math.pow(2,2/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 7) {
 
                    _a440*Math.pow(2,3/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 21) {
 
                    _a440*Math.pow(2,4/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 9) {
 
                    _a440*Math.pow(2,5/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 23) {
 
                    _a440*Math.pow(2,6/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 10) {
 
                    _a440*Math.pow(2,7/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 11) {
 
                    _a440*Math.pow(2,8/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 24) {
 
                    _a440*Math.pow(2,9/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 13) {
 
                    _a440*Math.pow(2,10/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 12) {
 
                    _a440*Math.pow(2,11/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 14) {
 
                    _a440*Math.pow(2,12/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 18) {
 
                    _a440*Math.pow(2,13/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 15) {
 
                    _a440*Math.pow(2,14/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 51) {
 
                    _a440*Math.pow(2,15/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 47) { // "[" = C#
 
                    _a440*Math.pow(2,16/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 52) { // "'" = D
 
                    _a440*Math.pow(2,17/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 48) { // "]" = D#
 
                    _a440*Math.pow(2,18/12.0) => tonic.freq;
 
                }
 
                if(msgKbd.which == 40) { // RETURN = E
 
                    _a440*Math.pow(2,19/12.0) => tonic.freq;
 
                }
 
               
 
                // Major(perfect) || minor(tritone) gQuality selection
 
                if(msgKbd.which == 16) {
 
                    0 => gQuality;
 
                    <<< "", "Major mode" >>>;
 
                }
 
                if(msgKbd.which == 17) {
 
                    1 => gQuality;
 
                    <<< "", "Minor mode" >>>;
 
                }
 
               
 
                updateInterval(gQuality, gInterval);
 
               
 
               
 
                // Mute controls
 
               
 
                // Space bar mute both sounds
 
                if(msgKbd.which == 44) {
 
                    1 => tonicMuted => intervalMuted;
 
                    0 => tonicTarget => intervalTarget;
 
                }
 
               
 
                // Left shift mute root (tonic) note
 
                if(msgKbd.which == 225) {
 
                    1 => tonicMuted;
 
                    0 => tonicTarget;
 
                }
 
               
 
                // Right shift mute the interval note
 
                if(msgKbd.which == 229) {
 
                    1 => intervalMuted;
 
                    0 => intervalTarget;
 
                }
 
               
 
            }
 
           
 
            // check for action type
 
            if( msgKbd.isButtonUp() )
 
            {
 
                // Mute controls
 
               
 
                // Space bar mute both sounds
 
                if(msgKbd.which == 44) {
 
                    0 => tonicMuted => intervalMuted;
 
                }
 
               
 
                // Left shift mute root (tonic) note
 
                if(msgKbd.which == 225) {
 
                    0 => tonicMuted;
 
                }
 
               
 
                // Right shift mute the interval note
 
                if(msgKbd.which == 229) {
 
                    0 => intervalMuted;
 
                }
 
            }
 
        }
 
    }
 
}
 
 
fun void updateInterval(int m, int i)
 
{
 
    Math.pow(2,intervals[m][i]/12.0)*tonic.freq() => interval.freq;
 
}
 
 
 
/**************************
 
* GET OSC MESSAGES
 
**************************/
 
 
// infinite event loop
 
fun void receiveOSC()
 
{
 
    // create our OSC receiver
 
    OscRecv recv;
 
    // use port 6449 (or whatever)
 
    6449 => recv.port;
 
    // start listening (launch thread)
 
    recv.listen();
 
   
 
    // create an address in the receiver, store in new variable
 
    recv.event( "/message, s i s s" ) @=> OscEvent @ oe;
 
   
 
    while( true )
 
    {
 
        // wait for event to arrive
 
        oe => now;
 
       
 
        // grab the next message from the queue.
 
        while( oe.nextMsg() )
 
        {
 
            string _base;
 
            int _interval;
 
            string _quality;
 
            string _tilt;
 
           
 
            // getFloat fetches the expected float (as indicated by "i f")
 
            oe.getString() => _base;
 
            oe.getInt() => _interval;
 
            oe.getString() => _quality;
 
            oe.getString() => _tilt;
 
           
 
            // print
 
            <<< "", "" >>>;
 
           
 
            <<< "*********** NEW MESSAGE RECEIVED ************", ""            >>>;
 
            <<< "Root key", _base >>>;
 
            <<< "Interval", _interval >>>;
 
            <<< "Quality", _quality >>>;
 
            <<< "Tilt", _interval >>>;
 
        }
 
    }
 
}
 
 
 
fun void printInstructions()
 
{
 
    <<< "", "" >>>;
 
    <<< "", "" >>>;
 
    <<< "", "This instrument play intervals, where the gain relationship" >>>;
 
    <<< "", "between the 2 playing pitches is controlled by the performer"  >>>;
 
    <<< "", "using the tilt sensor." >>>;
 
    <<< "", "" >>>;
 
    <<< "", "There is separate control over the pitch, using the keyboard." >>>;
 
    <<< "", "" >>>;
 
    <<< "", "- Use keys [ A - L ] as a piano keyboard starting at A (pitch) = A (key)" >>>;
 
    <<< "", "- Use numbers to set the interval (1: Prime, 2: Second, ..., 8: Octave)" >>>;
 
    <<< "", "- Use keys M (major/perfect) & N (minor/tritone) to control the quality of the interval" >>>;
 
    <<< "", "- Use UP/DOWN arrow keys to change the number of harmonics of the sound"  >>>;
 
    <<< "", "- Use LEFT/RIGHT arrow keys to change speed of rotation of the 'LeSLOrklie'" >>>;
 
    <<< "", "- To change octave use ',' (down) or '.' (up)" >>>;
 
    <<< "", "- '9' & '0' play with de-tuning" >>>;
 
    <<< "", "- Use 'space bar' or 'shift keys' to mute the sounds" >>>;
 
}
 
 
 
 
// Run the threads
 
spork ~ getMotion(); // Get motion input
 
spork ~ getKeys(); // Get keyboard input
 
spork ~ spin(); // Make the sound spee
 
spork ~ rampGains(); // Make the gain ratio change smooth
 
spork ~ receiveOSC();      // Listen to OSC messages
 
 
printInstructions();
 
 
 
// The infinite loop
 
while(true)
 
{
 
    100::ms => now;
 
}
 
 
</pre>
 

Revision as of 14:15, 24 May 2009

Description

This instrument play intervals. The tilting of the laptop controls the intensity of each note (tilting front or back play the root note and tilting to the sides play the "interval" note). The sound is played trough a LeSLOrklie speaker (it rotates around the Hemi at an adjustable spin frequency).

Usage

Installation

Running

  • Using a terminal go to the folder were "intervalis.ck" is located
  • On the terminal window type: (replace N with the number of output channels of the audio card)
    chuck -cN intervalis
  • Play!

Optional Arguments

Optionally you can type the following to run Intervalis:

chuck -cN intervalis:arg1:arg2:arg3:arg4

Where:

  • arg1: intial spining frequency [Hz]
  • arg2: spining frequency increment/decrement step [Hz]
  • arg3: side tilt mode (1 => vibrato; 0 => interval) [Boolean]
  • arg4: number of channels to implement the SLOrklie [int]

This list of parameters may vary in the future


Execution

  1. Select the root note by using 2nd and 3rd rows of the keyboard (from Tab & CAPS to ] & RETURN). See root note selection for details
  2. Select interval using the numbers (1 to 8)
  3. Play notes by tilting the laptop
  4. Optional:

Key mapping

Root note selection
F4# G4 G4# A4 A4# B4 C5 C5# D5 D5# E5 F5 F5# G5 G5# A5 A5# B5 C6 C6# D6 D6# E6
TAB CAPS Q A W S D R F T G H U J I K O L ; [ ' ]
Interval selection
  • To select the interval name use the number keys from 1 to 8.
  • To select the quality of the interval:
    • M : Major/Perfect
    • N : Minor/Tritone
  • To specify the direction of the interval:
    • - : Descending
    • = : Ascending (default)
Other control keys
Parameter Decrease Increase
Register , .
Detune 9 0
Spin frequency Arrow Left Arrow Right
Number of harmonics (timber) Arrow Down Arrow Up
Mute keys
Key Mutes ...
SPACE BAR Both notes
Left SHIFT Root note
Right SHIFT Interval note