xen-midi
Version:
Free-pitch polyphonic MIDI I/O based on webmidi.js using multi-channel pitch-bend
144 lines (143 loc) • 5.16 kB
TypeScript
import { Output, Input } from 'webmidi';
/**
* Pitch bend range measured in semitones (+-).
*/
export declare const BEND_RANGE_IN_SEMITONES = 2;
/**
* Abstraction for a pitch-bent midi channel.
* Polyphonic in pure octaves and 12edo in general.
*/
export type Voice = {
age: number;
channel: number;
centsOffset: number;
};
/**
* Free-pitch MIDI note to be played at a later time.
*/
export type Note = {
/** Frequency in Hertz (Hz) */
frequency: number;
/** Attack velocity from 0 to 127. */
rawAttack?: number;
/** Release velocity from 0 to 127. */
rawRelease?: number;
/** Note-on time in milliseconds (ms) as measured by `WebMidi.time`.
* If time is a string prefixed with "+" and followed by a number, the message will be delayed by that many milliseconds.
*/
time: DOMHighResTimeStamp | string;
/** Note duration in milliseconds (ms). */
duration: DOMHighResTimeStamp;
};
declare function emptyNoteOff(rawRelease?: number, time?: DOMHighResTimeStamp): void;
/**
* Returned by MIDI note on. Turns the note off when called.
*/
export type NoteOff = typeof emptyNoteOff;
/**
* Wrapper for a webmidi.js output.
* Uses multiple channels to achieve polyphonic microtuning.
*/
export declare class MidiOut {
output: Output | null;
channels: Set<number>;
log: (msg: string) => void;
private voices;
private lastEventTime;
/**
* Constuct a new wrapper for a webmidi.js output.
* @param output Output device or `null` if you need a dummy out.
* @param channels Channels to use for sending pitch bent MIDI notes. Number of channels determines maximum microtonal polyphony.
* @param log Logging function.
*/
constructor(output: Output | null, channels: Set<number>, log?: (msg: string) => void);
private sendPitchBendRange;
/**
* Select a voice that's using a cents offset compatible channel or the oldest voice if nothing can be re-used.
* @param centsOffset Cents offset (pitch-bend) from 12edo.
* @returns A voice for the next note-on event.
*/
private selectVoice;
/**
* Send a note-on event and pitch-bend to the output device on one of the available channels.
* @param frequency Frequency of the note in Hertz (Hz).
* @param rawAttack Attack velocity of the note from 0 to 127.
* @returns A callback for sending a corresponding note off on the correct channel.
*/
sendNoteOn(frequency: number, rawAttack?: number, time?: DOMHighResTimeStamp): NoteOff;
/**
* Schedule a series of notes to be played at a later time.
* Please note that this reserves the channels until all notes have finished playing.
* @param notes Notes to be played.
*/
playNotes(notes: Note[]): void;
/**
* Clear scheduled notes that have not yet been played.
* Will start working once the Chrome bug is fixed: https://bugs.chromium.org/p/chromium/issues/detail?id=471798
*/
clear(): void;
}
/**
* Function to call when a MIDI note-on event is received (e.g. for turning on your synth).
* Attack velocity is from 0 to 127.
* Must return a note-off callback (e.g. for turning off your synth).
*/
export type NoteOnCallback = (index: number, rawAttack: number, channel: number) => NoteOff;
/**
* Wrapper for webmidi.js input.
* Listens on multiple channels.
*/
export declare class MidiIn {
callback: NoteOnCallback;
channels: Set<number>;
/** Note-off map from (noteNumber + (midiChannel - 1) * 128) to callbacks. */
private noteOffMap;
private _noteOn;
private _noteOff;
log: (msg: string) => void;
/**
* Construct a new wrapper for a webmidi.js input device.
* @param callback Function to call when a note-on event is received on any of the available channels.
* @param channels Channels to listen on.
* @param log Logging function.
*/
constructor(callback: NoteOnCallback, channels: Set<number>, log?: (msg: string) => void);
/**
* Make this wrapper (and your callback) respond to note-on/off events from this MIDI input.
* @param input MIDI input to listen to.
*/
listen(input: Input): void;
/**
* Make this wrapper (and your callback) stop responding to note-on/off events from this MIDI input.
* @param input MIDI input that was listened to.
*/
unlisten(input: Input): void;
private noteOn;
private noteOff;
/**
* Fire global note-off.
*/
deactivate(): void;
}
/**
* Information about a MIDI key.
*/
export type MidiKeyInfo = {
/** Contiguous index of the key with other white keys. */
whiteNumber: number;
sharpOf?: undefined;
flatOf?: undefined;
} | {
whiteNumber?: undefined;
/** This black key is a sharp of that white key. */
sharpOf: number;
/** This black key is a flat of that white key. */
flatOf: number;
};
/**
* Get information about a MIDI key.
* @param chromaticNumber Contiguous chromatic index of the MIDI key
* @returns Information about the MIDI key.
*/
export declare function midiKeyInfo(chromaticNumber: number): MidiKeyInfo;
export {};