📄 midi_dec.c
字号:
#include<stdio.h>
#include "midi_dec.h"
static U32 MidiPointer;
static U32 ToRead = 0; //the number of bytes left to be read
static U32 TotleTime = 0;
static U32 DeltaTime = 0; //millisecond is the unit
static U32 Tempo = 500000; //the default Tempo is 120 beats/minute
static U16 MidiErrors = NO_MIDI_ERROR; //the midi error information
static HEAD_CHUNK MidiHead;
static MIDI_EVENT_STRU *MidiEeventList = NULL;
static MIDI_EVENT_STRU *LAST_EVT_PT = NULL;
/*****************************************************************
* Function Name: get_byte
* Param in:
* Result code:
* Description: read a byte from midi file
*****************************************************************/
U8 get_byte( void )
{
U8 c;
c = *(P_U8)MidiPointer;
MidiPointer = MidiPointer + 1;
ToRead--;
return ( c );
}
/*****************************************************************
* Function Name: to32bit
* Param in:
* Result code:
* Description: read 4 assigned to c1,c2,c3,c4
*****************************************************************/
U32 to32bit( U8 c1, U8 c2, U8 c3, U8 c4 )
{
U32 value;
value = (U32)(c1 & 0xff);
value = (U32)((value<<8) + (c2 & 0xff));
value = (U32)((value<<8) + (c3 & 0xff));
value = (U32)((value<<8) + (c4 & 0xff));
return ( value );
}
U16 to16bit( U8 c1, U8 c2 )
{
U16 value;
value = (U16)(c1 & 0xff);
value = (U16)((value<<8) + (c2 & 0xff));
return ( value );
}
/*****************************************************************
* Function Name: read32bit
* Param in:
* Result code:
* Description: read 4 bytes assigned to c1,c2,c3,c4
*****************************************************************/
U32 read32bit( void )
{
U8 c1, c2, c3, c4;
c1 = get_byte( );
c2 = get_byte( );
c3 = get_byte( );
c4 = get_byte( );
return ( to32bit(c1, c2, c3, c4) );
}
U16 read16bit( void )
{
U8 c1, c2;
c1 = get_byte( );
c2 = get_byte( );
return ( to16bit(c1, c2) );
}
/*****************************************************************
* Function Name: read_var_num
* Param in:
* Result code:
* Description: read the variable length number
*****************************************************************/
U32 read_var_num( void )
{
U32 value;
U8 c;
value = get_byte( );
if( value & 0x80)
{
value &= 0x7f;
do
{
c = get_byte( );
value = (value<<7) + (c & 0x7f);
}while( c & 0x80 );
}
return( value );
}
/******************************************************************************
* the routine converts delta times in ticks into millisecond.
* the else statement is needed because
* the formula is different for tracks based on notes and tracks based on SMPTE times.
* Its unit is millisecond(hao miao)
*********************************************************************************/
U32 ticks2sec( U32 ticks, S16 division)
{
//U8 smpte_format;
//U8 smpte_resolution;
U32 ms;
if(division > 0)
ms = (U32) ( ticks*Tempo/division/1000);
else
{
MidiErrors |= UNSUPPORT_TYPE;
/**********************reserved for future*****************************
smpte_format =(U8)( (division & 0xff00)>>8) ;
smpte_resolution =(U8) ( division & 0x00ff );
ms = (U32) ( (float)ticks / (smpte_format * smpte_resolution * 1000.0));
***********************************************************************/
}
return ms;
}
void read_head( void )
{
MidiHead.MThd = read32bit( );
if( MidiHead.MThd != 0x4D546864 )
MidiErrors |= NOT_MIDI_FILE;
ToRead = MidiHead.length = read32bit( ); //for the length
MidiHead.midi_type = read16bit( ); //for the format
if( MidiHead.midi_type >2 )
MidiErrors |= UNKNOWN_TYPE;
else
if( MidiHead.midi_type == 2 )
MidiErrors |= UNSUPPORT_TYPE;
MidiHead.track_num = read16bit(); //for track numbers
if( MidiHead.track_num >2 )
MidiErrors |= TRACK_NUM_ERROR;
MidiHead.division = read16bit(); //for the division
while ( ToRead > 0 ) // remove the extra bytes
(void) get_byte();
}
//******************************************************************************
// META EVENT
//******************************************************************************
void meta_event( U8 type )
{
U16 seq_num = 1;
U8 length,n;
U32 denom = 1;
U8 nnn,dd,cc,bb;
U8 hr,mn,se,fr,ff;
U8 ccc;
U8 temp;
U16 key_sig;
switch ( type )
{
case 0x00: //Sequence Number
{
(void)get_byte( ); //make pointer move next
seq_num = read16bit( );
break;
}
case 0x01: //Text event
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x02: //Copyright notice
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x03: // Sequence/Track name
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x04: //Instrument name
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x05: //Lyric
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x06: // Marker
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x07: // Cue point
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x08:
case 0x09:
case 0x0a:
case 0x0b:
case 0x0c:
case 0x0d:
case 0x0e:
case 0x0f: // These are all text events
case 0x20:
{
(void)get_byte( );
ccc = get_byte( );
break;
}
case 0x21: // UNrecognized command
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
case 0x2F: //end of track:FF 2F 00
{
if( get_byte( ) != 0 )
MidiErrors |= TRACK_END_ERROR; //the midi file's is damaged at the track end
break;
}
case 0x51: // Set tempo
{
Tempo = read32bit( );
Tempo &= 0x00FFFFFF ; // read 4 bytes ,but the first is no use (the size of tempo--3)
break;
}
case 0x54: //Set SMPTE offset, it has 5 bytes
{
(void) get_byte( );
hr = get_byte( );
mn = get_byte( );
se = get_byte( );
fr = get_byte( );
ff = get_byte( );
break;
}
case 0x58:
{
(void) get_byte( ); //only make the pointer to move next
nnn = get_byte( );
dd = get_byte( );
cc = get_byte( );
bb = get_byte( );
while ( (dd--) > 0 )
denom *= 2;
break;
}
case 0x59:
{
(void) get_byte( ); //only make the pointer to move next
key_sig = read16bit( );
break;
}
case 0x7f: //Sequencer Specific Meta-Event
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
default:
{
length = get_byte( );
for ( n=0; n<length; n++ )
{
temp = get_byte( );
}
break;
}
}
}
//******************************************************************************
// SYSEX EVENT
//******************************************************************************
void sysex()
{
return;
}
//******************************************************************************
// MIDI EVENT
//******************************************************************************
void channal_message(U8 status,U8 c1,U8 c2)
{
U8 channal = status & 0xf;
MIDI_EVENT_STRU *midi_evt;
switch ( status & 0xf0 )
{
case 0x90:
{
if( DeltaTime != 0)
{
if( ( midi_evt=(MIDI_EVENT_STRU*)malloc( sizeof(MIDI_EVENT_STRU)) ) == NULL )
return;
midi_evt->note_symbol = c1;
midi_evt->delta_time = DeltaTime;
//add a midi event struct
if( MidiEeventList == NULL )
{
MidiEeventList = midi_evt;
midi_evt->next = NULL;
LAST_EVT_PT = midi_evt;
}
else
{
LAST_EVT_PT->next = midi_evt;
midi_evt->next = NULL;
LAST_EVT_PT = midi_evt;
}
}
}
break;
/*********reserved for future**********************
case 0x80:
note_off(channal,c1,c2);
break;
case 0xa0:
pressure(channal,c1,c2);
break;
case 0xb0:
parameter(channal,c1,c2);
break;
case 0xe0:
pitchbend(channal,c1,c2);
break;
case 0xc0:
program(channal,c1);
break;
case 0xd0:
chanpressure(channal,c1);
break;
*************************************************/
}
}
void read_track( )
{
//the array is indexed by the high half of a status byte.
//It's value is either the number of bytes needed (1 or 2) for a channel message,or 0 (meaning it's not a channel message).
//the fist 8 bytes is 0x00 through 0x70 , the next 8 is 0x80 through 0xf0
U8 channal_type[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 1, 1, 2, 0 };
U8 c, c1, type;
U8 sysexcontinue = 0; // 1 if last message was an unfinished sysex
U8 running = 0; // 1 when running status used
U8 status = 0; // status value (e.g. 0x90==note-on)
U8 needed;
U32 ticks = 0;
TRACK_CHUNK track;
track.Mtrk = read32bit( ); //for the MTrk
if( track.Mtrk != 0x4D54726B )
MidiErrors |= TRACK_ERROR;
ToRead = track.length = read32bit( ); //for the length
while( ToRead > 0 )
{
ticks = read_var_num( ); //read the variable numbers
DeltaTime = ticks2sec( ticks, MidiHead.division ); //trun the delta time to milli seconds
TotleTime += DeltaTime;
c = get_byte( );
if ( sysexcontinue && c != 0xF7 )
MidiErrors |= SYSEX_ERROR;
if ( (c & 0x80) == 0 ) // running status
{
if ( status == 0 )
MidiErrors |= RUN_STATUS_ERROR;
running = 1;
}
else
{
status = c;
running = 0;
}
needed = channal_type[ (status>>4) & 0xf ];
if ( needed ) // ie. is it a channel message?
{
if ( running )
c1 = c;
else
c1 = get_byte( );
channal_message( status, c1, (needed>1) ? get_byte() : 0 );
continue;
}
switch ( c )
{
case 0xFF: // meta event , several message were ignored
{
type = get_byte( );
meta_event( type );
break;
}
case 0xF0: // start of system exclusive
{
if ( c==0xf7 )
sysex( );
else
sysexcontinue = 1; // merge into next msg
break;
}
case 0xF7: // sysex continuation or arbitrary stuff
{
if ( sysexcontinue == 1 )
{
if ( c == 0xf7 )
{
sysex( );
sysexcontinue = 0;
}
}
break;
}
default:
{
MidiErrors |= BAD_BYTE;
break;
}
}//end of switch
}
}
MIDI_EVENT_STRU *midi_decode( U32 Midi_Pointer )
{
MidiPointer = Midi_Pointer;
read_head();
MidiEeventList = NULL;
while ( MidiHead.track_num-- )
read_track();
return( MidiEeventList );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -