All files / src music5000-worklet.js

100% Statements 18/18
100% Branches 2/2
100% Functions 7/7
100% Lines 15/15

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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        1x 1x   29x       7x 7x         7x 498x 1x   500x       500x 500x 499x       230x 230x       1x  
/* global sampleRate, registerProcessor, AudioWorkletProcessor */
import { StereoRing } from "./stereo-ring.js";
import { ExcessLeadMs, MaxTargetLatencyMs, PersistentExcessSeconds, validTargetLatencyMs } from "./audio-latency.js";
 
const FullScale = 32768;
const CapacityMs = 2 * MaxTargetLatencyMs;
 
const framesFor = (ms) => Math.ceil((sampleRate * ms) / 1000);
 
class Music5000Processor extends AudioWorkletProcessor {
    constructor(options) {
        super(options);
        this.ring = new StereoRing(framesFor(CapacityMs), {
            targetFrames: framesFor(validTargetLatencyMs(options?.processorOptions?.targetLatencyMs)),
            excessFrames: framesFor(ExcessLeadMs),
            persistentExcessFrames: framesFor(1000 * PersistentExcessSeconds),
        });
        this.commands = {
            samples: (m) => this.ring.write(m.samples, 1 / FullScale),
            setTargetLatency: (m) => this.ring.setTargetFrames(framesFor(validTargetLatencyMs(m.targetLatencyMs))),
        };
        this.port.onmessage = (event) => this.onMessage(event.data);
    }
 
    onMessage(message) {
        const command = this.commands[message.command];
        if (!command) throw new Error(`Unknown Music 5000 command ${message.command}`);
        command(message);
    }
 
    process(inputs, outputs) {
        this.ring.read(outputs[0][0], outputs[0][1]);
        return true;
    }
}
 
registerProcessor("music5000", Music5000Processor);