soundbuffer(): how to use it with raw PCM data?

Can we talk about this? What does a string made of FORMAT_MONO8 look like? what about the other formats? the example code doesn’t do anything but make a momentary distorted glitch sound. if it’s writing 0xAD a bunch of times, that’s just going to correspond to a DC offset, which will damage the ipad speaker.

i’ve been trying to get the following code to work, but haven’t had much luck:

function setup()
    tap = false
    parameter.integer("freq",40,4000,440)
    parameter.number("length",0.1,4,0.2)                
end

local sampleRate = 44100 
local maxtemp = 0
local mintemp = 0

function makeBuffer()
    local data = ""
    local datum = {}
    local time
    local i
    numSamples = sampleRate * length
    local cycleLength = sampleRate / freq
    local counter = 0

    for i = 1,numSamples do
        datum[i] = math.sin( 2 * math.pi * ( counter / freq ) ) * 32768
        data = data .. string.format("%x", tostring( datum[i] ) )
        counter = counter + 1
        if( counter > cycleLength ) then
            counter = counter - cycleLength
            print( "counter: ", counter )
        end
    end
    print( "data should be ", numSamples * 2, "bytes long" )
    print( "data length ", string.len( data ) )
    print( datum[1], datum[2], datum[3] )
    return soundbuffer( data, FORMAT_MONO16, sampleRate )
end

function touched(touch)
    if touch.state == ENDED and
       touch.tapCount == 1 then
       tap = true
    end
end

function draw()
    background(0)
    if tap then
        b = makeBuffer()
        sound(b)
        tap = false
    end  
end

it makes a sound, but it ain’t no sinewave like it should be.

So, what format does it need the data in? normally raw PCM data on iOS is comprised of Float32’s, according to the CoreAudio reference guides.

I don’t know that much about sound synthesis, but I did a little researching a few months ago and made this code (which kind of does something similar to what you’re trying to do):

-- Creating a sound buffer object
function setup()
    tap = false
    parameter.integer("freq",1,4000,990) -- A
    parameter.number("length",0.1,1,0.5)            
end


-- Explode table
function _values(t)
    local i = 0
    return function() i = i + 1; return t[i] end
end

function _explodeNext(iter, t)
    local v = iter(t)
    if v ~= nil then
        return v, _explodeNext(iter, t)
    else
        return
    end 
end

function explodeTable(t)
    local iter = _values(t)
    return _explodeNext(iter, t)
end


function makeBuffer(len, multi)
    local data = ""
    datum="\\0\\xAD\\\"
    numSamples = freq * len * multi
    
    for i = 1,numSamples/#datum do
        data = data ..datum

    end
    
    return soundbuffer( data, FORMAT_MONO8, freq * multi)
end

function touched(touch)
    if touch.state == ENDED and
       touch.tapCount == 1 then
       tap = true
    end
end

function draw()
    background(0)
    
    -- delay, length, chord
    mymusic = { {0, 1.0, { 0, 4, 7, 12 } }, {1.0, 1.0, { 0, 5, 9, 12 } }, {1.0, 4.0, { 0, 4, 7, 12 } } }
    
    mymusic = { {0, 1, { -12, -8, -5 } }, {0, .25, { 4 } }, {.25, .25, { 4 } }, {.25, .5, { 4 } }, {0.5, .25, { 4 } }, {0, 1, { -12, -8, -5 } }, 
        {0.25, .25, { 4 } }, {0.25, .5, { 4 } },   
        {0.5, .25, { 4 } }, {0, 1, { -12, -8, -5 } },  {0.25, .25, { 7 } }, {0.25, .25, { 0 } }, {0.25, .25, { 2 } },
        {0.25, 1, { 4 } }, {0, 1, { -12, -8, -5 } } } 
    
    if tap then
        args = {}
        mul = 1
        for i, a in ipairs(mymusic) do
            t = a[1]
            l = a[2]
            chord = a[3]
            for j, v in ipairs(chord) do
                b = makeBuffer(l, 2 ^ (v/12))
                args[#args+1] = tween.delay(t, sound, b) 
                t = 0
           end
        end
        tween.sequence(explodeTable(args))
        tap = false
    end            
end

```

I also think (now that I'm remebering my research) that you need to keep the slashes by excusing the slash with a slash (look at the code). Hope this example helps a bit. Thanks!

@matkatmusic I tried fiddling with your code, but it keeps freezing everything up! I’ll keep trying…

But PCM comes in signed (-32766 to 32767) and unsigned (0 to 65535). Not sure which Codea is looking for.

Have you see this thread from a couple of years back? Not sure if it’s anywhere near what you want to do, but it is to do with sound…
http://twolivesleft.com/Codea/Talk/discussion/comment/5695#Comment_5695

@matkatmusic Here’s an 8bit solution. Signed ints are needed.

function setup()
    tap = false
    parameter.integer("freq",40,4000,440)
    parameter.number("length",0.1,4,0.2)                
end

local sampleRate = 44100 

function makeBuffer()
    local data = ""
    local datum = 0
    local time
    local i
    numSamples = sampleRate * length
    
    for i = 1,numSamples do 
        -- get a signed integer
        datum = math.floor(math.sin(( 2 * math.pi * i) * freq / sampleRate)* 127)
        -- turn it into a char and concat
        data = data .. string.char(datum + 128)
    end
    print( "data should be ", numSamples, "bytes long" )
    print( "data length ", string.len( data ) )
    return soundbuffer( data, FORMAT_MONO8, sampleRate )
end

function touched(touch)
    if touch.state == ENDED and
       touch.tapCount == 1 then
       tap = true
    end
end

function draw()
    background(0)
    if tap then
        b = makeBuffer()
        sound(b)
        tap = false
    end  
end

Notice that I stripped down to the bare minimum. Since sines are cyclical, unless you need to capture a single cycle, the counter function is not necessary.