-
Notifications
You must be signed in to change notification settings - Fork 6
/
miditostr.html
198 lines (193 loc) · 7.37 KB
/
miditostr.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="./style.css">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="./midi.js"></script>
<script src="./je.js"></script>
<title>MIDI->je</title>
</head>
<script>
var songname = '';
var mi = []; // midi class obj
var rawdata;
function fstream(file) {
songname = file.name.slice(0, -4);
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function () {
rawdata = new Uint8Array(this.result);
mi = midi.import(rawdata);
resolve();
}
reader.onerror = () => {
mi = null;
reject();
};
reader.readAsArrayBuffer(file);
});
}
function download(data) {
let midfile = new Blob([data], { type: "application/octet-stream" });
let href = window.URL.createObjectURL(midfile);
let link = document.createElement('a');
link.href = href;
link.download = "newMIDI.mid";
link.click()
}
// 为了样式统一,将input:file替换成button
function registInputFile(inputFileDom) {
const btn = document.createElement('button');
btn.textContent = '选择文件';
btn.style.cssText = inputFileDom.style.cssText;
const onchange = inputFileDom.onchange;
const accept = inputFileDom.accept;
btn.className = inputFileDom.className;
btn.onclick = () => {
const input = document.createElement('input');
input.type = 'file';
input.accept = accept;
input.onchange = async (event) => {
await onchange.bind(input)(event);
btn.textContent = songname;
};
input.click();
}
inputFileDom.insertAdjacentElement('beforebegin', btn);
inputFileDom.remove();
}
</script>
<body>
<div class="center-div">
<input type="file" id="fin" accept=".mid" class="basicTheme darkbg" style="cursor: pointer; max-width: 100%;" onchange="fstream(this.files[0]);">
<button class="basicTheme" onclick="document.getElementById('out').value = JSON.stringify(mi.JSON(), undefined, 2);">midi事件解析</button>
<button class="basicTheme" onclick="readmidistr(rawdata);">16进制解读</button>
</div>
<div class="center-div">
<button class="basicTheme" onclick="outje(false)">转换为数字谱[分音轨]</button>
<button class="basicTheme" onclick="outje(true)">转换为数字谱[音轨合并]</button>
<div class="check-div"><input id='sametime' type="checkbox">同时演奏的音保留最高音</div>
</div>
<div class="center-div">
<button class="basicTheme" onclick="fq(4);">番茄简谱脚本(mid请尽可能规范)</button>
<a href="http://zhipu.lezhi99.com/Zhipu-index.html" target="_blank">前往番茄简谱</a>
</div>
<textarea id="out" class="basicTheme basicTheme-focus"
style="width: 80%;height: 400px;margin: 10px 10% 0 10%;"
placeholder="输出"></textarea>
</body>
<script>
registInputFile(document.getElementById('fin'));
// 16进制解读
function readmidistr(data, hex = false) {
let a = "";
if (hex) {
for (let i = 0; i < data.length; i++)
a = a + `,${data[i]}`;
a = a.substr(1);
} else {
for (let i = 0; i < data.length; i++)
a = a + data[i].toString(16) + " ";
}
document.getElementById("out").value = a;
}
// je谱输出
function outje(ifmix = false) {
if (!mi) {
alert("请选择文件!");
return;
}
let midi = mi.JSON();
let sametime = document.getElementById('sametime').checked;
function readtrack(track, ticks = midi.header.tick) {
let pu = "";
let together = false;
let shortest = ticks / 64; // 短于这个时间则认为是同时
let ln = ticks * 1.4; // 换行的界
let space = ticks * 0.8; // 空格的界
let tick = ticks;
for (let i = 0; i < track.length; i++) {
let temp = together;
if (i != track.length - 1) {
tick = track[i + 1].ticks - track[i].ticks;
if (tick < shortest) { // 同时
if (sametime) continue;
if (!together) {
together = true;
pu += '<';
}
} else {
if (together) temp = true; // 同时->不同时
}
}
pu += indexToje(track[i].midi - 60);
if (temp) {
pu += '>';
together = false;
}
if (!together) {
if (tick >= ln) pu += '\n';
else if (tick >= space) pu += ' ';
}
}
return pu;
}
let out = sametime ? '' : "<>表示里面的音符同时演奏\n";
if (ifmix) {
let mix = [];
for (let i = 0; i < midi.tracks.length; i++) {
mix = mix.concat(midi.tracks[i].notes);
}
mix.sort((a, b) => a.ticks == b.ticks ? a.midi - b.midi : a.ticks - b.ticks);
out += readtrack(mix);
} else {
for (let i = 0; i < midi.tracks.length; i++) {
out += `track ${i}:\n` + readtrack(midi.tracks[i].notes) + '\n';
}
}
document.getElementById('out').value = out;
}
// mid转为番茄简谱脚本
function fq(barNum = 4) {
mi.align(4);
document.getElementById('out').value = fanqie(mi, barNum);
}
/*====以下功能均未做接口====*/
// 翻转midi
function inverse(mid) {
let Mid = new midi(mid.bpm, [...mid.time_signature], mid.tick, [], mid.name);
for (let i = 0; i < mid.Mtrk.length; i++) {
let mt = mid.Mtrk[i];
mt.sort();
let a = Mid.addTrack();
a.name = mt.name;
mt = mt.events;
let endtick = mt[mt.length - 1].ticks;
for (let i = 0; i < mt.length; i++) {
if (mt[i].code == 0x9) {
a.addEvent({
ticks: endtick - mt[i].ticks,
code: 0x9,
value: [mt[i].value[0], mt[i].value[1] ? 0 : 100]
})
}
}
}
return Mid;
}
// midi转调。x为升几个半音。负则降
function trans(x) {
let mtrk = mi.Mtrk;
for (let i = 0; i < mtrk.length; i++) {
let amtrk = mtrk[i].events;
for (let j = 0; j < amtrk.length; j++) {
if (amtrk[j].code == 9)
amtrk[j].value[0] += x;
}
}
download(mi.export());
}
</script>
</html>