Ecosyste.ms: Awesome

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

Awesome Lists | Featured Topics | Projects

https://github.com/grimmdude/MidiWriterJS

♬ A JavaScript library which provides an API for programmatically generating and creating expressive multi-track MIDI files and JSON.
https://github.com/grimmdude/MidiWriterJS

audio es6 javascript-library midi music node vexflow

Last synced: about 2 months ago
JSON representation

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

Awesome Lists containing this project

README

        

♬ MidiWriterJS
===============
[![npm version](https://img.shields.io/npm/v/midi-writer-js.svg)](https://www.npmjs.com/package/midi-writer-js)
![Tests](https://github.com/grimmdude/MidiWriterJS/actions/workflows/lint.js.yml/badge.svg)
![Lint](https://github.com/grimmdude/MidiWriterJS/actions/workflows/node.js.yml/badge.svg)
[![Try midi-writer-js on RunKit](https://badge.runkitcdn.com/midi-writer-js.svg)](https://npm.runkit.com/midi-writer-js)

MidiWriterJS is a JavaScript library providing an API for generating expressive multi-track MIDI files.

Note 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.

[Source Documentation](https://grimmdude.com/MidiWriterJS/docs/)

Install
------------
```sh
npm install midi-writer-js
```
Getting Started
------------

```javascript
import MidiWriter from 'midi-writer-js';

// Start with a new track
const track = new MidiWriter.Track();

// Define an instrument (optional):
track.addEvent(new MidiWriter.ProgramChangeEvent({instrument: 1}));

// Add some notes:
const note = new MidiWriter.NoteEvent({pitch: ['C4', 'D4', 'E4'], duration: '4'});
track.addEvent(note);

// Generate a data URI
const write = new MidiWriter.Writer(track);
console.log(write.dataUri());
```
Documentation
------------

### `MidiWriter.Track()`

- `addEvent({event}, mapFunction)`
- `setTempo(tempo)`
- `addText(text)`
- `addCopyright(text)`
- `addTrackName(text)`
- `addInstrumentName(text)`
- `addMarker(text)`
- `addCuePoint(text)`
- `addLyric(text)`
- `setTimeSignature(numerator, denominator)`

### `MidiWriter.NoteEvent({options})`

The 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.

Each 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.

The `NoteEvent` supports these 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. Pro tip: You can use the output from tonal functions to build scales, chords, intervals, etc. in this parameter.


duration
string or array


How long the note should sound.



  • 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 : where n is an explicit number of ticks (T128 = 1 beat)


If an array of durations is passed then the sum of the durations will be used.



wait
string or array
0
How long to wait before sounding note (rest). Takes same values as duration.


sequential
boolean
false
If true then array of pitches will be played sequentially as opposed to simulatanously.


velocity
number
50
How loud the note should sound, values 1-100.


repeat
number
1
How many times this event should be repeated.


channel
number
1
MIDI channel to use.


grace
string or array

Grace note to be applied to note event. Takes same value format as pitch


tick
number

Specific tick where this event should be played. If this parameter is supplied then wait is disregarded if also supplied.

### `MidiWriter.Writer(tracks)`
The `Writer` class provides a few ways to output the file:
- `buildFile()` *Uint8Array*
- `base64()` *string*
- `dataUri()` *string*
- `stdout()` *file stream (cli)*

### Hot Cross Buns
Here'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
street smarts you could also use it for programmatic crescendos and other property 'animation'.
```javascript
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 write = new MidiWriter.Writer(track);
console.log(write.dataUri());
```

### VexFlow Integration
MidiWriterJS 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:
```javascript

// ...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
* [Example with Magenta player](https://codepen.io/dirkk0/pen/rNZLXjZ) by Dirk Krause [@dirkk0](https://github.com/dirkk0)