//  JS OBJECT -  -  -  GNOELALEXMAY -  -  -  -  10-04-2009
//
//  RANGE ELEMENT OF ARPEGGIO_ALGORITHM JS-OBJECT
//
//
//  FOR COLLABORATIVE MODULE - 2009

inlets=5;
outlets=6;

// VARIABLES

channelSetup(5);        //  CALL SET-UP FUNCTION FOR HI-LOW RANGE ARRAY
amount=5;

channel=1;                                    //    VARIABLE FOR WHICH INLET/OUTLET IS IN USE
mode = 0;

function channelSetup(val) {
    modLow=new Array(val);
    modHi=new Array(val);

    for(i=0;i<val;i++) {
        modLow[i]=48;                                   //    LOW VALUE OF MODULO RANGE ( LOWEST OUTPUT VALUE)
        modHi[i]=60;                                    //    HIGH VALUE OF MODULO RANGE (HIGHEST OUTPUT VALUE)
    }
}





//    >>>>  >>>>  >>>>  >>>>  ******MAX_INPUT:  SET NOTE_RANGE

function range() {
    n=inlet;
    if(arguments.length==2) {                                           //    IF RANGE IS RECIEVED AS A PAIR
        modLow[n]=arguments[0];
        modHi[n]=arguments[1]+1;
        if(modHi[n]<=modLow[n]) modHi[n]=modLow[n]+1;    //    IF THEY OVERLAP, RESET HIGH TO LOW+1
    }
   post("NOTE_RANGE FOR CHANNEL "+n+" IS:  "+modLow[n]+" to "+(modHi[n]-1)+"\n");
}


//    >>>>  >>>>  >>>>  >>>>  ******MAX_INPUT:  SET MOD-RANGE MODE

function range_mode() {                                                         
    if(arguments.length) {
        if(mode!=0) mode=1;                                    //    IF MODE IS NOT 0, MODE IS 1
        mode=arguments[0];
    }
    //  *************************  post("RANGE-MODE: "+mode+"\n");
}



function msg_int(val) {
    channel=inlet;

    p=val;

    if(mode==0) outpitch=inRangeA(p, channel);          //    CHECK MOD_RANGE: MODE_1 - STORE IN 'B'
    if(mode==1) outpitch=inRangeB(p, channel);          //    CHECK MOD_RANGE: MODE_2 - STORE IN 'B'

    outlet(channel, outpitch);
}


//    >>>>  >>>>  >>>>  FUNCTION: MOD_RANGE CHECK  MODE A  <<<<  <<<<  <<<<
//
//            >>>>  >>>  IF OUT OF RANGE, COUNT IN FROM OTHER END  <<<  <<<

function inRangeA(val, c) {
    if(val>modLow[c] && val<modHi[c]) return val;      //    IF ALREADY IN RANGE, JUST RETURN THE VALUE

    hi=Math.abs(modHi[c]-modLow[c]);          //    ADJUST MOD RANGE TO START FROM ZERO (0 to hi)
    adj=val-modLow[c];                                   //    ADJUST VALUE SIMILARLY - STORE IN 'ADJ' (adjusted)
    
    if(adj<0) {                                                        //    IF LOWER THAN ZERO, THE MODULO WON'T
        do {                                                             //    WORK CORRECTLY....
             adj=hi+adj; }                                           //    ADD MOD-RANGE-AMOUNT...
            while(adj<0);                                           //    ...UNTIL VALUE IS POSITIVE
        }
    mod=adj%hi;                                                  //    DO MODULO ARITHMETIC - STORE IN 'MOD' (Modulo)
    val=mod+modLow[c];                                    //    RE-ADD THE LOW-RANGE VALUE (undo Adjust to Zero)

    return val;                                                        //    RETURN RANGE-DEPENDANT VALUE
}

//    >>>>  >>>>  >>>>  FUNCTION: MOD_RANGE CHECK  MODE B  <<<<  <<<<  <<<<
//
//            >>>>  >>>  IF OUT OF RANGE, COUNT IN FROM OTHER END  <<<  <<<

function inRangeB(val, c) {
    if(val>modLow[c] && val<modHi[c]) return val;  //    IF ALREADY IN RANGE, JUST RETURN THE VALUE

    while(val<modLow[c]) {                                  //    IF TOO LOW, ADD OCTAVES 'TILL IN RANGE
        val=val+12;
    }
    
    while(val>modHi[c]) {                                  //    IF TOO HIGH, SUBTRACT OCTAVES 'TILL IN RANGE
        val=val-12;
    }
                                                    //    THIS MEANS THAT IF LOW-HIGH MOD-RANGE IS LESS 
                                                    //    THAN AN OCTAVE, SOME NOTES MAY BE BOUNCED 
                                                    //    BACK DOWN BELOW THE LOW RANGE

    return val;                                                            //    RETURN RANGE-DEPENDANT VALUE
}


function info() {
    for(i=0;i<amount;i++) {
        outlet(5, "RANGE", i, modLow[i], modHi[i]);
    }
} 
