// @input lines:
// usage: 
//        @input devicenameforcode MIDI "substring match" [skip]
//        @input devicenameforcode OSC "*:9000"
//        @input devicenameforcode OSC "192.168.1.2:9000"
// can use any number of inputs. devicenameforcode must be unique, if you specify multiple @input lines
// with common devicenameforcode, it will use the first successful line and ignore subsequent lines with that name
// you can use any number of devices, too
// note: in OSCII-bot 0.4+, you can send OSC to an input device (which will return it to the last address from which
// a message was received)

@input r24 MIDI "ZOOM R"


// @output lines:
// usage: 
//        @output devicenameforcode OSC "127.0.0.1:8000" [maxpacketsize] [sleepamt]
//        @output devicenameforcode MIDI "substring match" [skip]
 
// maxpacketsize is 1024 by default, can lower or raise depending on network considerations
// sleepamt is 10 by default, sleeps for this many milliseconds after each packet. can be 0 for no sleep.
// note: in OSCII-bot 0.4+, you can also receive messages from an OSC output device (if the other end sends
// a message back to the source address)

@output localhost OSC "127.0.0.1:8000"

// code goes in one of @init, @timer, @oscmsg, or @midimsg sections

// special variables:
//   time        -- system timestamp (seconds, millisecond precision)
//   fmt0..fmt31 -- format variables for oscsend(), oscmatch(), sprintf(), match(), matchi(), and printf()
//   msg1..msg3  -- three bytes of MIDI, used by midisend() and set for each @midimsg call
//   msgdev      -- device index of incoming MIDI message, set by @midimsg
//   oscstr      -- only valid during @oscmsg, has string to OSC format
// 
// special functions:
//   printf("string %d blah");                       -- output to log, allows %d %u %f etc, fmt0..fmt31 used
//   oscsend(device_index, "/format", parameter);    -- /format can have a prefix char of b(ool) f(loat) i(nt) s(tring)
//                                                       or t(oggle -- no parameter) to specify parameter type. 
//                                                       if s, fmtX should be a string
//                                                       device_index can be -1 for all OSC outputs, -100 for all
//                                                       OSC outputs in all scripts (dangerous!)
//   oscmatch("/format");                            -- /format matched. supports wildcards (* + and ?), and 
//                                                       %d/%f/%u/%X etc, updating fmt0..fmt31. 
//                                                       returns 1 if full match, otherwise 0. fmt* may be updated
//                                                       this is an alias of matchi(parm,oscstr)
//   midisend(device_index);                         -- sends msg1/msg2/msg3 to device_index. device_index can be
//                                                       -1 for all MIDI outputs, or -100 for all MIDI outputs in all
//                                                       scripts (dangerous!)
//
//
// string manipulation functions:
//   sprintf(dest,"string %d blah");       -- format, output to dest (user string, 0..1023)
//   strlen(str);                          -- returns string length
//   match("*test*", "this is a test")     -- search for first parameter regex-style in second parameter
//   matchi("*test*", "this is a test")    -- search for first parameter regex-style in second parameter (case insensitive)
                                          // note: for matching %d/%s/etc, you can specify min/max lengths:
                                          // %s means 1 or more chars
                                          // %0s means 0 or more chars
                                          // %5s means exactly 5 chars
                                          // %5-s means 5 or more chars
                                          // %-10s means 1-10 chars
                                          // %3-5s means 3-5 chars. 
                                          // %0-5s means 0-5 chars. 

//   strcpy(str, srcstr);                  -- replaces str with srcstr
//   strcat(str, srcstr);                  -- appends srcstr to str 
//   strncpy(str, srcstr, maxlen);         -- replaces str with srcstr, up to maxlen (-1 for unlimited)
//   strncat(str, srcstr, maxlen);         -- appends up to maxlen of srcstr to str (-1 for unlimited)
//   strcmp(str, str2)                     -- compares strings
//   stricmp(str, str2)                    -- compares strings (ignoring case)
//   strncmp(str, str2, maxlen)            -- compares strings up to maxlen bytes
//   strnicmp(str, str2, maxlen)           -- compares strings (ignoring case) up to maxlen bytes
//   strcpy_from(str,srcstr, offset);      -- copies srcstr to str, but starts reading srcstr at offset offset
//   str_getchar(str, offset);             -- returns value at offset offset
//   str_setchar(str, offset, value);      -- sets value at offset offset
//   str_setlen(str, len);                 -- sets length of string (if increasing, will be space-padded)
//   str_delsub(str, pos, len);            -- deletes len chars at pos
//   str_insert(str, srcstr, pos);         -- inserts srcstr at pos
//   strcpy_substr(dest, src, offset, maxlen)


