@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.258 → 1.0.260

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.
Files changed (83) hide show
  1. package/README.md +45 -1
  2. package/dist/audio/AudioNodeFactory.d.ts +130 -0
  3. package/dist/audio/AudioNodeFactory.js +158 -0
  4. package/dist/audio/AudioPipeline.d.ts +89 -0
  5. package/dist/audio/AudioPipeline.js +138 -0
  6. package/dist/{MLNoiseSuppressor.d.ts → audio/MLNoiseSuppressor.d.ts} +7 -7
  7. package/dist/{MLNoiseSuppressor.js → audio/MLNoiseSuppressor.js} +19 -52
  8. package/dist/audio/index.d.ts +6 -0
  9. package/dist/audio/index.js +22 -0
  10. package/dist/channels/huddle/HuddleChannel.d.ts +87 -0
  11. package/dist/channels/huddle/HuddleChannel.js +152 -0
  12. package/dist/channels/huddle/HuddleTypes.d.ts +85 -0
  13. package/dist/channels/huddle/HuddleTypes.js +25 -0
  14. package/dist/channels/huddle/index.d.ts +5 -0
  15. package/dist/channels/huddle/index.js +21 -0
  16. package/dist/channels/index.d.ts +5 -0
  17. package/dist/channels/index.js +21 -0
  18. package/dist/channels/spatial/SpatialAudioChannel.d.ts +144 -0
  19. package/dist/channels/spatial/SpatialAudioChannel.js +476 -0
  20. package/dist/channels/spatial/SpatialAudioTypes.d.ts +85 -0
  21. package/dist/channels/spatial/SpatialAudioTypes.js +42 -0
  22. package/dist/channels/spatial/index.d.ts +5 -0
  23. package/dist/channels/spatial/index.js +21 -0
  24. package/dist/{EventManager.d.ts → core/EventManager.d.ts} +4 -2
  25. package/dist/{EventManager.js → core/EventManager.js} +5 -3
  26. package/dist/{MediasoupManager.d.ts → core/MediasoupManager.d.ts} +10 -4
  27. package/dist/{MediasoupManager.js → core/MediasoupManager.js} +56 -44
  28. package/dist/core/index.d.ts +5 -0
  29. package/dist/core/index.js +21 -0
  30. package/dist/index.d.ts +2 -2
  31. package/dist/index.js +43 -9
  32. package/dist/sdk/index.d.ts +36 -0
  33. package/dist/sdk/index.js +121 -0
  34. package/dist/types/events.d.ts +154 -0
  35. package/dist/{types.js → types/events.js} +3 -0
  36. package/dist/types/index.d.ts +7 -0
  37. package/dist/types/index.js +23 -0
  38. package/dist/types/participant.d.ts +65 -0
  39. package/dist/types/participant.js +5 -0
  40. package/dist/types/position.d.ts +47 -0
  41. package/dist/types/position.js +9 -0
  42. package/dist/types/room.d.ts +82 -0
  43. package/dist/types/room.js +5 -0
  44. package/dist/utils/audio/clarity-score.d.ts +33 -0
  45. package/dist/utils/audio/clarity-score.js +81 -0
  46. package/dist/utils/audio/index.d.ts +5 -0
  47. package/dist/utils/audio/index.js +21 -0
  48. package/dist/utils/audio/voice-filter.d.ts +30 -0
  49. package/dist/utils/audio/voice-filter.js +70 -0
  50. package/dist/utils/index.d.ts +7 -0
  51. package/dist/utils/index.js +23 -0
  52. package/dist/utils/position/coordinates.d.ts +37 -0
  53. package/dist/utils/position/coordinates.js +61 -0
  54. package/dist/utils/position/index.d.ts +6 -0
  55. package/dist/utils/position/index.js +22 -0
  56. package/dist/utils/position/normalize.d.ts +37 -0
  57. package/dist/utils/position/normalize.js +78 -0
  58. package/dist/utils/position/snap.d.ts +51 -0
  59. package/dist/utils/position/snap.js +81 -0
  60. package/dist/utils/smoothing/gain-smoothing.d.ts +45 -0
  61. package/dist/utils/smoothing/gain-smoothing.js +77 -0
  62. package/dist/utils/smoothing/index.d.ts +5 -0
  63. package/dist/utils/smoothing/index.js +21 -0
  64. package/dist/utils/smoothing/pan-smoothing.d.ts +43 -0
  65. package/dist/utils/smoothing/pan-smoothing.js +85 -0
  66. package/dist/utils/spatial/angle-calc.d.ts +24 -0
  67. package/dist/utils/spatial/angle-calc.js +69 -0
  68. package/dist/utils/spatial/distance-calc.d.ts +33 -0
  69. package/dist/utils/spatial/distance-calc.js +48 -0
  70. package/dist/utils/spatial/gain-calc.d.ts +37 -0
  71. package/dist/utils/spatial/gain-calc.js +52 -0
  72. package/dist/utils/spatial/head-position.d.ts +32 -0
  73. package/dist/utils/spatial/head-position.js +76 -0
  74. package/dist/utils/spatial/index.d.ts +9 -0
  75. package/dist/utils/spatial/index.js +25 -0
  76. package/dist/utils/spatial/listener-calc.d.ts +28 -0
  77. package/dist/utils/spatial/listener-calc.js +74 -0
  78. package/dist/utils/spatial/pan-calc.d.ts +48 -0
  79. package/dist/utils/spatial/pan-calc.js +80 -0
  80. package/package.json +1 -1
  81. package/dist/SpatialAudioManager.d.ts +0 -271
  82. package/dist/SpatialAudioManager.js +0 -1512
  83. package/dist/types.d.ts +0 -73
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Pan Calculations
3
+ *
4
+ * Functions for calculating stereo panning based on listener/source positions
5
+ */
6
+ import { Position, ListenerRight } from '../../types/position';
7
+ /**
8
+ * Panning values for left/right channels
9
+ */
10
+ export interface Panning {
11
+ left: number;
12
+ right: number;
13
+ }
14
+ /**
15
+ * Calculate listener's right-ear vector from yaw rotation
16
+ *
17
+ * COORDINATE SYSTEM: X=right, Y=up, Z=forward (datum at 0,0,0)
18
+ *
19
+ * Rotation convention (right-hand rule around Y-axis):
20
+ * yaw = 0° → facing +Z (forward), right ear points to +X
21
+ * yaw = 90° → facing +X (right), right ear points to -Z
22
+ * yaw = 180° → facing -Z (backward), right ear points to -X
23
+ * yaw = 270° → facing -X (left), right ear points to +Z
24
+ *
25
+ * @param yawDegrees Yaw rotation in degrees
26
+ * @returns Unit vector pointing to listener's right ear
27
+ */
28
+ export declare function calculateListenerRight(yawDegrees: number): ListenerRight;
29
+ /**
30
+ * Calculate pan value from listener and source positions
31
+ *
32
+ * Uses dot product projection onto listener's right-ear axis:
33
+ * dxLocal = vecToSource · listenerRight
34
+ *
35
+ * @param listenerPos Listener position
36
+ * @param sourcePos Sound source position
37
+ * @param listenerRight Listener's right-ear unit vector
38
+ * @returns Pan value from -1 (full left) to +1 (full right)
39
+ */
40
+ export declare function calculatePanFromPositions(listenerPos: Position, sourcePos: Position, listenerRight: ListenerRight): number;
41
+ /**
42
+ * Convert pan value (-1 to +1) to left/right channel percentages
43
+ *
44
+ * @param pan Pan value from -1 (full left) to +1 (full right)
45
+ * @param dxLocal Optional dxLocal value (unused, for compatibility)
46
+ * @returns Panning percentages for left and right channels
47
+ */
48
+ export declare function panValueToPanning(pan: number, dxLocal?: number): Panning;
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ /**
3
+ * Pan Calculations
4
+ *
5
+ * Functions for calculating stereo panning based on listener/source positions
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.calculateListenerRight = calculateListenerRight;
9
+ exports.calculatePanFromPositions = calculatePanFromPositions;
10
+ exports.panValueToPanning = panValueToPanning;
11
+ /**
12
+ * Calculate listener's right-ear vector from yaw rotation
13
+ *
14
+ * COORDINATE SYSTEM: X=right, Y=up, Z=forward (datum at 0,0,0)
15
+ *
16
+ * Rotation convention (right-hand rule around Y-axis):
17
+ * yaw = 0° → facing +Z (forward), right ear points to +X
18
+ * yaw = 90° → facing +X (right), right ear points to -Z
19
+ * yaw = 180° → facing -Z (backward), right ear points to -X
20
+ * yaw = 270° → facing -X (left), right ear points to +Z
21
+ *
22
+ * @param yawDegrees Yaw rotation in degrees
23
+ * @returns Unit vector pointing to listener's right ear
24
+ */
25
+ function calculateListenerRight(yawDegrees) {
26
+ const yawRad = (yawDegrees * Math.PI) / 180;
27
+ // Right ear vector - CLOCKWISE rotation (standard game engine convention)
28
+ return {
29
+ x: Math.cos(yawRad),
30
+ z: -Math.sin(yawRad), // NEGATIVE for clockwise rotation
31
+ };
32
+ }
33
+ /**
34
+ * Calculate pan value from listener and source positions
35
+ *
36
+ * Uses dot product projection onto listener's right-ear axis:
37
+ * dxLocal = vecToSource · listenerRight
38
+ *
39
+ * @param listenerPos Listener position
40
+ * @param sourcePos Sound source position
41
+ * @param listenerRight Listener's right-ear unit vector
42
+ * @returns Pan value from -1 (full left) to +1 (full right)
43
+ */
44
+ function calculatePanFromPositions(listenerPos, sourcePos, listenerRight) {
45
+ // Calculate relative vector (speaker relative to listener)
46
+ const vecToSource = {
47
+ x: sourcePos.x - listenerPos.x,
48
+ z: sourcePos.z - listenerPos.z,
49
+ };
50
+ // Project onto listener's right-ear axis using dot product
51
+ // Positive = sound is to the RIGHT of listener
52
+ // Negative = sound is to the LEFT of listener
53
+ const dxLocal = vecToSource.x * listenerRight.x + vecToSource.z * listenerRight.z;
54
+ // Calculate dzLocal (forward/back component)
55
+ // For CLOCKWISE rotation: Forward = right rotated 90° CW: (x,z) -> (-z,x)
56
+ const listenerForward = { x: -listenerRight.z, z: listenerRight.x };
57
+ const dzLocal = vecToSource.x * listenerForward.x + vecToSource.z * listenerForward.z;
58
+ // TRUE 360° SPATIAL AUDIO PANNING
59
+ // Calculate angle from listener to source using atan2
60
+ const angleToSource = Math.atan2(dxLocal, dzLocal); // Radians: -π to +π
61
+ const rawPanValue = Math.sin(angleToSource); // -1 to +1
62
+ return rawPanValue;
63
+ }
64
+ /**
65
+ * Convert pan value (-1 to +1) to left/right channel percentages
66
+ *
67
+ * @param pan Pan value from -1 (full left) to +1 (full right)
68
+ * @param dxLocal Optional dxLocal value (unused, for compatibility)
69
+ * @returns Panning percentages for left and right channels
70
+ */
71
+ function panValueToPanning(pan, dxLocal) {
72
+ const clamped = Math.max(-1, Math.min(1, pan));
73
+ // Map pan to asymmetric gains while keeping center at 100/100
74
+ const left = 100 * (1 - Math.max(0, clamped));
75
+ const right = 100 * (1 + Math.min(0, clamped));
76
+ return {
77
+ left: Math.max(0, Math.min(100, left)),
78
+ right: Math.max(0, Math.min(100, right)),
79
+ };
80
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newgameplusinc/odyssey-audio-video-sdk-dev",
3
- "version": "1.0.258",
3
+ "version": "1.0.260",
4
4
  "description": "Odyssey Spatial Audio & Video SDK using MediaSoup for real-time communication",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -1,271 +0,0 @@
1
- import { EventManager } from "./EventManager";
2
- import { Position } from "./types";
3
- type SpatialAudioDistanceConfig = {
4
- refDistance?: number;
5
- maxDistance?: number;
6
- rolloffFactor?: number;
7
- unit?: "auto" | "meters" | "centimeters";
8
- };
9
- type DenoiserOptions = {
10
- enabled?: boolean;
11
- threshold?: number;
12
- noiseFloor?: number;
13
- release?: number;
14
- attack?: number;
15
- holdMs?: number;
16
- maxReduction?: number;
17
- hissCut?: number;
18
- expansionRatio?: number;
19
- learnRate?: number;
20
- voiceBoost?: number;
21
- voiceSensitivity?: number;
22
- voiceEnhancement?: boolean;
23
- silenceFloor?: number;
24
- silenceHoldMs?: number;
25
- silenceReleaseMs?: number;
26
- speechBoost?: number;
27
- highBandGate?: number;
28
- highBandAttack?: number;
29
- highBandRelease?: number;
30
- };
31
- export type SpatialAudioOptions = {
32
- distance?: SpatialAudioDistanceConfig;
33
- denoiser?: DenoiserOptions;
34
- };
35
- export declare class SpatialAudioManager extends EventManager {
36
- private static readonly BUILD_STAMP;
37
- private audioContext;
38
- private participantNodes;
39
- private masterGainNode;
40
- private monitoringIntervals;
41
- private compressor;
42
- private options;
43
- private denoiseWorkletReady;
44
- private denoiseWorkletUrl?;
45
- private listenerPosition;
46
- private listenerInitialized;
47
- private listenerDirection;
48
- private listenerRight;
49
- private lastLogTime?;
50
- private localParticipantId;
51
- private isMasterMuted;
52
- private smoothedPanValues;
53
- private lastPanValue;
54
- private lastSpatialUpdateTime;
55
- private _spatialDebugTimes;
56
- private panSmoothingFactor;
57
- private panChangeThreshold;
58
- private panCenterDeadZone;
59
- private cachedSpeakerPositions;
60
- private cachedListenerPosition;
61
- private listenerPositionInitialized;
62
- private positionSnapThreshold;
63
- private _listenerDebugLogTime?;
64
- private mlSuppressor;
65
- private mlModelReady;
66
- constructor(options?: SpatialAudioOptions);
67
- getAudioContext(): AudioContext;
68
- /**
69
- * Initialize ML-based noise suppression (TensorFlow.js)
70
- * Falls back to AudioWorklet denoiser if ML initialization fails
71
- */
72
- initializeMLNoiseSuppression(modelUrl: string): Promise<void>;
73
- /**
74
- * Get current noise suppression mode
75
- */
76
- getNoiseSuppressionMode(): 'ml' | 'audioworklet' | 'none';
77
- /**
78
- * True if the TFJS model assets were loaded and the model is ready.
79
- * This does NOT mean it is currently processing the live WebAudio stream.
80
- */
81
- isMLModelLoaded(): boolean;
82
- /**
83
- * Setup spatial audio for a participant
84
- *
85
- * CRITICAL: Each participant gets their OWN audio processing chain:
86
- * Stream -> Source -> Panner -> Analyser -> Gain -> Compressor -> Output
87
- *
88
- * This ensures:
89
- * - Each voice is positioned independently in 3D space
90
- * - No server-side mixing required
91
- * - Scalable to unlimited participants (browser handles the mixing)
92
- *
93
- * @param participantId Unique ID for this participant
94
- * @param track Audio track from MediaSoup consumer
95
- * @param bypassSpatialization For testing - bypasses 3D positioning
96
- */
97
- setupSpatialAudioForParticipant(participantId: string, track: MediaStreamTrack, bypassSpatialization?: boolean): Promise<void>;
98
- private startMonitoring;
99
- /**
100
- * Toggle spatialization for a participant (for huddle/spatial switching)
101
- * @param participantId The participant to update
102
- * @param enableSpatialization True for spatial audio, false for non-spatial (huddle)
103
- */
104
- setParticipantSpatialization(participantId: string, enableSpatialization: boolean): void;
105
- /**
106
- * Update spatial audio position and orientation for a participant
107
- *
108
- * This is called every time we receive position/direction updates from the server.
109
- *
110
- * Position: Where the participant is in 3D space (their location)
111
- * Direction: Which way they're facing (their forward vector)
112
- *
113
- * Example:
114
- * - Position: (x: -200, y: 0, z: 100) = 2m to your left
115
- * - Direction: (x: 0, y: 1, z: 0) = facing forward (away from you)
116
- * - Result: Sound comes from your left, oriented as if speaking away
117
- *
118
- * The Web Audio API's PannerNode uses HRTF to create realistic 3D audio
119
- * based on these parameters plus the listener's position/orientation.
120
- *
121
- * @param participantId Who to update
122
- * @param position Where they are (from socket data)
123
- * @param direction Which way they're facing (from socket data)
124
- */
125
- updateSpatialAudio(participantId: string, position: Position, direction?: {
126
- x: number;
127
- y: number;
128
- z: number;
129
- }, _spatialMeta?: {
130
- pan?: number;
131
- dxLocal?: number;
132
- }): void;
133
- /**
134
- * Mute or unmute a participant's audio
135
- * Used for channel-based audio routing (huddle vs spatial)
136
- * @param participantId The participant to mute/unmute
137
- * @param muted True to mute, false to unmute
138
- */
139
- setParticipantMuted(participantId: string, muted: boolean): void;
140
- /**
141
- * Master mute/unmute for ALL audio output
142
- * Use this to prevent audio from playing until user explicitly joins the space.
143
- * @param muted True to mute all audio, false to unmute
144
- */
145
- setMasterMuted(muted: boolean): void;
146
- /**
147
- * Get current master mute state
148
- * @returns True if master mute is enabled
149
- */
150
- getMasterMuted(): boolean;
151
- /**
152
- * Update listener position and orientation
153
- * The \"listener\" is YOU - where your ears/head are positioned
154
- *
155
- * @param position Your HEAD position (camera position), not body position!
156
- * @param orientation Which way your head is facing (forward and up vectors)
157
- */
158
- setListenerPosition(position: Position, orientation: {
159
- forwardX: number;
160
- forwardY: number;
161
- forwardZ: number;
162
- upX: number;
163
- upY: number;
164
- upZ: number;
165
- }): void;
166
- /**
167
- * POSITION-ONLY MODE: Set listener HEAD position (no direction needed)
168
- * IMPORTANT: Uses CAMERA position (head) as listener, not body position!
169
- *
170
- * @param listenerPos Player body position (for reference, not used as listener)
171
- * @param cameraPos Camera/HEAD position - THIS is the actual listener position for audio
172
- * @param lookAtPos Look-at position (where camera is pointing) - stored but not used for panning
173
- * @param rot Rotation data (pitch, yaw, roll) - stored but not used for panning
174
- */
175
- setListenerFromLSD(listenerPos: Position, cameraPos: Position, lookAtPos: Position, rot?: {
176
- x: number;
177
- y: number;
178
- z: number;
179
- }, localParticipantId?: string): void;
180
- private applyListenerTransform;
181
- removeParticipant(participantId: string): void;
182
- resumeAudioContext(): Promise<void>;
183
- getAudioContextState(): AudioContextState;
184
- private getDistanceConfig;
185
- private applySpatialBoostIfNeeded;
186
- private getDistanceBetween;
187
- private calculateDistanceGain;
188
- private normalizePositionUnits;
189
- /**
190
- * Snap position to grid to prevent jitter from micro-movements
191
- * If the position hasn't changed significantly, return the cached position
192
- * This prevents gain/pan fluctuation when users are "stationary"
193
- *
194
- * @param position New incoming position
195
- * @param participantId Participant ID for caching (use 'listener' for listener)
196
- * @returns Snapped position (either new or cached)
197
- */
198
- private snapPosition;
199
- private getVectorFromListener;
200
- private applyDirectionalSuppression;
201
- /**
202
- * Dynamically adjust highpass filter based on voice characteristics
203
- * Analyzes audio spectrum and sets filter between 85-300Hz
204
- */
205
- private adjustVoiceAdaptiveFilter;
206
- private calculateClarityScore;
207
- private calculateProximityWeight;
208
- private calculateDirectionFocus;
209
- private normalizeVector;
210
- private clamp;
211
- private isDenoiserEnabled;
212
- /**
213
- * Compute estimated head/mouth position from body position
214
- * Body position is typically at feet/base - add head height offset
215
- * Average human head height: 1.6m (adjustable based on avatar)
216
- */
217
- private computeHeadPosition;
218
- private calculatePanning;
219
- private panningFromPanValue;
220
- /**
221
- * SMOOTH PAN VALUE to prevent random left/right jumping
222
- * Uses exponential moving average (EMA) to smooth out jittery position data
223
- * With SNAP behavior for large direction changes (e.g., turning around)
224
- * With DEAD-ZONE around center to prevent face-to-face oscillation
225
- * @param participantId The participant to smooth pan for
226
- * @param newPanValue The new calculated pan value (-1 to +1)
227
- * @returns Smoothed pan value
228
- */
229
- private smoothPanValue;
230
- private computeAzimuthFromPositions;
231
- /**
232
- * OLD METHOD - Kept for reference but not used in position-only mode
233
- * Calculate angle between listener and sound source in degrees (0-360)
234
- * 0° = front, 90° = right, 180° = back, 270° = left
235
- */
236
- private calculateAngle;
237
- /**
238
- * Calculate gain based on distance using logarithmic scale
239
- * Distance range: 0.5m to 15m
240
- * Gain range: 100% to 20% (reduced minimum for audibility at distance)
241
- * Uses smoother curve for more consistent audio across distances
242
- *
243
- * TUNED FOR CONSISTENT VOICE CLARITY:
244
- * - Near range (0-3m): Full volume for clear conversation
245
- * - Medium range (3-8m): Gradual falloff, still easily audible
246
- * - Far range (8-15m): Soft but still present
247
- */
248
- /**
249
- * Calculate gain based on distance - AGGRESSIVE FALLOFF
250
- *
251
- * Uses inverse-square law (realistic sound propagation) with floor:
252
- * Gain = 1 / (1 + k * distance²)
253
- *
254
- * Distance → Gain mapping:
255
- * - 0-1m → 100% (full volume, very close)
256
- * - 2m → ~80%
257
- * - 3m → ~55%
258
- * - 5m → ~30%
259
- * - 8m → ~15%
260
- * - 10m+ → 5% (minimum, barely audible)
261
- */
262
- private calculateLogarithmicGain;
263
- /**
264
- * Apply stereo panning to participant audio using StereoPannerNode
265
- * This provides STABLE left-right panning without jitter
266
- */
267
- private applyStereoPanning;
268
- private ensureDenoiseWorklet;
269
- private resolveOptions;
270
- }
271
- export {};