Hidden sound functions!

While I was fiddling around with getmetatable() on various Codea metatables, I discovered quite a few undocumented and unmentioned functions of sound() instances. When I run a debug print of all its values, it says this:

tostring = "Soundsource: "
type = "userdata"
getmetatable =

rewind: function: 0x171044890
stopPitch: function: 0x170c450a0
panTo: function: 0x171044b60
__tostring: function: 0x171044e30
fadeTo: function: 0x171045100
stopActions: function: 0x1710451c0
stopPan: function: 0x171045850
stop: function: 0x1710450d0
pitchTo: function: 0x171045820
stopFade: function: 0x170e58a50
__newindex: function: 0x170e5b570
__index: function: 0x170e58690
__gc: function: 0x171045160

As you can see, some new functions:

fadeTo
panTo
pitchTo
rewind
stop
stopActions
stopFade
stopPan
stopPitch

All the information I can discover is this:

fadeTo(volume, time) - tweens the volume to the specified over the time specified
panTo(pan, time) - tweens the pan to the specified over the time specified
pitchTo(pitch, time) - tweens the pitch to the specified over the time specified
rewind(?) - doesn't seem to take parameters, just stops the sound.
stop() - stops the sound
stopActions() - stops all tweens
stopFade() - stops volume tweening
stopPan() - stops pan tweening
stopPitch() - stops pitch tweening

Here’s the code I used to find them:

-- Metatesting

-- Use this function to perform your initial setup
function setup()
    print("Hello World!")
    parameter.action("Play Normal", function()
        if obj ~= nil then
            obj:stop()
        end
        obj = sound("Game Sounds One:Wind 1")
    end)
    parameter.action("Play Edited", function()
        if obj ~= nil then
            obj:stop()
        end
        obj = sound("Game Sounds One:Wind 1")
        obj.volume = 1
        obj:fadeTo(0, 2)
        tween.delay(1.5, function()
            obj:stopFade()
        end)
    end)
    parameter.action("Stop Sounds", function()
        if obj ~= nil then
            obj:stop()
        end
    end)
    local obj = sound("Game Sounds One:Wind 1")
    obj:stop()
    local str = "tostring = \"" .. tostring(obj) .. "\"\
type = \"" .. type(obj) .. "\"\
getmetatable =\
\
"
    for k, v in pairs(getmetatable(obj)) do
        str = str .. k .. ": " .. tostring(v) .. "\
"
    end
    print(str)
end

-- This function gets called once every frame
function draw()
    -- This sets a dark background color 
    background(40, 40, 50)

    -- This sets the line thickness
    strokeWidth(5)

    -- Do your drawing here
    
end

Cool discovery (I think, i don’t have my iPad with me)

@SkyTheCoder, nice work, I think these are not important because you can do them yourself with tween?

@SkyTheCoder Awesome, you’ve got an inquisitive mind haven’t you. I’ve been using tween.sequence to replicate pitchTo(), do they all work as described?

Uh… I’m kind of new to Codea… Don’t make fun but how DO you TWEEN?

@aurumcoder2624, tween takes these arguments:

tween(time, table, newTable, tweenType, callback) (tweenType and callback are optional)

so for example:

tween(2, _G, { x = 20 })

says: take 2 seconds to change values from table _G (where global variables are stored) to match the values in table { x = 20 }

basically it will, over 2 seconds, increment global variable x to equal 20.

Hope this isn’t too confusing!

Nah, I understand (vaguely)

But how does tween use this generator to animate figures?

@NatTheCoder These functions aren’t documented anywhere and even Simeon and John themselves down at TLL didn’t say anything about them. How did you or anyone else know them?

@JakAttak (in response to first comment) You can’t tween metatables, can you?

@Luatee As far as I know, they do.

@SkyTheCoder, interesting question, I hadn’t tried it

@SkyTheCoder nice find, I forgot we implemented these (and obviously forgot to document them). They are missing some error checking, but basically they work as you describe. Also note that these APIs might change in the future.

Is there any way to buffer the sound/music? I managed to make kind of a launchpad, but there is a little gap between the loops… Anyway, it sounds great!

These sound great and thank you @piinthesky for putting me onto this thread.

I was hoping that I could use them in this way but the sound definitely wont stop as yet.

Can you guys help?

if timer==69 then
        so=sound("Documents:7")
       -- sound("Documents:7",1)
            
    end
        if timer==150 then
            if so ~= nil then
            so:stop()
            end
        end

The intent is to cut short the sound. At the moment by time, but also to code it as part of a button that skips this part of the game.

Thanks
Rich

@Majormorgan Here’s an example that starts the sound when you tap the screen, then stops the sound when you tap the screen again. Slide to parameter switch to use a timer. The sound will start at 100 and stop at 200. Tapping the screen while the timer is running will reset the count and stop the sound if it’s playing.

function setup()
    parameter.boolean("use_timer",false,set)
    cnt=0
end

function draw()
    background(40, 40, 50)
    fill(255)
    if use_timer then
        text("sound starts at 100",WIDTH/2,HEIGHT-150)
        text("sound stops  at 200",WIDTH/2,HEIGHT-175)
        text("tap screen to reset count",WIDTH/2,HEIGHT-220)
        cnt=cnt+1
        text("count  "..cnt,WIDTH/2,HEIGHT-100)
        if cnt==100 then
            s=sound("Game Sounds One:Crowd Cheer")
        elseif cnt==200 then
            s:stop()
            s=nill
        end
    else
        if s==nil then
            text("Tap screen to start the sound",WIDTH/2,HEIGHT/2)
        else
            text("Tap screen to stop the sound",WIDTH/2,HEIGHT/2)
        end
    end
end

function set()
    cnt=0
    if s~=nil then
        s:stop()
    end
    s=nil
end

function touched(t)
    if t.state==BEGAN then
        if not use_timer then
            if s==nil then
                s=sound("Game Sounds One:Crowd Cheer")
            else
                s:stop()
                s=nil
            end
        else
            set()
        end
    end
end

Thanks @dave1707 - has the link gone missing? :wink:

@Majormorgan Sorry, I was in a hurry. After I wrote the message I forgot to post the program and just closed the iPad.

No problem @dave1707 - I put your code into a new codea project and it works fine.

So I’ve looked at your code and for what I need this should be it:

if timer==0 then
    --if s==nil then
                s=sound("Game Sounds One:Crowd Cheer")
            elseif timer==50 then
                s:stop()
                s=nil
            end
timer=timer+1

But for some reason it doesn’t stop the files.

No I think I know why. I am also playing music at the same time which is looping.

if playmusic==0 then
music("Project:Credits",true,0.4)
end

So now I’ve got this

if playmusic==0 then
mu=music("Project:Credits",true,0.4)
end

It’s because I wasn’t defining the music, regardless of s:stop() the music loop meant it was being ignored.

I was having such a muppet moment.

Thank you!

@Majormorgan I know that this is completely irrelevant, but you should start getting into the habit of keeping everything properly indented. It really does help a lot