@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.257 → 1.0.258
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/SpatialAudioManager.d.ts +1 -2
- package/dist/SpatialAudioManager.js +23 -48
- package/dist/index.js +2 -0
- package/package.json +1 -1
|
@@ -58,9 +58,8 @@ export declare class SpatialAudioManager extends EventManager {
|
|
|
58
58
|
private panCenterDeadZone;
|
|
59
59
|
private cachedSpeakerPositions;
|
|
60
60
|
private cachedListenerPosition;
|
|
61
|
+
private listenerPositionInitialized;
|
|
61
62
|
private positionSnapThreshold;
|
|
62
|
-
private cachedGainValues;
|
|
63
|
-
private gainChangeThreshold;
|
|
64
63
|
private _listenerDebugLogTime?;
|
|
65
64
|
private mlSuppressor;
|
|
66
65
|
private mlModelReady;
|
|
@@ -42,16 +42,11 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
42
42
|
this.cachedSpeakerPositions = new Map();
|
|
43
43
|
// Cache for last snapped listener position
|
|
44
44
|
this.cachedListenerPosition = { x: 0, y: 0, z: 0 };
|
|
45
|
+
// Track if listener position has been set at least once
|
|
46
|
+
this.listenerPositionInitialized = false;
|
|
45
47
|
// Minimum position change (in meters) to trigger recalculation
|
|
46
48
|
// 0.30m = 30cm - ignores pixel streaming jitter, physics wobble, breathing
|
|
47
|
-
// ALIGNED with server-side 100cm filter - this catches smaller jitter
|
|
48
49
|
this.positionSnapThreshold = 0.30;
|
|
49
|
-
// GAIN STABILIZATION: Prevents gain fluctuations when distance is stable
|
|
50
|
-
// Caches last calculated gain value for each participant
|
|
51
|
-
this.cachedGainValues = new Map();
|
|
52
|
-
// Minimum gain change (0-1 scale) to trigger update
|
|
53
|
-
// 0.05 = 5% change required - filters out tiny distance jitter
|
|
54
|
-
this.gainChangeThreshold = 0.05;
|
|
55
50
|
// NOTE: Rate limiting variables removed - setTargetAtTime provides sufficient smoothing
|
|
56
51
|
// The smoothPanValue() and position snapping handle jitter reduction
|
|
57
52
|
// ML Noise Suppressor (TensorFlow.js-based)
|
|
@@ -387,25 +382,20 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
387
382
|
// SNAP: Reduce jitter by ignoring micro-movements (<15cm)
|
|
388
383
|
const snappedSpeakerPos = this.snapPosition(normalizedBodyPosition, participantId);
|
|
389
384
|
const speakerHeadPosition = this.computeHeadPosition(snappedSpeakerPos);
|
|
390
|
-
//
|
|
391
|
-
const listenerPos = this.
|
|
385
|
+
// Use cached listener position if initialized, otherwise use current position
|
|
386
|
+
const listenerPos = this.listenerPositionInitialized
|
|
392
387
|
? this.cachedListenerPosition
|
|
393
388
|
: this.listenerPosition;
|
|
394
|
-
// DEBUG: Log positions for troubleshooting distance issues
|
|
395
|
-
const distX = speakerHeadPosition.x - listenerPos.x;
|
|
396
|
-
const distY = speakerHeadPosition.y - listenerPos.y;
|
|
397
|
-
const distZ = speakerHeadPosition.z - listenerPos.z;
|
|
398
389
|
// Step 2: Calculate 3D distance (Euclidean distance from datum-based positions)
|
|
399
390
|
// distance = √(Δx² + Δy² + Δz²)
|
|
400
391
|
const distance = this.getDistanceBetween(listenerPos, speakerHeadPosition);
|
|
401
|
-
//
|
|
402
|
-
|
|
403
|
-
const
|
|
404
|
-
if (
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
this.
|
|
408
|
-
return; // Skip all other processing
|
|
392
|
+
// DEBUG: Log distance and gain every 2 seconds
|
|
393
|
+
const now = Date.now();
|
|
394
|
+
const lastLog = this._spatialDebugTimes.get(participantId) || 0;
|
|
395
|
+
if (now - lastLog > 2000) {
|
|
396
|
+
this._spatialDebugTimes.set(participantId, now);
|
|
397
|
+
const calculatedGainDebug = this.calculateLogarithmicGain(distance);
|
|
398
|
+
console.log(`🔊 SPATIAL DEBUG [${participantId.substring(0, 8)}]: dist=${distance.toFixed(2)}m, gain=${calculatedGainDebug}%, listenerInit=${this.listenerPositionInitialized}, listener=(${listenerPos.x.toFixed(1)},${listenerPos.y.toFixed(1)},${listenerPos.z.toFixed(1)}), speaker=(${speakerHeadPosition.x.toFixed(1)},${speakerHeadPosition.y.toFixed(1)},${speakerHeadPosition.z.toFixed(1)})`);
|
|
409
399
|
}
|
|
410
400
|
// Step 3: Calculate relative vector (speaker relative to listener)
|
|
411
401
|
// vecToSource = speaker.pos - listener.pos
|
|
@@ -438,37 +428,22 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
438
428
|
const panning = this.panningFromPanValue(smoothedPanValue, dxLocal);
|
|
439
429
|
// Calculate gain based on distance
|
|
440
430
|
const calculatedGain = this.calculateLogarithmicGain(distance);
|
|
441
|
-
const
|
|
442
|
-
//
|
|
443
|
-
|
|
444
|
-
let finalGainValue = newGainValue;
|
|
445
|
-
if (cachedGain !== undefined) {
|
|
446
|
-
const gainChange = Math.abs(newGainValue - cachedGain);
|
|
447
|
-
if (gainChange < this.gainChangeThreshold) {
|
|
448
|
-
// Change too small - keep cached value for stability
|
|
449
|
-
finalGainValue = cachedGain;
|
|
450
|
-
}
|
|
451
|
-
else {
|
|
452
|
-
// Significant change - update cache
|
|
453
|
-
this.cachedGainValues.set(participantId, newGainValue);
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
else {
|
|
457
|
-
// First time - cache the value
|
|
458
|
-
this.cachedGainValues.set(participantId, newGainValue);
|
|
459
|
-
}
|
|
431
|
+
const gainValue = calculatedGain / 100; // Convert to 0-1 range
|
|
432
|
+
// DEBUG: Log RSD processing in SDK with ALL data for matching with Vue
|
|
433
|
+
console.log(`[SDK-RSD] id=${participantId.substring(0, 8)} | speakerPos=(${speakerHeadPosition.x.toFixed(1)},${speakerHeadPosition.y.toFixed(1)},${speakerHeadPosition.z.toFixed(1)}) | listenerPos=(${listenerPos.x.toFixed(1)},${listenerPos.y.toFixed(1)},${listenerPos.z.toFixed(1)}) | dist=${distance.toFixed(2)}m | gain=${(gainValue * 100).toFixed(0)}% | pan=${smoothedPanValue.toFixed(2)} (L:${panning.left.toFixed(0)}% R:${panning.right.toFixed(0)}%)`);
|
|
460
434
|
// Apply panning
|
|
461
435
|
this.applyStereoPanning(participantId, panning);
|
|
462
436
|
// Apply gain with Web Audio's built-in smoothing (setTargetAtTime)
|
|
437
|
+
// This provides all the smoothing needed - no additional caching required
|
|
463
438
|
const currentTime = this.audioContext.currentTime;
|
|
464
439
|
try {
|
|
465
440
|
// setTargetAtTime provides smooth exponential interpolation
|
|
466
441
|
// Time constant 0.1 = ~300ms to settle
|
|
467
|
-
nodes.gain.gain.setTargetAtTime(
|
|
442
|
+
nodes.gain.gain.setTargetAtTime(gainValue, currentTime, 0.1);
|
|
468
443
|
}
|
|
469
444
|
catch (err) {
|
|
470
445
|
// Fallback: If scheduling fails, set value directly (rare edge case)
|
|
471
|
-
nodes.gain.gain.value =
|
|
446
|
+
nodes.gain.gain.value = gainValue;
|
|
472
447
|
}
|
|
473
448
|
}
|
|
474
449
|
}
|
|
@@ -488,8 +463,6 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
488
463
|
// Smooth ramp to 0 (muted) or 1 (unmuted) - prevents click
|
|
489
464
|
// Time constant 0.05 = ~150ms to reach target (3 time constants)
|
|
490
465
|
nodes.gain.gain.setTargetAtTime(muted ? 0 : 1, this.audioContext.currentTime, 0.05);
|
|
491
|
-
// Update cached gain value when muting/unmuting
|
|
492
|
-
this.cachedGainValues.set(participantId, muted ? 0 : 1);
|
|
493
466
|
}
|
|
494
467
|
}
|
|
495
468
|
/**
|
|
@@ -532,6 +505,8 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
532
505
|
* @param rot Rotation data (pitch, yaw, roll) - stored but not used for panning
|
|
533
506
|
*/
|
|
534
507
|
setListenerFromLSD(listenerPos, cameraPos, lookAtPos, rot, localParticipantId) {
|
|
508
|
+
// DEBUG: Log LSD data received in SDK
|
|
509
|
+
console.log(`[SDK-LSD] cam=(${cameraPos.x.toFixed(1)},${cameraPos.y.toFixed(1)},${cameraPos.z.toFixed(1)}) rot=(${rot?.x?.toFixed(1)},${rot?.y?.toFixed(1)},${rot?.z?.toFixed(1)})`);
|
|
535
510
|
// Store local participant ID for logging
|
|
536
511
|
if (localParticipantId && !this.localParticipantId) {
|
|
537
512
|
this.localParticipantId = localParticipantId;
|
|
@@ -685,8 +660,6 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
685
660
|
this.participantNodes.delete(participantId);
|
|
686
661
|
// Clean up smoothed pan value tracking
|
|
687
662
|
this.smoothedPanValues.delete(participantId);
|
|
688
|
-
// Clean up cached gain values
|
|
689
|
-
this.cachedGainValues.delete(participantId);
|
|
690
663
|
// Clean up cached speaker position
|
|
691
664
|
this.cachedSpeakerPositions.delete(participantId);
|
|
692
665
|
}
|
|
@@ -780,10 +753,12 @@ class SpatialAudioManager extends EventManager_1.EventManager {
|
|
|
780
753
|
const cached = isListener
|
|
781
754
|
? this.cachedListenerPosition
|
|
782
755
|
: this.cachedSpeakerPositions.get(participantId);
|
|
783
|
-
// If no cached position, use this one as the baseline
|
|
784
|
-
|
|
756
|
+
// If no cached position or first time, use this one as the baseline
|
|
757
|
+
const isFirstTime = !cached || (!this.listenerPositionInitialized && isListener);
|
|
758
|
+
if (isFirstTime) {
|
|
785
759
|
if (isListener) {
|
|
786
760
|
this.cachedListenerPosition = { ...position };
|
|
761
|
+
this.listenerPositionInitialized = true;
|
|
787
762
|
}
|
|
788
763
|
else {
|
|
789
764
|
this.cachedSpeakerPositions.set(participantId, { ...position });
|
package/dist/index.js
CHANGED
|
@@ -436,6 +436,8 @@ class OdysseySpatialComms extends EventManager_1.EventManager {
|
|
|
436
436
|
}
|
|
437
437
|
});
|
|
438
438
|
this.socket.on("participant-position-updated", (data) => {
|
|
439
|
+
// DEBUG: Log position update received from socket
|
|
440
|
+
console.log(`[SDK-SOCKET] id=${data.participantId.substring(0, 8)} pos=(${data.position.x.toFixed(1)},${data.position.y.toFixed(1)},${data.position.z.toFixed(1)}) rot=(${data.rot?.x?.toFixed(1)},${data.rot?.y?.toFixed(1)},${data.rot?.z?.toFixed(1)})`);
|
|
439
441
|
const participant = this.room?.participants.get(data.participantId);
|
|
440
442
|
if (participant) {
|
|
441
443
|
participant.position = data.position;
|
package/package.json
CHANGED