您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

RnnoiseProcessor.js 5.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // @flow
  2. /**
  3. * Constant. Rnnoise default sample size, samples of different size won't work.
  4. */
  5. export const RNNOISE_SAMPLE_LENGTH: number = 480;
  6. /**
  7. * Constant. Rnnoise only takes inputs of 480 PCM float32 samples thus 480*4.
  8. */
  9. const RNNOISE_BUFFER_SIZE: number = RNNOISE_SAMPLE_LENGTH * 4;
  10. /**
  11. * Represents an adaptor for the rnnoise library compiled to webassembly. The class takes care of webassembly
  12. * memory management and exposes rnnoise functionality such as PCM audio denoising and VAD (voice activity
  13. * detection) scores.
  14. */
  15. export default class RnnoiseProcessor {
  16. /**
  17. * Rnnoise context object needed to perform the audio processing.
  18. */
  19. _context: ?Object;
  20. /**
  21. * State flag, check if the instance was destroyed.
  22. */
  23. _destroyed: boolean = false;
  24. /**
  25. * WASM interface through which calls to rnnoise are made.
  26. */
  27. _wasmInterface: Object;
  28. /**
  29. * WASM dynamic memory buffer used as input for rnnoise processing method.
  30. */
  31. _wasmPcmInput: Object;
  32. /**
  33. * The Float32Array index representing the start point in the wasm heap of the _wasmPcmInput buffer.
  34. */
  35. _wasmPcmInputF32Index: number;
  36. /**
  37. * WASM dynamic memory buffer used as output for rnnoise processing method.
  38. */
  39. _wasmPcmOutput: Object;
  40. /**
  41. * Constructor.
  42. *
  43. * @class
  44. * @param {Object} wasmInterface - WebAssembly module interface that exposes rnnoise functionality.
  45. */
  46. constructor(wasmInterface: Object) {
  47. // Considering that we deal with dynamic allocated memory employ exception safety strong guarantee
  48. // i.e. in case of exception there are no side effects.
  49. try {
  50. this._wasmInterface = wasmInterface;
  51. // For VAD score purposes only allocate the buffers once and reuse them
  52. this._wasmPcmInput = this._wasmInterface._malloc(RNNOISE_BUFFER_SIZE);
  53. if (!this._wasmPcmInput) {
  54. throw Error('Failed to create wasm input memory buffer!');
  55. }
  56. this._wasmPcmOutput = this._wasmInterface._malloc(RNNOISE_BUFFER_SIZE);
  57. if (!this._wasmPcmOutput) {
  58. wasmInterface._free(this._wasmPcmInput);
  59. throw Error('Failed to create wasm output memory buffer!');
  60. }
  61. // The HEAPF32.set function requires an index relative to a Float32 array view of the wasm memory model
  62. // which is an array of bytes. This means we have to divide it by the size of a float to get the index
  63. // relative to a Float32 Array.
  64. this._wasmPcmInputF32Index = this._wasmPcmInput / 4;
  65. this._context = this._wasmInterface._rnnoise_create();
  66. } catch (error) {
  67. // release can be called even if not all the components were initialized.
  68. this._releaseWasmResources();
  69. throw error;
  70. }
  71. }
  72. /**
  73. * Copy the input PCM Audio Sample to the wasm input buffer.
  74. *
  75. * @param {Float32Array} pcmSample - Array containing 16 bit format PCM sample stored in 32 Floats .
  76. * @returns {void}
  77. */
  78. _copyPCMSampleToWasmBuffer(pcmSample: Float32Array) {
  79. this._wasmInterface.HEAPF32.set(pcmSample, this._wasmPcmInputF32Index);
  80. }
  81. /**
  82. * Convert 32 bit Float PCM samples to 16 bit Float PCM samples and store them in 32 bit Floats.
  83. *
  84. * @param {Float32Array} f32Array - Array containing 32 bit PCM samples.
  85. * @returns {void}
  86. */
  87. _convertTo16BitPCM(f32Array: Float32Array) {
  88. for (const [ index, value ] of f32Array.entries()) {
  89. f32Array[index] = value * 0x7fff;
  90. }
  91. }
  92. /**
  93. * Release resources associated with the wasm context. If something goes downhill here
  94. * i.e. Exception is thrown, there is nothing much we can do.
  95. *
  96. * @returns {void}
  97. */
  98. _releaseWasmResources() {
  99. // For VAD score purposes only allocate the buffers once and reuse them
  100. if (this._wasmPcmInput) {
  101. this._wasmInterface._free(this._wasmPcmInput);
  102. this._wasmPcmInput = null;
  103. }
  104. if (this._wasmPcmOutput) {
  105. this._wasmInterface._free(this._wasmPcmOutput);
  106. this._wasmPcmOutput = null;
  107. }
  108. if (this._context) {
  109. this._wasmInterface._rnnoise_destroy(this._context);
  110. this._context = null;
  111. }
  112. }
  113. /**
  114. * Release any resources required by the rnnoise context this needs to be called
  115. * before destroying any context that uses the processor.
  116. *
  117. * @returns {void}
  118. */
  119. destroy() {
  120. // Attempting to release a non initialized processor, do nothing.
  121. if (this._destroyed) {
  122. return;
  123. }
  124. this._releaseWasmResources();
  125. this._destroyed = true;
  126. }
  127. /**
  128. * Calculate the Voice Activity Detection for a raw Float32 PCM sample Array.
  129. * The size of the array must be of exactly 480 samples, this constraint comes from the rnnoise library.
  130. *
  131. * @param {Float32Array} pcmFrame - Array containing 32 bit PCM samples.
  132. * @returns {Float} Contains VAD score in the interval 0 - 1 i.e. 0.90 .
  133. */
  134. calculateAudioFrameVAD(pcmFrame: Float32Array) {
  135. if (this._destroyed) {
  136. throw new Error('RnnoiseProcessor instance is destroyed, please create another one!');
  137. }
  138. const pcmFrameLength = pcmFrame.length;
  139. if (pcmFrameLength !== RNNOISE_SAMPLE_LENGTH) {
  140. throw new Error(`Rnnoise can only process PCM frames of 480 samples! Input sample was:${pcmFrameLength}`);
  141. }
  142. this._convertTo16BitPCM(pcmFrame);
  143. this._copyPCMSampleToWasmBuffer(pcmFrame);
  144. return this._wasmInterface._rnnoise_process_frame(this._context, this._wasmPcmOutput, this._wasmPcmInput);
  145. }
  146. }