// file functions:
//   fp = fopen("path", "r");    -- opens path in read mode. fp is >0 if succcess. prefix ^/ to get path of 
//                               -- script, i.e. "^/companion_file.dat". prefix ~/ for home directory (or desktop on win32), @/ for desktop.
// fclose(fp)
// fflush(fp)
// feof(fp)
// fread(fp,str,length)          -- binary safe read, returns length read
// fgets(fp,str)                 -- reads a line, returns length read (or 0 if eof)
// fgetc(fp)                     -- reads a character, returns <0 on EOF
// fwrite(fp,str,length)         -- binary safe write, writes min(length,strlen(str)), returns bytes written
// fprintf(fp,str)               -- writes string with format, returns bytes written




@init

destdevice = localhost; // can also be -1 for broadcast

// 0= simplistic /track/x/volume, /master/volume
// 1= /r24/rawfaderXX (00-09)
// 2= /action/XY/cc/soft (tracks 1-8), master goes to /r24/rawfader09
fader_mode=2;

@timer

// called around 100Hz, after each block of @midimsg/@oscmsg

@oscmsg
// receive an osc message. use:
// msgdev will be set to inmmoing message device
// oscmatch( "/track/%d/blah/%d/blah*") // *, +, and ? are wildcards (matching 0 or more, 1 or more, or 1 exactly chars). use %* to insert literal *, etc
// will set fmt0*. 
// oscparm(x,v) will get parameter value x, setting v to $'f', $'i', $'s', or 0 if invalid, etc. if $'s', you can get individual chars from the string using ((str_offs<<16) + parm_idx)

// can send MIDI via midisend(destdevice); // sends msg1/msg2/msg3

@midimsg 
// receives midi message
// special variables:
// msg1, msg2, msg3 (midi message bytes)
// msgdev == r24  // can check which device, if we care

(msg1&0xf0) == 0xe0 ? (

  // using this to learn for monitoring fx, rather than master track
  fader_mode > 0 ? (
     fmtstr = "f/r24/rawfader%02.0f"; // raw fader
     fmt0 = (msg1&0xf)+1;

     fader_mode > 1 && fmt0 != 9 ? (
       fmtstr = "f/action/%.0f/cc/soft"; // this is soft-takeover, track 01-08
       fmt0 = ((fmt0-1) * 8) + 20;
     );

     val=(msg2 + (msg3*128))/16383;
     val=val^0.75;
     oscsend(destdevice,fmtstr,val);
  ) : (
     fmtstr = (msg1&0xf) == 8 ? "f/master/volume" : "f/track/%.0f/volume";
     fmt0 = (msg1&0xf)+1;
     oscsend(destdevice,fmtstr,(msg2 + (msg3*128))/16383);
  );
);

msg1 == 0x90 ? (
  msg2 == 0x5b ? oscsend(destdevice, "b/rewind", msg3>64);
  msg2 == 0x5c ? oscsend(destdevice, "b/forward", msg3>64);

  msg3>64 ? (
    fmt0 = (msg2&7) + 1;

    msg2 < 8 ?  oscsend(destdevice, "t/track/%.0f/recarm/toggle", 0) :
      msg2 < 16 ?  oscsend(destdevice, "t/track/%.0f/solo/toggle", 0) :
        msg2 < 24 ?  oscsend(destdevice, "t/track/%.0f/mute/toggle", 0) : 
    (
      msg2 == 0x5e ? oscsend(destdevice, "b/play", 1);
      msg2 == 0x5d ? oscsend(destdevice, "b/stop", 1);
      msg2 == 0x5f ? oscsend(destdevice, "b/record", 1);
    )
  );
);

msg1 == 0xb0 ? (
  msg2 == 0x3c ? (
    oscsend(destdevice, "f/action/992/cc/relative", ((msg3&0x40) ? -1 : 1));
  );

);
