Skip to content

scribbletune/scribbletune

Repository files navigation

Scribbletune

Scribbletune

Create music with JavaScript. Use simple strings and arrays to craft rhythms, melodies, and chord progressions — then export MIDI files or play them live in the browser with Tone.js or use the CLI to directly emit MIDI file from your terminal.

npm version license


Install

npm install scribbletune

Quick start

Option 1: CLI

If you installed Scribbletune globally via npm i -g scribbletune then you can directly use scribbletune as the command. If you installed it locally via npm i scribbletune then please use npx scribbletune as the command.

Run modes:

# Global install
npm install -g scribbletune
scribbletune --help

# Local/project install
npm install scribbletune
npx scribbletune --help

Quick command examples:

Command format

scribbletune --riff <root> <mode> <pattern> <subdiv> [options]
scribbletune --chord <root> <mode> <pattern> <subdiv> <progression|random> [options]
scribbletune --arp <root> <mode> <pattern> <subdiv> <progression|random> [options]

Progression input rules for --chord and --arp:

1645            # degree digits
"I IV vi V"     # roman numerals (space separated)
I,IV,vi,V       # roman numerals (comma separated)
random          # generated progression
CM-FM-Am-GM     # explicit chord names (`root` and `mode` are ignored)

Common options:

--outfile <file.mid>  # default: music.mid
--subdiv <4n|8n|1m...>
--sizzle [sin|cos|rampUp|rampDown] [reps]
--sizzle-reps <number>
--amp <0-127>
--accent <x--x...>
--accent-low <0-127>
--style <letters>     # riff motif/style, e.g. AABC
--fit-pattern         # explicit enable (already enabled by default)
--no-fit-pattern      # disable automatic pattern fitting
--bpm <number>        # your DAW may or may not support it

Note: if your pattern uses [ and ] (for subdivisions), quote it in shell:

scribbletune --arp C3 major 1 'x-x[xx]-x-[xx]' 16n

Pattern helpers:

x.repeat(4)       # -> xxxx
'x-x[xx]'.repeat(2)
2(x-x[xx])        # prefix repeat shorthand
(x-x[xx])2        # suffix repeat shorthand

--riff examples

# Basic riff from scale
scribbletune --riff C3 phrygian x-xRx_RR --outfile riff.mid

# With motif/style and positional subdiv
scribbletune --riff C3 phrygian x-xRx_RR 8n --style AABC --sizzle sin 2 --outfile riff-aabc.mid

# Set riff subdivision via positional arg
scribbletune --riff C3 phrygian x-xRx_RR 8n --style AABC --outfile riff-8n.mid

# Pattern with subdivisions (quote [] in shell)
scribbletune --riff C3 phrygian 'x-x[xx]-x-[xx]' 8n --style AABC --outfile riff-subdiv.mid

Riff + motif note:

  • --style creates riff sections by repeating the full pattern per letter.
  • Example: --style AABC with pattern x-x[xx] creates 4 sections: A, A, B, C.
  • Repeated letters reuse the exact same generated section (same rhythm and same notes, including random R choices).

--chord examples

# Degree digits (resolved against root/mode)
scribbletune --chord C3 major xxxx 1m 1645 --sizzle cos 1 --outfile chords-1645.mid

# Roman numerals (space/comma separated)
scribbletune --chord C3 major xxxx 1m "I IV vi V" --outfile chords-roman.mid

# Random progression
scribbletune --chord C3 major xxxx 1m random --outfile chords-random.mid

# Explicit chord names (root/mode currently ignored for this style)
scribbletune --chord C3 major xxxx 1m CM-FM-Am-GM --outfile chords-explicit.mid

# Subdivisions in pattern
scribbletune --chord C3 major 'x-x[xx]-x-[xx]' 8n I,IV,vi,V --outfile chords-subdiv.mid

--arp examples

# Arp from degree progression
scribbletune --arp C3 major xxxx 1m 1736 --sizzle cos 4 --outfile arp-1736.mid

# Single degree "1" means tonic chord in the chosen key/mode
scribbletune --arp C3 major xxxx 4n 1 --outfile arp-degree-1.mid

# Arp from explicit chords
scribbletune --arp C3 major xxxx 1m CM-FM-Am-GM --count 4 --order 1234 --outfile arp-explicit.mid

# Custom note order inside each arpeggiated chord (one-based)
scribbletune --arp C3 major xxxx 4n 1 --order 2143 --outfile arp-order-2143.mid

# Same custom order using local dist build
node dist/cli.cjs --arp C3 major xxxx 4n 1 --order 2143 --outfile arp-order-local.mid

# Auto-fit is default (single x expands to full generated arp length)
scribbletune --arp C3 major x 4n 1736 --outfile arp-fit-default.mid

# Disable auto-fit if you want a short clip
scribbletune --arp C3 major x 4n 1736 --no-fit-pattern --outfile arp-no-fit.mid

--order behavior:

  • One-based order is supported (1234, 2143) and is recommended.
  • Zero-based order is also accepted for backward compatibility (0123, 1032).

Run scribbletune --help to see the latest CLI usage text.

Option 2: Node.js

import { scale, clip, midi } from "scribbletune";

const notes = scale("C4 major");
const c = clip({ notes, pattern: "x".repeat(8) });

midi(c, "c-major.mid");

Run it with node and open the .mid file in Ableton Live, GarageBand, Logic, or any DAW.

Option 3: Browser (with Tone.js)

Scribbletune's browser entry point adds Session, Channel, and live clip() support on top of Tone.js.

import { Session } from "scribbletune/browser";

const session = new Session();
const channel = session.createChannel({
  instrument: "PolySynth",
  clips: [
    { pattern: "x-x-", notes: "C4 E4 G4" },
    { pattern: "[-xx]", notes: "C4 D#4" },
  ],
});

await Tone.start();
Tone.Transport.start();
channel.startClip(0);

Standalone sample clip (no Session/Channel needed)

import { clip } from "scribbletune/browser";

const kickClip = clip({
  sample: "https://scribbletune.com/sounds/kick.wav",
  pattern: "x-x-",
});

const btn = document.querySelector("#btn");

btn.addEventListener("click", async () => {
  await Tone.start();
  Tone.Transport.start();
  kickClip.start(0);
});

Core concepts

Pattern language

Scribbletune uses a simple string notation to describe rhythms:

Char Meaning
x Note on
- Note off (rest)
_ Sustain previous note
R Random note (from randomNotes pool)
[] Subdivide (e.g. [xx] = two notes in one beat)
"x---x---x-x-x---"; // basic kick pattern
"[xx][xx]x-x-"; // hihat with subdivisions
"x___"; // one long sustained note

Scales and chords

Powered by harmonics:

import { scale, chord, scales, chords } from "scribbletune";

scale("C4 major"); // ['C4', 'D4', 'E4', 'F4', 'G4', 'A4', 'B4']
chord("CM"); // ['C4', 'E4', 'G4']
scales(); // list all available scale names
chords(); // list all available chord names

Arpeggios

import { arp } from "scribbletune";

arp({ chords: "CM FM", count: 4, order: "0123" });
// ['C4', 'E4', 'G4', 'C5', 'F4', 'A4', 'C5', 'F5']

Chord progressions

import { progression, getChordsByProgression } from "scribbletune";

progression("M", 4); // e.g. ['I', 'ii', 'V', 'IV']

getChordsByProgression("C4 major", "I IV V IV");
// 'CM_4 FM_4 GM_4 FM_4'

Browser API

The browser entry point (scribbletune/browser) provides everything above plus:

Session and Channel

import { Session } from "scribbletune/browser";

const session = new Session();
const drums = session.createChannel({
  sample: "https://scribbletune.com/sounds/kick.wav",
  clips: [{ pattern: "x---x---" }, { pattern: "x-x-x-x-" }],
});

const synth = session.createChannel({
  instrument: "PolySynth",
  clips: [{ pattern: "x-x-", notes: "C4 E4 G4" }],
});

await Tone.start();
Tone.Transport.start();

// Start clips independently
drums.startClip(0);
synth.startClip(0);

// Switch patterns on the fly
drums.startClip(1);

// Or start a row across all channels
session.startRow(0);

Channel options

Channels accept various sound sources:

// Built-in Tone.js synth (by name)
{ instrument: 'PolySynth' }

// Pre-built Tone.js instrument
{ instrument: new Tone.FMSynth() }

// Audio sample URL
{ sample: 'https://example.com/kick.wav' }

// Multi-sample instrument
{ samples: { C3: 'piano-c3.wav', D3: 'piano-d3.wav' } }

// With effects
{ instrument: 'PolySynth', effects: ['Chorus', 'Reverb'] }

API reference

Export Description
clip(params) Create a clip — returns note objects (Node.js) or a Tone.Sequence (browser)
midi(clip, filename?) Export a clip to a MIDI file
scale(name) Get notes of a scale, e.g. 'C4 minor'
chord(name) Get notes of a chord, e.g. 'CM'
scales() List all available scale names
chords() List all available chord names
arp(params) Generate arpeggiated note sequences
progression(type, count) Generate a chord progression ('M' or 'm')
getChordsByProgression(scale, degrees) Convert Roman numeral degrees to chord names
getChordDegrees(mode) Get Roman numeral degrees for a mode
Session (browser only) Manage multiple channels and coordinate playback

Development

npm install       # install dependencies
npm test          # run tests
npm run build     # build with tsup
npm run lint      # check with biome
npm run dev       # build in watch mode

If developing new features for the CLI, use the following command after running npm run build to test before publishing,

node dist/cli.cjs --help

License

MIT


scribbletune.com | Soundcloud