import { NoteOffEvent, NoteOnEvent } from "midifile-ts" import { noteOffMidiEvent, noteOnMidiEvent } from "../midi/MidiEvent" import { NoteEvent, TickProvider } from "../track" /** assemble noteOn and noteOff to single note event to append duration */ export function assemble( events: (T | TickNoteOffEvent | TickNoteOnEvent)[], ): (T | NoteEvent)[] { const noteOnEvents: TickNoteOnEvent[] = [] function findNoteOn(noteOff: TickNoteOffEvent): TickNoteOnEvent | null { const i = noteOnEvents.findIndex((e) => { return e.noteNumber === noteOff.noteNumber }) if (i < 0) { return null } const e = noteOnEvents[i] noteOnEvents.splice(i, 1) return e } const result: (T | NoteEvent)[] = [] events.forEach((e) => { if ("subtype" in e) { switch (e.subtype) { case "noteOn": noteOnEvents.push(e) break case "noteOff": { const noteOn = findNoteOn(e) if (noteOn != null) { const note: NoteEvent = { ...noteOn, subtype: "note", id: -1, tick: noteOn.tick, duration: e.tick - noteOn.tick, } result.push(note) } break } default: result.push(e) break } } else { result.push(e) } }) return result } export type TickNoteOnEvent = Omit & TickProvider export type TickNoteOffEvent = Omit & TickProvider // separate note to noteOn + noteOff export function deassemble( e: T | NoteEvent, ): (T | TickNoteOnEvent | TickNoteOffEvent)[] { if ("subtype" in e && e.subtype === "note") { const channel = (e as any)["channel"] ?? -1 const noteOn = noteOnMidiEvent(0, channel, e.noteNumber, e.velocity) const noteOff = noteOffMidiEvent(0, channel, e.noteNumber) return [ { ...noteOn, tick: e.tick }, { ...noteOff, tick: e.tick + e.duration }, ] } else { return [e as T] } }