{"id":26315709,"url":"https://github.com/grimmdude/midiwriterjs","last_synced_at":"2026-03-01T19:03:05.164Z","repository":{"id":5723265,"uuid":"53773105","full_name":"grimmdude/MidiWriterJS","owner":"grimmdude","description":"♬ A JavaScript library which provides an API for programmatically generating and creating expressive multi-track MIDI files and JSON.","archived":false,"fork":false,"pushed_at":"2023-10-17T16:28:12.000Z","size":2816,"stargazers_count":570,"open_issues_count":11,"forks_count":61,"subscribers_count":23,"default_branch":"master","last_synced_at":"2025-04-11T01:32:41.060Z","etag":null,"topics":["audio","es6","javascript-library","midi","music","node","vexflow"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/grimmdude.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null}},"created_at":"2016-03-13T07:35:57.000Z","updated_at":"2025-04-08T10:46:32.000Z","dependencies_parsed_at":"2024-04-19T19:54:08.269Z","dependency_job_id":"71b7c70d-26d5-483a-b987-272bfdc12cf1","html_url":"https://github.com/grimmdude/MidiWriterJS","commit_stats":{"total_commits":276,"total_committers":21,"mean_commits":"13.142857142857142","dds":0.5398550724637681,"last_synced_commit":"32cc2a2ba06ddff07b2d02abadf9f166f1c23546"},"previous_names":[],"tags_count":38,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmdude%2FMidiWriterJS","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmdude%2FMidiWriterJS/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmdude%2FMidiWriterJS/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/grimmdude%2FMidiWriterJS/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/grimmdude","download_url":"https://codeload.github.com/grimmdude/MidiWriterJS/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248596935,"owners_count":21130789,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","es6","javascript-library","midi","music","node","vexflow"],"created_at":"2025-03-15T12:19:51.938Z","updated_at":"2026-03-01T19:03:05.158Z","avatar_url":"https://github.com/grimmdude.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MidiWriterJS\n\n[![npm version](https://img.shields.io/npm/v/midi-writer-js.svg)](https://www.npmjs.com/package/midi-writer-js)\n![Tests](https://github.com/grimmdude/MidiWriterJS/actions/workflows/lint.js.yml/badge.svg)\n![Lint](https://github.com/grimmdude/MidiWriterJS/actions/workflows/node.js.yml/badge.svg)\n[![Try midi-writer-js on RunKit](https://badge.runkitcdn.com/midi-writer-js.svg)](https://npm.runkit.com/midi-writer-js)\n\nA JavaScript library for generating expressive multi-track MIDI files.\n\n- Multi-track MIDI file generation\n- Written in TypeScript with full type definitions\n- Works in Node.js (CJS \u0026 ESM) and the browser\n- Note names (`C#4`, `Eb5`) or raw MIDI numbers\n- Chords, arpeggios, grace notes, pitch bends, and more\n- Experimental VexFlow integration\n\n[Full API Documentation](https://grimmdude.com/MidiWriterJS/docs/)\n\n## Install\n\n```sh\nnpm install midi-writer-js\n```\n\n## Quick Start\n\n### ESM (recommended)\n\n```javascript\nimport MidiWriter from 'midi-writer-js';\n\nconst track = new MidiWriter.Track();\ntrack.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));\ntrack.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'D4', 'E4'], duration: '4', sequential: true}));\n\nconst writer = new MidiWriter.Writer(track);\nconsole.log(writer.dataUri());\n```\n\n### CommonJS\n\n```javascript\nconst MidiWriter = require('midi-writer-js');\n\nconst track = new MidiWriter.Track();\ntrack.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '2'}));\n\nconst writer = new MidiWriter.Writer(track);\nconsole.log(writer.dataUri());\n```\n\n### TypeScript\n\n```typescript\nimport MidiWriter from 'midi-writer-js';\n\nconst track = new MidiWriter.Track();\ntrack.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '2'}));\n\nconst writer = new MidiWriter.Writer(track);\nconst data: Uint8Array = writer.buildFile();\n```\n\n## Examples\n\n### Melody (Hot Cross Buns)\n\n```javascript\nimport MidiWriter from 'midi-writer-js';\n\nconst track = new MidiWriter.Track();\n\ntrack.addEvent([\n    new MidiWriter.NoteEvent({pitch: ['E4', 'D4'], duration: '4'}),\n    new MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),\n    new MidiWriter.NoteEvent({pitch: ['E4', 'D4'], duration: '4'}),\n    new MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),\n    new MidiWriter.NoteEvent({pitch: ['C4', 'C4', 'C4', 'C4', 'D4', 'D4', 'D4', 'D4'], duration: '8'}),\n    new MidiWriter.NoteEvent({pitch: ['E4', 'D4'], duration: '4'}),\n    new MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),\n  ], function(event, index) {\n    return {sequential: true};\n  }\n);\n\nconst writer = new MidiWriter.Writer(track);\nconsole.log(writer.dataUri());\n```\n\n### Chords vs. Sequential Notes\n\nWhen `pitch` is an array, the notes play as a chord by default. Set `sequential: true` to play them one after another instead.\n\n```javascript\n// Chord (notes play simultaneously)\ntrack.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '1'}));\n\n// Arpeggio (notes play sequentially)\ntrack.addEvent(new MidiWriter.NoteEvent({pitch: ['C4', 'E4', 'G4'], duration: '8', sequential: true}));\n```\n\n### Multi-Track\n\nPass an array of tracks to `Writer` to create a multi-track MIDI file.\n\n```javascript\nimport MidiWriter from 'midi-writer-js';\n\nconst melody = new MidiWriter.Track();\nmelody.addTrackName('Melody');\nmelody.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));\nmelody.addEvent(new MidiWriter.NoteEvent({pitch: ['E5', 'D5', 'C5'], duration: '4', sequential: true}));\n\nconst bass = new MidiWriter.Track();\nbass.addTrackName('Bass');\nbass.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 33}));\nbass.addEvent(new MidiWriter.NoteEvent({pitch: ['C2'], duration: '1'}));\n\nconst writer = new MidiWriter.Writer([melody, bass]);\nconsole.log(writer.dataUri());\n```\n\n### Controller Changes \u0026 Pitch Bend\n\n```javascript\nimport MidiWriter from 'midi-writer-js';\n\nconst track = new MidiWriter.Track();\n\n// Set volume via CC #7\ntrack.addEvent(new MidiWriter.ControllerChangeEvent({controllerNumber: 7, controllerValue: 100}));\n\n// Pitch bend ranging from -1.0 to 1.0 (0 = no bend)\ntrack.addEvent(new MidiWriter.PitchBendEvent({bend: 0.5}));\n\ntrack.addEvent(new MidiWriter.NoteEvent({pitch: ['E4'], duration: '2'}));\n\nconst writer = new MidiWriter.Writer(track);\nconsole.log(writer.dataUri());\n```\n\n## API Summary\n\n### `Track`\n\n| Method | Description |\n|---|---|\n| `addEvent(event, mapFunction?)` | Add one or more events. Supports method chaining. |\n| `setTempo(bpm, tick?)` | Set tempo in beats per minute. |\n| `setTimeSignature(numerator, denominator)` | Set time signature. |\n| `setKeySignature(sf, mi?)` | Set key signature (e.g., `'C'`, `'Dm'`, `'F#'`). |\n| `setPitchBend(bend)` | Set pitch bend (`-1.0` to `1.0`). |\n| `controllerChange(number, value, channel?, delta?)` | Add a controller change event. |\n| `addTrackName(text)` | Set the track name. |\n| `addText(text)` | Add a text event. |\n| `addCopyright(text)` | Add a copyright notice. |\n| `addInstrumentName(text)` | Set the instrument name. |\n| `addMarker(text)` | Add a marker event. |\n| `addCuePoint(text)` | Add a cue point event. |\n| `addLyric(text)` | Add a lyric event. |\n| `mergeTrack(track)` | Merge another track's events into this track. |\n| `removeEventsByName(name)` | Remove all events of a given type. |\n| `polyModeOn()` | Enable poly mode. |\n\n### `NoteEvent` Options\n\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003cth\u003eName\u003c/th\u003e\n\t\t\t\u003cth\u003eType\u003c/th\u003e\n\t\t\t\u003cth\u003eDefault\u003c/th\u003e\n\t\t\t\u003cth\u003eDescription\u003c/th\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/thead\u003e\n\t\u003ctbody\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003epitch\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003estring or array\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eEach pitch can be a string or valid MIDI note code.  Format for string is \u003ccode\u003eC#4\u003c/code\u003e.  You can use the output from \u003ca href=\"https://github.com/tonaljs/tonal\" target=\"_blank\"\u003etonal\u003c/a\u003e to build scales, chords, etc.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003eduration\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003estring or array\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003ccode\u003e'4'\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eHow long the note should sound (see \u003ca href=\"#duration-values\"\u003eDuration Values\u003c/a\u003e). If an array of durations is passed then the sum will be used.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003ewait\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003estring or array\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003ccode\u003e0\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eRest before sounding note. Takes same values as \u003cb\u003eduration\u003c/b\u003e.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003esequential\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eboolean\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003ccode\u003efalse\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eIf \u003ccode\u003etrue\u003c/code\u003e, array of pitches plays sequentially instead of as a chord.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003evelocity\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003enumber\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003ccode\u003e50\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eHow loud the note should sound, values 1-100.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003erepeat\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003enumber\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003ccode\u003e1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eHow many times this event should repeat.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003echannel\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003enumber\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003ccode\u003e1\u003c/code\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eMIDI channel to use (1-16).\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003egrace\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003estring or array\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eGrace note(s) applied before the main note. Takes same format as \u003ccode\u003epitch\u003c/code\u003e.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003estartTick\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003enumber\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eExplicit tick position for this event. If supplied, \u003ccode\u003ewait\u003c/code\u003e is ignored.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\t\u003ctr\u003e\n\t\t\t\u003ctd\u003e\u003cb\u003etick\u003c/b\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003enumber\u003c/td\u003e\n\t\t\t\u003ctd\u003e\u003c/td\u003e\n\t\t\t\u003ctd\u003eAlias for \u003ccode\u003estartTick\u003c/code\u003e.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n### `Writer`\n\n| Method | Returns | Description |\n|---|---|---|\n| `buildFile()` | `Uint8Array` | Build the MIDI file as a byte array. |\n| `base64()` | `string` | Base64-encoded string of the MIDI file. |\n| `dataUri()` | `string` | Data URI string (useful for playback or download links). |\n| `stdout()` | — | Write MIDI file to stdout (Node.js CLI usage). |\n| `setOption(key, value)` | `Writer` | Set an option on the writer instance. |\n\n### Event Classes\n\n| Class | Description |\n|---|---|\n| `NoteEvent` | High-level note event that generates NoteOn/NoteOff pairs. |\n| `NoteOnEvent` | Raw MIDI note-on event. |\n| `NoteOffEvent` | Raw MIDI note-off event. |\n| `ProgramChangeEvent` | Change the instrument (patch) on a channel. |\n| `PitchBendEvent` | Pitch bend event (`-1.0` to `1.0`). |\n| `ControllerChangeEvent` | Controller change (CC) event. |\n| `TempoEvent` | Set tempo (BPM). |\n| `TimeSignatureEvent` | Set time signature. |\n| `KeySignatureEvent` | Set key signature. |\n| `TextEvent` | General text meta event. |\n| `CopyrightEvent` | Copyright meta event. |\n| `TrackNameEvent` | Track/sequence name meta event. |\n| `InstrumentNameEvent` | Instrument name meta event. |\n| `MarkerEvent` | Marker meta event. |\n| `CuePointEvent` | Cue point meta event. |\n| `LyricEvent` | Lyric meta event. |\n| `EndTrackEvent` | End of track meta event (added automatically). |\n\nSee the [full API documentation](https://grimmdude.com/MidiWriterJS/docs/) for details on each class.\n\n### Duration Values\n\n| Value | Duration |\n|---|---|\n| `1` | Whole |\n| `2` | Half |\n| `d2` | Dotted half |\n| `dd2` | Double dotted half |\n| `4` | Quarter |\n| `4t` | Quarter triplet |\n| `d4` | Dotted quarter |\n| `dd4` | Double dotted quarter |\n| `8` | Eighth |\n| `8t` | Eighth triplet |\n| `d8` | Dotted eighth |\n| `dd8` | Double dotted eighth |\n| `16` | Sixteenth |\n| `16t` | Sixteenth triplet |\n| `32` | Thirty-second |\n| `64` | Sixty-fourth |\n| `Tn` | Explicit number of ticks (e.g., `T128` = 1 beat) |\n\n## VexFlow Integration\n\nMidiWriterJS can export MIDI from VexFlow voices, though this feature is **experimental**.\n\n```javascript\n// ...VexFlow code defining notes\nconst voice = create_4_4_voice().addTickables(notes);\n\nconst vexWriter = new MidiWriter.VexFlow();\nconst track = vexWriter.trackFromVoice(voice);\nconst writer = new MidiWriter.Writer([track]);\nconsole.log(writer.dataUri());\n```\n\n## Demos\n\n- [Example with Magenta player](https://codepen.io/dirkk0/pen/rNZLXjZ) by Dirk Krause [@dirkk0](https://github.com/dirkk0)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrimmdude%2Fmidiwriterjs","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgrimmdude%2Fmidiwriterjs","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgrimmdude%2Fmidiwriterjs/lists"}