Thursday, June 14, 2012

KIns progress: 6/14/12

New features:
-Sustained notes! When you release the key the note doesn't cut off immediately. Instead it fades out.
-Finer control over what keys do what. This is hopefully paving the way for the user to change the key mappings from a GUI.

Next step is to combine Lucy's GUI with this code below.


/*----------------------------------------------------------------------------
S.M.E.L.T. : Small Musically Expressive Laptop Toolkit

Copyright (c) 2008 Dan Trueman.  All rights reserved.
http://smelt.cs.princeton.edu/
http://soundlab.cs.princeton.edu/

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
U.S.A.
-----------------------------------------------------------------------------*/

//-----------------------------------------------------------------------------
// name: keyinmulti2.ck
// desc: this program creates an array filled with the keyboard code for
// each key on the keyboard, indexed by the keyboard row and column. Then,
// it treats each row as a string, which is "tuned" in the code. Pressing 
// a key will play the note.
//
// This version supports polyphony, and the note ends when you release the key!
// Warning: Due to hardware (not our fault), you may not be able to play all chords.
//
// to run (in command line chuck):
//     %> chuck keyinmulti2.ck
//
// to run (in miniAudicle):
//     (make sure VM is started, add the thing)

//
//-----------------------------------------------------------------------------

//Hid = human input device. It's a variable to hold whatever HID the program
//needs to use
Hid hi;
//Hidmsg contains data about what the HID is doing at any given moment
HidMsg msg;
//sound determines what sound the keyboard is making at any given time
0 => int sound;

//initializes the HID as the keyboard, and exits if there's no keyboard available
0 => int deviceNum;
hi.openKeyboard( deviceNum ) => int deviceAvailable;
if ( deviceAvailable == 0 ) me.exit();
<<< "keyboard '", hi.name(), "' ready" >>>;


//array with key codes, for MacBook anyhow
[41, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 78, 69], //esc, f1, f2… row
[53, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 45, 46, 42], //1234... row
[20, 26, 8, 21, 23, 28, 24, 12, 18, 19, 47, 48, 49], //qwer... row
[4, 22, 7, 9, 10, 11, 13, 14, 15, 51, 52], //asdf... row
[29, 27, 6, 25, 5, 17, 16, 54, 55, 56],   //zxcv... row
[224, 226, 227, 44, 231, 230, 80, 82, 81, 79], //bottom row inc. space and arrow keys
[43], //tab
[57], //caps lock
[40], //enter
[225], //left shift
[229] //right shift
]   @=> int row[][];

//our big array of pitch values, indexed by ASCII value
int keyToPitch_table[256];

//this function takes each row and tunes it in half steps, based
//on whatever fundamental pitch note specified
fun void tuneString(int whichString, int basepitch) {
    
    for (0 => int i; i < row[whichString].cap(); i++) {
        
        basepitch + i => keyToPitch_table[row[whichString][i]];
        
    }
    
}

//this function does the opposite of tuneString--it takes the given row
//and writes 9999 to each place. This number is later used when processing
//HID inputs to determine that a particular key was not assigned a pitch,
//and so it shouldn't make any noise at all when pressed.
fun void noString(int whichString) {
    
    for (0 => int i; i < row[whichString].cap(); i++) {
        
        9999 => keyToPitch_table[row[whichString][i]];
        
    }

    
}

//tune the strings!! This starts at (I think) A1, and then continues up by halftones
//each key. To hear the progression, go from left to right z->?, then up to a->",
//then q->]

tuneString(4, 55);
tuneString(3, 65);
tuneString(2, 76);
noString(0);
noString(5);
noString(6);
noString(7);
noString(8);
noString(9);
noString(10);



//makes the key sounds!
//currently configured to let the top row (number keys) control the type of sound
//the KIns makes. The code below should be pretty self-explanatory.
fun void keysound(float freq, Event noteOff) {
    
    if(sound==0){
    
    PercFlut sine => ADSR envelope => dac;
    envelope.set(10::ms, 25::ms, 0.1, 800::ms);
    
    freq => sine.freq;
    envelope.keyOn();
    noteOff => now;
    
    envelope.keyOff();
    800::ms => now;
    
    
    envelope =< dac;
}
else if(sound==1){
    
    BlowHole saw => ADSR envelope => dac;
    envelope.set(10::ms, 25::ms, 0.1, 800::ms);
    
    freq => saw.freq;
   
   saw.noteOn(1);
    envelope.keyOn();
    noteOff => now;
    
    envelope.keyOff();
    800::ms => now;
    saw.noteOff(1);
    
    
    envelope =< dac;
}
else if(sound ==2){
    Rhodey voc=> JCRev r => ADSR envelope =>dac;
    envelope.set(10::ms, 25::ms, 0.1, 800::ms);
    
    freq => voc.freq;
0.8 => voc.gain;
.8 => r.gain;
.2 => r.mix;

voc.noteOn(1);
envelope.keyOn();
    noteOff => now;
    envelope.keyOff();
    800::ms => now;
    voc.noteOff(1);
    
}
}

Event noteOffs[256];

//infinite time loop
while( true )
{
    
    hi => now;
    
    //only does things when there's a message coming in from the HID
    while( hi.recv( msg ) )
    {
        //only if the message from the HID is that a button was pressed...
        if( msg.isButtonDown() )
        {
            //the following if/elseif statements check to see if the button press
            //should cause the type of sound to change. Only the value
            //of sound needs to change, as the keysound function
            //handles actually producing the appropriate sound.
            if(msg.which==30){
                0 => sound;
            }
            else if(msg.which==31){
                1=>sound;
            }
            else if(msg.which==32){
                2=>sound;
            }
            else{
                if(keyToPitch_table[ msg.which ] != 9999){
            keyToPitch_table[ msg.which ] => Std.mtof => float freq;
            spork ~ keysound(freq, noteOffs[ msg.which] );
        }
    }
            
        }
        //if the message was not that a button was pressed...
        else
        {   
            noteOffs[ msg.which ].signal();
        }
    }
}

2 comments:

  1. Hey everyone, in all the keyboard players, starting with Lucy's I think, the floating pt frequency has to be cast as an int. The int cast just truncates I believe.

    I started working on fixing this, but then decided that Lucy knows about this already. There are 9 letter keys that don't map to anything. Is this intentional?

    It is a lot of fun to type this comment and hear the organ soundssssssssssssssss.

    ReplyDelete
  2. Hi Freda et al.,

    I've been playing with two programs in the drop box,
    01-KIns-FM-061212.ck and 01-dohBoard-FM.ck.
    One point of clarification, are these examples that you've
    put in for reference or have you added to them in some way? If
    you have added to them, make sure to add to the documentation at the top of the file.

    The dohBoard is fun, playing a soundfile at different frequencies
    (setting bar.freq) is wavetable synthesis. This can be really fun
    and a lot of interesting sounds can come out.

    Judy F

    ReplyDelete