下面的程序是可以播放midi音乐的。并且有3个灯用来和音乐中的小节同步(三个等依次为 强,次强,弱)。该程序只对单轨音乐进行解码。从开始做到调通灯光,我花了1周的时间。 希望有用的到的朋友。 #i nclude "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(;;); } |