File size: 2,595 Bytes
2f49513
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
 * 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);