@newgameplusinc/odyssey-audio-video-sdk-dev 1.0.258 → 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.
- package/README.md +45 -1
- package/dist/audio/AudioNodeFactory.d.ts +130 -0
- package/dist/audio/AudioNodeFactory.js +158 -0
- package/dist/audio/AudioPipeline.d.ts +89 -0
- package/dist/audio/AudioPipeline.js +138 -0
- package/dist/{MLNoiseSuppressor.d.ts → audio/MLNoiseSuppressor.d.ts} +7 -7
- package/dist/{MLNoiseSuppressor.js → audio/MLNoiseSuppressor.js} +13 -41
- package/dist/audio/index.d.ts +6 -0
- package/dist/audio/index.js +22 -0
- package/dist/channels/huddle/HuddleChannel.d.ts +87 -0
- package/dist/channels/huddle/HuddleChannel.js +152 -0
- package/dist/channels/huddle/HuddleTypes.d.ts +85 -0
- package/dist/channels/huddle/HuddleTypes.js +25 -0
- package/dist/channels/huddle/index.d.ts +5 -0
- package/dist/channels/huddle/index.js +21 -0
- package/dist/channels/index.d.ts +5 -0
- package/dist/channels/index.js +21 -0
- package/dist/channels/spatial/SpatialAudioChannel.d.ts +144 -0
- package/dist/channels/spatial/SpatialAudioChannel.js +455 -0
- package/dist/channels/spatial/SpatialAudioTypes.d.ts +85 -0
- package/dist/channels/spatial/SpatialAudioTypes.js +42 -0
- package/dist/channels/spatial/index.d.ts +5 -0
- package/dist/channels/spatial/index.js +21 -0
- package/dist/{EventManager.d.ts → core/EventManager.d.ts} +4 -2
- package/dist/{EventManager.js → core/EventManager.js} +5 -3
- package/dist/{MediasoupManager.d.ts → core/MediasoupManager.d.ts} +10 -4
- package/dist/{MediasoupManager.js → core/MediasoupManager.js} +31 -42
- package/dist/core/index.d.ts +5 -0
- package/dist/core/index.js +21 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +30 -6
- package/dist/sdk/index.d.ts +36 -0
- package/dist/sdk/index.js +121 -0
- package/dist/types/events.d.ts +154 -0
- package/dist/{types.js → types/events.js} +3 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.js +23 -0
- package/dist/types/participant.d.ts +65 -0
- package/dist/types/participant.js +5 -0
- package/dist/types/position.d.ts +47 -0
- package/dist/types/position.js +9 -0
- package/dist/types/room.d.ts +82 -0
- package/dist/types/room.js +5 -0
- package/dist/utils/audio/clarity-score.d.ts +33 -0
- package/dist/utils/audio/clarity-score.js +81 -0
- package/dist/utils/audio/index.d.ts +5 -0
- package/dist/utils/audio/index.js +21 -0
- package/dist/utils/audio/voice-filter.d.ts +30 -0
- package/dist/utils/audio/voice-filter.js +70 -0
- package/dist/utils/index.d.ts +7 -0
- package/dist/utils/index.js +23 -0
- package/dist/utils/position/coordinates.d.ts +37 -0
- package/dist/utils/position/coordinates.js +61 -0
- package/dist/utils/position/index.d.ts +6 -0
- package/dist/utils/position/index.js +22 -0
- package/dist/utils/position/normalize.d.ts +37 -0
- package/dist/utils/position/normalize.js +78 -0
- package/dist/utils/position/snap.d.ts +51 -0
- package/dist/utils/position/snap.js +81 -0
- package/dist/utils/smoothing/gain-smoothing.d.ts +45 -0
- package/dist/utils/smoothing/gain-smoothing.js +77 -0
- package/dist/utils/smoothing/index.d.ts +5 -0
- package/dist/utils/smoothing/index.js +21 -0
- package/dist/utils/smoothing/pan-smoothing.d.ts +43 -0
- package/dist/utils/smoothing/pan-smoothing.js +85 -0
- package/dist/utils/spatial/angle-calc.d.ts +24 -0
- package/dist/utils/spatial/angle-calc.js +69 -0
- package/dist/utils/spatial/distance-calc.d.ts +33 -0
- package/dist/utils/spatial/distance-calc.js +48 -0
- package/dist/utils/spatial/gain-calc.d.ts +37 -0
- package/dist/utils/spatial/gain-calc.js +52 -0
- package/dist/utils/spatial/head-position.d.ts +32 -0
- package/dist/utils/spatial/head-position.js +76 -0
- package/dist/utils/spatial/index.d.ts +9 -0
- package/dist/utils/spatial/index.js +25 -0
- package/dist/utils/spatial/listener-calc.d.ts +28 -0
- package/dist/utils/spatial/listener-calc.js +74 -0
- package/dist/utils/spatial/pan-calc.d.ts +48 -0
- package/dist/utils/spatial/pan-calc.js +80 -0
- package/package.json +1 -1
- package/dist/SpatialAudioManager.d.ts +0 -271
- package/dist/SpatialAudioManager.js +0 -1512
- 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,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,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;
|