Jump to content

[improvement] AssetManager onFinish called after sounds are ready to play


AlbertTJames
 Share

Recommended Posts

Hi,

I had trouble loading sounds and playing them directly at startup. I realised that the AssetManager calls the onFinish callback before loaded sounds _audioBuffer is set and are _readyToPlay.

 

I dont know if it was a designed choice but it would be really useful either if the asset manager waited by default for the readytoplay flag to be set, or if there was an option to set when adding the job to the manager.

Link to comment
Share on other sites

Hello,

I'm not sure to understand your issue. Here's the doc I've written on AssetManager + Sounds: http://doc.babylonjs.com/overviews/playing_sounds_and_music#loading-a-sound-using-the-assets-manager using this PG sample: http://www.babylonjs-playground.com/#PCY1J#8 and this one is playing immediatly once loaded: http://www.babylonjs-playground.com/#PCY1J#38

Can you please share a PG of the issue you've got on your side?

Thanks,

David

Link to comment
Share on other sites

Looking at your PG I understand the way it was intended to work. The asset manager loads raw data, then you state for each sound a callback when the Sound object will be finished transforming the data into readable sound (_audioBuffer) ?

 I see how I can fix my problem better on my end, and I am not sure indeed that the behavior I am requesting is really relevant, my bad.

To explain where my request come from is that I am building a little layer of abstraction above Babylon and I have a function that can load a bunch of assets and store them into an external object to be used by different scenes and interact with the website too. I was intended for user to simply call this function with an object like so:

taskObject.assetsToLoad = {
      logo2: '/assets/experiment-js-light.svg',
      heldenklage: {
        path: '/assets/sounds/nietzscheHeldenklage.mp3',
        type: 'sound',
      },
    }

the function would return a promise resolving when the assetManager finished all its work.

It was using the assetManager like that: http://www.babylonjs-playground.com/#PCY1J#40 

Anyways.. I understand that I have to give a callback when creating the sound, but in this context it is not ideal. 

I will just make a bunch of separate promises waiting for the sounds to be ready to play before resolving the main loader. 

But I am curious, what takes time between AssetManager loading and the sound being processed ? 

Link to comment
Share on other sites

So maybe - for this post not to be for nothing, here is the solution I am using to make sure the sounds are ready before resolving.

The deferred function I am using is pretty basic, adapted from somewhere, can't remember where.. maybe bluebird:

function Deferred() {
  this.resolve = null
  this.reject = null

  /* A newly created Pomise object.
   * Initially in pending state.
   */
  this.promise = new Promise((resolve, reject) => {
    this.resolve = resolve
    this.reject = reject
  })
  Object.freeze(this)
}

 

And there is the loading function, there is a lot of elements that will be useful to nobody, the two important part are surrounded by // IMPORTANT PART ++ // ?

loadAssets(assetObject = mandatory(), scene = mandatory(), assetFolder = '') {
    if (assetObject.constructor !== Object) {
      throw new Error('TaskObject.loadAssets: assetObject is not an Object')
    }

    if ((assetFolder === '') && (typeof this.ASSETS_FOLDER !== 'undefined')) {
      assetFolder = this.ASSETS_FOLDER
    }

    const textureFormats = ['png', 'bmp', 'jpg', 'tiff', 'svg']
    const soundFormats = ['wav', 'mp3', 'flac', 'aac', 'mp4', 'ogg']

    const assetManager = new BABYLON.AssetsManager(scene)
    const R = this.R

    const binaryPromises = []

    const names = Object.keys(assetObject)
    let field
    let type
    let path
    for (let i = 0; i < names.length; i++) {
      field = assetObject[names[i]]

      if (field.constructor === String) {
        path = this.ASSETS_FOLDER + field

        if (textureFormats.indexOf(R.getFormat(path)) !== -1) {
          type = 'texture'
        } else if (soundFormats.indexOf(R.getFormat(path)) !== -1) {
          type = 'sound'
        } else {
          console.warn('TaskObject.loadAssets: asset invalid or not implement with shorthand function')
          type = 'invalid'
        }
      } else if ((field.constructor === Object) && (Object.keys(field).includes(['path', 'type']))) {
        path = this.ASSETS_FOLDER + field.path
        type = field.type
      } else {
        console.warn('TaskObject.loadAssets: asset invalid or not implement with shorthand function')
        type = 'invalid'
      }

      if (type === 'texture') {
        const assetManagerTask = assetManager.addTextureTask(`${names[i]}Task`, path)
        assetManagerTask.onSuccess = function (task) {
          R.add({
            textures: {
              [this.textureName]: task.texture,
            },
          })
        }.bind({
          textureName: names[i],
        })
      } else if (type === 'sound') {
        // IMPORTANT PART ++++++++++ //
        const assetManagerTask = assetManager.addBinaryFileTask(`${names[i]}Task`, path)
        assetManagerTask.onSuccess = function (task) {
          const isReady = new Deferred()
          binaryPromises.push(isReady.promise)
          R.add({
            sounds: {
              [this.soundName]: new BABYLON.Sound(this.soundName, task.data, scene, isReady.resolve),
            },
          })
        }.bind({
          soundName: names[i],
        })
      }
      // TODO all the rest such as Meshes.. what else ?
    }

    /* --- Create a Deferred promise that will resolve after loading is complete --- */
    const loadDeferred = new Deferred()

    assetManager.load()
    assetManager.onFinish = function onFinish(tasks) {
      debuglog('TaskObject.loadAssets: tasks completed', tasks)

      // IMPORTANT PART +++++ //
      Promise.all(binaryPromises).then(() => loadDeferred.resolve(tasks))
    }

    return loadDeferred.promise
  }


Anyways, thanks :)

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...