@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.25 → 1.0.26
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/README.md +6 -0
- package/dist/SpatialAudioManager.d.ts +4 -0
- package/dist/SpatialAudioManager.js +35 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,8 @@ sdk.setListenerFromLSD(listenerPos, cameraPos, lookAtPos);
|
|
|
83
83
|
|
|
84
84
|
#### Noise-Cancellation Stack (What’s Included)
|
|
85
85
|
1. **Adaptive denoiser worklet** – learns each participant’s noise floor in real time, then applies a multi-band downward expander plus dynamic low/high-pass shaping.
|
|
86
|
+
- `speechBoost` lifts the low/mid band only when speech confidence is high, keeping consonants bright without reintroducing floor noise.
|
|
87
|
+
- `highBandGate` + `highBandAttack/Release` clamp constant fan hiss in the 4–12 kHz band whenever speechPresence is low, so background whoosh never leaks through live mics.
|
|
86
88
|
2. **Optional voice enhancement** – autocorrelation-derived confidence (inspired by the tuner article) can raise the reduction floor when speech is present to keep vocals bright.
|
|
87
89
|
3. **Silence gate** – if energy stays below `silenceFloor` for a configurable hold window, the track ramps to true silence, then wakes instantly once voice energy returns.
|
|
88
90
|
4. **Classic filters** – fixed high-pass/low-pass filters shave off rumble and hiss before signals reach the HRTF panner.
|
|
@@ -101,6 +103,10 @@ These layers run entirely in Web Audio, so you can ship “AirPods-style” back
|
|
|
101
103
|
silenceFloor: 0.00075,
|
|
102
104
|
silenceHoldMs: 520,
|
|
103
105
|
silenceReleaseMs: 160,
|
|
106
|
+
speechBoost: 0.35,
|
|
107
|
+
highBandGate: 0.7,
|
|
108
|
+
highBandAttack: 0.25,
|
|
109
|
+
highBandRelease: 0.12,
|
|
104
110
|
},
|
|
105
111
|
});
|
|
106
112
|
```
|
|
@@ -23,6 +23,10 @@ type DenoiserOptions = {
|
|
|
23
23
|
silenceFloor?: number;
|
|
24
24
|
silenceHoldMs?: number;
|
|
25
25
|
silenceReleaseMs?: number;
|
|
26
|
+
speechBoost?: number;
|
|
27
|
+
highBandGate?: number;
|
|
28
|
+
highBandAttack?: number;
|
|
29
|
+
highBandRelease?: number;
|
|
26
30
|
};
|
|
27
31
|
export type SpatialAudioOptions = {
|
|
28
32
|
distance?: SpatialAudioDistanceConfig;
|
|
@@ -94,6 +94,10 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
94
94
|
silenceFloor: this.options.denoiser?.silenceFloor,
|
|
95
95
|
silenceHoldMs: this.options.denoiser?.silenceHoldMs,
|
|
96
96
|
silenceReleaseMs: this.options.denoiser?.silenceReleaseMs,
|
|
97
|
+
speechBoost: this.options.denoiser?.speechBoost,
|
|
98
|
+
highBandGate: this.options.denoiser?.highBandGate,
|
|
99
|
+
highBandAttack: this.options.denoiser?.highBandAttack,
|
|
100
|
+
highBandRelease: this.options.denoiser?.highBandRelease,
|
|
97
101
|
},
|
|
98
102
|
});
|
|
99
103
|
}
|
|
@@ -603,6 +607,10 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
603
607
|
this.voiceBoost = this._sanitize(cfg.voiceBoost, 0, 1, 0.6);
|
|
604
608
|
this.voiceSensitivity = this._sanitize(cfg.voiceSensitivity, 0.05, 0.9, 0.35);
|
|
605
609
|
this.voiceEnhancement = cfg.voiceEnhancement === true;
|
|
610
|
+
this.speechBoost = this._sanitize(cfg.speechBoost, 0, 1.5, 0.35);
|
|
611
|
+
this.highBandGate = this._sanitize(cfg.highBandGate, 0, 1, 0.7);
|
|
612
|
+
this.highBandAttack = this._sanitize(cfg.highBandAttack, 0.01, 1, 0.25);
|
|
613
|
+
this.highBandRelease = this._sanitize(cfg.highBandRelease, 0.01, 1, 0.12);
|
|
606
614
|
this.silenceFloor = this._sanitize(cfg.silenceFloor, 0.0002, 0.02, 0.00085);
|
|
607
615
|
this.gateGraceSamples = Math.round(sampleRate * 0.45);
|
|
608
616
|
this.postSpeechHoldSamples = Math.round(sampleRate * 0.35);
|
|
@@ -649,6 +657,8 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
649
657
|
muteGain: 1,
|
|
650
658
|
graceSamplesRemaining: this.gateGraceSamples,
|
|
651
659
|
postSpeechHold: 0,
|
|
660
|
+
highBandEnv: this.silenceFloor,
|
|
661
|
+
broadbandEnv: this.silenceFloor,
|
|
652
662
|
};
|
|
653
663
|
}
|
|
654
664
|
return this.channelState[index];
|
|
@@ -820,13 +830,27 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
820
830
|
let processed = sample * state.gain;
|
|
821
831
|
|
|
822
832
|
state.lpState = this.hfAlpha * state.lpState + (1 - this.hfAlpha) * processed;
|
|
823
|
-
const
|
|
833
|
+
const lowComponent = state.lpState;
|
|
834
|
+
const highComponent = processed - lowComponent;
|
|
835
|
+
|
|
836
|
+
// Track broadband/high-band envelopes for multi-band gating
|
|
837
|
+
state.broadbandEnv += (Math.abs(processed) - state.broadbandEnv) * 0.12;
|
|
838
|
+
const highEnvDelta = Math.abs(highComponent) - state.highBandEnv;
|
|
839
|
+
const highEnvCoef = highEnvDelta > 0 ? this.highBandAttack : this.highBandRelease;
|
|
840
|
+
state.highBandEnv += highEnvDelta * highEnvCoef;
|
|
841
|
+
|
|
824
842
|
const hissRatio = Math.min(
|
|
825
843
|
1,
|
|
826
|
-
Math.abs(highComponent) / (Math.abs(
|
|
844
|
+
Math.abs(highComponent) / (Math.abs(lowComponent) + 1e-5)
|
|
827
845
|
);
|
|
828
846
|
const hissGain = 1 - hissRatio * (this.hissCut * (1 - 0.4 * speechPresence));
|
|
829
|
-
|
|
847
|
+
|
|
848
|
+
const highEnvRatio = state.highBandEnv / (state.broadbandEnv + 1e-5);
|
|
849
|
+
const gateAmount = this.highBandGate * Math.max(0, highEnvRatio - speechPresence * 0.5);
|
|
850
|
+
const gatedHigh = highComponent * hissGain * (1 - gateAmount);
|
|
851
|
+
|
|
852
|
+
const speechLift = 1 + this.speechBoost * speechPresence;
|
|
853
|
+
processed = lowComponent * speechLift + gatedHigh;
|
|
830
854
|
|
|
831
855
|
const muteTarget = state.isSilenced ? 0.05 : 1;
|
|
832
856
|
const smoothing = state.isSilenced ? 0.12 : 0.42;
|
|
@@ -885,6 +909,10 @@ registerProcessor('odyssey-denoise', OdysseyDenoiseProcessor);
|
|
|
885
909
|
silenceFloor: 0.00075,
|
|
886
910
|
silenceHoldMs: 520,
|
|
887
911
|
silenceReleaseMs: 160,
|
|
912
|
+
speechBoost: 0.35,
|
|
913
|
+
highBandGate: 0.7,
|
|
914
|
+
highBandAttack: 0.25,
|
|
915
|
+
highBandRelease: 0.12,
|
|
888
916
|
};
|
|
889
917
|
return {
|
|
890
918
|
distance: {
|
|
@@ -910,6 +938,10 @@ registerProcessor('odyssey-denoise', OdysseyDenoiseProcessor);
|
|
|
910
938
|
silenceFloor: options?.denoiser?.silenceFloor ?? denoiserDefaults.silenceFloor,
|
|
911
939
|
silenceHoldMs: options?.denoiser?.silenceHoldMs ?? denoiserDefaults.silenceHoldMs,
|
|
912
940
|
silenceReleaseMs: options?.denoiser?.silenceReleaseMs ?? denoiserDefaults.silenceReleaseMs,
|
|
941
|
+
speechBoost: options?.denoiser?.speechBoost ?? denoiserDefaults.speechBoost,
|
|
942
|
+
highBandGate: options?.denoiser?.highBandGate ?? denoiserDefaults.highBandGate,
|
|
943
|
+
highBandAttack: options?.denoiser?.highBandAttack ?? denoiserDefaults.highBandAttack,
|
|
944
|
+
highBandRelease: options?.denoiser?.highBandRelease ?? denoiserDefaults.highBandRelease,
|
|
913
945
|
},
|
|
914
946
|
};
|
|
915
947
|
}
|
package/package.json
CHANGED