https://github.com/scribbletune/scribbletune
Create music with JavaScript
https://github.com/scribbletune/scribbletune
ableton ableton-live chords javascript live midi music nodejs scale webaudio webaudioapi webmidi
Last synced: 11 days ago
JSON representation
Create music with JavaScript
- Host: GitHub
- URL: https://github.com/scribbletune/scribbletune
- Owner: scribbletune
- License: mit
- Created: 2013-11-25T21:44:43.000Z (over 12 years ago)
- Default Branch: master
- Last Pushed: 2026-02-18T06:31:26.000Z (22 days ago)
- Last Synced: 2026-02-18T06:41:04.120Z (22 days ago)
- Topics: ableton, ableton-live, chords, javascript, live, midi, music, nodejs, scale, webaudio, webaudioapi, webmidi
- Language: TypeScript
- Homepage: https://scribbletune.com
- Size: 2.14 MB
- Stars: 3,762
- Watchers: 88
- Forks: 237
- Open Issues: 20
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE.txt
Awesome Lists containing this project
- awesome-rainmana - scribbletune/scribbletune - Create music with JavaScript (TypeScript)
README
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.
---
## Install
```bash
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:
```bash
# Global install
npm install -g scribbletune
scribbletune --help
# Local/project install
npm install scribbletune
npx scribbletune --help
```
Quick command examples:
#### Command format
```bash
scribbletune --riff [options]
scribbletune --chord [options]
scribbletune --arp [options]
```
Progression input rules for `--chord` and `--arp`:
```bash
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:
```bash
--outfile # default: music.mid
--subdiv <4n|8n|1m...>
--sizzle [sin|cos|rampUp|rampDown] [reps]
--sizzle-reps
--amp <0-127>
--accent
--accent-low <0-127>
--style # riff motif/style, e.g. AABC
--fit-pattern # explicit enable (already enabled by default)
--no-fit-pattern # disable automatic pattern fitting
--bpm # your DAW may or may not support it
```
Note: if your pattern uses `[` and `]` (for subdivisions), quote it in shell:
```bash
scribbletune --arp C3 major 1 'x-x[xx]-x-[xx]' 16n
```
Pattern helpers:
```bash
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
```bash
# 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
```bash
# 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
```bash
# 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
```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](https://tonejs.github.io/).
```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)
```js
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) |
```js
"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](https://github.com/scribbletune/harmonics):
```js
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
```js
import { arp } from "scribbletune";
arp({ chords: "CM FM", count: 4, order: "0123" });
// ['C4', 'E4', 'G4', 'C5', 'F4', 'A4', 'C5', 'F5']
```
### Chord progressions
```js
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
```js
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:
```js
// 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
```bash
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,
```bash
node dist/cli.cjs --help
```
## License
MIT
---
[scribbletune.com](https://scribbletune.com) | [Soundcloud](https://soundcloud.com/scribbletune)