⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 midi_dec.c

📁 一个操作系统源代码 用于嵌入式设备 在Vc++环境下仿真 成功移植到多款处理器上
💻 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 + -