import assert from 'node:assert/strict'; import test from 'node:test'; import { parsePatternEvents } from '../src/lib/parsers'; function buildPattern(records: number[][], bars: number = 4, declaredCount = records.length) { const data = new Uint8Array(4 + records.length * 8); data[1] = bars; data[2] = declaredCount & 0xff; data[3] = declaredCount >> 8; records.forEach((record, index) => { data.set(record, 4 + index * 8); }); return data; } test('parses note records without changing the derived note shape', () => { const result = parsePatternEvents(buildPattern([[0x34, 0x12, 3 << 3, 64, 99, 0x78, 0x56, 7]])); assert.equal(result.bars, 4); assert.equal(result.recordCount, 1); assert.deepEqual(result.notes, { 3: [{ note: 64, position: 0x1234, duration: 0x5678, velocity: 99 }], }); assert.deepEqual(result.events[0], { type: 'note', kind: 0, position: 0x1234, source: 3, flags: 7, rawData: new Uint8Array([0x34, 0x12, 3 << 3, 64, 99, 0x78, 0x56, 7]), pad: 3, note: 64, velocity: 99, duration: 0x5678, }); }); test('parses and normalizes fader records', () => { const result = parsePatternEvents(buildPattern([[0x60, 0, 1, 7, 9, 0xff, 0x7f, 128]])); assert.deepEqual(result.notes, {}); assert.deepEqual(result.events[0], { type: 'fader', kind: 1, position: 96, source: 0, flags: 128, rawData: new Uint8Array([0x60, 0, 1, 7, 9, 0xff, 0x7f, 128]), parameter: 7, reserved: 9, rawValue: 32767, value: 1, }); }); test('preserves MIDI and unknown records', () => { const midi = [1, 0, (4 << 3) | 2, 0xd0, 75, 3, 4, 5]; const unknown = [2, 0, (5 << 3) | 6, 10, 11, 12, 13, 14]; const result = parsePatternEvents(buildPattern([midi, unknown])); assert.deepEqual(result.events[0], { type: 'midi', kind: 2, position: 1, source: 4, flags: 5, rawData: new Uint8Array(midi), data: new Uint8Array([0xd0, 75, 3, 4]), }); assert.deepEqual(result.events[1], { type: 'unknown', kind: 6, position: 2, source: 5, flags: 14, rawData: new Uint8Array(unknown), data: new Uint8Array([10, 11, 12, 13]), }); }); test('uses the uint16 header count and ignores undeclared or partial records', () => { const records = Array.from({ length: 300 }, (_, index) => [ index & 0xff, index >> 8, 0, 60, 100, 1, 0, 0, ]); const data = buildPattern([...records, [0, 0, 1, 0, 0, 0, 0, 0]], 8, 300); const truncated = data.slice(0, data.length - 3); const result = parsePatternEvents(truncated); assert.equal(result.recordCount, 300); assert.equal(result.events.length, 300); assert.equal(result.events[299].position, 299); });