Position Audio Issue


Adding positional audio creates this issue sometimes

Sounds like a JavaScript floating error, not an 8thwall error. Add:
if (isFinite([your value])) {
// your code
}

tbh not sure where to add this, since All I doing is extending on tap to place example, instead of just placing model, I am also attaching positional audio to it, so I am not explicitly setting any value apart from setting volume of audio which is hardcoded while cloning.

import * as ecs from '@8thwall/ecs'

const {THREE} = (window as any)

// Components used by the Tap Place spawner
const {BoxGeometry, Material, Position, Quaternion, Scale, Shadow, ScaleAnimation} = ecs
const {vec3} = ecs.math

const componentsForClone = [
  Position, Quaternion, Scale, Shadow, BoxGeometry, Material, ScaleAnimation, ecs.PositionAnimation,
  ecs.RotateAnimation, ecs.CustomPropertyAnimation, ecs.CustomVec3Animation, ecs.FollowAnimation,
  ecs.LookAtAnimation, ecs.GltfModel, ecs.Collider, ecs.ParticleEmitter, ecs.Ui, ecs.Audio,
]

const cloneComponents = (sourceEid, targetEid, world) => {
  componentsForClone.forEach((component, i) => {
    if (component.has(world, sourceEid)) {
      const properties = component.get(world, sourceEid)
      const newProps = {}
      Object.keys(properties).forEach((key) => {
        const value = properties[key]
        if (typeof value === 'number') {
          if (Number.isFinite(value)) {
            newProps[key] = value
          } else {
            console.error(key, ' : Value is not finite')
          }
        } else {
          newProps[key] = value
        }
      })
      if (i === 17) {
        component.set(world, targetEid, {...newProps, volume: 0.8, paused: false, maxDistance: 100})
      } else {
        component.set(world, targetEid, {...newProps})
      }
      // console.log(newProps)
    }
  })
}

const v = vec3.zero()
const touchPoint = vec3.zero()

let objectCounter = 0

ecs.registerComponent({
  name: 'Tap Place',
  schema: {
    entityToSpawn1: ecs.eid,
    entityToSpawn2: ecs.eid,
    entityToSpawn3: ecs.eid,
    audioEntity1: ecs.eid,
    audioEntity2: ecs.eid,
    audioEntity3: ecs.eid,
    groundEntity: ecs.eid,
  },
  add: (world, component) => {
    // const overlay = document.createElement('div')
    // overlay.style.position = 'absolute'
    // overlay.style.top = '0px'
    // overlay.style.bottom = '0px'
    // overlay.style.left = '0px'
    // overlay.style.right = '0px'
    // overlay.style.background = 'black'
    // overlay.style.display = 'flex'
    // overlay.style.justifyContent = 'center'
    // overlay.style.alignItems = 'center'

    // const button = document.createElement('button')
    // button.innerText = 'Start'

    // overlay.appendChild(button)

    // // console.log(world)

    // document.body.appendChild(overlay)

    const {groundEntity, entityToSpawn1, entityToSpawn2, entityToSpawn3, audioEntity1, audioEntity2, audioEntity3} = component.schema

    if (!groundEntity) {
      console.error('Ground entity not set in schema')
      return
    }

    const pianoObject = world.three.entityToObject.get(entityToSpawn1)
    pianoObject.visible = false

    const saxophoneObject = world.three.entityToObject.get(entityToSpawn2)
    saxophoneObject.visible = false

    const violinObject = world.three.entityToObject.get(entityToSpawn3)
    violinObject.visible = false

    const entityOptions = [entityToSpawn1, entityToSpawn2, entityToSpawn3]
    const entityAudioOptions = [audioEntity1, audioEntity2, audioEntity3]
    // const audioOptions = ['https://raw.githubusercontent.com/Bhushan-Ctruh/assets/main/piano.mp3', 'https://raw.githubusercontent.com/Bhushan-Ctruh/assets/main/violin.mp3', 'https://raw.githubusercontent.com/Bhushan-Ctruh/assets/main/saxophone.mp3']

    const raycaster = new THREE.Raycaster()
    const mouse = new THREE.Vector2()
    let lastInteractionTime = 0

    function handleInteraction(event) {
      if (objectCounter === 3) return
      const currentTime = Date.now()
      if (currentTime - lastInteractionTime < 500) {
        return
      }
      lastInteractionTime = currentTime

      if (event.touches) {
        mouse.x = (event.touches[0].clientX / window.innerWidth) * 2 - 1
        mouse.y = -(event.touches[0].clientY / window.innerHeight) * 2 + 1
      } else {
        mouse.x = (event.clientX / window.innerWidth) * 2 - 1
        mouse.y = -(event.clientY / window.innerHeight) * 2 + 1
      }

      raycaster.setFromCamera(mouse, world.three.activeCamera)

      const groundObject = world.three.entityToObject.get(groundEntity)

      if (!groundObject) {
        console.error('Ground object not found for entity ID:', groundEntity)
        return
      }

      const intersects = raycaster.intersectObject(groundObject, true)

      if (intersects.length > 0) {
        touchPoint.setFrom(intersects[0].point)

        const prompt = document.getElementById('promptText')
        if (prompt) {
          prompt.style.display = 'none'
        }

        const newEid = world.createEntity()

        const selectedEntityToSpawn = entityOptions[objectCounter]
        const selectedAudio = entityAudioOptions[objectCounter]
        if (selectedEntityToSpawn) {
          // Clone an entity at the target position, with an initial scale of zero.
          cloneComponents(selectedEntityToSpawn, newEid, world)
          cloneComponents(selectedAudio, newEid, world)
          Position.set(world, newEid, touchPoint)
          Scale.set(world, newEid, v.makeZero())
        } else {
          alert('Somthing went wrong')
        }

        console.log(objectCounter)

        ScaleAnimation.set(world, newEid, {
          fromX: 0,
          fromY: 0,
          fromZ: 0,
          toX: objectCounter === 1 ? 0.1 : 1,
          toY: objectCounter === 1 ? 0.1 : 1,
          toZ: objectCounter === 1 ? 0.1 : 1,
          duration: 500,
          loop: false,
          easeIn: true,
          easeOut: true,
        })
        objectCounter++
      }
    }

    // button.addEventListener('click', (e) => {
    //   e.stopPropagation()
    //   overlay.remove()
    // })
    window.addEventListener('pointerup', handleInteraction)
  },
})

Though as you suggested I have added finite check for number values, but it still seems to break. Also one thing I have observed that it breaks a lot on ios devices compared to android.

const value === ‘number’ seems to be the issue there. If “value” can be Infinity, typeof value === ‘number’ still results in try for infinite numbers. I would change that to:
if (typeof value === ‘number’ && isFinite(value))

You can’t simply replace the typeof since arrays can also be finite and you want to be sure to associate it correctly.

Or, better yet, refactor to a switch case so you’re not dealing with nested if statements:

Object.keys(properties).forEach((key) => {
        const value = properties[key]
        switch(typeof value){
          case 'number':
            if (Number.isFinite(value)) newProps[key] = value
            break;
          default:
            newProps[key] = value
        }
      })

replaced with switch statement and it still breaks with same issue. I tried logging and I don’t think thats where the issue is tbh.
Found this thread on three js Failed to execute 'linearRampToValueAtTime' on 'AudioParam' · Issue #20718 · mrdoob/three.js · GitHub

Yea… Honestly have no idea then. Sorry… (Canadian)

But then is it issue with my implementation or is it some issue with 8th wall. How should I even proceed?