SkillAgentSearch skills...

MidiWriterJS

♬ A JavaScript library which provides an API for programmatically generating and creating expressive multi-track MIDI files and JSON.

Install / Use

/learn @grimmdude/MidiWriterJS
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

MidiWriterJS

npm version Tests Lint Try midi-writer-js on RunKit

A JavaScript library for generating expressive multi-track MIDI files.

  • Multi-track MIDI file generation
  • Written in TypeScript with full type definitions
  • Works in Node.js (CJS & ESM) and the browser
  • Note names (C#4, Eb5) or raw MIDI numbers
  • Chords, arpeggios, grace notes, pitch bends, and more
  • Experimental VexFlow integration

Full API Documentation

Install

npm install midi-writer-js

Quick Start

ESM (recommended)

import MidiWriter from 'midi-writer-js';

const track = new MidiWriter.Track();
track.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));
track.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'D4', 'E4'], duration: '4', sequential: true}));

const writer = new MidiWriter.Writer(track);
console.log(writer.dataUri());

CommonJS

const MidiWriter = require('midi-writer-js');

const track = new MidiWriter.Track();
track.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '2'}));

const writer = new MidiWriter.Writer(track);
console.log(writer.dataUri());

TypeScript

import MidiWriter from 'midi-writer-js';

const track = new MidiWriter.Track();
track.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '2'}));

const writer = new MidiWriter.Writer(track);
const data: Uint8Array = writer.buildFile();

Examples

Melody (Hot Cross Buns)

import MidiWriter from 'midi-writer-js';

const track = new MidiWriter.Track();

track.addEvent([
    new MidiWriter.NoteEvent({pitch: ['E4', 'D4'], duration: '4'}),
    new MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),
    new MidiWriter.NoteEvent({pitch: ['E4', 'D4'], duration: '4'}),
    new MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),
    new MidiWriter.NoteEvent({pitch: ['C4', 'C4', 'C4', 'C4', 'D4', 'D4', 'D4', 'D4'], duration: '8'}),
    new MidiWriter.NoteEvent({pitch: ['E4', 'D4'], duration: '4'}),
    new MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),
  ], function(event, index) {
    return {sequential: true};
  }
);

const writer = new MidiWriter.Writer(track);
console.log(writer.dataUri());

Chords vs. Sequential Notes

When pitch is an array, the notes play as a chord by default. Set sequential: true to play them one after another instead.

// Chord (notes play simultaneously)
track.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '1'}));

// Arpeggio (notes play sequentially)
track.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '8', sequential: true}));

Multi-Track

Pass an array of tracks to Writer to create a multi-track MIDI file.

import MidiWriter from 'midi-writer-js';

const melody = new MidiWriter.Track();
melody.addTrackName('Melody');
melody.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));
melody.addEvent(new MidiWriter.NoteEvent({pitch: ['E5', 'D5', 'C5'], duration: '4', sequential: true}));

const bass = new MidiWriter.Track();
bass.addTrackName('Bass');
bass.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 33}));
bass.addEvent(new MidiWriter.NoteEvent({pitch: ['C2'], duration: '1'}));

const writer = new MidiWriter.Writer([melody, bass]);
console.log(writer.dataUri());

Controller Changes & Pitch Bend

import MidiWriter from 'midi-writer-js';

const track = new MidiWriter.Track();

// Set volume via CC #7
track.addEvent(new MidiWriter.ControllerChangeEvent({controllerNumber: 7, controllerValue: 100}));

// Pitch bend ranging from -1.0 to 1.0 (0 = no bend)
track.addEvent(new MidiWriter.PitchBendEvent({bend: 0.5}));

track.addEvent(new MidiWriter.NoteEvent({pitch: ['E4'], duration: '2'}));

const writer = new MidiWriter.Writer(track);
console.log(writer.dataUri());

API Summary

Track

| Method | Description | |---|---| | addEvent(event, mapFunction?) | Add one or more events. Supports method chaining. | | setTempo(bpm, tick?) | Set tempo in beats per minute. | | setTimeSignature(numerator, denominator) | Set time signature. | | setKeySignature(sf, mi?) | Set key signature (e.g., 'C', 'Dm', 'F#'). | | setPitchBend(bend) | Set pitch bend (-1.0 to 1.0). | | controllerChange(number, value, channel?, delta?) | Add a controller change event. | | addTrackName(text) | Set the track name. | | addText(text) | Add a text event. | | addCopyright(text) | Add a copyright notice. | | addInstrumentName(text) | Set the instrument name. | | addMarker(text) | Add a marker event. | | addCuePoint(text) | Add a cue point event. | | addLyric(text) | Add a lyric event. | | mergeTrack(track) | Merge another track's events into this track. | | removeEventsByName(name) | Remove all events of a given type. | | polyModeOn() | Enable poly mode. |

