"Fossies" - the Fresh Open Source Software Archive

Member "jitsi-meet-7555/react/features/stream-effects/rnnoise/RnnoiseProcessor.ts" (28 Sep 2023, 6375 Bytes) of package /linux/misc/jitsi-meet-7555.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) TypeScript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 /* eslint-disable no-bitwise */
    2 
    3 interface IRnnoiseModule extends EmscriptenModule {
    4     _rnnoise_create: () => number;
    5     _rnnoise_destroy: (context: number) => void;
    6     _rnnoise_process_frame: (context: number, input: number, output: number) => number;
    7 }
    8 
    9 /**
   10  * Constant. Rnnoise default sample size, samples of different size won't work.
   11  */
   12 export const RNNOISE_SAMPLE_LENGTH = 480;
   13 
   14 /**
   15  *  Constant. Rnnoise only takes inputs of 480 PCM float32 samples thus 480*4.
   16  */
   17 const RNNOISE_BUFFER_SIZE: number = RNNOISE_SAMPLE_LENGTH * 4;
   18 
   19 /**
   20  *  Constant. Rnnoise only takes operates on 44.1Khz float 32 little endian PCM.
   21  */
   22 const PCM_FREQUENCY = 44100;
   23 
   24 /**
   25  * Used to shift a 32 bit number by 16 bits.
   26  */
   27 const SHIFT_16_BIT_NR = 32768;
   28 
   29 /**
   30  * Represents an adaptor for the rnnoise library compiled to webassembly. The class takes care of webassembly
   31  * memory management and exposes rnnoise functionality such as PCM audio denoising and VAD (voice activity
   32  * detection) scores.
   33  */
   34 export default class RnnoiseProcessor {
   35     /**
   36      * Rnnoise context object needed to perform the audio processing.
   37      */
   38     private _context: number;
   39 
   40     /**
   41      * State flag, check if the instance was destroyed.
   42      */
   43     private _destroyed = false;
   44 
   45     /**
   46      * WASM interface through which calls to rnnoise are made.
   47      */
   48     private _wasmInterface: IRnnoiseModule;
   49 
   50     /**
   51      * WASM dynamic memory buffer used as input for rnnoise processing method.
   52      */
   53     private _wasmPcmInput: number;
   54 
   55     /**
   56      * The Float32Array index representing the start point in the wasm heap of the _wasmPcmInput buffer.
   57      */
   58     private _wasmPcmInputF32Index: number;
   59 
   60     /**
   61      * Constructor.
   62      *
   63      * @class
   64      * @param {Object} wasmInterface - WebAssembly module interface that exposes rnnoise functionality.
   65      */
   66     constructor(wasmInterface: IRnnoiseModule) {
   67         // Considering that we deal with dynamic allocated memory employ exception safety strong guarantee
   68         // i.e. in case of exception there are no side effects.
   69         try {
   70             this._wasmInterface = wasmInterface;
   71 
   72             // For VAD score purposes only allocate the buffers once and reuse them
   73             this._wasmPcmInput = this._wasmInterface._malloc(RNNOISE_BUFFER_SIZE);
   74 
   75             this._wasmPcmInputF32Index = this._wasmPcmInput >> 2;
   76 
   77             if (!this._wasmPcmInput) {
   78                 throw Error('Failed to create wasm input memory buffer!');
   79             }
   80 
   81             this._context = this._wasmInterface._rnnoise_create();
   82         } catch (error) {
   83             // release can be called even if not all the components were initialized.
   84             this.destroy();
   85             throw error;
   86         }
   87     }
   88 
   89     /**
   90      * Release resources associated with the wasm context. If something goes downhill here
   91      * i.e. Exception is thrown, there is nothing much we can do.
   92      *
   93      * @returns {void}
   94      */
   95     _releaseWasmResources(): void {
   96         // For VAD score purposes only allocate the buffers once and reuse them
   97         if (this._wasmPcmInput) {
   98             this._wasmInterface._free(this._wasmPcmInput);
   99         }
  100 
  101         if (this._context) {
  102             this._wasmInterface._rnnoise_destroy(this._context);
  103         }
  104     }
  105 
  106     /**
  107      * Rnnoise can only operate on a certain PCM array size.
  108      *
  109      * @returns {number} - The PCM sample array size as required by rnnoise.
  110      */
  111     getSampleLength(): number {
  112         return RNNOISE_SAMPLE_LENGTH;
  113     }
  114 
  115     /**
  116      * Rnnoise can only operate on a certain format of PCM sample namely float 32 44.1Kz.
  117      *
  118      * @returns {number} - PCM sample frequency as required by rnnoise.
  119      */
  120     getRequiredPCMFrequency(): number {
  121         return PCM_FREQUENCY;
  122     }
  123 
  124     /**
  125      * Release any resources required by the rnnoise context this needs to be called
  126      * before destroying any context that uses the processor.
  127      *
  128      * @returns {void}
  129      */
  130     destroy(): void {
  131         // Attempting to release a non initialized processor, do nothing.
  132         if (this._destroyed) {
  133             return;
  134         }
  135 
  136         this._releaseWasmResources();
  137 
  138         this._destroyed = true;
  139     }
  140 
  141     /**
  142      * Calculate the Voice Activity Detection for a raw Float32 PCM sample Array.
  143      * The size of the array must be of exactly 480 samples, this constraint comes from the rnnoise library.
  144      *
  145      * @param {Float32Array} pcmFrame - Array containing 32 bit PCM samples.
  146      * @returns {Float} Contains VAD score in the interval 0 - 1 i.e. 0.90.
  147      */
  148     calculateAudioFrameVAD(pcmFrame: Float32Array): number {
  149         return this.processAudioFrame(pcmFrame);
  150     }
  151 
  152     /**
  153      * Process an audio frame, optionally denoising the input pcmFrame and returning the Voice Activity Detection score
  154      * for a raw Float32 PCM sample Array.
  155      * The size of the array must be of exactly 480 samples, this constraint comes from the rnnoise library.
  156      *
  157      * @param {Float32Array} pcmFrame - Array containing 32 bit PCM samples. Parameter is also used as output
  158      * when {@code shouldDenoise} is true.
  159      * @param {boolean} shouldDenoise - Should the denoised frame be returned in pcmFrame.
  160      * @returns {Float} Contains VAD score in the interval 0 - 1 i.e. 0.90 .
  161      */
  162     processAudioFrame(pcmFrame: Float32Array, shouldDenoise: Boolean = false): number {
  163         // Convert 32 bit Float PCM samples to 16 bit Float PCM samples as that's what rnnoise accepts as input
  164         for (let i = 0; i < RNNOISE_SAMPLE_LENGTH; i++) {
  165             this._wasmInterface.HEAPF32[this._wasmPcmInputF32Index + i] = pcmFrame[i] * SHIFT_16_BIT_NR;
  166         }
  167 
  168         // Use the same buffer for input/output, rnnoise supports this behavior
  169         const vadScore = this._wasmInterface._rnnoise_process_frame(
  170             this._context,
  171             this._wasmPcmInput,
  172             this._wasmPcmInput
  173         );
  174 
  175         // Rnnoise denoises the frame by default but we can avoid unnecessary operations if the calling
  176         // client doesn't use the denoised frame.
  177         if (shouldDenoise) {
  178             // Convert back to 32 bit PCM
  179             for (let i = 0; i < RNNOISE_SAMPLE_LENGTH; i++) {
  180                 pcmFrame[i] = this._wasmInterface.HEAPF32[this._wasmPcmInputF32Index + i] / SHIFT_16_BIT_NR;
  181             }
  182         }
  183 
  184         return vadScore;
  185     }
  186 }