<script>
var midiSrc='/res/25469pm201.mid'//修改此处的midi音乐文件的地址为自己资源的地址
/**
*加载二进制文件
*/
var buffer;
var bufferLen;
function loadMidi(src="/res/baga.mid"){
var req = new XMLHttpRequest();
req.open('GET', src);
req.responseType = "arraybuffer";
req.send();
req.onreadystatechange = function () {
if (req.readyState === 4) {
var bufferTemp = req.response;
var dataview = new DataView(bufferTemp);
var ints = new Uint8Array(bufferTemp.byteLength);
for (var i = 0; i < ints.length; i++) {
ints[i] = dataview.getUint8(i);
}
buffer=ints;
bufferLen=buffer.length;
}
}
}
loadMidi(midiSrc);
var bufferIdx=0;
var tick=120;
var trackType=0;
var trackNum=0;
var trackRoad=[];
/**
*读取midi文件
*/
function ascToStr(asc){
return String.fromCharCode(asc);
}
function arrToStr(arr){
let strs='';
for(let i in arr){
strs= strs + ascToStr(arr[i]);
}
console.log('arrToStr',arr,strs);
return strs;
}
function getByteNum(arr){
let str='';
let len=arr.length;
for(let i=0;i<len;i++){
let tmp=arr[i].toString(2);
let tmpLen=tmp.length;
if(tmpLen<8){
for(let j=0;j<8-tmpLen;j++){
tmp='0' + tmp;
}
}
str = str+tmp;
}
return parseInt(str,2);
}
function headerChunk(){
let strs=arrToStr([buffer[bufferIdx++],buffer[bufferIdx++],buffer[bufferIdx++],buffer[bufferIdx++]]);
if(strs!=='MThd')return 'start not from MThd';
let byteLength= buffer[bufferIdx++] +''+ buffer[bufferIdx++] +'' + buffer[bufferIdx++] + '' + buffer[bufferIdx++];
console.log('MThd byteLength:',byteLength);
trackType = getByteNum( [ buffer[bufferIdx++], buffer[bufferIdx++] ] );
console.log('音轨类型:',trackType);
trackNum=getByteNum([ buffer[bufferIdx++],buffer[bufferIdx++] ]);
console.log('轨道数:',trackNum);
tick = getByteNum([buffer[bufferIdx++],buffer[bufferIdx++]]);
console.log('tick:',tick);
console.log('bufferIdx',bufferIdx);
}
function getDynamicByte(){
let num=0;
let arr=[];
let flag=true;
while(flag){
if(buffer[bufferIdx]<255){
arr.push(buffer[bufferIdx]);
if(buffer[bufferIdx]<128){
flag=false;
}
bufferIdx++;
}else{
flag=false;
}
}
let len=arr.length;
for(let i=0;i<len;i++){
if(arr[i]>=128){
num+=Math.pow(128,len-i-1)*(arr[i]-128);
}else{
num+=arr[i];
}
}
return num;
}
function printTxt(str='',num){
for(let i=0;i<num;i++){
str = str + ascToStr(buffer[bufferIdx++]);
}
console.log('printTxt',str,num);
}
function trackChunk(){
let strs=arrToStr([buffer[bufferIdx++],buffer[bufferIdx++],buffer[bufferIdx++],buffer[bufferIdx++]]);
if(strs!=='MTrk')return 'start not from MTrk';
let len=getByteNum([ buffer[bufferIdx++],buffer[bufferIdx++],buffer[bufferIdx++],buffer[bufferIdx++] ]);
console.log('音轨开头',strs,'长度',len);
let j=bufferIdx+len;
while(bufferIdx<j){
//读取deltime
let deltime=getDynamicByte();
console.log('deltime',deltime);
//meta-event 事件
if(buffer[bufferIdx]==255){
bufferIdx++;
if(buffer[bufferIdx]===0){
console.log('音序号:',getByteNum([ buffer[bufferIdx++], buffer[bufferIdx++] ]) );
}else if(buffer[bufferIdx]===1){
let num=getDynamicByte();
printTxt('文字事件: ',num);
}else if(buffer[bufferIdx]===2){
let num=getDynamicByte();
printTxt('版权: ',num);
}else if(buffer[bufferIdx]===3){
bufferIdx++;
let num=getDynamicByte();
printTxt('歌曲/音轨名称: ',num);
}else if(buffer[bufferIdx]===4){
bufferIdx++;
let num=getDynamicByte();
printTxt('乐器名称: ',num);
}else if(buffer[bufferIdx]===5){
let num=getDynamicByte();
printTxt('歌词: ',num);
}else if(buffer[bufferIdx]===6){
let num=getDynamicByte();
printTxt('标记: ',num);
}else if(buffer[bufferIdx]===7){
let num=getDynamicByte();
printTxt('注释: ',num);
}else if(buffer[bufferIdx]===47){
printTxt('音轨结束: ',buffer[++bufferIdx]);
bufferIdx++;
j=bufferIdx;//强制退出循环
}else if(buffer[bufferIdx]===81){
let num=buffer[++bufferIdx];
bufferIdx++;
let dynamicArr=[];
for(let i=0;i<num;i++){
dynamicArr.push(buffer[bufferIdx++]);
}
let speed=getByteNum(dynamicArr);
console.log('播放速度:',num,' 四分音符为',speed,dynamicArr);
}else if(buffer[bufferIdx]===88){
bufferIdx++;
let num=buffer[bufferIdx++];
console.log('指定节拍: 长度',num,',',buffer[bufferIdx++],'/',Math.pow(2,buffer[bufferIdx++]),'拍号',',节拍器时钟:',buffer[bufferIdx++],'(1个四分音符占的midi间隔),一个四分音符时值等于',buffer[bufferIdx++],'个三十二分音符');
}
}else{
// console.log('bufferIdx',bufferIdx);
if(buffer[bufferIdx]>=128 && buffer[bufferIdx]<=143){
console.log('关闭音符 第',buffer[bufferIdx]-128,'音轨,音符',buffer[++bufferIdx],'力度',buffer[++bufferIdx]);
bufferIdx++;
}else if(buffer[bufferIdx]>=144 && buffer[bufferIdx]<=159){
console.log('打开音符,第',buffer[bufferIdx]-144,'音轨,音符',buffer[++bufferIdx],'力度',buffer[++bufferIdx]);
bufferIdx++;
}else if(buffer[bufferIdx]>=160 && buffer[bufferIdx]<=175){
console.log('触后音符,第',buffer[bufferIdx]-160,'音轨,音符',buffer[++bufferIdx],'力度',buffer[++bufferIdx]);
bufferIdx++;
}else if(buffer[bufferIdx]>=176 && buffer[bufferIdx]<=191){
console.log('设置',buffer[bufferIdx]-176,'通道,',buffer[++bufferIdx],'号控制器值为',buffer[++bufferIdx]);
bufferIdx++;
}else if(buffer[bufferIdx]>=192 && buffer[bufferIdx]<=207){
console.log('设置',buffer[bufferIdx]-192,'号通道音色值为',buffer[++bufferIdx]);
bufferIdx++;
}else if(buffer[bufferIdx]>=208 && buffer[bufferIdx]<=223){
console.log('设置',buffer[bufferIdx]-192,'通道,音色值为',buffer[++bufferIdx],buffer[++bufferIdx]);
bufferIdx++
}else{
console.log('其它事件,标识符号',buffer[bufferIdx++]);
}
}
}
}
function analysisMidi(){
console.log('buffer',buffer);
headerChunk();
let len=buffer.length;
while(bufferIdx<len){
trackChunk();
}
}
setTimeout(function() {
analysisMidi();
}, 2000);
</script>
解读输出如下:
如果愿意支持本人的创作,请下载源代码吧!下载地址