home *** CD-ROM | disk | FTP | other *** search
/ Millennium Time Capsule / AC2000.BIN / disks / ac11disk / midimon / minimon.c < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-09  |  6.6 KB  |  240 lines

  1. /*
  2.  *    Atari Computing MIDI programming in C tutorial
  3.  *    ©1998 Danny McAleer
  4.  *    This code is freeware - feel free to tamper and use as you please!
  5.  *    
  6.  *    This is a simple program to decipher MIDI messages...
  7.  *    It should hopefully explain the way most common MIDI messages
  8.  *    are received and sent, so you can then use this knowledge in your
  9.  *    own MIDI programs (ones that are more interesting than this!!!)
  10.  *
  11.  *    Compiled and written using Lattice C
  12.  *
  13.  */
  14.  
  15. #include <osbind.h>
  16. #include <stdio.h>
  17.  
  18. #define     midi_in()    Bconin(3)
  19. #define        midi_out(x)    Bconout(3, x)
  20. #define        poll_midi()    Bconstat(3)
  21. #define        poll_kbd()    Bconstat(2)
  22. #define        check_kbd()    Bconin(2)
  23. #define     BYTE        unsigned char
  24.  
  25. /*  **     function declarations  **  */
  26. void     main(void);
  27. void    draw_menu(void);
  28. void     evnt_loop(void);
  29. void    process_midi_msg(BYTE);
  30. void     print_controller(BYTE);
  31. void     print_sysex(BYTE);
  32.  
  33.  
  34. void main(void)
  35. {
  36.     draw_menu();
  37.     evnt_loop();
  38.     exit(1);
  39. }
  40.     
  41. void draw_menu(void)
  42. {
  43.     printf("\033H\033f\n MIDI monitor ");
  44.     printf("\n press [x] to exit");
  45. }
  46.  
  47. void evnt_loop(void)
  48. {
  49.     BYTE         m;
  50.     char        k;
  51.  
  52.     while(1)
  53.     {
  54.         if(poll_kbd()!=0){
  55.             k = check_kbd();
  56.             if(k == 'x')    break;
  57.         }
  58.         if(poll_midi()!=0){
  59.             m = midi_in();
  60.             /* first, check that the message received isn't active sensing! */
  61.             if(m!=0xfe)    process_midi_msg(m);
  62.         }
  63.     }
  64. }
  65.  
  66. void process_midi_msg(BYTE m)
  67. {
  68.     BYTE     channel, msg;
  69.     BYTE    midibuff[2048];    
  70.     int        x;
  71.     
  72.     /* if a channel message is sent, filter out the channel */
  73.     if( m >= 0x80)
  74.     {
  75.         channel = (m&0x0f) + 1; /* find channel number */
  76.         msg     = m&0xf0;        /* remove channel and ascertain message */
  77.     }
  78.  
  79.     switch(msg)
  80.     {
  81.         case 0xc0:
  82.             /* 
  83.              *     this is a program change, and these 
  84.              *     have one data byte that holds the patch number
  85.              */
  86.             midibuff[0] = midi_in();
  87.             printf("\033E\n\n program change #%3d received on channel %2d", midibuff[0], channel);
  88.             break;
  89.  
  90.         case 0x90:
  91.             /*
  92.              *     note on message - this is followed by two data bytes:
  93.              *     first the note number, then the velocity
  94.              */
  95.             for(x=0;x<2;x++)    midibuff[x] = midi_in();
  96.             if(midibuff[1]>0)
  97.                 printf("\033E\n\n note on  number %3d of velocity %3d received on channel %2d", midibuff[0], midibuff[1], channel);
  98.             else printf("\033E\n\n note off number %3d received on channel %2d", midibuff[0], channel);
  99.             break;
  100.  
  101.         case 0x80:
  102.             /*
  103.               *     note off message - note that some synthesizers send
  104.              *     not on messages with a velocity of zero - it's the same thing, 
  105.              *     although this time, a release velocity can be specified
  106.              */
  107.             for(x=0;x<2;x++)    midibuff[x] = midi_in();
  108.             printf("\033E\n\n note off number %3d of velocity %3d received on channel %2d", midibuff[0], midibuff[1], channel);
  109.             break;
  110.  
  111.         case 0xa0:
  112.             /*
  113.               *    polyphonic aftertouch is followed by two data bytes,
  114.              *     the first for the note, the second, the value of the aftertouch
  115.              */
  116.             for(x=0;x<2;x++)    midibuff[x] = midi_in();
  117.             printf("\033E\n\n polyphonic aftertouch on note %3d of value %3d received on channel %2d", midibuff[0], midibuff[1], channel);    
  118.             break;
  119.         
  120.         case 0xd0:
  121.             /* 
  122.              *    channel aftertouch: this type of aftertouch is
  123.              *    globally applied to all notes on one channel, so 
  124.              *    it only has one data byte for the value
  125.              */
  126.             midibuff[0] = midi_in();
  127.             printf("\033E\n\n channel aftertouch of value %3d received on channel %2d", midibuff[0], channel);
  128.             break;
  129.  
  130.         case 0xe0:
  131.             /*
  132.              *    pitch bend wheel - followed by two data bytes, 
  133.              *    that are joined together to form one value (since the range 
  134.              *    of the pitch bend is greater than 128 it needs two bytes!)
  135.              */
  136.             for(x=0;x<2;x++)    midibuff[x] = midi_in();
  137.             printf("\033E\n\n pitch bend on channel %2d ", channel);
  138.             break;
  139.  
  140.         case 0xb0:
  141.             /*
  142.              *    controller message: there are 128 MIDI controllers,
  143.              *    some of which are defined, others are not. The first
  144.              *    data byte specifies the controller number, the second
  145.              *    is the value of that controller
  146.              */
  147.             for(x=0;x<2;x++)    midibuff[x] = midi_in();
  148.             printf("\033E\n\n control change value %3d received on channel %2d", midibuff[1], channel);
  149.             print_controller(midibuff[0]);
  150.             break;
  151.  
  152.             /* 
  153.              *    below are some system messages - these aren't
  154.              *    channel specific...
  155.              */
  156.         case 0xf8:
  157.             printf("\n received MIDI clock message");
  158.             break;
  159.         case 0xfa:
  160.             printf("\n received sequencer start message");
  161.             break;
  162.         case 0xfb:
  163.             printf("\n received sequencer continue message");
  164.             break;
  165.         case 0xfc:
  166.             printf("\n received sequencer stop message");
  167.             break;
  168.  
  169.         case 0xf0:
  170.             printf("\033E\n\n received system exclusive message");
  171.             for(x=0;x<2048;x++){
  172.                 midibuff[x] = midi_in();
  173.                 if(midibuff[x] == 0xf7)    break;
  174.             }
  175.             printf("\n manufacturer's ID : %2d ", midibuff[0]);
  176.             print_sysex(midibuff[0]);
  177.             printf("\n model number      : %3d", midibuff[1]);
  178.             printf("\n unit number       : %3d", midibuff[2]);
  179.             printf("\n number of bytes   : %3d", x);
  180.             break;
  181.         default:
  182.             break;
  183.     }
  184.     Vsync();
  185.  
  186. }
  187.  
  188. void print_sysex(BYTE m)
  189. {
  190.     char *str;
  191.     /*
  192.      *    each manufacturer has its own ID for system exclusives
  193.      *    so that a message meant for a Korg, for example, will
  194.      *    be ignored by a Roland synth, and so on...
  195.      *    Further, each model and revision of model has its own number too!
  196.      *    Below are just a few...
  197.        */
  198.     switch(m)
  199.     {
  200.         case 0x07:    str = "Kurzweil";    break;
  201.         case 0x0f:    str = "Ensoniq";    break;
  202.         case 0x10:    str = "Oberheim";    break;
  203.         case 0x18:    str = "E-mu";        break;
  204.         case 0x1a:    str = "ART";        break;
  205.         case 0x40:    str = "Kawai";        break;
  206.         case 0x41:    str = "Roland";        break;
  207.         case 0x42:    str = "Korg";        break;
  208.         case 0x43:    str = "Yamaha";        break;
  209.         case 0x44:
  210.         case 0x45:    str = "Casio";        break;
  211.         default: str = "Unrecognised";    break;
  212.     }
  213.     printf("(%s)", str);
  214. }
  215.  
  216. void print_controller(BYTE m)
  217. {
  218.     char *str;
  219.     switch(m)
  220.     {
  221.         /*     
  222.          *    below are just a few of the more commonly 
  223.          *    used controller types - there are loads more!
  224.          */
  225.         case 0x01:    str = "modulation wheel";    break;
  226.         case 0x02:    str = "breath controller";    break;
  227.         case 0x04:    str = "foot controller";    break;
  228.         case 0x05:    str = "portamento time";    break;
  229.         case 0x07:    str = "volume";                break;
  230.         case 0x0a:    str = "pan";                break;
  231.         case 0x0b:    str = "expression pedal";    break;
  232.         case 0x40:    str = "damper pedal";        break;
  233.         case 0x41:    str = "portamento on/off";    break;
  234.         case 0x79:    str = "reset all controllers";    break;
  235.         case 0x7a:    str = "local on/off trigger";    break;
  236.         case 0x7b:    str = "all notes off";            break;
  237.         default:    str = "undefined or unrecognised";    break;
  238.     }
  239.     printf("\n message type is %s", str);
  240. }