// midiraw.c
//
// Reads three numbers from STDIN and sends them out the midi port.
//
// Examples:
// midiraw 90 45 127 # turns on the 110Hz A at velocity 127
// midiraw 90 60 127 # turns on  middle C at velocity 127
// Nessie = 45, 47, 48, 50, 52, 53, 55, 57, 59, 60, 62, 64
//           A   B   C   D   E   F   G   a   b   c   d   e
// midiraw 80 60 127 # turns off middle C at velocity 127 (sometimes matters)
// midiraw B0  7 127 # turns the MSB channel volume up full
// midiraw B0  7   0 # turns the MSB channel volume down all the way
//                     volume also affects (persists) playing on keyboard itself
//                     and keyboards (like yamaha15) with bargraph show the
//                     change on the bargraph when data is sent from this prog.
// midiraw C0 64 64  # sets instrument to SprnoSax (Voice number 65)
// midiraw C0  0  0  # sets instrument to GrandPno (Voice number 1)
// midiraw C0 127 127# sets instrument to Gunshot (Voice number 128)
// midiraw C0 128 128# has no effect (128 or higher, e.g. Voice 129 or higher)
//
// midiraw A0 45 127 # maximum aftertouch level for 110 Hz A on channel 1 (A0)
// midiraw A0 45 0   # minimum aftertouch level for 110 Hz A on channel 1 (A0)
//
// Steve Mann and Mark Post, 2005 January 10th
// mann@eyetap.org; mark@eyetap.org
//
// This program reads 3 bytes from STDIN and writes the 3 bytes out to midi
// output so you can tinker around and see what the bytes mean.
//
// It is based on Craig Stuart Sapp's
// http://ccrma-www.stanford.edu/~craig/articles/linuxmidi/output/method1.c
//
// We also found another useful site:
// http://users.argonet.co.uk/users/lenny/midi/tech/spec.html
//
// For example, here is a summary of some of the sets of 3 numbers that
// you can send out using this program:
// 90 3C 40	Note On, C4	C4 On
// B0 54 3C	PTC from C4	No audible change YET (until invoked)
// 90 40 40	Note On, E4	Glide from C4 to E4
// 80 3C 40	Note Off, C4	No audible change
// 80 40 40	Note Off, E4	E4 Off
//
// The following all pertain to B0, e.g. B0 07 127 sets MSB Channel Volume
//	High resolution continuous controllers (MSB)
//	4	Foot Controller
//	5	Portamento Time
//	7	Channel Volume
//	High resolution continuous controllers (LSB)
//	37	Portamento Time
//	39	Channel Volume

#include <linux/soundcard.h>
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>

int main(int argc, char **argv) {
//   char* device =  "/dev/midi";
   char* device =  "/dev/midi00";
   unsigned char decon[3]  = {0x90, 60, 127}; /* decon note on */
   unsigned char instructioncode, param1, param2;
   unsigned char instructioncodenew, param1new, param2new;
   int fd = open(device, O_WRONLY, 0);
   if (argc!=4) {
    fprintf(stderr,"Use: %s hex instruction, param1 (in base A), param2 (in base A)\n",argv[0]);
    fprintf(stderr,"Example: %s 90 45 127 sends instruction 0x90 (note on) 110 Hz A (45) at 127\n",argv[0]);
    fprintf(stderr,"Example: %s B0 07 20 turns channel 1 volume down to 20\n",argv[0]);
    //fprintf(stderr,"you will now encounter a Segmentation fault\n");
    exit(1);
   }
   if (fd < 0) {
      printf("Error: cannot open %s\n", device);
      exit(1);
   }
   sscanf(argv[1],"%X",&instructioncode);
   instructioncodenew=instructioncode;
   sscanf(argv[2],"%d",&param1);
   param1new=param1;
   sscanf(argv[3],"%d",&param2);
   param2new=param2;
   fprintf(stderr,"instructioncode%%x=%X, param1%%d=%d, param2%%d=%d\n",instructioncodenew, param1new, param2new);
   decon[0]=instructioncodenew;
   decon[1]=param1new;
   decon[2]=param2new;
   write(fd, decon, sizeof(decon));
   //fflush(fd);
   //fsync(fd);
   //usleep(1000);
   //fdatasync(fd);

   usleep(1000);
 
   // step 3: (optional) close the OSS device
   close(fd);
   //usleep(1000);

   return 0;
}

