@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.257 → 1.0.259

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} +13 -41
  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 +455 -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} +31 -42
  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 +30 -4
  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 -272
  82. package/dist/SpatialAudioManager.js +0 -1537
  83. package/dist/types.d.ts +0 -73
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Coordinate System Conversions
3
+ *
4
+ * Converts between Unreal Engine and Standard coordinate systems
5
+ *
6
+ * Unreal Engine: X=forward, Y=right, Z=up (centimeters)
7
+ * Standard/WebAudio: X=right, Y=up, Z=forward (meters)
8
+ */
9
+ import { Position } from '../../types/position';
10
+ /**
11
+ * Convert Unreal Engine coordinates to Standard coordinates
12
+ *
13
+ * Unreal: X=forward, Y=right, Z=up (centimeters)
14
+ * Standard: X=right, Y=up, Z=forward (meters)
15
+ *
16
+ * @param unreal Position in Unreal coordinates
17
+ * @returns Position in Standard coordinates (meters)
18
+ */
19
+ export declare function unrealToStandard(unreal: Position): Position;
20
+ /**
21
+ * Convert Standard coordinates to Unreal Engine coordinates
22
+ *
23
+ * Standard: X=right, Y=up, Z=forward (meters)
24
+ * Unreal: X=forward, Y=right, Z=up (centimeters)
25
+ *
26
+ * @param standard Position in Standard coordinates
27
+ * @returns Position in Unreal coordinates (centimeters)
28
+ */
29
+ export declare function standardToUnreal(standard: Position): Position;
30
+ /**
31
+ * Auto-detect and convert to Standard coordinates
32
+ * Assumes Unreal if values > 50 (likely centimeters)
33
+ *
34
+ * @param position Position to convert
35
+ * @returns Position in Standard coordinates (meters)
36
+ */
37
+ export declare function autoConvertToStandard(position: Position): Position;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ /**
3
+ * Coordinate System Conversions
4
+ *
5
+ * Converts between Unreal Engine and Standard coordinate systems
6
+ *
7
+ * Unreal Engine: X=forward, Y=right, Z=up (centimeters)
8
+ * Standard/WebAudio: X=right, Y=up, Z=forward (meters)
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.unrealToStandard = unrealToStandard;
12
+ exports.standardToUnreal = standardToUnreal;
13
+ exports.autoConvertToStandard = autoConvertToStandard;
14
+ /**
15
+ * Convert Unreal Engine coordinates to Standard coordinates
16
+ *
17
+ * Unreal: X=forward, Y=right, Z=up (centimeters)
18
+ * Standard: X=right, Y=up, Z=forward (meters)
19
+ *
20
+ * @param unreal Position in Unreal coordinates
21
+ * @returns Position in Standard coordinates (meters)
22
+ */
23
+ function unrealToStandard(unreal) {
24
+ return {
25
+ x: unreal.y / 100, // Unreal Y (right) → Standard X (right), cm → m
26
+ y: unreal.z / 100, // Unreal Z (up) → Standard Y (up), cm → m
27
+ z: unreal.x / 100, // Unreal X (forward) → Standard Z (forward), cm → m
28
+ };
29
+ }
30
+ /**
31
+ * Convert Standard coordinates to Unreal Engine coordinates
32
+ *
33
+ * Standard: X=right, Y=up, Z=forward (meters)
34
+ * Unreal: X=forward, Y=right, Z=up (centimeters)
35
+ *
36
+ * @param standard Position in Standard coordinates
37
+ * @returns Position in Unreal coordinates (centimeters)
38
+ */
39
+ function standardToUnreal(standard) {
40
+ return {
41
+ x: standard.z * 100, // Standard Z (forward) → Unreal X (forward), m → cm
42
+ y: standard.x * 100, // Standard X (right) → Unreal Y (right), m → cm
43
+ z: standard.y * 100, // Standard Y (up) → Unreal Z (up), m → cm
44
+ };
45
+ }
46
+ /**
47
+ * Auto-detect and convert to Standard coordinates
48
+ * Assumes Unreal if values > 50 (likely centimeters)
49
+ *
50
+ * @param position Position to convert
51
+ * @returns Position in Standard coordinates (meters)
52
+ */
53
+ function autoConvertToStandard(position) {
54
+ const maxAxis = Math.max(Math.abs(position.x), Math.abs(position.y), Math.abs(position.z));
55
+ if (maxAxis > 50) {
56
+ // Likely Unreal coordinates (centimeters)
57
+ return unrealToStandard(position);
58
+ }
59
+ // Already in meters, assume Standard
60
+ return { ...position };
61
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Position utilities - Re-exports all position functions
3
+ */
4
+ export * from './normalize';
5
+ export * from './snap';
6
+ export * from './coordinates';
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ /**
3
+ * Position utilities - Re-exports all position functions
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ __exportStar(require("./normalize"), exports);
21
+ __exportStar(require("./snap"), exports);
22
+ __exportStar(require("./coordinates"), exports);
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Position Normalization
3
+ *
4
+ * Functions for normalizing position units (cm to meters, etc.)
5
+ */
6
+ import { Position } from '../../types/position';
7
+ /**
8
+ * Normalize position units to meters
9
+ * Detects if values are likely in centimeters and converts
10
+ *
11
+ * @param position Position to normalize
12
+ * @param unit Force unit interpretation: 'auto' | 'meters' | 'centimeters'
13
+ * @returns Position in meters
14
+ */
15
+ export declare function normalizePositionUnits(position: Position, unit?: 'auto' | 'meters' | 'centimeters'): Position;
16
+ /**
17
+ * Convert meters to centimeters
18
+ *
19
+ * @param position Position in meters
20
+ * @returns Position in centimeters
21
+ */
22
+ export declare function metersToCentimeters(position: Position): Position;
23
+ /**
24
+ * Convert centimeters to meters
25
+ *
26
+ * @param position Position in centimeters
27
+ * @returns Position in meters
28
+ */
29
+ export declare function centimetersToMeters(position: Position): Position;
30
+ /**
31
+ * Check if position values are likely in centimeters
32
+ *
33
+ * @param position Position to check
34
+ * @param threshold Threshold for detection (default: 50)
35
+ * @returns True if likely centimeters
36
+ */
37
+ export declare function isLikelyCentimeters(position: Position, threshold?: number): boolean;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ /**
3
+ * Position Normalization
4
+ *
5
+ * Functions for normalizing position units (cm to meters, etc.)
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.normalizePositionUnits = normalizePositionUnits;
9
+ exports.metersToCentimeters = metersToCentimeters;
10
+ exports.centimetersToMeters = centimetersToMeters;
11
+ exports.isLikelyCentimeters = isLikelyCentimeters;
12
+ /**
13
+ * Normalize position units to meters
14
+ * Detects if values are likely in centimeters and converts
15
+ *
16
+ * @param position Position to normalize
17
+ * @param unit Force unit interpretation: 'auto' | 'meters' | 'centimeters'
18
+ * @returns Position in meters
19
+ */
20
+ function normalizePositionUnits(position, unit = 'auto') {
21
+ if (unit === 'meters') {
22
+ return { ...position };
23
+ }
24
+ if (unit === 'centimeters') {
25
+ return {
26
+ x: position.x / 100,
27
+ y: position.y / 100,
28
+ z: position.z / 100,
29
+ };
30
+ }
31
+ // Auto-detect: if any axis > 50, likely centimeters
32
+ const maxAxis = Math.max(Math.abs(position.x), Math.abs(position.y), Math.abs(position.z));
33
+ if (maxAxis > 50) {
34
+ return {
35
+ x: position.x / 100,
36
+ y: position.y / 100,
37
+ z: position.z / 100,
38
+ };
39
+ }
40
+ return { ...position };
41
+ }
42
+ /**
43
+ * Convert meters to centimeters
44
+ *
45
+ * @param position Position in meters
46
+ * @returns Position in centimeters
47
+ */
48
+ function metersToCentimeters(position) {
49
+ return {
50
+ x: position.x * 100,
51
+ y: position.y * 100,
52
+ z: position.z * 100,
53
+ };
54
+ }
55
+ /**
56
+ * Convert centimeters to meters
57
+ *
58
+ * @param position Position in centimeters
59
+ * @returns Position in meters
60
+ */
61
+ function centimetersToMeters(position) {
62
+ return {
63
+ x: position.x / 100,
64
+ y: position.y / 100,
65
+ z: position.z / 100,
66
+ };
67
+ }
68
+ /**
69
+ * Check if position values are likely in centimeters
70
+ *
71
+ * @param position Position to check
72
+ * @param threshold Threshold for detection (default: 50)
73
+ * @returns True if likely centimeters
74
+ */
75
+ function isLikelyCentimeters(position, threshold = 50) {
76
+ const maxAxis = Math.max(Math.abs(position.x), Math.abs(position.y), Math.abs(position.z));
77
+ return maxAxis > threshold;
78
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Position Snapping
3
+ *
4
+ * Functions for reducing position jitter by snapping to a grid
5
+ */
6
+ import { Position } from '../../types/position';
7
+ /**
8
+ * Snap configuration
9
+ */
10
+ export interface SnapConfig {
11
+ threshold: number;
12
+ }
13
+ /**
14
+ * Default snap configuration
15
+ * 0.30m = 30cm - ignores pixel streaming jitter, physics wobble, breathing
16
+ */
17
+ export declare const SNAP_CONFIG: SnapConfig;
18
+ /**
19
+ * Position snap cache for reducing jitter
20
+ */
21
+ export declare class PositionSnapCache {
22
+ private cache;
23
+ private threshold;
24
+ constructor(threshold?: number);
25
+ /**
26
+ * Snap position to reduce jitter
27
+ * Returns cached position if movement is below threshold
28
+ *
29
+ * @param position New position
30
+ * @param id Identifier for this position (participantId or 'listener')
31
+ * @returns Snapped position
32
+ */
33
+ snap(position: Position, id: string): Position;
34
+ /**
35
+ * Clear cached position for an ID
36
+ */
37
+ clear(id: string): void;
38
+ /**
39
+ * Clear all cached positions
40
+ */
41
+ clearAll(): void;
42
+ }
43
+ /**
44
+ * Simple position snap without caching
45
+ * Snaps to grid based on threshold
46
+ *
47
+ * @param position Position to snap
48
+ * @param gridSize Grid size for snapping
49
+ * @returns Snapped position
50
+ */
51
+ export declare function snapPositionSimple(position: Position, gridSize?: number): Position;
@@ -0,0 +1,81 @@
1
+ "use strict";
2
+ /**
3
+ * Position Snapping
4
+ *
5
+ * Functions for reducing position jitter by snapping to a grid
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.PositionSnapCache = exports.SNAP_CONFIG = void 0;
9
+ exports.snapPositionSimple = snapPositionSimple;
10
+ /**
11
+ * Default snap configuration
12
+ * 0.30m = 30cm - ignores pixel streaming jitter, physics wobble, breathing
13
+ */
14
+ exports.SNAP_CONFIG = {
15
+ threshold: 0.30,
16
+ };
17
+ /**
18
+ * Position snap cache for reducing jitter
19
+ */
20
+ class PositionSnapCache {
21
+ constructor(threshold = exports.SNAP_CONFIG.threshold) {
22
+ this.cache = new Map();
23
+ this.threshold = threshold;
24
+ }
25
+ /**
26
+ * Snap position to reduce jitter
27
+ * Returns cached position if movement is below threshold
28
+ *
29
+ * @param position New position
30
+ * @param id Identifier for this position (participantId or 'listener')
31
+ * @returns Snapped position
32
+ */
33
+ snap(position, id) {
34
+ const cached = this.cache.get(id);
35
+ // If no cached position, use this one as baseline
36
+ if (!cached || (cached.x === 0 && cached.y === 0 && cached.z === 0)) {
37
+ this.cache.set(id, { ...position });
38
+ return position;
39
+ }
40
+ // Calculate movement distance
41
+ const dx = position.x - cached.x;
42
+ const dy = position.y - cached.y;
43
+ const dz = position.z - cached.z;
44
+ const movedDistance = Math.sqrt(dx * dx + dy * dy + dz * dz);
45
+ // If moved more than threshold, update cache and use new position
46
+ if (movedDistance > this.threshold) {
47
+ this.cache.set(id, { ...position });
48
+ return position;
49
+ }
50
+ // Position hasn't changed significantly - return cached
51
+ return cached;
52
+ }
53
+ /**
54
+ * Clear cached position for an ID
55
+ */
56
+ clear(id) {
57
+ this.cache.delete(id);
58
+ }
59
+ /**
60
+ * Clear all cached positions
61
+ */
62
+ clearAll() {
63
+ this.cache.clear();
64
+ }
65
+ }
66
+ exports.PositionSnapCache = PositionSnapCache;
67
+ /**
68
+ * Simple position snap without caching
69
+ * Snaps to grid based on threshold
70
+ *
71
+ * @param position Position to snap
72
+ * @param gridSize Grid size for snapping
73
+ * @returns Snapped position
74
+ */
75
+ function snapPositionSimple(position, gridSize = 0.1) {
76
+ return {
77
+ x: Math.round(position.x / gridSize) * gridSize,
78
+ y: Math.round(position.y / gridSize) * gridSize,
79
+ z: Math.round(position.z / gridSize) * gridSize,
80
+ };
81
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Gain Smoothing
3
+ *
4
+ * Functions for smoothing audio gain changes to prevent clicks/pops
5
+ */
6
+ /**
7
+ * Apply smooth gain transition using Web Audio API's setTargetAtTime
8
+ *
9
+ * @param gainNode The GainNode to modify
10
+ * @param targetGain Target gain value (0-1)
11
+ * @param audioContext AudioContext for timing
12
+ * @param timeConstant Time constant for transition (default: 0.1 = ~300ms to settle)
13
+ */
14
+ export declare function applyGainSmooth(gainNode: GainNode, targetGain: number, audioContext: AudioContext, timeConstant?: number): void;
15
+ /**
16
+ * Gain tracker for managing gain values per participant
17
+ */
18
+ export declare class GainTracker {
19
+ private lastValues;
20
+ /**
21
+ * Get last gain value for a participant
22
+ */
23
+ get(participantId: string): number | undefined;
24
+ /**
25
+ * Set last gain value for a participant
26
+ */
27
+ set(participantId: string, value: number): void;
28
+ /**
29
+ * Clear gain value for a participant
30
+ */
31
+ clear(participantId: string): void;
32
+ /**
33
+ * Clear all gain values
34
+ */
35
+ clearAll(): void;
36
+ }
37
+ /**
38
+ * Apply smooth stereo pan transition
39
+ *
40
+ * @param stereoPanner The StereoPannerNode to modify
41
+ * @param panValue Target pan value (-1 to +1)
42
+ * @param audioContext AudioContext for timing
43
+ * @param timeConstant Time constant for transition (default: 0.05 = ~150ms)
44
+ */
45
+ export declare function applyStereoPanSmooth(stereoPanner: StereoPannerNode, panValue: number, audioContext: AudioContext, timeConstant?: number): void;
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ /**
3
+ * Gain Smoothing
4
+ *
5
+ * Functions for smoothing audio gain changes to prevent clicks/pops
6
+ */
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.GainTracker = void 0;
9
+ exports.applyGainSmooth = applyGainSmooth;
10
+ exports.applyStereoPanSmooth = applyStereoPanSmooth;
11
+ /**
12
+ * Apply smooth gain transition using Web Audio API's setTargetAtTime
13
+ *
14
+ * @param gainNode The GainNode to modify
15
+ * @param targetGain Target gain value (0-1)
16
+ * @param audioContext AudioContext for timing
17
+ * @param timeConstant Time constant for transition (default: 0.1 = ~300ms to settle)
18
+ */
19
+ function applyGainSmooth(gainNode, targetGain, audioContext, timeConstant = 0.1) {
20
+ try {
21
+ gainNode.gain.setTargetAtTime(targetGain, audioContext.currentTime, timeConstant);
22
+ }
23
+ catch (err) {
24
+ // Fallback: set value directly
25
+ gainNode.gain.value = targetGain;
26
+ }
27
+ }
28
+ /**
29
+ * Gain tracker for managing gain values per participant
30
+ */
31
+ class GainTracker {
32
+ constructor() {
33
+ this.lastValues = new Map();
34
+ }
35
+ /**
36
+ * Get last gain value for a participant
37
+ */
38
+ get(participantId) {
39
+ return this.lastValues.get(participantId);
40
+ }
41
+ /**
42
+ * Set last gain value for a participant
43
+ */
44
+ set(participantId, value) {
45
+ this.lastValues.set(participantId, value);
46
+ }
47
+ /**
48
+ * Clear gain value for a participant
49
+ */
50
+ clear(participantId) {
51
+ this.lastValues.delete(participantId);
52
+ }
53
+ /**
54
+ * Clear all gain values
55
+ */
56
+ clearAll() {
57
+ this.lastValues.clear();
58
+ }
59
+ }
60
+ exports.GainTracker = GainTracker;
61
+ /**
62
+ * Apply smooth stereo pan transition
63
+ *
64
+ * @param stereoPanner The StereoPannerNode to modify
65
+ * @param panValue Target pan value (-1 to +1)
66
+ * @param audioContext AudioContext for timing
67
+ * @param timeConstant Time constant for transition (default: 0.05 = ~150ms)
68
+ */
69
+ function applyStereoPanSmooth(stereoPanner, panValue, audioContext, timeConstant = 0.05) {
70
+ try {
71
+ stereoPanner.pan.setTargetAtTime(panValue, audioContext.currentTime, timeConstant);
72
+ }
73
+ catch (err) {
74
+ // Fallback: set value directly
75
+ stereoPanner.pan.value = panValue;
76
+ }
77
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Smoothing utilities - Re-exports all smoothing functions
3
+ */
4
+ export * from './pan-smoothing';
5
+ export * from './gain-smoothing';
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Smoothing utilities - Re-exports all smoothing functions
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
17
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
18
+ };
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ __exportStar(require("./pan-smoothing"), exports);
21
+ __exportStar(require("./gain-smoothing"), exports);
@@ -0,0 +1,43 @@
1
+ /**
2
+ * Pan Smoothing
3
+ *
4
+ * Classes and functions for smoothing stereo panning values
5
+ * to prevent audio jitter and rapid left/right jumping
6
+ */
7
+ /**
8
+ * Pan smoother configuration
9
+ */
10
+ export interface PanSmootherOptions {
11
+ smoothingFactor?: number;
12
+ changeThreshold?: number;
13
+ centerDeadZone?: number;
14
+ }
15
+ /**
16
+ * Default pan smoother options
17
+ */
18
+ export declare const DEFAULT_PAN_SMOOTHER_OPTIONS: Required<PanSmootherOptions>;
19
+ /**
20
+ * Pan smoother class
21
+ * Smooths pan values using EMA with dead-zone and threshold
22
+ */
23
+ export declare class PanSmoother {
24
+ private smoothedValues;
25
+ private options;
26
+ constructor(options?: PanSmootherOptions);
27
+ /**
28
+ * Smooth a pan value for a participant
29
+ *
30
+ * @param participantId Participant ID
31
+ * @param newPanValue New pan value (-1 to +1)
32
+ * @returns Smoothed pan value
33
+ */
34
+ smooth(participantId: string, newPanValue: number): number;
35
+ /**
36
+ * Clear smoothed value for a participant
37
+ */
38
+ clear(participantId: string): void;
39
+ /**
40
+ * Clear all smoothed values
41
+ */
42
+ clearAll(): void;
43
+ }
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ /**
3
+ * Pan Smoothing
4
+ *
5
+ * Classes and functions for smoothing stereo panning values
6
+ * to prevent audio jitter and rapid left/right jumping
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.PanSmoother = exports.DEFAULT_PAN_SMOOTHER_OPTIONS = void 0;
10
+ /**
11
+ * Default pan smoother options
12
+ */
13
+ exports.DEFAULT_PAN_SMOOTHER_OPTIONS = {
14
+ smoothingFactor: 0.35,
15
+ changeThreshold: 0.02,
16
+ centerDeadZone: 0.03,
17
+ };
18
+ /**
19
+ * Pan smoother class
20
+ * Smooths pan values using EMA with dead-zone and threshold
21
+ */
22
+ class PanSmoother {
23
+ constructor(options = {}) {
24
+ this.smoothedValues = new Map();
25
+ this.options = { ...exports.DEFAULT_PAN_SMOOTHER_OPTIONS, ...options };
26
+ }
27
+ /**
28
+ * Smooth a pan value for a participant
29
+ *
30
+ * @param participantId Participant ID
31
+ * @param newPanValue New pan value (-1 to +1)
32
+ * @returns Smoothed pan value
33
+ */
34
+ smooth(participantId, newPanValue) {
35
+ const previousPan = this.smoothedValues.get(participantId);
36
+ // DEAD-ZONE: If new pan is very close to center, snap to exactly 0
37
+ let targetPan = newPanValue;
38
+ if (Math.abs(newPanValue) < this.options.centerDeadZone) {
39
+ targetPan = 0;
40
+ }
41
+ // If no previous value, initialize with current value
42
+ if (previousPan === undefined) {
43
+ this.smoothedValues.set(participantId, targetPan);
44
+ return targetPan;
45
+ }
46
+ // Calculate the change from previous pan
47
+ const panChange = Math.abs(targetPan - previousPan);
48
+ // If change is below threshold, keep previous value (prevents micro-jitter)
49
+ if (panChange < this.options.changeThreshold) {
50
+ return previousPan;
51
+ }
52
+ // Determine effective smoothing factor based on change magnitude
53
+ let effectiveSmoothingFactor = 0.7; // High smoothing = slow but stable
54
+ const signFlipped = (previousPan > 0 && targetPan < 0) || (previousPan < 0 && targetPan > 0);
55
+ const bothNearCenter = Math.abs(previousPan) < 0.2 && Math.abs(targetPan) < 0.2;
56
+ if (bothNearCenter) {
57
+ // Near center - use moderate smoothing
58
+ effectiveSmoothingFactor = 0.5;
59
+ }
60
+ else if (signFlipped && panChange > 1.0) {
61
+ // Full flip - likely jitter, use HEAVY smoothing
62
+ effectiveSmoothingFactor = 0.85;
63
+ }
64
+ // Apply exponential moving average smoothing
65
+ const smoothedPan = previousPan * effectiveSmoothingFactor + targetPan * (1 - effectiveSmoothingFactor);
66
+ // Apply dead-zone to final smoothed value
67
+ const finalPan = Math.abs(smoothedPan) < this.options.centerDeadZone ? 0 : smoothedPan;
68
+ // Store for next update
69
+ this.smoothedValues.set(participantId, finalPan);
70
+ return finalPan;
71
+ }
72
+ /**
73
+ * Clear smoothed value for a participant
74
+ */
75
+ clear(participantId) {
76
+ this.smoothedValues.delete(participantId);
77
+ }
78
+ /**
79
+ * Clear all smoothed values
80
+ */
81
+ clearAll() {
82
+ this.smoothedValues.clear();
83
+ }
84
+ }
85
+ exports.PanSmoother = PanSmoother;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Angle Calculations
3
+ *
4
+ * Functions for computing angles between positions
5
+ */
6
+ import { Position } from '../../types/position';
7
+ /**
8
+ * Compute azimuth angle from listener to source
9
+ *
10
+ * @param listener Listener position
11
+ * @param source Source position
12
+ * @returns Angle in degrees (0-360), where 0° = forward (+Z), 90° = right (+X)
13
+ */
14
+ export declare function computeAzimuthFromPositions(listener: Position, source: Position): number;
15
+ /**
16
+ * Calculate angle between listener and sound source in degrees
17
+ * Takes into account listener's forward direction
18
+ *
19
+ * @param listenerPos Listener position
20
+ * @param sourcePos Source position
21
+ * @param listenerForward Listener's forward direction vector
22
+ * @returns Angle in degrees (0-360): 0° = front, 90° = right, 180° = back, 270° = left
23
+ */
24
+ export declare function calculateAngleToSource(listenerPos: Position, sourcePos: Position, listenerForward: Position): number;