NoteEvent Options

| Name | Type | Default | Description | |---|---|---|---| | pitch | string or array | | Each pitch can be a string or valid MIDI note code. Format for string is C#4. You can use the output from tonal to build scales, chords, etc. | | duration | string or array | '4' | How long the note should sound (see Duration Values). If an array of durations is passed then the sum will be used. | | wait | string or array | 0 | Rest before sounding note. Takes same values as duration. | | sequential | boolean | false | If true, array of pitches plays sequentially instead of as a chord. | | velocity | number | 50 | How loud the note should sound, values 1-100. | | repeat | number | 1 | How many times this event should repeat. | | channel | number | 1 | MIDI channel to use (1-16). | | grace | string or array | | Grace note(s) applied before the main note. Takes same format as pitch. | | startTick | number | | Explicit tick position for this event. If supplied, wait is ignored. | | tick | number | | Alias for startTick. |

Writer

| Method | Returns | Description | |---|---|---| | buildFile() | Uint8Array | Build the MIDI file as a byte array. | | base64() | string | Base64-encoded string of the MIDI file. | | dataUri() | string | Data URI string (useful for playback or download links). | | stdout() | — | Write MIDI file to stdout (Node.js CLI usage). | | setOption(key, value) | Writer | Set an option on the writer instance. |

Event Classes

| Class | Description | |---|---| | NoteEvent | High-level note event that generates NoteOn/NoteOff pairs. | | NoteOnEvent | Raw MIDI note-on event. | | NoteOffEvent | Raw MIDI note-off event. | | ProgramChangeEvent | Change the instrument (patch) on a channel. | | PitchBendEvent | Pitch bend event (-1.0 to 1.0). | | ControllerChangeEvent | Controller change (CC) event. | | TempoEvent | Set tempo (BPM). | | TimeSignatureEvent | Set time signature. | | KeySignatureEvent | Set key signature. | | TextEvent | General text meta event. | | CopyrightEvent | Copyright meta event. | | TrackNameEvent | Track/sequence name meta event. | | InstrumentNameEvent | Instrument name meta event. | | MarkerEvent | Marker meta event. | | CuePointEvent | Cue point meta event. | | LyricEvent | Lyric meta event. | | EndTrackEvent | End of track meta event (added automatically). |

See the full API documentation for details on each class.

Duration Values

| Value | Duration | |---|---| | 1 | Whole | | 2 | Half | | d2 | Dotted half | | dd2 | Double dotted half | | 4 | Quarter | | 4t | Quarter triplet | | d4 | Dotted quarter | | dd4 | Double dotted quarter | | 8 | Eighth | | 8t | Eighth triplet | | d8 | Dotted eighth | | dd8 | Double dotted eighth | | 16 | Sixteenth | | 16t | Sixteenth triplet | | 32 | Thirty-second | | 64 | Sixty-fourth | | Tn | Explicit number of ticks (e.g., T128 = 1 beat) |

Recipes

Rests

Use the wait property to add silence before a note. There is no dedicated rest event — wait accepts the same duration values as duration.

// Quarter rest followed by a quarter note
track.addEvent(new MidiWriter.NoteEvent({pitch: 'C4', duration: '4', wait: '4'}));

// Half rest followed by a whole note
track.addEvent(new MidiWriter.NoteEvent({pitch: 'E4', duration: '1', wait: '2'}));

Drums (Channel 10)

MIDI channel 10 is reserved for percussion. Pitch values map to drum sounds (e.g., C2 = kick, D2 = snare, F#2 = hi-hat).

const drums = new MidiWriter.Track();
drums.addTrackName('Drums');
drums.addEvent(new MidiWriter.NoteEvent({pitch: ['C2'], duration: '4', channel: 10, velocity: 80}));
drums.addEvent(new MidiWriter.NoteEvent({pitch: ['D2'], duration: '4', channel: 10, velocity: 80}));
drums.addEvent(new MidiWriter.NoteEvent({pitch: ['F#2'], duration: '8', channel: 10, repeat: 4}));

Dynamics (Velocity)

Control note loudness with velocity (1-100). Simulate a crescendo by gradually increasing velocity.

track.addEvent(new MidiWriter.NoteEvent({pitch: 'C4', duration: '4', velocity: 30}));  // piano
track.addEvent(new MidiWriter.NoteEvent({pitch: 'E4', duration: '4', velocity: 60}));  // mezzo-forte
track.addEvent(new MidiWriter.NoteEvent({pitch: 'G4', duration: '4', velocity: 100})); // fortissimo

Tempo Changes

Set tempo at the start of a track, or change it mid-track by speci

Related Skills

View on GitHub
GitHub Stars594
CategoryContent
Updated4h ago
Forks64

Languages

JavaScript

Security Score

100/100

Audited on Mar 28, 2026

No findings