File size: 2,701 Bytes
a446897
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
 An in-place replacement for ScriptProcessorNode using AudioWorklet
 */
class RecorderProcessor extends AudioWorkletProcessor {
    // 0. Determine the buffer size (this is the same as the 1st argument of ScriptProcessor)
    bufferSize = 2048
    // 1. Track the current buffer fill level
    _bytesWritten = 0

    // 2. Create a buffer of fixed size
    _buffer = new Float32Array(this.bufferSize)

    constructor() {
        super()
        this.initBuffer()
    }

    initBuffer() {
        this._bytesWritten = 0
    }

    isBufferEmpty() {
        return this._bytesWritten === 0
    }

    isBufferFull() {
        return this._bytesWritten === this.bufferSize
    }

    /**
     * @param {Float32Array[][]} inputs
     * @returns {boolean}
     */
    process(inputs) {
        // Grabbing the 1st channel similar to ScriptProcessorNode
        this.append(inputs[0][0])

        return true
    }

    /**
     *
     * @param {Float32Array} channelData
     */
    append(channelData) {
        if (this.isBufferFull()) {
            this.flush()
        }

        if (!channelData) return

        for (let i = 0; i < channelData.length; i++) {
            this._buffer[this._bytesWritten++] = channelData[i]
        }
    }

    flush() {
        // trim the buffer if ended prematurely
        const buffer = this._bytesWritten < this.bufferSize
            ? this._buffer.slice(0, this._bytesWritten)
            : this._buffer
        const result = this.downsampleBuffer(buffer, 44100, 16000);
        this.port.postMessage(result)
        this.initBuffer()
    }

    downsampleBuffer (buffer, sampleRate, outSampleRate) {
        if (outSampleRate == sampleRate) {
            return buffer;
        }
        if (outSampleRate > sampleRate) {
            throw 'downsampling rate show be smaller than original sample rate';
        }
        var sampleRateRatio = sampleRate / outSampleRate;
        var newLength = Math.round(buffer.length / sampleRateRatio);
        var result = new Int16Array(newLength);
        var offsetResult = 0;
        var offsetBuffer = 0;
        while (offsetResult < result.length) {
            var nextOffsetBuffer = Math.round((offsetResult + 1) * sampleRateRatio);
            var accum = 0,
                count = 0;
            for (var i = offsetBuffer; i < nextOffsetBuffer && i < buffer.length; i++) {
                accum += buffer[i];
                count++;
            }

            result[offsetResult] = Math.min(1, accum / count) * 0x7fff;
            offsetResult++;
            offsetBuffer = nextOffsetBuffer;
        }
        return result.buffer;
    };

}

registerProcessor("recorder.worklet", RecorderProcessor)