递归火山软件开发平台

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 火山 源码 类库
查看: 34|回复: 0
打印 上一主题 下一主题

[视窗] 【源码】mid文件转换成单片机音乐数据

[复制链接]

6

主题

11

帖子

236

积分

中级会员

Rank: 3Rank: 3

积分
236
跳转到指定楼层
楼主
本帖最后由 mogo 于 2026-2-9 11:44 编辑


输入文本简谱格式(至少三个字符才算有效):
第一个字符表示唱名:1234567 或 CDEFGAB ,0为休止符。
第二个字符表示第几个八度:0123456789。
第三个字符表示节拍:
1 = 三十二分音符,(八分之一拍,3个下划线)
2 = 十六分音符,(四分之一拍,2个下划线)
3 = 八分音符,(半拍,1个下划线)
4 = 四分音符,(一拍)
5 = 二分音符(后边一个减号,两拍)
6 = 全音符(后边三个减号,四拍)
之后的字符:#*升音,/降音,.附点音符(包括双附点)
用空格表示音符结束,换行也需要先添加空格。

输出数据格式:
第1个字节为基准音,表示歌曲最低音,以半音为单位。
第2到第9个字节为节拍数组,共8个节拍,单位为4000/256=15.625ms。
其它数据如下:
高5位为音阶,加上基准音为实际音阶,最多只能表示0~30共31个半音。31表示休止符不发声。
低3位表示节拍,数值为节拍数组的索引。
尾字节为0xFF表示结束。如果需要暂停发音的时间是最长时间使用连续的空音符。
  1. #define CALC_TIMER_VALUE(freq)  (unsigned int)(65536 - (FOSC/(float)(CRYSTAL * 2 * (freq))))

  2. unsigned int __code FREQ[] = { // 音阶表(完整88键)
  3.     //  A0-B0
  4.     CALC_TIMER_VALUE(27.50), CALC_TIMER_VALUE(29.14), CALC_TIMER_VALUE(30.87),
  5.    
  6.     //  C1-B1
  7.     CALC_TIMER_VALUE(32.70), CALC_TIMER_VALUE(34.65), CALC_TIMER_VALUE(36.71),
  8.     CALC_TIMER_VALUE(38.89), CALC_TIMER_VALUE(41.20), CALC_TIMER_VALUE(43.65),
  9.     CALC_TIMER_VALUE(46.25), CALC_TIMER_VALUE(48.99), CALC_TIMER_VALUE(51.91),
  10.     CALC_TIMER_VALUE(55.00), CALC_TIMER_VALUE(58.27), CALC_TIMER_VALUE(61.74),
  11.    
  12.     //  C2-B2
  13.     CALC_TIMER_VALUE(65.41), CALC_TIMER_VALUE(69.30), CALC_TIMER_VALUE(73.42),
  14.     CALC_TIMER_VALUE(77.78), CALC_TIMER_VALUE(82.41), CALC_TIMER_VALUE(87.31),
  15.     CALC_TIMER_VALUE(92.50), CALC_TIMER_VALUE(98.00), CALC_TIMER_VALUE(103.83),
  16.     CALC_TIMER_VALUE(110.00), CALC_TIMER_VALUE(116.54), CALC_TIMER_VALUE(123.47),
  17.    
  18.     //  C3-B3
  19.     CALC_TIMER_VALUE(130.81), CALC_TIMER_VALUE(138.59), CALC_TIMER_VALUE(146.83),
  20.     CALC_TIMER_VALUE(155.56), CALC_TIMER_VALUE(164.81), CALC_TIMER_VALUE(174.61),
  21.     CALC_TIMER_VALUE(185.00), CALC_TIMER_VALUE(196.00), CALC_TIMER_VALUE(207.65),
  22.     CALC_TIMER_VALUE(220.00), CALC_TIMER_VALUE(233.08), CALC_TIMER_VALUE(246.94),
  23.    
  24.     //  C4-B4
  25.     CALC_TIMER_VALUE(261.63), CALC_TIMER_VALUE(277.18), CALC_TIMER_VALUE(293.66),
  26.     CALC_TIMER_VALUE(311.13), CALC_TIMER_VALUE(329.63), CALC_TIMER_VALUE(349.23),
  27.     CALC_TIMER_VALUE(369.99), CALC_TIMER_VALUE(392.00), CALC_TIMER_VALUE(415.30),
  28.     CALC_TIMER_VALUE(440.00), CALC_TIMER_VALUE(466.16), CALC_TIMER_VALUE(493.88),
  29.    
  30.     //  C5-B5
  31.     CALC_TIMER_VALUE(523.25), CALC_TIMER_VALUE(554.37), CALC_TIMER_VALUE(587.33),
  32.     CALC_TIMER_VALUE(622.25), CALC_TIMER_VALUE(659.26), CALC_TIMER_VALUE(698.46),
  33.     CALC_TIMER_VALUE(739.99), CALC_TIMER_VALUE(783.99), CALC_TIMER_VALUE(830.61),
  34.     CALC_TIMER_VALUE(880.00), CALC_TIMER_VALUE(932.33), CALC_TIMER_VALUE(987.77),
  35.    
  36.     // C6-B6
  37.     CALC_TIMER_VALUE(1046.50), CALC_TIMER_VALUE(1108.73), CALC_TIMER_VALUE(1174.66),
  38.     CALC_TIMER_VALUE(1244.51), CALC_TIMER_VALUE(1318.51), CALC_TIMER_VALUE(1396.91),
  39.     CALC_TIMER_VALUE(1479.98), CALC_TIMER_VALUE(1567.98), CALC_TIMER_VALUE(1661.22),
  40.     CALC_TIMER_VALUE(1760.00), CALC_TIMER_VALUE(1864.66), CALC_TIMER_VALUE(1975.53),
  41.    
  42.     // C7-B7
  43.     CALC_TIMER_VALUE(2093.00), CALC_TIMER_VALUE(2217.46), CALC_TIMER_VALUE(2349.32),
  44.     CALC_TIMER_VALUE(2489.02), CALC_TIMER_VALUE(2637.02), CALC_TIMER_VALUE(2793.83),
  45.     CALC_TIMER_VALUE(2959.96), CALC_TIMER_VALUE(3135.96), CALC_TIMER_VALUE(3322.44),
  46.     CALC_TIMER_VALUE(3520.00), CALC_TIMER_VALUE(3729.31), CALC_TIMER_VALUE(3951.07),
  47.    
  48.     // C8
  49.     CALC_TIMER_VALUE(4186.01)
  50. };
