如何使用Tone.JS播放MIDI文件?

3
在查阅Tone.JS文档时,我发现它支持MIDI文件。
为了使用MIDI文件,您需要首先使用Midi将它们转换成Tone.js可以理解的JSON格式。虽然有许多在线资源可将MIDI转换为JSON,但我没有找到任何代码示例或任何文档来演示MIDI文件和/或JSON文件的用法。
在浏览文档时,我只发现了播放.mp3文件和使用效果的示例。即使通过谷歌搜索也没有发现相关信息。
是否有人能提供给我一个代码片段来演示这个?
3个回答

1

请查看http://tonejs.github.io/Midi/的源代码。JS代码位于<body>底部的<script>标签中。

看起来您需要手动遍历对象,并使用tonejs调度每个音符。以下是代码的相关部分。currentMidi是使用从上传框读取的midi文件结果构建的Midi对象。然后循环遍历currentMidi,并处理和安排其轨道和音符。

let currentMidi = null;

function parseFile(file) {
    //read the file
    const reader = new FileReader();
    reader.onload = function (e) {
        const midi = new Midi(e.target.result);
        document.querySelector(
            "#ResultsText"
        ).value = JSON.stringify(midi, undefined, 2);
        document
            .querySelector("tone-play-toggle")
            .removeAttribute("disabled");
        currentMidi = midi;
    };
    reader.readAsArrayBuffer(file);
}

const synths = [];
document
    .querySelector("tone-play-toggle")
    .addEventListener("play", (e) => {
        const playing = e.detail;
        if (playing && currentMidi) {
            const now = Tone.now() + 0.5;
            currentMidi.tracks.forEach((track) => {
                //create a synth for each track
                const synth = new Tone.PolySynth(Tone.Synth, {
                    envelope: {
                        attack: 0.02,
                        decay: 0.1,
                        sustain: 0.3,
                        release: 1,
                    },
                }).toDestination();
                synths.push(synth);
                //schedule all of the events
                track.notes.forEach((note) => {
                    synth.triggerAttackRelease(
                        note.name,
                        note.duration,
                        note.time + now,
                        note.velocity
                    );
                });
            });
        } else {
            //dispose the synth and make a new one
            while (synths.length) {
                const synth = synths.shift();
                synth.disconnect();
            }
        }
    });

要获取Midi类,您需要https://github.com/Tonejs/Midi。我认为他们声称它是tonejs友好的有点夸张,因为您仍然需要编写代码来播放单个音符,并进行所有必需的设置。我希望能有一个单一的函数来播放返回的Midi对象。


0

如果您需要处理多个附加的副作用并触发注释,您可以使用传输功能来安排它们以确保它们同时发生:

aSingleParsedMidiTrack.notes.forEach((note) => {
    const startTime = Tone.Time(note.time).toSeconds();
    const duration = Tone.Time(note.duration).toSeconds();

    Tone.Transport.schedule((time) => {

      sharedState.synth.triggerAttackRelease(
        note.name,
        duration,
        startTime,
        note.velocity
      );

      // side effects
      piano.dispatchEvent(
        new CustomEvent("highlight", { detail: { notes: [note.name] } })
      );
      canvas.dispatchEvent(
        new CustomEvent("paint", { detail: { notes: [note.name] } })
      );
    }, startTime);
}

Tone.Transport.start(0); // start at the beginning

这确保副作用在音符声音的头部进行处理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接