Craft 3D AudioSource - A very basic directional audio playing class.

Add this component to an empty entity and call entity:play() in order to unpause the audioSource. If loop is set to true, then it will continuously play the audio. If listener ~= nil then the audioSource will calculate the volume and pan using logarithmic rolloff based on the listener’s position.

**Changed the code after @binaryblues found a bug, now the volume and pan are updated while the audioSource is looping

audioSource=class()
function audioSource:init(entity,audio,loop,listener)
    self.entity=entity
    entity.audio=audio or nil
    entity.listener=listener or nil
    entity.paused=true
    entity.volume=1
    entity.pan=0
    entity.pitch=1
    entity.minDist=0
    entity.maxDist=100
    entity.loop=loop or false
    self.entity.play=function(entity)
        self.entity.paused=false
    end
end


function audioSource:update()
    if self.entity.listener~=nil then
        self.entity.dist=self.entity.listener.position:dist(self.entity.position)
        if self.entity.listener.x~=self.entity.x then
            self.entity.distX=self.entity.listener.x-self.entity.x
        else self.entity.distX=0 end
        self.entity.volume=
        1/self.entity.dist
        if self.entity.distX<0 then
            self.entity.pan=-(1*self.entity.distX*self.entity.volume)
        elseif self.entity.distX>0 then
            self.entity.pan=-(1*self.entity.distX*self.entity.volume)
        else self.entity.pan=0
        end
    end
    if self.entity.paused==false and self.entity.listener==nil then
        self.entity.sound=sound(self.entity.audio,
        self.entity.volume,
        self.entity.pitch,
        self.entity.pan,
        self.entity.loop)
        self.entity.paused=true
    end
    if self.entity.paused==false and self.entity.listener~=nil then
        self.entity.sound=sound(self.entity.audio,
        self.entity.volume,
        self.entity.pitch,
        self.entity.pan,
        self.entity.loop)
        self.entity.paused=true
    end
    if self.entity.sound~=nil and not self.entity.sound.paused then
        self.entity.sound.volume=self.entity.volume
        self.entity.sound.pan=self.entity.pan
    end
end

Very good!

I thought about the sound effect. It’s really good. But my update doesn’t seem to be working? my test code below:

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    e = scene:entity()
    e2= scene:entity()
    e.position = vec3(0,0,0)
    e.rotation = quat.eulerAngles(45,45,0) 
    myCanvas = e:add(canvas,100,200,color(83, 80, 233))
    myAudio = e:add(audioSource,asset.downloaded.A_Hero_s_Quest.Arrow_Shoot_1,true,e2)
    e:play()
    
    parameter.number("x",-100,100,0)
end

function update(dt)
    -- Update the scene (physics, transforms etc)
    scene:update(dt)
    e2.x = x
end

-- Called automatically by codea 
function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()	
    -- e:draw(12,23,10,10,color(227, 233, 80),drawRnd)
    e:draw(function() drawRnd(e.w2,e.h2,32,32,color(0,255,0,255))end)
end

function touched(touch)
    if touch.state == BEGAN then
        print("e2:",e2.position)
        print("e:",e.position)
    end
end

@binaryblues

Here’s a quick example I made, I can see how that would be confusing!

function setup()
    -- Create a new craft scene
    scene = craft.scene()

    -- Create a new entity
    e=scene:entity()

    -- Add the audioSource and set it's listener to the camera
    
e:add(audioSource,asset.downloaded.A_Hero_s_Quest.Arrow_Shoot_1,false,scene.camera)

    --Add a monkey because they're cool
    e:add(craft.renderer,craft.model(asset.builtin.Primitives.Monkey))

    -- Move the camera forward and rotate it
    scene.camera.position=vec3(0,0,40)
    scene.camera.eulerAngles=vec3(0,-180,0)

    parameter.number("tx",-360,360)
    tx=0
    parameter.number("ty",-360,360)
    ty=0
    parameter.number("tz",-360,360)
    tz=0
    parameter.action("play",function()
        e:play()
    end)
end

function update(dt)
    scene:update(dt)
    -- move the monkey and hit the play action!
    e.position=vec3(tx,ty,tz)
end

function draw()
    update(DeltaTime)

    -- Draw the scene
    scene:draw()
end

@arismoko What I mean is that if I manually change the X value of the e2 in the code, I get a pretty amazing sound effect, but when I use the parameter.number to dynamically adjust it, the sound intensity doesn’t seem to change at all, check out my test video:

https://youtu.be/XxLOatN-fXE

Here’s the effect of manually modifying the X value in the code, which is pretty obvious?

https://youtu.be/BBcHw_mxuEE

I see, I never stopped to check that. So when a loop has begun, it seems like the volume doesn’t actually update? I’ll have to figure out a different way to loop through the sound in that case. Thank you so much for finding that! @binaryblues

Thanks for your share! I loved the sound effect and thought it would be cool to use in dungeon games in the future, with players hearing footsteps approaching in the dark

@binaryblues absolutely! if you manage to find a use for this that would be awesome! I just updated it, it was a lot easier than I thought it would be. Here is a video of it looping and updating. Thanks for the help again!

https://youtube.com/watch?v=cJP6rPDDMqE

Thanks for your update! It’s all good. It’s working really well?