复制代码
  1. volatile __bit sounding;//播放声音
  2. unsigned char playOffset;//基础音,调式偏移量
  3. unsigned char *playMeter;//节拍数组
  4. unsigned char *playTrack;//音乐数据指针
  5. __bit playEnable = 0;//是否正在播放

  6. void PlayStop(void) { //停止播放
  7.         playEnable = 0;
  8.         sounding = 0;
  9.         SPEAKER = 0;
  10. }

  11. void PlayNote(unsigned char note){ //更改正在播放的音符
  12.         if(note<88){
  13.                 unsigned int freq = FREQ[note];
  14.                 RCAP2H = freq >> 8;
  15.                 RCAP2L = freq & 0xFF;
  16.                 sounding = 1;
  17.         }
  18.         else sounding=0;
  19. }

  20. void PlayMusic(void){ //播放状态更新,每15.625ms调用一次
  21.         static unsigned char length;
  22.         static unsigned char meter;
  23.         static __bit playing = 0;
  24.         if (!playEnable)return;        
  25.         if (playing){
  26.                 if (length<meter){
  27.                         length++;
  28.                 } else {
  29.                         playing=0;
  30.                         playTrack++;
  31.                 }
  32.         }else if(*playTrack != 0xFF){        
  33.                 unsigned char noteData = *playTrack;// 获取当前音符数据
  34.                 unsigned char midiNote = (noteData >> 3) & 0x1F;//高5位为MIDI音阶
  35.                 unsigned char beatIndex = noteData & 0x07;//低3位为节拍索引
  36.                 meter = *(playMeter+beatIndex);
  37.                 length = 0;
  38.                 if(midiNote==0x1F) PlayNote(0x7F);
  39.                 else PlayNote(midiNote+playOffset);
  40.                 playing=1;
  41.         }else PlayStop();
  42. }

  43. void PlayStart(unsigned char *track) { //开始播放
  44.         playOffset = *track - 21;//第0字节为MIDI音阶,减去音频数组起点A0
  45.         playMeter = track+1;//每1-8字节为节拍
  46.         playTrack = track+9;//第9字节开始音乐数据
  47.         playEnable = 1;
  48. }

  49. void T2Interrupt(void) __interrupt 5 __using 3{
  50.     TF2=0;//必须软件置零
  51.         if (sounding) SPEAKER = !SPEAKER;
  52. }
复制代码


main.v (621.94 KB, 下载次数: 0)
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|递归火山软件开发平台 ( 鄂ICP备18029190号 )

GMT+8, 2026-2-9 14:08 , Processed in 0.083560 second(s), 20 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表