{"version":3,"sources":["src/common/RiffPcmEncoder.ts"],"names":[],"mappings":"AAGA,qBAAa,cAAc;IAEvB,OAAO,CAAC,oBAAoB,CAAS;IACrC,OAAO,CAAC,qBAAqB,CAAS;IACtC,OAAO,CAAC,gBAAgB,CAAa;gBAElB,gBAAgB,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM;IAK/D,MAAM,uEA0DZ;IAED,OAAO,CAAC,SAAS,CAIhB;IAED,OAAO,CAAC,eAAe,CAKtB;IAED,OAAO,CAAC,oBAAoB,CA0B3B;CACJ","file":"RiffPcmEncoder.d.ts","sourcesContent":["// Copyright (c) Microsoft Corporation. All rights reserved.\n// Licensed under the MIT license.\n\nexport class RiffPcmEncoder {\n\n    private privActualSampleRate: number;\n    private privDesiredSampleRate: number;\n    private privChannelCount: number = 1;\n\n    public constructor(actualSampleRate: number, desiredSampleRate: number) {\n        this.privActualSampleRate = actualSampleRate;\n        this.privDesiredSampleRate = desiredSampleRate;\n    }\n\n    public encode = (\n        needHeader: boolean,\n        actualAudioFrame: Float32Array): ArrayBuffer => {\n\n        const audioFrame = this.downSampleAudioFrame(actualAudioFrame, this.privActualSampleRate, this.privDesiredSampleRate);\n\n        if (!audioFrame) {\n            return null;\n        }\n\n        const audioLength = audioFrame.length * 2;\n\n        if (!needHeader) {\n            const buffer = new ArrayBuffer(audioLength);\n            const view = new DataView(buffer);\n            this.floatTo16BitPCM(view, 0, audioFrame);\n\n            return buffer;\n        }\n\n        const buffer = new ArrayBuffer(44 + audioLength);\n\n        const bitsPerSample = 16;\n        const bytesPerSample = bitsPerSample / 8;\n        // We dont know ahead of time about the length of audio to stream. So set to 0.\n        const fileLength = 0;\n\n        // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DataView\n        const view = new DataView(buffer);\n\n        /* RIFF identifier */\n        this.setString(view, 0, \"RIFF\");\n        /* file length */\n        view.setUint32(4, fileLength, true);\n        /* RIFF type & Format */\n        this.setString(view, 8, \"WAVEfmt \");\n        /* format chunk length */\n        view.setUint32(16, 16, true);\n        /* sample format (raw) */\n        view.setUint16(20, 1, true);\n        /* channel count */\n        view.setUint16(22, this.privChannelCount, true);\n        /* sample rate */\n        view.setUint32(24, this.privDesiredSampleRate, true);\n        /* byte rate (sample rate * block align) */\n        view.setUint32(28, this.privDesiredSampleRate * this.privChannelCount * bytesPerSample, true);\n        /* block align (channel count * bytes per sample) */\n        view.setUint16(32, this.privChannelCount * bytesPerSample, true);\n        /* bits per sample */\n        view.setUint16(34, bitsPerSample, true);\n        /* data chunk identifier */\n        this.setString(view, 36, \"data\");\n        /* data chunk length */\n        view.setUint32(40, fileLength, true);\n\n        this.floatTo16BitPCM(view, 44, audioFrame);\n\n        return buffer;\n    }\n\n    private setString = (view: DataView, offset: number, str: string): void => {\n        for (let i = 0; i < str.length; i++) {\n            view.setUint8(offset + i, str.charCodeAt(i));\n        }\n    }\n\n    private floatTo16BitPCM = (view: DataView, offset: number, input: Float32Array): void => {\n        for (let i = 0; i < input.length; i++ , offset += 2) {\n            const s = Math.max(-1, Math.min(1, input[i]));\n            view.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);\n        }\n    }\n\n    private downSampleAudioFrame = (\n        srcFrame: Float32Array,\n        srcRate: number,\n        dstRate: number): Float32Array => {\n\n        if (dstRate === srcRate || dstRate > srcRate) {\n            return srcFrame;\n        }\n\n        const ratio = srcRate / dstRate;\n        const dstLength = Math.round(srcFrame.length / ratio);\n        const dstFrame = new Float32Array(dstLength);\n        let srcOffset = 0;\n        let dstOffset = 0;\n        while (dstOffset < dstLength) {\n            const nextSrcOffset = Math.round((dstOffset + 1) * ratio);\n            let accum = 0;\n            let count = 0;\n            while (srcOffset < nextSrcOffset && srcOffset < srcFrame.length) {\n                accum += srcFrame[srcOffset++];\n                count++;\n            }\n            dstFrame[dstOffset++] = accum / count;\n        }\n\n        return dstFrame;\n    }\n}\n"]}