{"id":13433659,"url":"https://github.com/grimmdude/MidiWriterJS","last_synced_at":"2025-03-17T13:30:38.961Z","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":541,"open_issues_count":7,"forks_count":58,"subscribers_count":22,"default_branch":"master","last_synced_at":"2024-04-14T11:56:11.758Z","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":"2024-04-19T19:54:18.137Z","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":243558478,"owners_count":20310573,"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":"2024-07-31T02:01:32.226Z","updated_at":"2025-03-17T13:30:38.925Z","avatar_url":"https://github.com/grimmdude.png","language":"JavaScript","readme":"\u0026#9836; 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\nMidiWriterJS is a JavaScript library providing an API for generating expressive multi-track MIDI files.  \n\nNote that the `master` branch is in active development so if you're looking for a tried and true stable version please use the latest release.\n\n[Source Documentation](https://grimmdude.com/MidiWriterJS/docs/)\n\nInstall\n------------\n```sh\nnpm install midi-writer-js\n```\nGetting Started\n------------\n\n```javascript\nimport MidiWriter from 'midi-writer-js';\n\n// Start with a new track\nconst track = new MidiWriter.Track();\n\n// Define an instrument (optional):\ntrack.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));\n\n// Add some notes:\nconst note = new MidiWriter.NoteEvent({pitch: ['C4', 'D4', 'E4'], duration: '4'});\ntrack.addEvent(note);\n\n// Generate a data URI\nconst write = new MidiWriter.Writer(track);\nconsole.log(write.dataUri());\n```\nDocumentation\n------------\n\n### `MidiWriter.Track()`\n\n- `addEvent({event}, mapFunction)`\n- `setTempo(tempo)`\n- `addText(text)`\n- `addCopyright(text)`\n- `addTrackName(text)`\n- `addInstrumentName(text)`\n- `addMarker(text)`\n- `addCuePoint(text)`\n- `addLyric(text)`\n- `setTimeSignature(numerator, denominator)`\n\n### `MidiWriter.NoteEvent({options})`\n\nThe MIDI spec defines that each note must have a `NoteOnEvent` and `NoteOffEvent` (or `NoteOnEvent` with zero velocity) event, marking the beginning and end of the sounding note.  While it's possible to manually add these events to a track with `Track.addEvent()`, the `NoteEvent` provides a more intuitive interface for doing this with a single, \"pseudo\" event.  Under the hood, the `NoteEvent` event generates the relevant `NoteOnEvent` and `NoteOffEvent` events.\n\nEach MIDI event has a `delta` property, which is used to define the number of ticks to wait after the previous event.  This can be challenging to calculate if you're not necessarily adding events in a serial fashion.  Because of this, you can alternatively use the `tick` property to define the exact tick where the event should fall.\n\nThe `NoteEvent` supports these 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.  Pro tip: You can use the output from \u003ca href=\"https://github.com/danigb/tonal\" target=\"_blank\"\u003etonal\u003c/a\u003e functions to build scales, chords, intervals, etc. in this parameter.\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\u003c/td\u003e\n\t\t\t\u003ctd\u003e\n\t\t\t\tHow long the note should sound.\n\t\t\t\t\u003cul\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e1\u003c/code\u003e  : whole\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e2\u003c/code\u003e  : half\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003ed2\u003c/code\u003e : dotted half\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003edd2\u003c/code\u003e : double dotted half\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e4\u003c/code\u003e  : quarter\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e4t\u003c/code\u003e  : quarter triplet\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003ed4\u003c/code\u003e : dotted quarter\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003edd4\u003c/code\u003e : double dotted quarter\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e8\u003c/code\u003e  : eighth\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e8t\u003c/code\u003e : eighth triplet\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003ed8\u003c/code\u003e : dotted eighth\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003edd8\u003c/code\u003e : double dotted eighth\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e16\u003c/code\u003e : sixteenth\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e16t\u003c/code\u003e : sixteenth triplet\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e32\u003c/code\u003e : thirty-second\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003e64\u003c/code\u003e : sixty-fourth\u003c/li\u003e\n\t\t\t\t\t\u003cli\u003e\u003ccode\u003eTn\u003c/code\u003e : where n is an explicit number of ticks (T128 = 1 beat)\u003c/li\u003e\n\t\t\t\t\u003c/ul\u003e\n\t\t\t\tIf an array of durations is passed then the sum of the durations will be used.\n\t\t\t\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\u003eHow long to wait before sounding note (rest).  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 true then array of pitches will be played sequentially as opposed to simulatanously.\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 be repeated.\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.\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 to be applied to note event.  Takes same value 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\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\u003eSpecific tick where this event should be played.  If this parameter is supplied then \u003ccode\u003ewait\u003c/code\u003e is disregarded if also supplied.\u003c/td\u003e\n\t\t\u003c/tr\u003e\n\t\u003c/tbody\u003e\n\u003c/table\u003e\n\n\n### `MidiWriter.Writer(tracks)`\nThe `Writer` class provides a few ways to output the file:\n- `buildFile()` *Uint8Array*\n- `base64()` *string*\n- `dataUri()` *string*\n- `stdout()` *file stream (cli)*\n\n### Hot Cross Buns\nHere's an example of how everyone's favorite song \"Hot Cross Buns\" could be written.  Note use of the mapping function passed as the second argument of `addEvent()`.  This can be used to apply specific properties to all events.  With some \nstreet smarts you could also use it for programmatic crescendos and other property 'animation'.\n```javascript\nimport MidiWriter from 'midi-writer-js';\n\nconst track = new MidiWriter.Track();\n\ntrack.addEvent([\n\t\tnew MidiWriter.NoteEvent({pitch: ['E4','D4'], duration: '4'}),\n\t\tnew MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),\n\t\tnew MidiWriter.NoteEvent({pitch: ['E4','D4'], duration: '4'}),\n\t\tnew MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'}),\n\t\tnew MidiWriter.NoteEvent({pitch: ['C4', 'C4', 'C4', 'C4', 'D4', 'D4', 'D4', 'D4'], duration: '8'}),\n\t\tnew MidiWriter.NoteEvent({pitch: ['E4','D4'], duration: '4'}),\n\t\tnew MidiWriter.NoteEvent({pitch: ['C4'], duration: '2'})\n\t], function(event, index) {\n    return {sequential: true};\n  }\n);\n\nconst write = new MidiWriter.Writer(track);\nconsole.log(write.dataUri());\n```\n\n### VexFlow Integration\nMidiWriterJS can export MIDI from VexFlow voices, though this feature is still experimental.  Current usage is to use `MidiWriter.VexFlow.trackFromVoice(voice)` to create a MidiWriterJS `Track` object:\n```javascript\n\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\n## Demos\n* [Example with Magenta player](https://codepen.io/dirkk0/pen/rNZLXjZ) by Dirk Krause [@dirkk0](https://github.com/dirkk0)\n","funding_links":[],"categories":["JavaScript","Libraries: Web MIDI API"],"sub_categories":["Web MIDI API"],"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"}