CI / Frontend - type-check & test (push) Canceled after 0s
직접 만든 연습곡 다섯 파일을 공개 보관함에 등록했다. 별빛 계단은 입문과 쉬움 두 단계로 제공한다. MIDI 파서 검사와 백엔드 단위 테스트 5개를 통과했다. 운영 백업은 /home/syskiller/piano/backups/bach-to-basics/20261009-beginner-midi 에 있다. 백엔드만 갱신했고 비회원 목록과 다운로드를 확인했다. 실제 USB MIDI 장치 검사는 남아 있다. 사전 훅은 로컬 pnpm 의존성 불일치로 실행되지 않아 관련 검사를 직접 수행했다.
33 lines
1.4 KiB
JavaScript
33 lines
1.4 KiB
JavaScript
import fs from "node:fs";
|
|
import path from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import midiPackage from "../frontend/node_modules/@tonejs/midi/build/Midi.js";
|
|
|
|
const { Midi } = midiPackage;
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "backend", "sample_midi");
|
|
const expected = [
|
|
["starlight-steps-beginner.mid", 4],
|
|
["starlight-steps-easy.mid", 4],
|
|
["evening-waltz-beginner.mid", 3],
|
|
["sunrise-arpeggio-easy.mid", 4],
|
|
["black-key-pentatonic-beginner.mid", 4],
|
|
];
|
|
|
|
for (const [name, meter] of expected) {
|
|
const midi = new Midi(fs.readFileSync(path.join(root, name)));
|
|
const [right, left] = midi.tracks;
|
|
if (midi.tracks.length !== 2 || !right?.notes.length || !left?.notes.length) {
|
|
throw new Error(`${name}: 오른손과 왼손 트랙이 각각 필요합니다`);
|
|
}
|
|
if (midi.duration < 60 || midi.duration > 90) {
|
|
throw new Error(`${name}: 곡 길이가 1분에서 1분 30초 사이여야 합니다 (${midi.duration.toFixed(1)}초)`);
|
|
}
|
|
if (midi.header.timeSignatures[0]?.timeSignature[0] !== meter) {
|
|
throw new Error(`${name}: 박자가 일치하지 않습니다`);
|
|
}
|
|
if ([...right.notes, ...left.notes].some((note) => note.midi < 21 || note.midi > 108)) {
|
|
throw new Error(`${name}: 피아노 음역을 벗어났습니다`);
|
|
}
|
|
console.log(`${name}: ${midi.duration.toFixed(1)}초, 오른손 ${right.notes.length}음, 왼손 ${left.notes.length}음`);
|
|
}
|