Add lazy piano transcription and optional leased server worker
This commit is contained in:
50
frontend/piano-core.test.js
Normal file
50
frontend/piano-core.test.js
Normal file
@@ -0,0 +1,50 @@
|
||||
const { test } = require('node:test'),
|
||||
assert = require('node:assert/strict');
|
||||
const P = require('./piano-core');
|
||||
test('compact notes sort, round timing and infer hands below middle C', () => {
|
||||
const notes = P.normalizeNotes([
|
||||
{ pitch: 60, start: 1.23456, end: 1.8, velocity: 85 },
|
||||
{ pitch: 48, start: 0, end: 0.5, velocity: 150 },
|
||||
{ pitch: 55, start: 2, end: 3, velocity: 40, hand: 'right' },
|
||||
]);
|
||||
assert.equal(notes[0].hand, 'left');
|
||||
assert.equal(notes[0].velocity, 127);
|
||||
assert.equal(notes[1].start, 1.235);
|
||||
assert.equal(notes[1].hand, 'right');
|
||||
assert.equal(notes[2].hand, 'right');
|
||||
});
|
||||
test('invalid notes are rejected and tiny notes retain positive duration', () => {
|
||||
assert.throws(() => P.normalizeNotes([{ pitch: 200, start: 0, end: 1, velocity: 90 }]));
|
||||
assert.throws(() => P.normalizeNotes([{ pitch: 60, start: 2, end: 1, velocity: 90 }]));
|
||||
const [note] = P.normalizeNotes([{ pitch: 60, start: 0.0001, end: 0.0002, velocity: 0 }]);
|
||||
assert.ok(note.end > note.start);
|
||||
});
|
||||
test('Basic Pitch output converts amplitude to MIDI velocity and active notes use exclusive ends', () => {
|
||||
const notes = P.fromBasicPitch([
|
||||
{ pitchMidi: 60, startTimeSeconds: 1, durationSeconds: 0.5, amplitude: 0.5 },
|
||||
]);
|
||||
assert.equal(notes[0].velocity, 64);
|
||||
assert.equal(P.activeNotes(notes, 1).length, 1);
|
||||
assert.equal(P.activeNotes(notes, 1.5).length, 0);
|
||||
assert.deepEqual(P.practiceRange(95, 100), { start: 95, end: 100 });
|
||||
assert.equal(P.practiceRange(100, 100), null);
|
||||
});
|
||||
test('browser engine prefers WebGPU and reliably falls back to CPU', async () => {
|
||||
const { selectBackend } = await import('./piano-engine.mjs');
|
||||
const calls = [];
|
||||
const tf = {
|
||||
setBackend: async (name) => {
|
||||
calls.push(name);
|
||||
return true;
|
||||
},
|
||||
};
|
||||
assert.equal(await selectBackend(tf, true, async () => {}), 'webgpu');
|
||||
assert.deepEqual(calls, ['webgpu']);
|
||||
const fallback = { setBackend: async (name) => name === 'cpu' };
|
||||
assert.equal(
|
||||
await selectBackend(fallback, true, async () => {
|
||||
throw new Error('Unavailable GPU');
|
||||
}),
|
||||
'cpu',
|
||||
);
|
||||
});
|
||||
Reference in New Issue
Block a user