递归火山软件开发平台
标题:
【源码】mid文件转换成单片机音乐数据
[打印本页]
作者:
mogo
时间:
3 小时前
标题:
【源码】mid文件转换成单片机音乐数据
本帖最后由 mogo 于 2026-2-9 11:44 编辑
(, 下载次数: 0)
上传
点击文件名下载附件
输入文本简谱格式(至少三个字符才算有效):
第一个字符表示唱名: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表示结束。如果需要暂停发音的时间是最长时间使用连续的空音符。
#define CALC_TIMER_VALUE(freq) (unsigned int)(65536 - (FOSC/(float)(CRYSTAL * 2 * (freq))))
unsigned int __code FREQ[] = { // 音阶表(完整88键)
// A0-B0
CALC_TIMER_VALUE(27.50), CALC_TIMER_VALUE(29.14), CALC_TIMER_VALUE(30.87),
// C1-B1
CALC_TIMER_VALUE(32.70), CALC_TIMER_VALUE(34.65), CALC_TIMER_VALUE(36.71),
CALC_TIMER_VALUE(38.89), CALC_TIMER_VALUE(41.20), CALC_TIMER_VALUE(43.65),
CALC_TIMER_VALUE(46.25), CALC_TIMER_VALUE(48.99), CALC_TIMER_VALUE(51.91),
CALC_TIMER_VALUE(55.00), CALC_TIMER_VALUE(58.27), CALC_TIMER_VALUE(61.74),
// C2-B2
CALC_TIMER_VALUE(65.41), CALC_TIMER_VALUE(69.30), CALC_TIMER_VALUE(73.42),
CALC_TIMER_VALUE(77.78), CALC_TIMER_VALUE(82.41), CALC_TIMER_VALUE(87.31),
CALC_TIMER_VALUE(92.50), CALC_TIMER_VALUE(98.00), CALC_TIMER_VALUE(103.83),
CALC_TIMER_VALUE(110.00), CALC_TIMER_VALUE(116.54), CALC_TIMER_VALUE(123.47),
// C3-B3
CALC_TIMER_VALUE(130.81), CALC_TIMER_VALUE(138.59), CALC_TIMER_VALUE(146.83),
CALC_TIMER_VALUE(155.56), CALC_TIMER_VALUE(164.81), CALC_TIMER_VALUE(174.61),
CALC_TIMER_VALUE(185.00), CALC_TIMER_VALUE(196.00), CALC_TIMER_VALUE(207.65),
CALC_TIMER_VALUE(220.00), CALC_TIMER_VALUE(233.08), CALC_TIMER_VALUE(246.94),
// C4-B4
CALC_TIMER_VALUE(261.63), CALC_TIMER_VALUE(277.18), CALC_TIMER_VALUE(293.66),
CALC_TIMER_VALUE(311.13), CALC_TIMER_VALUE(329.63), CALC_TIMER_VALUE(349.23),
CALC_TIMER_VALUE(369.99), CALC_TIMER_VALUE(392.00), CALC_TIMER_VALUE(415.30),
CALC_TIMER_VALUE(440.00), CALC_TIMER_VALUE(466.16), CALC_TIMER_VALUE(493.88),
// C5-B5
CALC_TIMER_VALUE(523.25), CALC_TIMER_VALUE(554.37), CALC_TIMER_VALUE(587.33),
CALC_TIMER_VALUE(622.25), CALC_TIMER_VALUE(659.26), CALC_TIMER_VALUE(698.46),
CALC_TIMER_VALUE(739.99), CALC_TIMER_VALUE(783.99), CALC_TIMER_VALUE(830.61),
CALC_TIMER_VALUE(880.00), CALC_TIMER_VALUE(932.33), CALC_TIMER_VALUE(987.77),
// C6-B6
CALC_TIMER_VALUE(1046.50), CALC_TIMER_VALUE(1108.73), CALC_TIMER_VALUE(1174.66),
CALC_TIMER_VALUE(1244.51), CALC_TIMER_VALUE(1318.51), CALC_TIMER_VALUE(1396.91),
CALC_TIMER_VALUE(1479.98), CALC_TIMER_VALUE(1567.98), CALC_TIMER_VALUE(1661.22),
CALC_TIMER_VALUE(1760.00), CALC_TIMER_VALUE(1864.66), CALC_TIMER_VALUE(1975.53),
// C7-B7
CALC_TIMER_VALUE(2093.00), CALC_TIMER_VALUE(2217.46), CALC_TIMER_VALUE(2349.32),
CALC_TIMER_VALUE(2489.02), CALC_TIMER_VALUE(2637.02), CALC_TIMER_VALUE(2793.83),
CALC_TIMER_VALUE(2959.96), CALC_TIMER_VALUE(3135.96), CALC_TIMER_VALUE(3322.44),
CALC_TIMER_VALUE(3520.00), CALC_TIMER_VALUE(3729.31), CALC_TIMER_VALUE(3951.07),
// C8
CALC_TIMER_VALUE(4186.01)
};
复制代码
volatile __bit sounding;//播放声音
unsigned char playOffset;//基础音,调式偏移量
unsigned char *playMeter;//节拍数组
unsigned char *playTrack;//音乐数据指针
__bit playEnable = 0;//是否正在播放
void PlayStop(void) { //停止播放
playEnable = 0;
sounding = 0;
SPEAKER = 0;
}
void PlayNote(unsigned char note){ //更改正在播放的音符
if(note<88){
unsigned int freq = FREQ[note];
RCAP2H = freq >> 8;
RCAP2L = freq & 0xFF;
sounding = 1;
}
else sounding=0;
}
void PlayMusic(void){ //播放状态更新,每15.625ms调用一次
static unsigned char length;
static unsigned char meter;
static __bit playing = 0;
if (!playEnable)return;
if (playing){
if (length<meter){
length++;
} else {
playing=0;
playTrack++;
}
}else if(*playTrack != 0xFF){
unsigned char noteData = *playTrack;// 获取当前音符数据
unsigned char midiNote = (noteData >> 3) & 0x1F;//高5位为MIDI音阶
unsigned char beatIndex = noteData & 0x07;//低3位为节拍索引
meter = *(playMeter+beatIndex);
length = 0;
if(midiNote==0x1F) PlayNote(0x7F);
else PlayNote(midiNote+playOffset);
playing=1;
}else PlayStop();
}
void PlayStart(unsigned char *track) { //开始播放
playOffset = *track - 21;//第0字节为MIDI音阶,减去音频数组起点A0
playMeter = track+1;//每1-8字节为节拍
playTrack = track+9;//第9字节开始音乐数据
playEnable = 1;
}
void T2Interrupt(void) __interrupt 5 __using 3{
TF2=0;//必须软件置零
if (sounding) SPEAKER = !SPEAKER;
}
复制代码
(, 下载次数: 0)
上传
点击文件名下载附件
欢迎光临 递归火山软件开发平台 (https://bbs.voldp.com/)
Powered by Discuz! X3.4