midi-player-demo / src /common /midi /midiConversion.test.ts
Yann
test
f23825d
raw
history blame
4.02 kB
import * as fs from "fs"
import { AnyEvent } from "midifile-ts"
import * as path from "path"
import { serialize } from "serializr"
import { emptySong } from "../song/SongFactory"
import { NoteEvent } from "../track"
import Track from "../track/Track"
import {
noteOffMidiEvent,
noteOnMidiEvent,
setTempoMidiEvent,
timeSignatureMidiEvent,
} from "./MidiEvent"
import {
createConductorTrackIfNeeded,
songFromMidi,
songToMidi,
songToMidiEvents,
} from "./midiConversion"
// id for each event will not be serialized in midi file
// we change ids sorted by order in events array
const reassignIDs = (track: Track) => {
track.events.forEach((e, i) => {
track.events[i].id = i
})
}
describe("SongFile", () => {
it("write and read", () => {
const song = emptySong()
const note = song.tracks[1].addEvent<NoteEvent>({
type: "channel",
subtype: "note",
noteNumber: 57,
tick: 960,
velocity: 127,
duration: 240,
})
song.tracks.forEach(reassignIDs)
const bytes = songToMidi(song)
const song2 = songFromMidi(bytes)
song2.filepath = song.filepath // filepath will not be serialized
expect(serialize(song2)).toStrictEqual(serialize(song))
})
describe("songToMidiEvents", () => {
const expectEveryTrackHaveEndOfTrackEvent = (tracks: AnyEvent[][]) => {
for (const track of tracks) {
expect(
track.findIndex(
(e) => e.type === "meta" && e.subtype === "endOfTrack",
),
).toBe(track.length - 1)
}
}
const openFile = (fileName: string): AnyEvent[][] => {
const song = songFromMidi(
fs.readFileSync(path.join(__dirname, "../../../testdata/", fileName))
.buffer,
)
return songToMidiEvents(song)
}
describe("format 1", () => {
const rawTracks = openFile("tracks.mid")
it("every tracks have endOfTrack event", () => {
expect(rawTracks.length).toBe(18)
expectEveryTrackHaveEndOfTrackEvent(rawTracks)
})
})
describe("format 0", () => {
const rawTracks = openFile("format0.mid")
it("every tracks have endOfTrack event", () => {
expect(rawTracks.length).toBe(17)
expectEveryTrackHaveEndOfTrackEvent(rawTracks)
})
})
})
describe("signal events", () => {
it("should save the track color", () => {
const song = emptySong()
song.tracks[1].setColor({
red: 12,
green: 34,
blue: 56,
alpha: 78,
})
const bytes = songToMidi(song)
const song2 = songFromMidi(bytes)
expect(song2.tracks[1].color).toMatchObject({
red: 12,
green: 34,
blue: 56,
alpha: 78,
})
})
})
describe("createConductorTrackIfNeeded", () => {
it("should not create the conductor track", () => {
const tracks: AnyEvent[][] = [
[timeSignatureMidiEvent(0, 4, 4), setTempoMidiEvent(120, 500000)],
[noteOnMidiEvent(0, 1, 60, 100), noteOffMidiEvent(120, 1, 60, 0)],
]
const result = createConductorTrackIfNeeded(tracks)
expect(result).toStrictEqual([
[timeSignatureMidiEvent(0, 4, 4), setTempoMidiEvent(120, 500000)],
[noteOnMidiEvent(0, 1, 60, 100), noteOffMidiEvent(120, 1, 60, 0)],
])
})
it("should create the conductor track", () => {
const tracks: AnyEvent[][] = [
[
timeSignatureMidiEvent(0, 4, 4),
setTempoMidiEvent(120, 500000),
noteOnMidiEvent(120, 5, 60, 100),
noteOffMidiEvent(120, 5, 60, 0),
],
[noteOnMidiEvent(0, 2, 60, 100), noteOffMidiEvent(120, 2, 60, 0)],
]
const result = createConductorTrackIfNeeded(tracks)
expect(result).toStrictEqual([
[timeSignatureMidiEvent(0, 4, 4), setTempoMidiEvent(120, 500000)],
[noteOnMidiEvent(240, 5, 60, 100), noteOffMidiEvent(120, 5, 60, 0)],
[noteOnMidiEvent(0, 2, 60, 100), noteOffMidiEvent(120, 2, 60, 0)],
])
})
})
})