Update portaudio.jl
This commit is contained in:
parent
26fd1fdf23
commit
9c23d02066
1 changed files with 155 additions and 2 deletions
157
src/portaudio.jl
157
src/portaudio.jl
|
@ -1,14 +1,15 @@
|
||||||
typealias PaTime Cdouble
|
typealias PaTime Cdouble
|
||||||
typealias PaError Cint
|
typealias PaError Cint
|
||||||
typealias PaSampleFormat Culong
|
typealias PaSampleFormat Culong
|
||||||
# PaStream is always used as an opaque type, so we're always dealing with the
|
# PaStream is always used as an opaque type, so we're always dealing
|
||||||
# pointer
|
# with the pointer
|
||||||
typealias PaStream Ptr{Void}
|
typealias PaStream Ptr{Void}
|
||||||
typealias PaDeviceIndex Cint
|
typealias PaDeviceIndex Cint
|
||||||
typealias PaHostApiIndex Cint
|
typealias PaHostApiIndex Cint
|
||||||
typealias PaTime Cdouble
|
typealias PaTime Cdouble
|
||||||
typealias PaHostApiTypeId Cint
|
typealias PaHostApiTypeId Cint
|
||||||
typealias PaStreamCallback Void
|
typealias PaStreamCallback Void
|
||||||
|
typealias PaStreamFlags Culong
|
||||||
|
|
||||||
const PA_NO_ERROR = 0
|
const PA_NO_ERROR = 0
|
||||||
const PA_INPUT_OVERFLOWED = -10000 + 19
|
const PA_INPUT_OVERFLOWED = -10000 + 19
|
||||||
|
@ -81,6 +82,90 @@ function destroy(stream::PortAudioStream)
|
||||||
portaudio_inited = false
|
portaudio_inited = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
type Pa_StreamParameters
|
||||||
|
device::PaDeviceIndex
|
||||||
|
channelCount::Cint
|
||||||
|
sampleFormat::PaSampleFormat
|
||||||
|
suggestedLatency::PaTime
|
||||||
|
hostAPISpecificStreamInfo::Ptr{Void}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Pa_OpenStream(device::PaDeviceIndex,
|
||||||
|
channels::Cint, input::Bool,
|
||||||
|
sampleFormat::PaSampleFormat,
|
||||||
|
sampleRate::Cdouble, framesPerBuffer::Culong)
|
||||||
|
#=
|
||||||
|
Open a single stream, not necessarily the default one
|
||||||
|
The stream is unidirectional, either inout or default output
|
||||||
|
see http://portaudio.com/docs/v19-doxydocs/portaudio_8h.html
|
||||||
|
=#
|
||||||
|
streamPtr::Array{PaStream} = PaStream[0]
|
||||||
|
ioParameters = Pa_StreamParameters(device, channels,
|
||||||
|
sampleFormat, PaTime(0.001),
|
||||||
|
Ptr{Void}(0))
|
||||||
|
if input
|
||||||
|
err = ccall((:Pa_OpenStream, libportaudio), PaError,
|
||||||
|
(Ptr{PaStream}, Ref{Pa_StreamParameters}, Ptr{Void},
|
||||||
|
Cdouble, Culong, Culong,
|
||||||
|
Ptr{PaStreamCallback}, Ptr{Void}),
|
||||||
|
streamPtr, ioParameters, Ptr{Void}(0),
|
||||||
|
sampleRate, framesPerBuffer, 0,
|
||||||
|
Ptr{PaStreamCallback}(0), Ptr{Void}(0))
|
||||||
|
else
|
||||||
|
err = ccall((:Pa_OpenStream, libportaudio), PaError,
|
||||||
|
(Ptr{PaStream}, Ptr{Void}, Ref{Pa_StreamParameters},
|
||||||
|
Cdouble, Culong, Culong,
|
||||||
|
Ptr{PaStreamCallback}, Ptr{Void}),
|
||||||
|
streamPtr, Ptr{Void}(0), ioParameters,
|
||||||
|
sampleRate, framesPerBuffer, 0,
|
||||||
|
Ptr{PaStreamCallback}(0), Ptr{Void}(0))
|
||||||
|
end
|
||||||
|
handle_status(err)
|
||||||
|
streamPtr[1]
|
||||||
|
end
|
||||||
|
|
||||||
|
type Pa_AudioStream <: AudioStream
|
||||||
|
root::AudioMixer
|
||||||
|
info::DeviceInfo
|
||||||
|
show_warnings::Bool
|
||||||
|
stream::PaStream
|
||||||
|
sformat::PaSampleFormat
|
||||||
|
# NOTE: SharedArray is broken under Windows in the initial v0.40
|
||||||
|
# but later development versions may have corrected this
|
||||||
|
# this is only used by the input stream subprocess currently
|
||||||
|
sbuffer::SharedArray
|
||||||
|
parent_working::Bool
|
||||||
|
|
||||||
|
function Pa_AudioStream(device_index, channels=2, input=false,
|
||||||
|
sample_rate::Integer=44100,
|
||||||
|
framesPerBuffer::Integer=2048,
|
||||||
|
show_warnings::Bool=false,
|
||||||
|
sample_format::PaSampleFormat=paInt16)
|
||||||
|
#=
|
||||||
|
Get device parameters needed for opening with portaudio
|
||||||
|
default is input as 44100/16bit int, same as CD audio type input
|
||||||
|
=#
|
||||||
|
require_portaudio_init()
|
||||||
|
stream = Pa_OpenStream(device_index, channels, input, sample_format,
|
||||||
|
Cdouble(sample_rate), Culong(framesPerBuffer))
|
||||||
|
Pa_StartStream(stream)
|
||||||
|
root = AudioMixer()
|
||||||
|
datatype = PaSampleFormat_to_T(sample_format)
|
||||||
|
sbuf = SharedArray(datatype, framesPerBuffer)
|
||||||
|
this = new(root, DeviceInfo(sample_rate, framesPerBuffer),
|
||||||
|
show_warnings, stream, sample_format, sbuf, false)
|
||||||
|
info("Scheduling PortAudio Render Task...")
|
||||||
|
# the task will actually start running the next time the current task yields
|
||||||
|
if input
|
||||||
|
@schedule(pa_input_task(this))
|
||||||
|
else
|
||||||
|
@schedule(pa_output_task(this))
|
||||||
|
end
|
||||||
|
this
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
############ Internal Functions ############
|
############ Internal Functions ############
|
||||||
|
|
||||||
function portaudio_task(stream::PortAudioStream)
|
function portaudio_task(stream::PortAudioStream)
|
||||||
|
@ -112,6 +197,74 @@ function portaudio_task(stream::PortAudioStream)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function PaSampleFormat_to_T(fmt::PaSampleFormat)
|
||||||
|
#=
|
||||||
|
Helper function to make the right type of buffer for various
|
||||||
|
sample formats. Converts PaSampleFormat to a typeof
|
||||||
|
=#
|
||||||
|
retval = UInt8(0x0)
|
||||||
|
if fmt == 1
|
||||||
|
retval = Float32(1.0)
|
||||||
|
elseif fmt == 2
|
||||||
|
retval = Int32(0x02)
|
||||||
|
elseif fmt == 4
|
||||||
|
retval = Int24(0x04)
|
||||||
|
elseif fmt == 8
|
||||||
|
retval = Int16(0x08)
|
||||||
|
elseif fmt == 16
|
||||||
|
retval = Int8(0x10)
|
||||||
|
elseif fmt == 32
|
||||||
|
retval = UInt8(0x20)
|
||||||
|
else
|
||||||
|
info("Flawed input to PaSampleFormat_to_primitive")
|
||||||
|
end
|
||||||
|
typeof(retval)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pa_input_task(stream::Pa_AudioStream)
|
||||||
|
#=
|
||||||
|
Get input device data, pass as SharedArray, no rendering
|
||||||
|
=#
|
||||||
|
info("PortAudio Input Task Running...")
|
||||||
|
n = bufsize(stream)
|
||||||
|
try
|
||||||
|
while true
|
||||||
|
while ((Pa_GetStreamReadAvailable(stream.stream) < n ) |
|
||||||
|
stream.parent_working)
|
||||||
|
sleep(0.005)
|
||||||
|
end
|
||||||
|
Pa_ReadStream(stream.stream, sdata(stream.sbuffer), n,
|
||||||
|
stream.show_warnings)
|
||||||
|
stream.parent_working = true
|
||||||
|
sleep(0.005)
|
||||||
|
end
|
||||||
|
catch ex
|
||||||
|
warn("Audio Input Task died with exception: $ex")
|
||||||
|
Base.show_backtrace(STDOUT, catch_backtrace())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function pa_output_task(stream::Pa_AudioStream)
|
||||||
|
#=
|
||||||
|
Send output device data, no rendering
|
||||||
|
=#
|
||||||
|
info("PortAudio Output Task Running...")
|
||||||
|
n = bufsize(stream)
|
||||||
|
datatype = PaSampleFormat_to_T(stream.sformat)
|
||||||
|
buffer = zeros(datatype, n)
|
||||||
|
try
|
||||||
|
while true
|
||||||
|
while Pa_GetStreamWriteAvailable(stream.stream) < n
|
||||||
|
sleep(0.005)
|
||||||
|
end
|
||||||
|
Pa_WriteStream(stream.stream, buffer, n, stream.show_warnings)
|
||||||
|
end
|
||||||
|
catch ex
|
||||||
|
warn("Audio Output Task died with exception: $ex")
|
||||||
|
Base.show_backtrace(STDOUT, catch_backtrace())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
type PaDeviceInfo
|
type PaDeviceInfo
|
||||||
struct_version::Cint
|
struct_version::Cint
|
||||||
name::Ptr{Cchar}
|
name::Ptr{Cchar}
|
||||||
|
|
Loading…
Reference in a new issue