Loading Audio

I can’t seem to load audio outside of the scenes’ preload method. If I want to manually load assets, like images, outside of the preload method I’m able to do so. But with sound, it throws an error when trying to play that audio by the key I specified.

Something I’m missing?

What’s the error?

First, you need to load audio in preload function.

preload() {
    this.load.audio('mySound', 'beep.mp3');`
}

Then you can play that audio with key mySound in create function.

create() {
    let sfx = this.sound.add('mySound');
    sfx.play();
}

Check out this example.

1 Like

If you call any this.load methods from outside of Scene.preload then you need to start the Loader going yourself by calling Loader.start() . It’s only automatically started during the Scene preload.

Phaser.Loader.LoaderPlugin

If you load an audio file outside of preload(), it will not instantly be available. You have to wait for the filecomplete event.

create() {
  let songLoader = this.load.audio('song', ['assets/sounds/0781.ogg'])
  songLoader.on('filecomplete', () => this.sound.add('song').play())
  songLoader.start()
}

Or if you want to use async/await:

async create() {

  const asyncLoader = loaderPlugin => {
    return new Promise(resolve => {
      loaderPlugin.on('filecomplete', () => resolve()).on('loaderror', () => resolve())
      loaderPlugin.start()
    })
  }

  await asyncLoader(this.load.audio('song', ['assets/sounds/0781.ogg']))
  this.sound.add('song').play()
}
2 Likes

Oh, I just found out something interesting. I’m making a “Loader” scene, it comes into view on top when transitioning between scenes. What my Loader scene was doing was checking the progress of the loader, and when it was >= 1 it would init the next scene (Title scene for example), and in that scene it would start the audio. Something internally isn’t ready to play the audio even though the load progress value is >= 1, you have to wait for the complete event.

Here is some sample code to replicate:

class Test extends Phaser.Scene {
    constructor() {
        super({ key: 'Test' })
    }

    create() {
        this.load.progress = 0;

        this.load.audio('music', ['./some-bg-music.ogg', './some-bg-music.mp3']);
        this.load.once('complete', () => {
            // this will play just fine
            // this.sound.play('music', { loop: -1 });
        });
        this.load.start();
    }

    update() {
        // this will not work
        if (this.load.progress >= 1) {
            this.load.progress = 0;

            // can't do it like this, something internal going on is preventing me from playing this sound asap
            this.sound.play('music', { loop: -1 });
        }
    }
}

let game = new Phaser.Game({
    type: Phaser.AUTO,
    width: 480,
    height: 320,
    parent: 'game-wrapper',
    loader: {
        path: './assets/'
    },
    scene: [Test]
});

You can use !this.load.isLoading() instead

playing = false

create() {
  this.load.audio('song', ['assets/sounds/0781.ogg'])
  this.load.start()
}

update() {
  if (!this.playing && !this.load.isLoading()) {
    this.playing = true
    this.sound.play('song') // this works
  }

Also, the load.*() methods don’t load anything immediately, regardless of asset type, whether called in preload() or not.