Skip to content

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

License

Notifications You must be signed in to change notification settings

grimmdude/MidiWriterJS

Repository files navigation

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)

VexFlow Integration

MidiWriterJS can export MIDI from VexFlow voices, though this feature is experimental.

// ...VexFlow code defining notes
const voice = create_4_4_voice().addTickables(notes);

const vexWriter = new MidiWriter.VexFlow();
const track = vexWriter.trackFromVoice(voice);
const writer = new MidiWriter.Writer([track]);
console.log(writer.dataUri());

Demos

License

MIT

About

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

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 21