Skip to content

Instantly share code, notes, and snippets.

@jkrumbiegel
Last active December 5, 2021 20:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jkrumbiegel/d309bde8635cfb32d7db598bf30c98ee to your computer and use it in GitHub Desktop.
Save jkrumbiegel/d309bde8635cfb32d7db598bf30c98ee to your computer and use it in GitHub Desktop.
basic portaudio
using Pkg
pkg"activate @portaudio"
using PortAudio.LibPortAudio
mutable struct Audio
ptr::Ptr{Float32}
buffer::Vector{Float32} # vector reference so no problems with garbage collection
len::Int
pos::Ptr{Cint} # position of player in buffer
posvec::Vector{Cint} # vector reference so no problems with garbage collection
end
function Audio(vec::Vector{Float32})
posvec = Cint[1]
Audio(
Base.unsafe_convert(Ptr{Float32}, vec),
vec, # for garbage safety
length(vec),
Base.unsafe_convert(Ptr{Cint}, posvec),
posvec, # for garbage safety
)
end
function mycallback(inputbuffer, outputbuffer, framecount, timeinfo, statusflags, userdata)::Cint
audio = unsafe_load(Ptr{Audio}(userdata))
ptr = audio.ptr
pos = unsafe_load(audio.pos, 1)
for i in 1:256
x = unsafe_load(ptr, pos - 1 + i)
unsafe_store!(outputbuffer, x, 2i - 1)
unsafe_store!(outputbuffer, x, 2i)
end
newpos = mod1(pos + 256, audio.len)
unsafe_store!(audio.pos, newpos, 1)
return 0
end
cfunc = @cfunction mycallback Cint (Ptr{Float32}, Ptr{Float32}, Culong, Ptr{LibPortAudio.PaStreamCallbackTimeInfo}, LibPortAudio.PaStreamCallbackFlags, Ptr{Cvoid})
macro checkerr(exp)
quote
errcode = $(esc(exp))
e = LibPortAudio.PaErrorCode(errcode)
if e != LibPortAudio.paNoError
error("PortAudio errored with status code $errcode ($(string(e)))")
end
end
end
let
buflen = 4096
framecount = 256
samplerate = 44100
buffer = zeros(Float32, buflen)
audio = Audio(buffer)
try
@checkerr LibPortAudio.Pa_Initialize()
mutable_pointer = Ref{Ptr{LibPortAudio.PaStream}}(0)
@checkerr LibPortAudio.Pa_OpenDefaultStream(
mutable_pointer,
0,
2,
LibPortAudio.paFloat32,
samplerate,
framecount,
cfunc,
Ref(audio),
)
pointer_to = mutable_pointer[]
@checkerr LibPortAudio.Pa_StartStream(pointer_to)
starttime = time()
lastplayhead = 1
period = 0.0
increment = 0.02
while true
playhead = Int(audio.posvec[1])
nsamples = mod(playhead - lastplayhead, buflen)
nsamples <= 0 && continue
pos = lastplayhead
lastplayhead = playhead
for i in 1:nsamples
buffer[pos] = 0.3 * sin(period)
pos = mod1(pos + 1 , buflen)
period += increment
end
increment = 0.04 + 0.002 * sin(2pi * 3 * time())
yield()
if time() - starttime > 2
break
end
end
@checkerr LibPortAudio.Pa_StopStream(pointer_to)
finally
@checkerr LibPortAudio.Pa_Terminate()
end
@show audio.posvec
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment