Scribbletune can be used as a Node.js module to export MIDI files from the terminal OR in the browser along with Tone.js.
Install Scribbletune from npm
npm i scribbletune
Now you can create MIDI files from the terminal
const scribble = require('scribbletune');
const clip = scribble.clip({
notes: scribble.scale('C4 major'),
pattern: 'x'.repeat(8)
});
scribble.midi(clip); // creates a file called music.mid in the same location as this script was created and run.
There are a couple of ways to use Scribbletune in the browser.
Use the latest available precompiled version of Scribbletune from CDNjs and reference it in your HTML right after Tone.js (replace LATEST_VERSION_FROM_CDNJS with the latest version from CDNjs).
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.7.43/Tone.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/scribbletune/LATEST_VERSION_FROM_CDNJS/scribbletune.js"></script>
This will make a global object called scribble available for you to use in your script.
console.log(scribble.scale('C4 major')); // outputs ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4']
Install scribbletune and webpack from npm
npm i scribbletune
npm i vite --save-dev
Create a bare minimum vite.config.js file with
import { defineConfig } from "vite";
export default defineConfig({});
Create a file called script.js and enter the following in there
import { Session } from "scribbletune/browser";
const btnStart = document.getElementById("start");
const btnPlay1 = document.getElementById("play1");
const btnPlay2 = document.getElementById("play2");
const btnPlay3 = document.getElementById("play3");
const btnStop = document.getElementById("stop");
let channel;
let isReady = false;
btnStart.addEventListener("click", async () => {
// Resume audio context (required for browsers)
await Tone.start();
console.log("Audio context started");
// Create session and channel
const session = new Session();
channel = session.createChannel({
instrument: "PolySynth",
clips: [
{ pattern: "x-x-", notes: "C4 E4 G4" },
{ pattern: "x[xx]", notes: "C#4 D#4" },
{ pattern: "[xxxx]", notes: ["G4", "D5"] },
],
eventCb: (event, data) => {
console.log("Channel event:", event, data);
if (event === "loaded") {
isReady = true;
console.log("Channel is ready to play!");
}
if (event === "error") {
console.error("Channel error:", data.e);
}
},
});
// Start the transport
Tone.Transport.start();
console.log("Transport started");
});
btnPlay1.addEventListener("click", () => {
if (!isReady) {
console.log("Channel not ready yet. Click 'Start context' first.");
return;
}
console.log("Starting clip 0");
channel.startClip(0);
});
btnPlay2.addEventListener("click", () => {
if (!isReady) {
console.log("Channel not ready yet. Click 'Start context' first.");
return;
}
console.log("Starting clip 1");
channel.startClip(1);
});
btnPlay3.addEventListener("click", () => {
if (!isReady) {
console.log("Channel not ready yet. Click 'Start context' first.");
return;
}
console.log("Starting clip 2");
channel.startClip(2);
});
btnStop.addEventListener("click", () => {
if (channel) {
console.log(`Stopping clip ${channel.activeClipIdx}`);
channel.stopClip(channel.activeClipIdx);
}
});
Now create a file called index.html and enter the following in it
<!doctype html>
<html>
<head>
<title>Testing Scribbletune</title>
</head>
<body>
<div>
<p>The Audio context needs to be started by a user gesture.</p>
<button id="start">Start context</button>
</div>
<div>
<p>
Once audio context is started by a user gesture, you can use the
start/stop methods on clip objects. The clips will align per bar, so if
you start a clip in the middle of a bar, it will wait until the next bar
to start playing.
</p>
<button id="play1">Play Clip 1</button>
<button id="play2">Play Clip 2</button>
<button id="play3">Play Clip 3</button>
<hr />
<button id="stop">Stop</button>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.7.43/Tone.js"></script>
<script type="module" src="/script.js"></script>
</body>
</html>
Run the following command to start a dev server locally,
npx vite
Now load http://localhost:5173/ in your browser and click the start button to start the audio context. After that, click Play to hear the C4, E4, G4 notes played in a loop at an interval of a quarter note.