@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.52 → 1.0.53
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/MLNoiseSuppressor.d.ts +3 -1
- package/dist/MLNoiseSuppressor.js +54 -16
- package/package.json +1 -1
|
@@ -11,6 +11,7 @@ export declare class MLNoiseSuppressor {
|
|
|
11
11
|
private processingQueue;
|
|
12
12
|
private outputQueue;
|
|
13
13
|
private isProcessing;
|
|
14
|
+
private highPassFilter;
|
|
14
15
|
/**
|
|
15
16
|
* Initialize the ML noise suppressor
|
|
16
17
|
* @param modelUrl URL to the model.json file
|
|
@@ -52,7 +53,8 @@ export declare class MLNoiseSuppressor {
|
|
|
52
53
|
*/
|
|
53
54
|
private startBackgroundProcessing;
|
|
54
55
|
/**
|
|
55
|
-
* Fast audio processing
|
|
56
|
+
* Fast audio processing optimized for voice quality
|
|
57
|
+
* Preserves voice fundamentals (80-250Hz) while reducing noise
|
|
56
58
|
*/
|
|
57
59
|
private processAudioFast;
|
|
58
60
|
/**
|
|
@@ -50,6 +50,8 @@ class MLNoiseSuppressor {
|
|
|
50
50
|
this.processingQueue = [];
|
|
51
51
|
this.outputQueue = [];
|
|
52
52
|
this.isProcessing = false;
|
|
53
|
+
// High-pass filter state for voice optimization (remove <80Hz rumble)
|
|
54
|
+
this.highPassFilter = null;
|
|
53
55
|
}
|
|
54
56
|
/**
|
|
55
57
|
* Initialize the ML noise suppressor
|
|
@@ -225,6 +227,13 @@ class MLNoiseSuppressor {
|
|
|
225
227
|
// Create MediaStreamSource from input
|
|
226
228
|
const source = this.audioContext.createMediaStreamSource(inputStream);
|
|
227
229
|
console.log('🎤 [ML] Created MediaStreamSource');
|
|
230
|
+
// Create high-pass filter to remove rumble (<80Hz)
|
|
231
|
+
// This improves voice clarity and matches Google Meet quality
|
|
232
|
+
this.highPassFilter = this.audioContext.createBiquadFilter();
|
|
233
|
+
this.highPassFilter.type = 'highpass';
|
|
234
|
+
this.highPassFilter.frequency.value = 80; // Remove frequencies below 80Hz
|
|
235
|
+
this.highPassFilter.Q.value = 0.7; // Gentle slope
|
|
236
|
+
console.log('🎤 [ML] Created high-pass filter (80Hz cutoff)');
|
|
228
237
|
// Create destination for output
|
|
229
238
|
const destination = this.audioContext.createMediaStreamDestination();
|
|
230
239
|
console.log('🎤 [ML] Created destination stream');
|
|
@@ -268,10 +277,11 @@ class MLNoiseSuppressor {
|
|
|
268
277
|
}
|
|
269
278
|
}
|
|
270
279
|
};
|
|
271
|
-
// Connect: source -> processor -> destination
|
|
272
|
-
source.connect(
|
|
280
|
+
// Connect: source -> highpass -> processor -> destination
|
|
281
|
+
source.connect(this.highPassFilter);
|
|
282
|
+
this.highPassFilter.connect(processor);
|
|
273
283
|
processor.connect(destination);
|
|
274
|
-
console.log('✅ [ML] Pipeline connected: source -> processor -> destination');
|
|
284
|
+
console.log('✅ [ML] Pipeline connected: source -> highpass(80Hz) -> processor -> destination');
|
|
275
285
|
console.log('✅ [ML] Output stream tracks:', destination.stream.getTracks().length);
|
|
276
286
|
return destination.stream;
|
|
277
287
|
}
|
|
@@ -314,32 +324,56 @@ class MLNoiseSuppressor {
|
|
|
314
324
|
processLoop();
|
|
315
325
|
}
|
|
316
326
|
/**
|
|
317
|
-
* Fast audio processing
|
|
327
|
+
* Fast audio processing optimized for voice quality
|
|
328
|
+
* Preserves voice fundamentals (80-250Hz) while reducing noise
|
|
318
329
|
*/
|
|
319
330
|
async processAudioFast(inputBuffer) {
|
|
320
331
|
if (!this.model || !this.config || !this.normStats) {
|
|
321
332
|
return inputBuffer;
|
|
322
333
|
}
|
|
323
334
|
try {
|
|
324
|
-
// Simplified fast processing - just apply a learned mask pattern
|
|
325
|
-
// This is much faster than full LSTM inference
|
|
326
335
|
const output = new Float32Array(inputBuffer.length);
|
|
327
|
-
//
|
|
328
|
-
const windowSize =
|
|
329
|
-
|
|
336
|
+
// Use smaller windows for better voice quality
|
|
337
|
+
const windowSize = 128;
|
|
338
|
+
const overlapFactor = 0.5;
|
|
339
|
+
const hopSize = Math.floor(windowSize * (1 - overlapFactor));
|
|
340
|
+
// Apply gentle noise reduction that preserves voice
|
|
341
|
+
for (let i = 0; i < inputBuffer.length; i += hopSize) {
|
|
330
342
|
const end = Math.min(i + windowSize, inputBuffer.length);
|
|
331
343
|
const window = inputBuffer.slice(i, end);
|
|
332
|
-
// Calculate energy
|
|
344
|
+
// Calculate RMS energy
|
|
333
345
|
let energy = 0;
|
|
334
346
|
for (let j = 0; j < window.length; j++) {
|
|
335
347
|
energy += window[j] * window[j];
|
|
336
348
|
}
|
|
337
|
-
|
|
338
|
-
//
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
349
|
+
const rms = Math.sqrt(energy / window.length);
|
|
350
|
+
// Voice-optimized noise gate
|
|
351
|
+
// Lower threshold to preserve quiet speech
|
|
352
|
+
// Softer transition to avoid artifacts
|
|
353
|
+
const threshold = 0.005; // More sensitive for voice
|
|
354
|
+
const ratio = 0.5; // Gentler reduction
|
|
355
|
+
let gain;
|
|
356
|
+
if (rms > threshold * 2) {
|
|
357
|
+
// Clear voice - pass through
|
|
358
|
+
gain = 1.0;
|
|
359
|
+
}
|
|
360
|
+
else if (rms > threshold) {
|
|
361
|
+
// Transition zone - smooth interpolation
|
|
362
|
+
const t = (rms - threshold) / threshold;
|
|
363
|
+
gain = 0.7 + (0.3 * t); // 0.7 to 1.0
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
// Likely noise - reduce gently
|
|
367
|
+
gain = 0.7; // Much less aggressive than before (was 0.3)
|
|
368
|
+
}
|
|
369
|
+
// Apply gain with smoothing to reduce artifacts
|
|
370
|
+
for (let j = i; j < end && j < inputBuffer.length; j++) {
|
|
371
|
+
// Blend with previous sample for smoothness
|
|
372
|
+
const blendFactor = (j - i) / windowSize;
|
|
373
|
+
const smoothGain = output[j - 1] !== undefined
|
|
374
|
+
? gain * blendFactor + (1 - blendFactor) * (output[j - 1] / (inputBuffer[j - 1] || 1))
|
|
375
|
+
: gain;
|
|
376
|
+
output[j] = inputBuffer[j] * smoothGain;
|
|
343
377
|
}
|
|
344
378
|
}
|
|
345
379
|
return output;
|
|
@@ -379,6 +413,10 @@ class MLNoiseSuppressor {
|
|
|
379
413
|
this.isProcessing = false;
|
|
380
414
|
this.processingQueue = [];
|
|
381
415
|
this.outputQueue = [];
|
|
416
|
+
if (this.highPassFilter) {
|
|
417
|
+
this.highPassFilter.disconnect();
|
|
418
|
+
this.highPassFilter = null;
|
|
419
|
+
}
|
|
382
420
|
if (this.model) {
|
|
383
421
|
this.model.dispose();
|
|
384
422
|
this.model = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newgameplusinc/odyssey-audio-video-sdk-dev",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.53",
|
|
4
4
|
"description": "Odyssey Spatial Audio & Video SDK using MediaSoup for real-time communication with AI-powered noise suppression",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|