| | import { BasicMIDI } from "./basic_midi.js"; |
| | import { messageTypes, MIDIMessage } from "./midi_message.js"; |
| | import { IndexedByteArray } from "../utils/indexed_array.js"; |
| | import { SpessaSynthWarn } from "../utils/loggin.js"; |
| |
|
| | |
| | |
| | |
| | export class MIDIBuilder extends BasicMIDI |
| | { |
| | |
| | |
| | |
| | |
| | |
| | constructor(name, timeDivision = 480, initialTempo = 120) |
| | { |
| | super(); |
| | this.timeDivision = timeDivision; |
| | this.midiName = name; |
| | this.encoder = new TextEncoder(); |
| | this.rawMidiName = this.encoder.encode(name); |
| | |
| | |
| | this.addNewTrack(name); |
| | this.addSetTempo(0, initialTempo); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | addSetTempo(ticks, tempo) |
| | { |
| | const array = new IndexedByteArray(3); |
| | |
| | tempo = 60000000 / tempo; |
| | |
| | |
| | array[0] = (tempo >> 16) & 0xFF; |
| | array[1] = (tempo >> 8) & 0xFF; |
| | array[2] = tempo & 0xFF; |
| | |
| | this.addEvent(ticks, 0, messageTypes.setTempo, array); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | addNewTrack(name, port = 0) |
| | { |
| | this.tracksAmount++; |
| | if (this.tracksAmount > 1) |
| | { |
| | this.format = 1; |
| | } |
| | this.tracks.push([]); |
| | this.tracks[this.tracksAmount - 1].push( |
| | new MIDIMessage(0, messageTypes.endOfTrack, new IndexedByteArray(0)) |
| | ); |
| | this.addEvent(0, this.tracksAmount - 1, messageTypes.trackName, this.encoder.encode(name)); |
| | this.addEvent(0, this.tracksAmount - 1, messageTypes.midiPort, [port]); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | addEvent(ticks, track, event, eventData) |
| | { |
| | if (!this.tracks[track]) |
| | { |
| | throw new Error(`Track ${track} does not exist. Add it via addTrack method.`); |
| | } |
| | if (event === messageTypes.endOfTrack) |
| | { |
| | SpessaSynthWarn( |
| | "The EndOfTrack is added automatically and does not influence the duration. Consider adding a voice event instead."); |
| | return; |
| | } |
| | |
| | this.tracks[track].pop(); |
| | this.tracks[track].push(new MIDIMessage( |
| | ticks, |
| | event, |
| | new IndexedByteArray(eventData) |
| | )); |
| | |
| | this.tracks[track].push(new MIDIMessage( |
| | ticks, |
| | messageTypes.endOfTrack, |
| | new IndexedByteArray(0) |
| | )); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | addNoteOn(ticks, track, channel, midiNote, velocity) |
| | { |
| | channel %= 16; |
| | midiNote %= 128; |
| | velocity %= 128; |
| | this.addEvent( |
| | ticks, |
| | track, |
| | messageTypes.noteOn | channel, |
| | [midiNote, velocity] |
| | ); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | addNoteOff(ticks, track, channel, midiNote) |
| | { |
| | channel %= 16; |
| | midiNote %= 128; |
| | this.addEvent( |
| | ticks, |
| | track, |
| | messageTypes.noteOff | channel, |
| | [midiNote, 64] |
| | ); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | addProgramChange(ticks, track, channel, programNumber) |
| | { |
| | channel %= 16; |
| | programNumber %= 128; |
| | this.addEvent( |
| | ticks, |
| | track, |
| | messageTypes.programChange | channel, |
| | [programNumber] |
| | ); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | addControllerChange(ticks, track, channel, controllerNumber, controllerValue) |
| | { |
| | channel %= 16; |
| | controllerNumber %= 128; |
| | controllerValue %= 128; |
| | this.addEvent( |
| | ticks, |
| | track, |
| | messageTypes.controllerChange | channel, |
| | [controllerNumber, controllerValue] |
| | ); |
| | } |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | addPitchWheel(ticks, track, channel, MSB, LSB) |
| | { |
| | channel %= 16; |
| | MSB %= 128; |
| | LSB %= 128; |
| | this.addEvent( |
| | ticks, |
| | track, |
| | messageTypes.pitchBend | channel, |
| | [LSB, MSB] |
| | ); |
| | } |
| | } |