removed blocksize parameter

This commit is contained in:
Jakub Wronowski 2020-02-18 23:04:51 +01:00
parent bea3577abe
commit 1fe68cf857

View file

@ -13,10 +13,7 @@ export PortAudioStream
include("libportaudio.jl") include("libportaudio.jl")
# These sizes are all in frames # This size is in frames
# the block size is what we request from portaudio if no blocksize is given.
const DEFAULT_BLOCKSIZE=4096
# data is passed to and from portaudio in chunks with this many frames, because # data is passed to and from portaudio in chunks with this many frames, because
# we need to interleave the samples # we need to interleave the samples
@ -34,6 +31,10 @@ mutable struct PortAudioDevice
maxoutchans::Int maxoutchans::Int
defaultsamplerate::Float64 defaultsamplerate::Float64
idx::PaDeviceIndex idx::PaDeviceIndex
lowinputlatency::Float64
lowoutputlatency::Float64
highinputlatency::Float64
highoutputlatency::Float64
end end
PortAudioDevice(info::PaDeviceInfo, idx) = PortAudioDevice( PortAudioDevice(info::PaDeviceInfo, idx) = PortAudioDevice(
@ -42,7 +43,11 @@ PortAudioDevice(info::PaDeviceInfo, idx) = PortAudioDevice(
info.max_input_channels, info.max_input_channels,
info.max_output_channels, info.max_output_channels,
info.default_sample_rate, info.default_sample_rate,
idx) idx,
info.default_low_input_latency,
info.default_low_output_latency,
info.default_high_input_latency,
info.default_high_output_latency)
function devices() function devices()
ndevices = Pa_GetDeviceCount() ndevices = Pa_GetDeviceCount()
@ -59,7 +64,7 @@ devnames() = join(["\"$(dev.name)\"" for dev in devices()], "\n")
mutable struct PortAudioStream{T} mutable struct PortAudioStream{T}
samplerate::Float64 samplerate::Float64
blocksize::Int latency::Float64
stream::PaStream stream::PaStream
warn_xruns::Bool warn_xruns::Bool
sink # untyped because of circular type definition sink # untyped because of circular type definition
@ -68,17 +73,13 @@ mutable struct PortAudioStream{T}
# this inner constructor is generally called via the top-level outer # this inner constructor is generally called via the top-level outer
# constructor below # constructor below
# TODO: handle blocksize=0, that should be the default and generally works
# much better than trying to specify
# TODO: expose latency parameter
# TODO: pre-fill outbut buffer on init # TODO: pre-fill outbut buffer on init
# TODO: recover from xruns - currently with low latencies (e.g. 0.01) it # TODO: recover from xruns - currently with low latencies (e.g. 0.01) it
# will run fine for a while and then fail with the first xrun. # will run fine for a while and then fail with the first xrun.
# TODO: figure out whether we can get deterministic latency... # TODO: figure out whether we can get deterministic latency...
# TODO: write a latency tester app
function PortAudioStream{T}(indev::PortAudioDevice, outdev::PortAudioDevice, function PortAudioStream{T}(indev::PortAudioDevice, outdev::PortAudioDevice,
inchans, outchans, sr, blocksize, inchans, outchans, sr,
warn_xruns, latency) where {T} latency, warn_xruns) where {T}
inchans = inchans == -1 ? indev.maxinchans : inchans inchans = inchans == -1 ? indev.maxinchans : inchans
outchans = outchans == -1 ? outdev.maxoutchans : outchans outchans = outchans == -1 ? outdev.maxoutchans : outchans
inparams = (inchans == 0) ? inparams = (inchans == 0) ?
@ -87,12 +88,12 @@ mutable struct PortAudioStream{T}
outparams = (outchans == 0) ? outparams = (outchans == 0) ?
Ptr{Pa_StreamParameters}(0) : Ptr{Pa_StreamParameters}(0) :
Ref(Pa_StreamParameters(outdev.idx, outchans, type_to_fmt[T], latency, C_NULL)) Ref(Pa_StreamParameters(outdev.idx, outchans, type_to_fmt[T], latency, C_NULL))
this = new(sr, blocksize, C_NULL, warn_xruns) this = new(sr, latency, C_NULL, warn_xruns)
# finalizer(close, this) # finalizer(close, this)
this.sink = PortAudioSink{T}(outdev.name, this, outchans) this.sink = PortAudioSink{T}(outdev.name, this, outchans)
this.source = PortAudioSource{T}(indev.name, this, inchans) this.source = PortAudioSource{T}(indev.name, this, inchans)
this.stream = suppress_err() do this.stream = suppress_err() do
Pa_OpenStream(inparams, outparams, sr, blocksize, paNoFlag, Pa_OpenStream(inparams, outparams, sr, 0, paNoFlag,
nothing, nothing) nothing, nothing)
end end
@ -102,6 +103,10 @@ mutable struct PortAudioStream{T}
end end
end end
function defaultlatency(devices...)
return maximum(d -> d.highoutputlatency, devices) #TODO(jakubwro): add in/out and high/low logic
end
# this is the top-level outer constructor that all the other outer constructors end up calling # this is the top-level outer constructor that all the other outer constructors end up calling
""" """
PortAudioStream(inchannels=2, outchannels=2; options...) PortAudioStream(inchannels=2, outchannels=2; options...)
@ -118,16 +123,16 @@ Options:
* `eltype`: Sample type of the audio stream (defaults to Float32) * `eltype`: Sample type of the audio stream (defaults to Float32)
* `samplerate`: Sample rate (defaults to device sample rate) * `samplerate`: Sample rate (defaults to device sample rate)
* `blocksize`: Size of the blocks that are written to and read from the audio * `latency`: Requested latency. Stream could underrun when too low,
device. (Defaults to $DEFAULT_BLOCKSIZE) consider using provided device defaults
* `warn_xruns`: Display a warning if there is a stream overrun or underrun, * `warn_xruns`: Display a warning if there is a stream overrun or underrun,
which often happens when Julia is compiling, or with a which often happens when Julia is compiling, or with a
particularly large GC run. This can be quite verbose so is particularly large GC run. This can be quite verbose so is
false by default. false by default.
""" """
function PortAudioStream(indev::PortAudioDevice, outdev::PortAudioDevice, function PortAudioStream(indev::PortAudioDevice, outdev::PortAudioDevice,
inchans=2, outchans=2; eltype=Float32, samplerate=-1, blocksize=DEFAULT_BLOCKSIZE, inchans=2, outchans=2; eltype=Float32, samplerate=-1,
warn_xruns=false, latency=0.1) latency=defaultlatency(indev, outdev), warn_xruns=false)
if samplerate == -1 if samplerate == -1
sampleratein = indev.defaultsamplerate sampleratein = indev.defaultsamplerate
samplerateout = outdev.defaultsamplerate samplerateout = outdev.defaultsamplerate
@ -142,7 +147,7 @@ function PortAudioStream(indev::PortAudioDevice, outdev::PortAudioDevice,
samplerate = samplerateout samplerate = samplerateout
end end
end end
PortAudioStream{eltype}(indev, outdev, inchans, outchans, samplerate, blocksize, warn_xruns, latency) PortAudioStream{eltype}(indev, outdev, inchans, outchans, samplerate, latency, warn_xruns)
end end
# handle device names given as streams # handle device names given as streams
@ -208,7 +213,7 @@ end
isopen(stream::PortAudioStream) = stream.stream != C_NULL isopen(stream::PortAudioStream) = stream.stream != C_NULL
SampledSignals.samplerate(stream::PortAudioStream) = stream.samplerate SampledSignals.samplerate(stream::PortAudioStream) = stream.samplerate
SampledSignals.blocksize(stream::PortAudioStream) = stream.blocksize SampledSignals.blocksize(stream::PortAudioStream) = trunc(Int, stream.samplerate * stream.latency)
eltype(stream::PortAudioStream{T}) where T = T eltype(stream::PortAudioStream{T}) where T = T
read(stream::PortAudioStream, args...) = read(stream.source, args...) read(stream::PortAudioStream, args...) = read(stream.source, args...)
@ -220,7 +225,7 @@ flush(stream::PortAudioStream) = flush(stream.sink)
function show(io::IO, stream::PortAudioStream) function show(io::IO, stream::PortAudioStream)
println(io, typeof(stream)) println(io, typeof(stream))
println(io, " Samplerate: ", samplerate(stream), "Hz") println(io, " Samplerate: ", samplerate(stream), "Hz")
print(io, " Buffer Size: ", stream.blocksize, " frames") print(io, " Buffer Size: ", blocksize(stream), " frames")
if nchannels(stream.sink) > 0 if nchannels(stream.sink) > 0
print(io, "\n ", nchannels(stream.sink), " channel sink: \"", name(stream.sink), "\"") print(io, "\n ", nchannels(stream.sink), " channel sink: \"", name(stream.sink), "\"")
end end
@ -253,7 +258,7 @@ end
SampledSignals.nchannels(s::Union{PortAudioSink, PortAudioSource}) = s.nchannels SampledSignals.nchannels(s::Union{PortAudioSink, PortAudioSource}) = s.nchannels
SampledSignals.samplerate(s::Union{PortAudioSink, PortAudioSource}) = samplerate(s.stream) SampledSignals.samplerate(s::Union{PortAudioSink, PortAudioSource}) = samplerate(s.stream)
SampledSignals.blocksize(s::Union{PortAudioSink, PortAudioSource}) = s.stream.blocksize SampledSignals.blocksize(s::Union{PortAudioSink, PortAudioSource}) = blocksize(s.stream)
eltype(::Union{PortAudioSink{T}, PortAudioSource{T}}) where {T} = T eltype(::Union{PortAudioSink{T}, PortAudioSource{T}}) where {T} = T
function close(s::Union{PortAudioSink, PortAudioSource}) function close(s::Union{PortAudioSink, PortAudioSource})
throw(ErrorException("Attempted to close PortAudioSink or PortAudioSource. throw(ErrorException("Attempted to close PortAudioSink or PortAudioSource.