📄 mp3.c
字号:
//下面的程序是可以播放midi音乐的。并且有3个灯用来和音乐中的小节同步(三个等依次为 强,次强,弱)。该程序只对单轨音乐进行解码。从开始做到调通灯光,我花了1周的时间。
//希望有用的到的朋友。
#include "reg52.h"
/**********************************************************************
Name: Midi_Player
Version: 1.0
hardware: 8052
Author: jiangkeqiang
Email: brave_man.student#sina.com.cn
comment: hoping you can benifit from these code
/*********************************************************************/
#define BUFFER_LEN 528
void send_data(unsigned char *dat,unsigned int len);
unsigned long read4byte();
unsigned short read2byte();
unsigned char read1byte();
unsigned int get_wait_time(unsigned long wait);
unsigned char do_event();
unsigned long GetVLE ();
void led_blink();
unsigned long get_different(unsigned long begin,unsigned long end);
void loadsongtobuffer();
unsigned char code song[] =//this is a midi file
{
0x4d,0x54,0x68,0x64,0x00,0x00,0x00,0x06,0x00,0x00,
0x00,0x01,0x00,0x78,0x4d,0x54,0x72,0x6b,0x00,0x00,
0x3a,0x71,0x00,0xff,0x58,0x04,0x01,0x02,0x18,0x08,
0x00,0xff,0x59,0x02,0x00,0x00,0x00,0xff,0x51,0x03,
0x03,0xa9,0x80,0x00,0xc0,0x49,0x00,0xb0,0x07,0x7f,
0x00,0xc1,0x21,0x00,0xb1,0x07,0x54,0x00,0xc2,0x00,
0x00,0xb2,0x07,0x5f,0x00,0xc3,0x2e,0x00,0xb3,0x07,
0x5b,0x00,0x0a,0x62,0x00,0xc4,0x19,0x00,0xb4,0x07,
0x64,0x00,0x0a,0x34,0x00,0xc5,0x68,0x00,0xb5,0x07
};//由于减少没用信息,这里的内容不足一首歌曲。使用时
//只需要把这里替换成你想换的歌曲
//unsigned long idata time_wait=0xffff;
unsigned long idata overflow_count=0;
unsigned short idata tempo;
//unsigned long idata byte_of_track;
unsigned char idata com_data[4];
unsigned char idata last_command;
unsigned char idata paizi=4;
unsigned char idata jie_len;
unsigned char idata ledsqu[6];
unsigned char idata ledindex;
unsigned char xdata song_buffer[BUFFER_LEN];
unsigned char xdata * idata ptr=song_buffer;
unsigned short idata counter=0;
//unsigned long led_count=0;
bit next_is_begin = 0;
bit load = 1;
//0---2/4
//1---3/4
//2---4/4
//3---6/8
unsigned short base_count=0;//1/4音符需要的overflow_count数
void timer1_ISR (void) interrupt 3
{
//中断一次经历1/1800秒
TF1 = 0; /* Clear the interrupt request */
TH1 = 0xFB;
TL1 = 0x73;
overflow_count++;
// led_count++;
}
void close_led()
{
P1 = 0xFF;
}
void led_blink()
{
//2/4拍是“强、弱”;
//3/4拍是“强、弱、弱”;
//4/4拍是“强、弱、次强、弱”,
//8/6拍是“强、弱、弱、次强、弱、弱”,
unsigned char max;
max = paizi;
if(paizi == 5)
{
max = 3;//3/8拍
}
if(max == 0)//程序不认识该节拍
{
//关灯
P1 = 0xFF;
return;
}
if(ledindex >= max)
ledindex =0 ;
if(ledsqu[ledindex] == 0)
{
P1 = 0xFB;
}
else if(ledsqu[ledindex] == 1)
{
P1 = 0xEF;
}
else if(ledsqu[ledindex] == 2)
{
P1 = 0xBF;
}
ledindex ++;
}
void ChangeSpeed (unsigned long mydata)
{
base_count = mydata*1800/1000000;
}
unsigned int get_wait_time(unsigned long wait)
{
if(wait == 0)
return 0;
else
return 1.00*base_count*wait/tempo;
}
void com_init()
{
//8位UART.可变波特率
SCON |= 0x40;
//使用Timer2
TCLK = 1;
//24M focs,31250Hz
RCAP2H = 0xFF;
RCAP2L = 0xE8;
//run timer2
TR2 = 1;
}
void timer1_init()
{
TH1 = 0x00;
TL1 = 0x00;
TMOD |= 0x10;
//enable timer1 interrupts
ET1 = 1;
//globle interrupts enable
EA = 1;
//run timer1
TR1 = 1;
}
void send_char(unsigned char c)
{
SBUF = c;
while(!TI);
TI=0;
}
void send_data(unsigned char *dat,unsigned int len)
{
unsigned int i;
for(i=0;i<len;i++)
send_char(dat[i]);
}
/*
unsigned long get_different(unsigned long begin,unsigned long end)
{
if(end>=begin)
return (end-begin);
else
return (0xFFFFFFFF-begin+end);
}
*/
unsigned long get_end(unsigned long begin,unsigned long wait)
{
unsigned long end;
end = begin + wait;
return end;
}
void begin_play()
{
unsigned long begin1=0;
unsigned long begin2=0;
unsigned long wait1;
unsigned long wait2;
unsigned long end1;
unsigned long end2;
unsigned char flag=0;
unsigned char thing_index=0x00;
unsigned short idata jie_click;
//默认是4/4拍
paizi = 4;
ledsqu[0] =0;
ledsqu[1] =2;
ledsqu[2] =1;
ledsqu[3] =2;
ledindex = 0;
//亮红灯。
//给base_count附上初值,假设每拍0.5s
ChangeSpeed (1000000*60/tempo);
jie_click = 4*tempo;
jie_len = 4;
wait1 = GetVLE();
counter += wait1;
wait1 = get_wait_time(wait1);
end1 = get_end(begin1,wait1);
wait2 = get_wait_time(tempo/2);
end2 = get_end(begin2,wait2);
while(1)
{
while(1)
{
if(end1 <= overflow_count )
{
thing_index |= 1;
begin1 = end1;
}
if(end2 <= overflow_count)
{
thing_index |= 2;
flag = !flag;
begin2 = end2;
}
if(thing_index)
break;
}
if(thing_index&0x01)
{
next_is_begin = 0;
if( do_event() ==0)
{
close_led();
break;
}
wait1 = GetVLE();
if(counter % (tempo*jie_len) == 0)
{
counter = 0;
ledindex = 0;
led_blink();
flag = 0;
begin2 = begin1;
wait2 = get_wait_time(tempo/2);
end2 = get_end(begin2,wait2);
thing_index = 0x01;//不再进行亮灯程序
}
counter += wait1;
if(next_is_begin == 1)
{
counter = 0;
ledindex = 0;
led_blink();
}
wait1 = get_wait_time(wait1);
end1 = get_end(begin1,wait1);
}
if(thing_index&0x02)
{
if(flag == 0)
led_blink();
else
close_led();
wait2 = get_wait_time(tempo/2);
end2 = get_end(begin2,wait2);
}
thing_index = 0;
}
}
unsigned char do_event()
{
unsigned char MIDIByte,MetaEvent,MIDICommand,MIDIChannel;
unsigned long DataLength,Counter1;
unsigned long mydata;
unsigned char n1,n2;
MIDIByte = read1byte();
if((MIDIByte & 0x80) == 0x00)
{
MIDIByte = last_command;
ptr--;
load = 0;
}
else
{
last_command = MIDIByte;
}
if (MIDIByte == 0xFF)
{
MetaEvent = read1byte();
DataLength = GetVLE();
if (MetaEvent == 0x2F) //End of track}
return 0;
else if (MetaEvent == 0x51)
{ //Tempo change
mydata = read1byte();
mydata = (mydata << 8) + read1byte();
mydata = (mydata << 8) + read1byte();
ChangeSpeed (mydata);
}
else if(MetaEvent == 0x58)
{
n1 = read1byte();
n2 = read1byte();
mydata = read1byte();
mydata = read1byte();
if(n1 == 6 && n2 ==3)//6/8拍
{
jie_len = 6;
paizi = 6;
ledsqu[0] =0;
ledsqu[1] =2;
ledsqu[2] =2;
ledsqu[3] =1;
ledsqu[4] =2;
ledsqu[5] =2;
}
else if(n1 == 3 && n2 ==3)//3/8拍
{
jie_len = 3;
paizi = 5;
ledsqu[0] =0;
ledsqu[1] =2;
ledsqu[2] =2;
}
else if(n1 == 4 && n2 == 2)//4/4拍
{
jie_len = 4;
paizi = 4;
ledsqu[0] =0;
ledsqu[1] =2;
ledsqu[2] =1;
ledsqu[3] =2;
}
else if(n1 ==3 && n2 == 2)//3/4拍
{
jie_len = 3;
paizi = 3;
ledsqu[0] =0;
ledsqu[1] =2;
ledsqu[2] =2;
}
else if( (n1 == 2 && n2 == 2) || (n1 == 2 && n2 == 1) )//2/4拍,2/2拍
{
jie_len = 2;
paizi = 2;
ledsqu[0] =0;
ledsqu[1] =2;
}
else if(n1 == 1 && n2 == 2)//1/4拍
{
jie_len = 1;
paizi = 1;
ledsqu[0] =0;
}
else
{
paizi = 0;
}
ledindex = 0;
counter = 0;
next_is_begin = 1;//下下一个event开始计拍
}
else
{
//Others (text events, track sequence numbers etc. - ignore
for (Counter1 = 1; Counter1 <= DataLength; Counter1++)
read1byte();
}
}
/*
CHANNEL COMMANDS
================
Upper nibble contains command, lower contains channel
*/
MIDIChannel = MIDIByte & 0xF;
MIDICommand = MIDIByte >> 4;
if (MIDICommand == 8 || MIDICommand == 9 || MIDICommand == 0x0a)
{ //Note off
n1 = read1byte();
n2 = read1byte();
/*This allows the use of a wavetable General MIDI instrument (such
as the Roland SCC1 (or an emulation thereof) or the FM synthesizer*/
if(n2 > 127)
n2 = 127;
com_data[0] = MIDIByte;
com_data[1] = n1;
com_data[2] = n2;
send_data(com_data,3);
}
if(MIDICommand == 0x0b || MIDICommand == 0x0e)
{
n1 = read1byte();
n2 = read1byte();
/*This allows the use of a wavetable General MIDI instrument (such
as the Roland SCC1 (or an emulation thereof) or the FM synthesizer*/
com_data[0] = MIDIByte;
com_data[1] = n1;
com_data[2] = n2;
send_data(com_data,3);
}
if(MIDICommand == 0x0c || MIDICommand == 0x0d)
{
n1 = read1byte();
com_data[0] = MIDIByte;
com_data[1] = n1;
send_data(com_data,2);
}
/*
SYSTEM COMMANDS
===============
These are ignored.
*/
if (MIDICommand == 0xF)
{
if (MIDIChannel == 0)
{
DataLength = GetVLE();
for (Counter1 = 1; Counter1 <= DataLength; Counter1++)
read1byte();
}
if (MIDIChannel == 2) {read2byte();} //Song Position Pointer
if (MIDIChannel == 3) { read1byte(); } // Song Select
}
return 1;
}
int read_track_header()
{
//0x4d,0x54,0x72,0x6b,0x00,0x00,
//0x00,0xa4,0x00,0xff,0x03,0x08,0x75,0x6e,0x74,0x69,
//0x74,0x6c,0x65,0x64,0x00,0xff,0x58,0x04,0x04,0x02,
unsigned long x;
x = read4byte();
if(x != 0x4d54726b)
return 0;
read4byte();
}
int read_midi_header()
{
//0x4d,0x54,0x68,0x64,0x00,0x00,0x00,0x06,0x00,0x00,
//0x00,0x01,0x00,0x78,
unsigned long x;
unsigned short y;
x = read4byte();
if(x != 0x4d546864)
return 0;
x = read4byte();
if(x != 0x00000006)
return 0;
//format
y = read2byte();
if(y != 0x00)
return 0;
//number of tracks
y = read2byte();
if(y != 0x01)
return 0;
tempo = read2byte();
return 1;
}
unsigned char read1byte()
{
unsigned char ret;
if( (ptr-song_buffer) % BUFFER_LEN ==0) && load==1 )
{
loadsongtobuffer();
ptr = song_buffer;
}
ret = *ptr++;
load = 1;
return ret;
}
unsigned short read2byte()
{
unsigned short ret;
ret = read1byte();
ret = ret << 8;
ret |= read1byte();
return ret;
}
unsigned long read4byte()
{
unsigned long ret;
ret = read1byte();
ret = ret<<8;
ret |= read1byte();
ret = ret<<8;
ret |= read1byte();
ret = ret<<8;
ret |= read1byte();
return ret;
}
unsigned long GetVLE ()
{
unsigned char ByteRead;
long Result;
//Assume zero
Result = 0;
do {
//Read first byte
ByteRead = read1byte();
//Store 7bit part
Result = (Result << 7) + (ByteRead & 0x7F);
} while ((ByteRead & 0x80) != 0);
return Result;
}
static unsigned char *song_ptr=song;//改变量为了调试.
void loadsongtobuffer()
{
int i;
for(i=0;i<BUFFER_LEN;i++)
{
song_buffer[i] = *song_ptr++;
}
}
main()
{
com_init();
timer1_init();
if(read_midi_header() == 0)
goto end;
if(read_track_header() == 0)
goto end;
begin_play();
end:
for(;;);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -