首页 > 解决方案 > 在节点中将midi转换为mp3

问题描述

所以我在使用scribbletune的节点中开发一个应用程序

要创建一个 midi 文件:

const clip = scribble.clip({
  notes: cMajor,
  pattern: 'xxxxxxx'
});

scribble.midi(clip, 'c-major.mid');

我希望能够在浏览器中播放这个文件。据我所知,无法使用音频标签在浏览器中播放 midi:

<audio controls>
  <source src="horse.ogg" type="audio/ogg">
</audio>

所以我想我应该首先将midi文件转换为mp3文件。我一直在网上搜索可以做到这一点但没有找到任何东西的节点包。

这听起来应该是可能的。

关于如何在节点中实现这一点的任何提示?

标签: node.js

解决方案


如果您只想在浏览器中播放生成的 MIDI 并首先将文件转换为ogg并使用音频标签播放它不是必需的,MidiConvertTone.js (如Scribbletune文档中简要说明的那样)可以完成这项工作。

我已经编写了一个示例:

const http = require("http");

const MidiConvert = require("midiconvert"); // npm install midiconvert
const scribble = require("scribbletune"); // npm install scribbletune

const createMidiForToneJs = (notes, pattern) => {
  let clip = scribble.clip({
    notes,
    pattern
  });

  let midiData;

  // The callback is called synchronously (https://github.com/scribbletune/scribbletune/blob/ebda52d7a2835f28b3ddab15488c22bc1d425e7b/src/midi.js#L37)
  scribble.midi(
    clip,
    null, // setting filename to null will cause this method to return bytes (via the callback)
    (err, bytes) => {
      // err is always null
      midiData = bytes;
    }
  );

  return MidiConvert.parse(midiData);
};

const server = http.createServer((req, res) => {
  // Don't mind the naivety of the following URL router
  switch (req.url.toLowerCase()) {
    case "/":
      res.end(indexHTMLContents);
      break;
    case "/midi.json":
      res.statusCode = 200;
      res.setHeader("Content-Type", "application/json");
      const jsonString = JSON.stringify(createMidiForToneJs("CM", "xxxxxxx"));
      res.end(jsonString);
      break;
    default:
      res.statusCode = 404;
      res.end();
  }
});

server.listen(3000); // Open http://localhost:3000 in browser

// -- The HTML and Javascript for the "/" route. Obviously, don't do this in production!

const jsToBeExecutedInBrowser = () => {
  document.querySelector("button").addEventListener(
    "click",
    async () => {
      Tone.Transport.clear();
      Tone.Transport.stop();

      const synth = new Tone.Synth().toMaster();

      const response = await fetch("/midi.json");
      const midiJson = await response.json();

      const midi = MidiConvert.fromJSON(midiJson);

      Tone.Transport.bpm.value = midi.bpm;
      Tone.Transport.timeSignature = midi.timeSignature;

      midi.tracks.forEach(track => {
        new Tone.Part((time, event) => {
          synth.triggerAttackRelease(
            event.name,
            event.duration,
            time,
            event.velocity
          );
        }, track.notes).start(midi.startTime);
      });

      Tone.Transport.start();
    },
    false
  );
};

const indexHTMLContents = `<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <title>Midi Player</title>
  </head>
  <body>
  <button>Play!</button>
  <script src="https://unpkg.com/tone"></script>
  <script src="https://unpkg.com/midiconvert"></script>
  <script>
  (${jsToBeExecutedInBrowser.toString()})();
  </script>
  </body>
</html>`;

推荐阅读