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

fix: [#2450] Sound looping regression #2451

Merged
merged 2 commits into from
Aug 5, 2022
Merged
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Fixed

- Fixed issue where `ex.Sound.loop` was not working, and switching tab visibility would cause odd behavior with looping `ex.Sound`
- Fixed issue where screenshots from `ex.Engine.screenshot()` did not match the smoothing set on the engine.
- Fixed incorrect event type returned when `ex.Actor.on('postupdate', (event) => {...})`.
- Fixed issue where using numerous `ex.Text` instances would cause Excalibur to crash webgl by implementing a global font cache.
Expand Down
13 changes: 13 additions & 0 deletions sandbox/tests/sound/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,19 @@
<title>Sound</title>
</head>
<body>
<label for="loop">Loop</label>
<input id="loop" type="checkbox">
<label for="playback-rate">Set playback rate</label>
<input
id="playback-rate"
class="playback-rate-control"
type="range"
min="0.25"
max="3"
step="0.05"
value="1"
/>
<span id="playback-rate-value">1.0</span>
<script src="../../lib/excalibur.js"></script>
<script src="sound.js"></script>
</body>
Expand Down
Binary file added sandbox/tests/sound/loop.mp3
Binary file not shown.
14 changes: 12 additions & 2 deletions sandbox/tests/sound/sound.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ var game = new ex.Engine({



var sound = new ex.Sound('./preview.ogg');
sound.playbackRate = 2.0;
var sound = new ex.Sound('./loop.mp3');
var loader = new ex.Loader([
sound
]);
Expand Down Expand Up @@ -73,6 +72,17 @@ pause.on('pointerdown', () => {
});
game.currentScene.add(pause);

var loopCheckbox = document.querySelector('#loop') as HTMLInputElement;
loopCheckbox.onchange = (e) => {
sound.loop = !!(e.target as any).value;
}

var playbackRate = document.querySelector('#playback-rate') as HTMLInputElement;
var playbackValue = document.querySelector('#playback-rate-value') as HTMLInputElement;
playbackRate.oninput = () => {
sound.playbackRate = +playbackRate.value;
playbackValue.textContent = playbackRate.value;
};

game.currentScene.onPostUpdate = () => {
currentTimeLabel.text = 'Current Time: ' + sound.getPlaybackPosition().toFixed(2);
Expand Down
7 changes: 6 additions & 1 deletion src/engine/Resources/Sound/WebAudioInstance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ export class WebAudioInstance implements Audio {
// Buffer nodes are single use
this._createNewBufferSource();
this._handleEnd();
this._instance.start(0, data.pausedAt * this._playbackRate, this.duration);
if (this.loop) {
// when looping don't set a duration
this._instance.start(0, data.pausedAt * this._playbackRate);
} else {
this._instance.start(0, data.pausedAt * this._playbackRate, this.duration);
}
data.startedAt = (this._audioContext.currentTime - data.pausedAt);
data.pausedAt = 0;
},
Expand Down
28 changes: 28 additions & 0 deletions src/spec/SoundSpec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,34 @@ describe('Sound resource', () => {
});
});

it('should not provide a duration if looping', async () => {
await sut.load();

const webaudio = new ex.WebAudioInstance(sut.data);
spyOn(webaudio as any, '_createNewBufferSource');
const instance = jasmine.createSpyObj('AudioBufferSourceNode', ['start']);
(webaudio as any)._instance = instance;
webaudio.loop = true;
webaudio.play();

expect((webaudio as any)._createNewBufferSource).toHaveBeenCalled();
expect(instance.start).toHaveBeenCalledWith(0, 0);
});

it('should provide a duration if not looping', async () => {
await sut.load();

const webaudio = new ex.WebAudioInstance(sut.data);
spyOn(webaudio as any, '_createNewBufferSource');
const instance = jasmine.createSpyObj('AudioBufferSourceNode', ['start']);
(webaudio as any)._instance = instance;
webaudio.loop = false;
webaudio.play();

expect((webaudio as any)._createNewBufferSource).toHaveBeenCalled();
expect(instance.start).toHaveBeenCalledWith(0, 0, sut.duration);
});

it('should set tracks volume value same as own', (done) => {
sut.load().then(() => {
sut.volume = 0.5;
Expand Down