|
9 | 9 | <PanelPiano v-if="currentInstrumentType === 'piano'" /> |
10 | 10 | <PanelGuitar v-if="currentInstrumentType === 'guitar-acoustic'" /> |
11 | 11 | <div |
12 | | - class="max-w-[1200px] mt-5 mx-auto w-full h-auto max-h-[800px] flex min-h-[70vh] gap-5 flex-row max-[1200px]:flex-col max-[1200px]:w-auto max-[1200px]:max-h-max max-[1200px]:overflow-x-auto" |
| 12 | + class="max-w-[1200px] mt-5 mx-auto w-full h-auto max-h-[800px] flex min-h-[70vh] gap-5 flex-row max-[1200px]:flex-col-reverse max-[1200px]:w-auto max-[1200px]:max-h-max max-[1200px]:overflow-x-auto" |
13 | 13 | > |
14 | 14 | <PanelEditor |
15 | 15 | v-model:formData="formData" |
|
24 | 24 | ></div> |
25 | 25 | </div> |
26 | 26 | <PanelExample @load-example="loadExample" /> |
27 | | - <PanelSnOptions v-model:options="snOptions" /> |
28 | | - <PanelRoadmap /> |
29 | 27 | <PanelSyntax /> |
30 | 28 | <PanelQa /> |
| 29 | + <PanelSnOptions v-model:options="snOptions" /> |
| 30 | + <PanelRoadmap /> |
31 | 31 | <NoteContextMenu |
32 | 32 | :isVisible="isContextMenuVisible" |
33 | 33 | :x="contextMenuX" |
@@ -61,6 +61,7 @@ import PanelGuitar from './components/PanelGuitar.vue'; |
61 | 61 | import { usePianoStore } from './stores'; |
62 | 62 | import { usePlayer } from './use/usePlayer'; |
63 | 63 | import { useTone } from './use/useTone'; |
| 64 | +import { parseMidi } from 'midi-file'; |
64 | 65 |
|
65 | 66 | const panelOperateRef: Ref<InstanceType<typeof PanelOperate> | null> = |
66 | 67 | ref(null); |
@@ -280,31 +281,74 @@ function handleExportFile() { |
280 | 281 | } |
281 | 282 |
|
282 | 283 | /** |
283 | | - * 处理导入乐谱文件 |
| 284 | + * 处理导入文件事件 |
284 | 285 | * @param {File} file - 导入的文件对象 |
285 | | - * @param {string} content - 文件内容 |
286 | | - * @returns {void} |
| 286 | + * @param {string | ArrayBuffer | any | null} data - 读取到的文件内容 (字符串, ArrayBuffer, 或解析后的对象) |
| 287 | + * @param {string} type - 文件的MIME类型 |
287 | 288 | */ |
288 | | -function handleImportFile(file: File, content: string) { |
289 | | - const ext = file.name.split('.').pop()?.toLowerCase(); |
290 | | - try { |
291 | | - if (ext === 'json') { |
292 | | - const json = JSON.parse(content); |
293 | | - if (typeof json === 'string') { |
294 | | - inputType.value = SNDataType.ABC; |
295 | | - abcStr.value = json; |
296 | | - } else { |
| 289 | +function handleImportFile( |
| 290 | + file: File, |
| 291 | + data: string | ArrayBuffer | any | null, |
| 292 | + type: string, |
| 293 | +) { |
| 294 | + const fileName = file.name.toLowerCase(); |
| 295 | + if (fileName.endsWith('.json')) { |
| 296 | + const parsedData = JSON.parse(data); |
| 297 | + formData.value = parsedData; |
| 298 | + inputType.value = SNDataType.TEMPLATE; |
| 299 | + } else if (fileName.endsWith('.txt')) { |
| 300 | + abcStr.value = data; |
| 301 | + inputType.value = SNDataType.ABC; |
| 302 | + } else if (fileName.endsWith('.mid') || fileName.endsWith('.midi')) { |
| 303 | + // 处理 MIDI 文件 |
| 304 | + if (data instanceof ArrayBuffer) { |
| 305 | + try { |
| 306 | + const midi = parseMidi(new Uint8Array(data)); |
| 307 | + const snTemplateData: SNTemplate = convertMidiToSnTemplate(midi); |
| 308 | + formData.value = snTemplateData; |
297 | 309 | inputType.value = SNDataType.TEMPLATE; |
298 | | - formData.value = json; |
| 310 | + } catch (error) { |
| 311 | + console.error('Error parsing MIDI file:', error); |
| 312 | + // Handle parsing errors |
299 | 313 | } |
300 | | - } else if (ext === 'txt') { |
301 | | - inputType.value = SNDataType.ABC; |
302 | | - abcStr.value = content; |
303 | 314 | } else { |
304 | | - alert('仅支持json或txt格式'); |
| 315 | + console.error( |
| 316 | + 'Expected ArrayBuffer data for MIDI file, but received', |
| 317 | + typeof data, |
| 318 | + ); |
| 319 | + // Handle unexpected data type |
305 | 320 | } |
306 | | - } catch (err) { |
307 | | - alert('文件解析失败,请检查格式'); |
| 321 | + } else { |
| 322 | + // 处理其他不支持的文件类型 |
| 323 | + console.warn('Unsupported file type imported:', file.name, 'Type:', type); |
308 | 324 | } |
309 | 325 | } |
| 326 | +
|
| 327 | +/** |
| 328 | + * 将解析后的 MIDI 数据转换为 SimpleNotation 模板格式 (SNTemplate). |
| 329 | + * TODO: 实现具体的转换逻辑 |
| 330 | + * @param {any} midiData - 解析后的 MIDI 数据对象 (来自 midi-file 库) |
| 331 | + * @returns {SNTemplate} 转换后的 SimpleNotation 模板数据 |
| 332 | + */ |
| 333 | +function convertMidiToSnTemplate(midiData: any): SNTemplate { |
| 334 | + console.warn( |
| 335 | + 'convertMidiToSnTemplate function is a placeholder. Implement MIDI to SNTemplate conversion here.', |
| 336 | + midiData, |
| 337 | + ); |
| 338 | + // TODO: 在此处实现从 midiData 中提取乐谱信息并构建 SNTemplate 对象的逻辑 |
| 339 | + // 示例: 返回一个默认的空模板或包含部分信息的模板 |
| 340 | + return { |
| 341 | + info: { |
| 342 | + title: midiData.header.name || 'Imported MIDI', |
| 343 | + composer: '', |
| 344 | + lyricist: '', |
| 345 | + time: '4', // 需要从 MIDI 事件中解析 |
| 346 | + tempo: '120', // 需要从 MIDI 事件中解析 |
| 347 | + key: 'C', // 需要从 MIDI 事件中解析 |
| 348 | + beat: '4', // 需要从 MIDI 事件中解析 |
| 349 | + }, |
| 350 | + score: '', // 需要从 MIDI 音符事件中生成简谱字符串 |
| 351 | + lyric: '', // 需要从 MIDI 歌词事件中生成歌词字符串 |
| 352 | + }; |
| 353 | +} |
310 | 354 | </script> |
0 commit comments