An open API service indexing awesome lists of open source software.

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

Awesome Lists containing this project

README

          


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

```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)