Jack2 1.9.6

midi_unpack.h

00001 /*
00002  * Copyright (c) 2006,2007 Dmitry S. Baikov
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00017  */
00018 
00019 #ifndef __jack_midi_unpack_h__
00020 #define __jack_midi_unpack_h__
00021 
00022 enum {
00023     MIDI_UNPACK_MAX_MSG = 1024
00024 };
00025 
00026 typedef struct
00027 {
00028     int pos, need, size;
00029     unsigned char data[MIDI_UNPACK_MAX_MSG];
00030 }
00031 midi_unpack_t;
00032 
00033 static inline
00034 void midi_unpack_init(midi_unpack_t *u)
00035 {
00036     u->pos = 0;
00037     u->size = sizeof(u->data);
00038     u->need = u->size;
00039 }
00040 
00041 static inline
00042 void midi_unpack_reset(midi_unpack_t *u)
00043 {
00044     u->pos = 0;
00045     u->need = u->size;
00046 }
00047 
00048 static const unsigned char midi_voice_len[] =
00049     {
00050         3, /*0x80 Note Off*/
00051         3, /*0x90 Note On*/
00052         3, /*0xA0 Aftertouch*/
00053         3, /*0xB0 Control Change*/
00054         2, /*0xC0 Program Change*/
00055         2, /*0xD0 Channel Pressure*/
00056         3, /*0xE0 Pitch Wheel*/
00057         1  /*0xF0 System*/
00058     };
00059 
00060 static const unsigned char midi_system_len[] =
00061     {
00062         0, /*0xF0 System Exclusive Start*/
00063         2, /*0xF1 MTC Quarter Frame*/
00064         3, /*0xF2 Song Postion*/
00065         2, /*0xF3 Song Select*/
00066         0, /*0xF4 undefined*/
00067         0, /*0xF5 undefined*/
00068         1, /*0xF6 Tune Request*/
00069         1  /*0xF7 System Exlusive End*/
00070     };
00071 
00072 static
00073 int midi_unpack_buf(midi_unpack_t *buf, const unsigned char *data, int len, void *jack_port_buf, jack_nframes_t time)
00074 {
00075     int i;
00076     for (i = 0; i < len; ++i) {
00077         const unsigned char byte = data[i];
00078         if (byte >= 0xF8) // system realtime
00079         {
00080             jack_midi_event_write(jack_port_buf, time, &data[i], 1);
00081             //printf("midi_unpack: written system relatime event\n");
00082             //midi_input_write(in, &data[i], 1);
00083         } else if (byte < 0x80) // data
00084         {
00085             assert (buf->pos < buf->size);
00086             buf->data[buf->pos++] = byte;
00087         } else if (byte < 0xF0) // voice
00088         {
00089             assert (byte >= 0x80 && byte < 0xF0);
00090             //buf->need = ((byte|0x0F) == 0xCF || (byte|0x0F)==0xDF) ? 2 : 3;
00091             buf->need = midi_voice_len[(byte-0x80)>>4];
00092             buf->data[0] = byte;
00093             buf->pos = 1;
00094         } else if (byte == 0xF7) // sysex end
00095         {
00096             assert (buf->pos < buf->size);
00097             buf->data[buf->pos++] = byte;
00098             buf->need = buf->pos;
00099         } else {
00100             assert (byte >= 0xF0 && byte < 0xF8);
00101             buf->pos = 1;
00102             buf->data[0] = byte;
00103             buf->need = midi_system_len[byte - 0xF0];
00104             if (!buf->need)
00105                 buf->need = buf->size;
00106         }
00107         if (buf->pos == buf->need) {
00108             // TODO: deal with big sysex'es (they are silently dropped for now)
00109             if (buf->data[0] >= 0x80 || (buf->data[0] == 0xF0 && buf->data[buf->pos-1] == 0xF7)) {
00110                 /* convert Note On with velocity 0 to Note Off */
00111                 if ((buf->data[0] & 0xF0) == 0x90 && buf->data[2] == 0) {
00112                     // we use temp array here to keep running status sync
00113                     jack_midi_data_t temp[3] = { 0x80, 0, 0x40 };
00114                     temp[0] |= buf->data[0] & 0x0F;
00115                     temp[1] = buf->data[1];
00116                     jack_midi_event_write(jack_port_buf, time, temp, 3);
00117                 } else
00118                     jack_midi_event_write(jack_port_buf, time, &buf->data[0], buf->pos);
00119                 //printf("midi_unpack: written %d-byte event\n", buf->pos);
00120                 //midi_input_write(in, &buf->data[0], buf->pos);
00121             }
00122             /* keep running status */
00123             if (buf->data[0] >= 0x80 && buf->data[0] < 0xF0)
00124                 buf->pos = 1;
00125             else {
00126                 buf->pos = 0;
00127                 buf->need = buf->size;
00128             }
00129         }
00130     }
00131     assert (i == len);
00132     return i;
00133 }
00134 
00135 #endif /* __jack_midi_unpack_h__ */