/* * SPDX-FileCopyrightText: Copyright (c) 2024 NVIDIA CORPORATION & AFFILIATES. All rights reserved. * SPDX-License-Identifier: Apache-2.0 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class LinearPCMProcessor extends AudioWorkletProcessor { // The size of the buffer in miliseconds. An audio block is posted to the main thread // every time the buffer is full, which means a large buffer will emit less frequently // (higher latency), but more efficiently (fewer I/O interruptions between the worker // and the main thread) static BUFFER_SIZE_MS = 32; constructor() { super(); // the "sampleRate" is available on the global scope in AudioWorklet files. The linter // doesn't know that, so it incorrectly raises an error when accessing it. The comment // below disables the linter for that specific line. const rate = sampleRate; const bufferSize = (rate / 1000) * LinearPCMProcessor.BUFFER_SIZE_MS; this.buffer = new Int16Array(bufferSize); this.offset = 0; } /** * Converts input data from Float32Array to Int16Array, and stores it to * to the buffer. When the buffer is full, its content is posted to the main * thread, and the buffer is emptied */ process(inputList, _outputList, _parameters) { // Assumes the input is mono (1 channel). If there are more channels, they // are ignored const input = inputList[0][0]; // first channel of first input for (let i = 0; i < input.length; i++) { const sample = Math.max(-1, Math.min(1, input[i])); this.buffer[i + this.offset] = sample < 0 ? sample * 0x8000 : sample * 0x7fff; } this.offset += input.length; // Once the buffer is filled entirely, flush the buffer if (this.offset >= this.buffer.length - 1) { this.flush(); } return true; } /** * Sends the buffer's content to the main thread via postMessage(), and reset * the offset to 0 */ flush() { this.offset = 0; this.port.postMessage(this.buffer); } } registerProcessor("linear-pcm-processor", LinearPCMProcessor);