npm package: @huffduff/midi-writer-ts
Description: A fork of midi-writer-js, a library providing an API for generating MIDI files.
Author: Garrett Grimm
Latest version: 3.2.3

&#9836; MidiWriterJS
===============
![NPM Version](https://img.shields.io/npm/v/%40huffduff%2Fmidi-writer-ts)

![Tests](https://github.com/tommyo/MidiWriterJS/actions/workflows/lint.js.yml/badge.svg)
![Lint](https://github.com/tommyo/MidiWriterJS/actions/workflows/node.js.yml/badge.svg)

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 @huffduff/midi-writer-ts
```
Getting Started
------------

```typescript
import { Track, Writer, NoteEvent, ProgramChangeEvent } from '@huffduff/midi-writer-ts';

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

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

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

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

### `Track()`

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

### `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:

<table>
	<thead>
		<tr>
			<th>Name</th>
			<th>Type</th>
			<th>Default</th>
			<th>Description</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td><b>pitch</b></td>
			<td>string or array</td>
			<td></td>
			<td>Each pitch can be a string or valid MIDI note code.  Format for string is <code>C#4</code>.  Pro tip: You can use the output from <a href="https://github.com/danigb/tonal" target="_blank">tonal</a> functions to build scales, chords, intervals, etc. in this parameter.</td>
		</tr>
		<tr>
			<td><b>duration</b></td>
			<td>string or array</td>
			<td></td>
			<td>
				How long the note should sound.
				<ul>
					<li><code>1</code>  : whole</li>
					<li><code>2</code>  : half</li>
					<li><code>d2</code> : dotted half</li>
					<li><code>dd2</code> : double dotted half</li>
					<li><code>4</code>  : quarter</li>
					<li><code>4t</code>  : quarter triplet</li>
					<li><code>d4</code> : dotted quarter</li>
					<li><code>dd4</code> : double dotted quarter</li>
					<li><code>8</code>  : eighth</li>
					<li><code>8t</code> : eighth triplet</li>
					<li><code>d8</code> : dotted eighth</li>
					<li><code>dd8</code> : double dotted eighth</li>
					<li><code>16</code> : sixteenth</li>
					<li><code>16t</code> : sixteenth triplet</li>
					<li><code>32</code> : thirty-second</li>
					<li><code>64</code> : sixty-fourth</li>
					<li><code>Tn</code> : where n is an explicit number of ticks (T128 = 1 beat)</li>
				</ul>
				If an array of durations is passed then the sum of the durations will be used.
			</td>
		</tr>
		<tr>
			<td><b>wait</b></td>
			<td>string or array</td>
			<td><code>0</code></td>
			<td>How long to wait before sounding note (rest).  Takes same values as <b>duration</b>.</td>
		</tr>
		<tr>
			<td><b>sequential</b></td>
			<td>boolean</td>
			<td><code>false</code></td>
			<td>If true then array of pitches will be played sequentially as opposed to simulatanously.</td>
		</tr>
		<tr>
			<td><b>velocity</b></td>
			<td>number</td>
			<td><code>50</code></td>
			<td>How loud the note should sound, values 1-100.</td>
		</tr>
		<tr>
			<td><b>repeat</b></td>
			<td>number</td>
			<td><code>1</code></td>
			<td>How many times this event should be repeated.</td>
		</tr>
		<tr>
			<td><b>channel</b></td>
			<td>number</td>
			<td><code>1</code></td>
			<td>MIDI channel to use.</td>
		</tr>
		<tr>
			<td><b>grace</b></td>
			<td>string or array</td>
			<td></td>
			<td>Grace note to be applied to note event.  Takes same value format as <code>pitch</code></td>
		</tr>
		<tr>
			<td><b>tick</b></td>
			<td>number</td>
			<td></td>
			<td>Specific tick where this event should be played.  If this parameter is supplied then <code>wait</code> is disregarded if also supplied.</td>
		</tr>
	</tbody>
</table>


### `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'.
```typescript
import { Track, NoteEvent, Writer } from 'midi-writer-js';

const track = new Track();

track.addEvent([
		new NoteEvent({pitch: ['E4','D4'], duration: '4'}),
		new NoteEvent({pitch: ['C4'], duration: '2'}),
		new NoteEvent({pitch: ['E4','D4'], duration: '4'}),
		new NoteEvent({pitch: ['C4'], duration: '2'}),
		new NoteEvent({pitch: ['C4', 'C4', 'C4', 'C4', 'D4', 'D4', 'D4', 'D4'], duration: '8'}),
		new NoteEvent({pitch: ['E4','D4'], duration: '4'}),
		new NoteEvent({pitch: ['C4'], duration: '2'})
	], 
  (event, index) => ({ 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:
```typescript

// ...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)