@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.22 → 1.0.24
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 +11 -11
- package/dist/SpatialAudioManager.js +44 -31
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -84,27 +84,27 @@ sdk.setListenerFromLSD(listenerPos, cameraPos, lookAtPos);
|
|
|
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
86
|
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
|
-
3. **Silence gate** – if energy stays below `silenceFloor` for a configurable hold window, the track ramps to true silence,
|
|
87
|
+
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
88
|
4. **Classic filters** – fixed high-pass/low-pass filters shave off rumble and hiss before signals reach the HRTF panner.
|
|
89
89
|
|
|
90
90
|
These layers run entirely in Web Audio, so you can ship “AirPods-style” background rejection in any browser without native code.
|
|
91
91
|
```ts
|
|
92
92
|
const sdk = new OdysseySpatialComms(serverUrl, {
|
|
93
93
|
denoiser: {
|
|
94
|
-
threshold: 0.
|
|
95
|
-
maxReduction: 0.
|
|
96
|
-
hissCut: 0.
|
|
97
|
-
holdMs:
|
|
98
|
-
voiceBoost: 0.
|
|
99
|
-
voiceSensitivity: 0.
|
|
94
|
+
threshold: 0.0085,
|
|
95
|
+
maxReduction: 0.9,
|
|
96
|
+
hissCut: 0.55,
|
|
97
|
+
holdMs: 230,
|
|
98
|
+
voiceBoost: 0.65,
|
|
99
|
+
voiceSensitivity: 0.33,
|
|
100
100
|
voiceEnhancement: true,
|
|
101
|
-
silenceFloor: 0.
|
|
102
|
-
silenceHoldMs:
|
|
103
|
-
silenceReleaseMs:
|
|
101
|
+
silenceFloor: 0.0008,
|
|
102
|
+
silenceHoldMs: 480,
|
|
103
|
+
silenceReleaseMs: 180,
|
|
104
104
|
},
|
|
105
105
|
});
|
|
106
106
|
```
|
|
107
|
-
Voice enhancement (autocorrelation-based speech detection) is **off by default** to keep the gate extra quiet; enable it when you want brighter close-talk voicing.
|
|
107
|
+
Voice enhancement (autocorrelation-based speech detection) is **off by default** to keep the gate extra quiet; enable it when you want brighter close-talk voicing. Tweak `silenceFloor` / `silenceHoldMs` if you need either more aggressive hiss removal or softer gating.
|
|
108
108
|
|
|
109
109
|
#### How Spatial Audio Is Built
|
|
110
110
|
1. **Telemetry ingestion** – each LSD packet is passed through `setListenerFromLSD(listenerPos, cameraPos, lookAtPos)` so the Web Audio listener matches the player’s real head/camera pose.
|
|
@@ -603,11 +603,12 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
603
603
|
this.voiceBoost = this._sanitize(cfg.voiceBoost, 0, 1, 0.6);
|
|
604
604
|
this.voiceSensitivity = this._sanitize(cfg.voiceSensitivity, 0.05, 0.9, 0.35);
|
|
605
605
|
this.voiceEnhancement = cfg.voiceEnhancement === true;
|
|
606
|
-
this.silenceFloor = this._sanitize(cfg.silenceFloor, 0.0002, 0.02, 0.
|
|
606
|
+
this.silenceFloor = this._sanitize(cfg.silenceFloor, 0.0002, 0.02, 0.00085);
|
|
607
|
+
this.gateGraceSamples = Math.round(sampleRate * 0.45);
|
|
607
608
|
this.silenceHoldSamples = Math.max(
|
|
608
609
|
8,
|
|
609
610
|
Math.round(
|
|
610
|
-
sampleRate * this._sanitize(cfg.silenceHoldMs, 40, 1200,
|
|
611
|
+
sampleRate * this._sanitize(cfg.silenceHoldMs, 40, 1200, 320) / 1000
|
|
611
612
|
)
|
|
612
613
|
);
|
|
613
614
|
this.silenceReleaseSamples = Math.max(
|
|
@@ -645,6 +646,7 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
645
646
|
silenceReleaseCounter: 0,
|
|
646
647
|
isSilenced: false,
|
|
647
648
|
muteGain: 1,
|
|
649
|
+
graceSamplesRemaining: this.gateGraceSamples,
|
|
648
650
|
};
|
|
649
651
|
}
|
|
650
652
|
return this.channelState[index];
|
|
@@ -748,27 +750,38 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
748
750
|
state.quietSamples = 0;
|
|
749
751
|
}
|
|
750
752
|
|
|
751
|
-
if (state.
|
|
752
|
-
state.
|
|
753
|
+
if (state.graceSamplesRemaining > 0) {
|
|
754
|
+
state.graceSamplesRemaining--;
|
|
755
|
+
state.isSilenced = false;
|
|
756
|
+
state.silenceSamples = 0;
|
|
757
|
+
state.silenceReleaseCounter = 0;
|
|
753
758
|
} else {
|
|
754
|
-
|
|
755
|
-
|
|
759
|
+
const belowFloor = state.envelope < this.silenceFloor;
|
|
760
|
+
if (belowFloor && speechPresence < 0.25) {
|
|
761
|
+
state.silenceSamples++;
|
|
762
|
+
} else {
|
|
763
|
+
state.silenceSamples = Math.max(0, state.silenceSamples - 3);
|
|
764
|
+
}
|
|
756
765
|
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
766
|
+
if (!state.isSilenced && state.silenceSamples > this.silenceHoldSamples) {
|
|
767
|
+
state.isSilenced = true;
|
|
768
|
+
state.silenceReleaseCounter = 0;
|
|
769
|
+
}
|
|
761
770
|
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
) {
|
|
767
|
-
state.silenceReleaseCounter++;
|
|
768
|
-
if (state.silenceReleaseCounter > this.silenceReleaseSamples) {
|
|
771
|
+
if (state.isSilenced) {
|
|
772
|
+
const wakeFromEnergy = state.envelope > this.silenceFloor * 1.25;
|
|
773
|
+
const wakeFromVoice = speechPresence > 0.2;
|
|
774
|
+
if (wakeFromEnergy || wakeFromVoice) {
|
|
769
775
|
state.isSilenced = false;
|
|
770
776
|
state.silenceSamples = 0;
|
|
771
777
|
state.silenceReleaseCounter = 0;
|
|
778
|
+
} else {
|
|
779
|
+
state.silenceReleaseCounter++;
|
|
780
|
+
if (state.silenceReleaseCounter > this.silenceReleaseSamples) {
|
|
781
|
+
state.isSilenced = false;
|
|
782
|
+
state.silenceSamples = 0;
|
|
783
|
+
state.silenceReleaseCounter = 0;
|
|
784
|
+
}
|
|
772
785
|
}
|
|
773
786
|
} else {
|
|
774
787
|
state.silenceReleaseCounter = 0;
|
|
@@ -805,7 +818,7 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
805
818
|
processed = state.lpState + highComponent * hissGain;
|
|
806
819
|
|
|
807
820
|
const muteTarget = state.isSilenced ? 0 : 1;
|
|
808
|
-
state.muteGain += (muteTarget - state.muteGain) * 0.
|
|
821
|
+
state.muteGain += (muteTarget - state.muteGain) * 0.18;
|
|
809
822
|
processed *= state.muteGain;
|
|
810
823
|
|
|
811
824
|
outChannel[i] = processed;
|
|
@@ -845,21 +858,21 @@ registerProcessor('odyssey-denoise', OdysseyDenoiseProcessor);
|
|
|
845
858
|
};
|
|
846
859
|
const denoiserDefaults = {
|
|
847
860
|
enabled: true,
|
|
848
|
-
threshold: 0.
|
|
849
|
-
noiseFloor: 0.
|
|
850
|
-
release: 0.
|
|
851
|
-
attack: 0.
|
|
852
|
-
holdMs:
|
|
853
|
-
maxReduction: 0.
|
|
854
|
-
hissCut: 0.
|
|
855
|
-
expansionRatio: 2.
|
|
861
|
+
threshold: 0.0085,
|
|
862
|
+
noiseFloor: 0.0023,
|
|
863
|
+
release: 0.24,
|
|
864
|
+
attack: 0.34,
|
|
865
|
+
holdMs: 230,
|
|
866
|
+
maxReduction: 0.9,
|
|
867
|
+
hissCut: 0.55,
|
|
868
|
+
expansionRatio: 2.2,
|
|
856
869
|
learnRate: 0.05,
|
|
857
|
-
voiceBoost: 0.
|
|
858
|
-
voiceSensitivity: 0.
|
|
870
|
+
voiceBoost: 0.65,
|
|
871
|
+
voiceSensitivity: 0.33,
|
|
859
872
|
voiceEnhancement: false,
|
|
860
|
-
silenceFloor: 0.
|
|
861
|
-
silenceHoldMs:
|
|
862
|
-
silenceReleaseMs:
|
|
873
|
+
silenceFloor: 0.0008,
|
|
874
|
+
silenceHoldMs: 480,
|
|
875
|
+
silenceReleaseMs: 180,
|
|
863
876
|
};
|
|
864
877
|
return {
|
|
865
878
|
distance: {
|
package/package.json
CHANGED