excalibur 0.32.0-alpha.1601 → 0.32.0-alpha.17
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/CHANGELOG.md +11 -0
- package/build/dist/Resources/Sound/AudioContext.d.ts +4 -0
- package/build/dist/Resources/Sound/Sound.d.ts +37 -2
- package/build/dist/Resources/Sound/WebAudioInstance.d.ts +1 -0
- package/build/dist/excalibur.development.js +26 -9
- package/build/dist/excalibur.js +26 -9
- package/build/dist/excalibur.min.development.js +30 -30
- package/build/dist/excalibur.min.js +30 -30
- package/build/esm/excalibur.development.js +26 -9
- package/build/esm/excalibur.js +26 -9
- package/build/esm/excalibur.min.development.js +261 -243
- package/build/esm/excalibur.min.js +261 -243
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -17,6 +17,17 @@ This project adheres to [Semantic Versioning](http://semver.org/).
|
|
|
17
17
|
### Added
|
|
18
18
|
|
|
19
19
|
|
|
20
|
+
- Added new parameter to `ex.Sounds` to schedule start time, this allows you to synchronize playback of multiple audio tracks
|
|
21
|
+
```typescript
|
|
22
|
+
const start500MsFromNow = AudioContextFactory.currentTime() + 500;
|
|
23
|
+
|
|
24
|
+
Resources.MusicSurface.play({ volume: .5, scheduledStartTime: start500MsFromNow });
|
|
25
|
+
// Start layered tracks at 0 volume so they are synchronized
|
|
26
|
+
Resources.MusicIndDrums.play({ volume: 0, scheduledStartTime: start500MsFromNow });
|
|
27
|
+
Resources.MusicIndTopper.play({ volume: 0, scheduledStartTime: start500MsFromNow });
|
|
28
|
+
Resources.MusicGroovyDrums.play({ volume: 0, scheduledStartTime: start500MsFromNow });
|
|
29
|
+
Resources.MusicGroovyTopper.play({ volume: 0, scheduledStartTime: start500MsFromNow });
|
|
30
|
+
```
|
|
20
31
|
- Added new Timer events!
|
|
21
32
|
```typescript
|
|
22
33
|
const timer = new ex.Timer({...});
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Audio } from '../../Interfaces/Audio';
|
|
2
2
|
import type { Engine } from '../../Engine';
|
|
3
|
+
import { WebAudioInstance } from './WebAudioInstance';
|
|
3
4
|
import { NativeSoundEvent, NativeSoundProcessedEvent } from '../../Events/MediaEvents';
|
|
4
5
|
import type { Loadable } from '../../Interfaces/Index';
|
|
5
6
|
import { Logger } from '../../Util/Log';
|
|
@@ -61,6 +62,26 @@ export interface SoundOptions {
|
|
|
61
62
|
*/
|
|
62
63
|
position?: number;
|
|
63
64
|
}
|
|
65
|
+
export interface PlayOptions {
|
|
66
|
+
/**
|
|
67
|
+
* Volume to play between [0, 1]
|
|
68
|
+
*/
|
|
69
|
+
volume?: number;
|
|
70
|
+
/**
|
|
71
|
+
* Schedule time to play in milliseconds from the audio context origin
|
|
72
|
+
*
|
|
73
|
+
* Compute using the audio context
|
|
74
|
+
*
|
|
75
|
+
* ```typescript
|
|
76
|
+
* const sound: Sound = ...;
|
|
77
|
+
* const oneThousandMillisecondsFromNow = AudioContextFactory.currentTime + 1000;
|
|
78
|
+
*
|
|
79
|
+
* sound.play({ scheduledStartTime: oneThousandMillisecondsFromNow });
|
|
80
|
+
*
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
scheduledStartTime?: number;
|
|
84
|
+
}
|
|
64
85
|
/**
|
|
65
86
|
* The {@apilink Sound} object allows games built in Excalibur to load audio
|
|
66
87
|
* components, from soundtracks to sound effects. {@apilink Sound} is an {@apilink Loadable}
|
|
@@ -105,6 +126,20 @@ export declare class Sound implements Audio, Loadable<AudioBuffer> {
|
|
|
105
126
|
*/
|
|
106
127
|
get bustCache(): boolean;
|
|
107
128
|
set bustCache(val: boolean);
|
|
129
|
+
/**
|
|
130
|
+
* Schedule time to play in milliseconds from the audio context origin
|
|
131
|
+
*
|
|
132
|
+
* Compute using the audio context
|
|
133
|
+
*
|
|
134
|
+
* ```typescript
|
|
135
|
+
* const sound: Sound = ...;
|
|
136
|
+
* const oneThousandMillisecondsFromNow = AudioContextFactory.currentTime + 1000;
|
|
137
|
+
*
|
|
138
|
+
* sound.scheduledStartTime = oneThousandMillisecondsFromNow;
|
|
139
|
+
*
|
|
140
|
+
* ```
|
|
141
|
+
*/
|
|
142
|
+
scheduledStartTime: number;
|
|
108
143
|
private _loop;
|
|
109
144
|
private _volume;
|
|
110
145
|
private _isStopped;
|
|
@@ -136,7 +171,7 @@ export declare class Sound implements Audio, Loadable<AudioBuffer> {
|
|
|
136
171
|
* Play the sound, returns a promise that resolves when the sound is done playing
|
|
137
172
|
* An optional volume argument can be passed in to play the sound. Max volume is 1.0
|
|
138
173
|
*/
|
|
139
|
-
play(
|
|
174
|
+
play(volumeOrConfig?: number | PlayOptions): Promise<boolean>;
|
|
140
175
|
/**
|
|
141
176
|
* Stop the sound, and do not rewind
|
|
142
177
|
*/
|
|
@@ -160,7 +195,7 @@ export declare class Sound implements Audio, Loadable<AudioBuffer> {
|
|
|
160
195
|
* Get Id of provided AudioInstance in current trackList
|
|
161
196
|
* @param track {@apilink Audio} which Id is to be given
|
|
162
197
|
*/
|
|
163
|
-
getTrackId(track:
|
|
198
|
+
getTrackId(track: WebAudioInstance): number;
|
|
164
199
|
private _resumePlayback;
|
|
165
200
|
/**
|
|
166
201
|
* Starts playback, returns a promise that resolves when playback is complete
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! excalibur - 0.32.0-alpha.
|
|
1
|
+
/*! excalibur - 0.32.0-alpha.17+d1b9643 - 2025-12-22
|
|
2
2
|
https://github.com/excaliburjs/Excalibur
|
|
3
3
|
Copyright (c) 2025 Excalibur.js <https://github.com/excaliburjs/Excalibur/graphs/contributors>
|
|
4
4
|
Licensed BSD-2-Clause
|
|
@@ -23444,6 +23444,12 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23444
23444
|
}
|
|
23445
23445
|
return this._INSTANCE;
|
|
23446
23446
|
}
|
|
23447
|
+
/**
|
|
23448
|
+
* Return the current audio context time in millseconds
|
|
23449
|
+
*/
|
|
23450
|
+
static currentTime() {
|
|
23451
|
+
return AudioContextFactory.create().currentTime * 1e3;
|
|
23452
|
+
}
|
|
23447
23453
|
}
|
|
23448
23454
|
function isLegacyWebAudioSource(source) {
|
|
23449
23455
|
return !!source.playbackState;
|
|
@@ -23606,9 +23612,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23606
23612
|
this._createNewBufferSource();
|
|
23607
23613
|
this._handleEnd();
|
|
23608
23614
|
if (this.loop) {
|
|
23609
|
-
this._instance.start(
|
|
23615
|
+
this._instance.start(this.scheduledStartTime, data.pausedAt * this._playbackRate);
|
|
23610
23616
|
} else {
|
|
23611
|
-
this._instance.start(
|
|
23617
|
+
this._instance.start(this.scheduledStartTime, data.pausedAt * this._playbackRate, this.duration);
|
|
23612
23618
|
}
|
|
23613
23619
|
data.startedAt = this._audioContext.currentTime - data.pausedAt;
|
|
23614
23620
|
data.pausedAt = 0;
|
|
@@ -23658,6 +23664,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23658
23664
|
this._playStarted = () => {
|
|
23659
23665
|
};
|
|
23660
23666
|
this._playbackRate = 1;
|
|
23667
|
+
this.scheduledStartTime = 0;
|
|
23661
23668
|
this._createNewBufferSource();
|
|
23662
23669
|
}
|
|
23663
23670
|
_createNewBufferSource() {
|
|
@@ -23855,6 +23862,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23855
23862
|
constructor(...pathsOrSoundOption) {
|
|
23856
23863
|
this.events = new EventEmitter();
|
|
23857
23864
|
this.logger = Logger.getInstance();
|
|
23865
|
+
this.scheduledStartTime = 0;
|
|
23858
23866
|
this._loop = false;
|
|
23859
23867
|
this._volume = 1;
|
|
23860
23868
|
this._isStopped = false;
|
|
@@ -24023,7 +24031,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24023
24031
|
* Play the sound, returns a promise that resolves when the sound is done playing
|
|
24024
24032
|
* An optional volume argument can be passed in to play the sound. Max volume is 1.0
|
|
24025
24033
|
*/
|
|
24026
|
-
play(
|
|
24034
|
+
play(volumeOrConfig) {
|
|
24027
24035
|
if (!this.isLoaded()) {
|
|
24028
24036
|
this.logger.warn("Cannot start playing. Resource", this.path, "is not loaded yet");
|
|
24029
24037
|
return Promise.resolve(true);
|
|
@@ -24032,14 +24040,21 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24032
24040
|
this.logger.warn("Cannot start playing. Engine is in a stopped state.");
|
|
24033
24041
|
return Promise.resolve(false);
|
|
24034
24042
|
}
|
|
24035
|
-
|
|
24043
|
+
let scheduledStart = 0;
|
|
24044
|
+
if (volumeOrConfig instanceof Object) {
|
|
24045
|
+
const { volume, scheduledStartTime } = volumeOrConfig;
|
|
24046
|
+
scheduledStart = (scheduledStartTime != null ? scheduledStartTime : 0) / 1e3 || scheduledStart;
|
|
24047
|
+
this.volume = volume != null ? volume : this.volume;
|
|
24048
|
+
} else {
|
|
24049
|
+
this.volume = volumeOrConfig != null ? volumeOrConfig : this.volume;
|
|
24050
|
+
}
|
|
24036
24051
|
if (this.isPaused()) {
|
|
24037
24052
|
return this._resumePlayback();
|
|
24038
24053
|
} else {
|
|
24039
24054
|
if (this.position) {
|
|
24040
24055
|
this.seek(this.position);
|
|
24041
24056
|
}
|
|
24042
|
-
return this._startPlayback();
|
|
24057
|
+
return this._startPlayback(scheduledStart);
|
|
24043
24058
|
}
|
|
24044
24059
|
}
|
|
24045
24060
|
/**
|
|
@@ -24109,10 +24124,11 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24109
24124
|
getTrackId(track) {
|
|
24110
24125
|
return this._tracks.indexOf(track);
|
|
24111
24126
|
}
|
|
24112
|
-
async _resumePlayback() {
|
|
24127
|
+
async _resumePlayback(scheduledStart = 0) {
|
|
24113
24128
|
if (this.isPaused()) {
|
|
24114
24129
|
const resumed = [];
|
|
24115
24130
|
for (const track of this._tracks) {
|
|
24131
|
+
track.scheduledStartTime = scheduledStart;
|
|
24116
24132
|
resumed.push(
|
|
24117
24133
|
track.play().then(() => {
|
|
24118
24134
|
this._tracks.splice(this.getTrackId(track), 1);
|
|
@@ -24129,8 +24145,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24129
24145
|
/**
|
|
24130
24146
|
* Starts playback, returns a promise that resolves when playback is complete
|
|
24131
24147
|
*/
|
|
24132
|
-
async _startPlayback() {
|
|
24148
|
+
async _startPlayback(scheduledStartTime = 0) {
|
|
24133
24149
|
const track = this._getTrackInstance(this.data);
|
|
24150
|
+
track.scheduledStartTime = scheduledStartTime;
|
|
24134
24151
|
const complete = await track.play(() => {
|
|
24135
24152
|
this.events.emit("playbackstart", new NativeSoundEvent(this, track));
|
|
24136
24153
|
this.logger.debug("Playing new instance for sound", this.path);
|
|
@@ -33614,7 +33631,7 @@ Read more about this issue at https://excaliburjs.com/docs/performance`
|
|
|
33614
33631
|
this._count += count;
|
|
33615
33632
|
}
|
|
33616
33633
|
}
|
|
33617
|
-
const EX_VERSION = "0.32.0-alpha.
|
|
33634
|
+
const EX_VERSION = "0.32.0-alpha.17+d1b9643";
|
|
33618
33635
|
polyfill();
|
|
33619
33636
|
exports2.ActionCompleteEvent = ActionCompleteEvent;
|
|
33620
33637
|
exports2.ActionContext = ActionContext;
|
package/build/dist/excalibur.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! excalibur - 0.32.0-alpha.
|
|
1
|
+
/*! excalibur - 0.32.0-alpha.17+d1b9643 - 2025-12-22
|
|
2
2
|
https://github.com/excaliburjs/Excalibur
|
|
3
3
|
Copyright (c) 2025 Excalibur.js <https://github.com/excaliburjs/Excalibur/graphs/contributors>
|
|
4
4
|
Licensed BSD-2-Clause
|
|
@@ -23444,6 +23444,12 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23444
23444
|
}
|
|
23445
23445
|
return this._INSTANCE;
|
|
23446
23446
|
}
|
|
23447
|
+
/**
|
|
23448
|
+
* Return the current audio context time in millseconds
|
|
23449
|
+
*/
|
|
23450
|
+
static currentTime() {
|
|
23451
|
+
return AudioContextFactory.create().currentTime * 1e3;
|
|
23452
|
+
}
|
|
23447
23453
|
}
|
|
23448
23454
|
function isLegacyWebAudioSource(source) {
|
|
23449
23455
|
return !!source.playbackState;
|
|
@@ -23606,9 +23612,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23606
23612
|
this._createNewBufferSource();
|
|
23607
23613
|
this._handleEnd();
|
|
23608
23614
|
if (this.loop) {
|
|
23609
|
-
this._instance.start(
|
|
23615
|
+
this._instance.start(this.scheduledStartTime, data.pausedAt * this._playbackRate);
|
|
23610
23616
|
} else {
|
|
23611
|
-
this._instance.start(
|
|
23617
|
+
this._instance.start(this.scheduledStartTime, data.pausedAt * this._playbackRate, this.duration);
|
|
23612
23618
|
}
|
|
23613
23619
|
data.startedAt = this._audioContext.currentTime - data.pausedAt;
|
|
23614
23620
|
data.pausedAt = 0;
|
|
@@ -23658,6 +23664,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23658
23664
|
this._playStarted = () => {
|
|
23659
23665
|
};
|
|
23660
23666
|
this._playbackRate = 1;
|
|
23667
|
+
this.scheduledStartTime = 0;
|
|
23661
23668
|
this._createNewBufferSource();
|
|
23662
23669
|
}
|
|
23663
23670
|
_createNewBufferSource() {
|
|
@@ -23855,6 +23862,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
23855
23862
|
constructor(...pathsOrSoundOption) {
|
|
23856
23863
|
this.events = new EventEmitter();
|
|
23857
23864
|
this.logger = Logger.getInstance();
|
|
23865
|
+
this.scheduledStartTime = 0;
|
|
23858
23866
|
this._loop = false;
|
|
23859
23867
|
this._volume = 1;
|
|
23860
23868
|
this._isStopped = false;
|
|
@@ -24023,7 +24031,7 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24023
24031
|
* Play the sound, returns a promise that resolves when the sound is done playing
|
|
24024
24032
|
* An optional volume argument can be passed in to play the sound. Max volume is 1.0
|
|
24025
24033
|
*/
|
|
24026
|
-
play(
|
|
24034
|
+
play(volumeOrConfig) {
|
|
24027
24035
|
if (!this.isLoaded()) {
|
|
24028
24036
|
this.logger.warn("Cannot start playing. Resource", this.path, "is not loaded yet");
|
|
24029
24037
|
return Promise.resolve(true);
|
|
@@ -24032,14 +24040,21 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24032
24040
|
this.logger.warn("Cannot start playing. Engine is in a stopped state.");
|
|
24033
24041
|
return Promise.resolve(false);
|
|
24034
24042
|
}
|
|
24035
|
-
|
|
24043
|
+
let scheduledStart = 0;
|
|
24044
|
+
if (volumeOrConfig instanceof Object) {
|
|
24045
|
+
const { volume, scheduledStartTime } = volumeOrConfig;
|
|
24046
|
+
scheduledStart = (scheduledStartTime != null ? scheduledStartTime : 0) / 1e3 || scheduledStart;
|
|
24047
|
+
this.volume = volume != null ? volume : this.volume;
|
|
24048
|
+
} else {
|
|
24049
|
+
this.volume = volumeOrConfig != null ? volumeOrConfig : this.volume;
|
|
24050
|
+
}
|
|
24036
24051
|
if (this.isPaused()) {
|
|
24037
24052
|
return this._resumePlayback();
|
|
24038
24053
|
} else {
|
|
24039
24054
|
if (this.position) {
|
|
24040
24055
|
this.seek(this.position);
|
|
24041
24056
|
}
|
|
24042
|
-
return this._startPlayback();
|
|
24057
|
+
return this._startPlayback(scheduledStart);
|
|
24043
24058
|
}
|
|
24044
24059
|
}
|
|
24045
24060
|
/**
|
|
@@ -24109,10 +24124,11 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24109
24124
|
getTrackId(track) {
|
|
24110
24125
|
return this._tracks.indexOf(track);
|
|
24111
24126
|
}
|
|
24112
|
-
async _resumePlayback() {
|
|
24127
|
+
async _resumePlayback(scheduledStart = 0) {
|
|
24113
24128
|
if (this.isPaused()) {
|
|
24114
24129
|
const resumed = [];
|
|
24115
24130
|
for (const track of this._tracks) {
|
|
24131
|
+
track.scheduledStartTime = scheduledStart;
|
|
24116
24132
|
resumed.push(
|
|
24117
24133
|
track.play().then(() => {
|
|
24118
24134
|
this._tracks.splice(this.getTrackId(track), 1);
|
|
@@ -24129,8 +24145,9 @@ If you want to do custom drawing, use Actor.graphics, or any onPreDraw or onPost
|
|
|
24129
24145
|
/**
|
|
24130
24146
|
* Starts playback, returns a promise that resolves when playback is complete
|
|
24131
24147
|
*/
|
|
24132
|
-
async _startPlayback() {
|
|
24148
|
+
async _startPlayback(scheduledStartTime = 0) {
|
|
24133
24149
|
const track = this._getTrackInstance(this.data);
|
|
24150
|
+
track.scheduledStartTime = scheduledStartTime;
|
|
24134
24151
|
const complete = await track.play(() => {
|
|
24135
24152
|
this.events.emit("playbackstart", new NativeSoundEvent(this, track));
|
|
24136
24153
|
this.logger.debug("Playing new instance for sound", this.path);
|
|
@@ -33614,7 +33631,7 @@ Read more about this issue at https://excaliburjs.com/docs/performance`
|
|
|
33614
33631
|
this._count += count;
|
|
33615
33632
|
}
|
|
33616
33633
|
}
|
|
33617
|
-
const EX_VERSION = "0.32.0-alpha.
|
|
33634
|
+
const EX_VERSION = "0.32.0-alpha.17+d1b9643";
|
|
33618
33635
|
polyfill();
|
|
33619
33636
|
exports2.ActionCompleteEvent = ActionCompleteEvent;
|
|
33620
33637
|
exports2.ActionContext = ActionContext;
|