File size: 2,112 Bytes
f23825d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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<T extends {}>(
  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<NoteOnEvent, "channel" | "deltaTime"> &
  TickProvider
export type TickNoteOffEvent = Omit<NoteOffEvent, "channel" | "deltaTime"> &
  TickProvider

// separate note to noteOn + noteOff
export function deassemble<T extends {}>(
  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]
  }
}