Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: setup positional audio #1596

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/core/src/asset/AssetType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,5 +48,7 @@ export enum AssetType {
/** Font. */
Font = "Font",
/** Source Font, include ttf、 otf and woff. */
SourceFont = "SourceFont"
SourceFont = "SourceFont",
/** AudioClip, inclue ogg, wav and mp3 */
Audio = "Audio"
}
52 changes: 52 additions & 0 deletions packages/core/src/audio/AudioClip.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Engine } from "../Engine";
import { ReferResource } from "../asset/ReferResource";

/**
* Audio Clip
*/
export class AudioClip extends ReferResource {
/** the name of clip */
name: string;

private _audioBuffer: AudioBuffer;

/**
* the number of discrete audio channels
*/
get channels(): Readonly<number> {
return this._audioBuffer.numberOfChannels;
}

/**
* the sample rate, in samples per second
*/
get sampleRate(): Readonly<number> {
return this._audioBuffer.sampleRate;
}

/**
* the duration, in seconds
*/
get duration(): Readonly<number> {
return this._audioBuffer.duration;
}

/**
* get the clip's audio buffer
*/
getData(): AudioBuffer {
return this._audioBuffer;
}

/**
* set audio buffer for the clip
*/
setData(value: AudioBuffer): void {
this._audioBuffer = value;
}

constructor(engine: Engine, name: string = null) {
super(engine);
this.name = name;
}
}
66 changes: 66 additions & 0 deletions packages/core/src/audio/AudioListener.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Component } from "../Component";
import { Entity } from "../Entity";
import { TransformModifyFlags } from "../Transform";
import { ignoreClone } from "../clone/CloneManager";
import { AudioManager } from "./AudioManager";

/**
* Audio Listener
* only one per scene
*/
export class AudioListener extends Component {
private _context: AudioContext;

/**
* @internal
*/
constructor(entity: Entity) {
super(entity);
const gain = AudioManager.context.createGain();
gain.connect(AudioManager.context.destination);
AudioManager.listener = gain;

this._context = AudioManager.context;
this._onTransformChanged = this._onTransformChanged.bind(this);
this._registerEntityTransformListener();

this._setListenerPose();
}

/**
* @internal
*/
@ignoreClone
protected _onTransformChanged(type: TransformModifyFlags) {
this._setListenerPose();
}

/**
* @internal
*/
protected override _onDestroy(): void {
super._onDestroy();
AudioManager.listener = null;
this.entity.transform._updateFlagManager.removeListener(this._onTransformChanged);
}

private _registerEntityTransformListener() {
this.entity.transform._updateFlagManager.addListener(this._onTransformChanged);
}

private _setListenerPose() {
const { position, worldUp, worldForward } = this.entity.transform;
const { listener, currentTime } = this._context;

listener.positionX.setValueAtTime(position.x, currentTime);
listener.positionY.setValueAtTime(position.y, currentTime);
listener.positionZ.setValueAtTime(position.z, currentTime);

listener.upX.setValueAtTime(worldUp.x, currentTime);
listener.upY.setValueAtTime(worldUp.y, currentTime);
listener.upZ.setValueAtTime(worldUp.z, currentTime);

listener.forwardX.setValueAtTime(worldForward.x, currentTime);
listener.forwardY.setValueAtTime(worldForward.y, currentTime);
}
}
48 changes: 48 additions & 0 deletions packages/core/src/audio/AudioManager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/**
* @internal
* Audio Manager
*/
export class AudioManager {
/** @internal */
private static _context: AudioContext;
/** @internal */
private static _listener: GainNode;

private static _unlocked: boolean = false;

/**
* Audio context
*/
static get context(): AudioContext {
if (!AudioManager._context) {
AudioManager._context = new window.AudioContext();
}
if (AudioManager._context.state !== "running") {
window.document.addEventListener("pointerdown", AudioManager._unlock, true);
}
return AudioManager._context;
}

/**
* Audio Listener. Can only have one listener in a Scene.
*/
static get listener(): GainNode {
return AudioManager._listener;
}

static set listener(value: GainNode) {
AudioManager._listener = value;
}

private static _unlock(): void {
if (AudioManager._unlocked) {
return;
}
AudioManager._context.resume().then(() => {
if (AudioManager._context.state === "running") {
window.document.removeEventListener("pointerdown", AudioManager._unlock, true);
AudioManager._unlocked = true;
}
});
}
}
Loading