refactored to remove background task and only write to PA during user writes
This commit is contained in:
parent
6830452b9c
commit
9bafaeaa45
1 changed files with 24 additions and 39 deletions
|
@ -11,6 +11,8 @@ include("libportaudio.jl")
|
||||||
|
|
||||||
export PortAudioSink, PortAudioSource
|
export PortAudioSink, PortAudioSource
|
||||||
|
|
||||||
|
const DEFAULT_BUFSIZE=4096
|
||||||
|
|
||||||
# initialize PortAudio on module load
|
# initialize PortAudio on module load
|
||||||
Pa_Initialize()
|
Pa_Initialize()
|
||||||
|
|
||||||
|
@ -40,21 +42,21 @@ type PortAudioSink{T, U} <: SampleSink
|
||||||
nchannels::Int
|
nchannels::Int
|
||||||
samplerate::U
|
samplerate::U
|
||||||
bufsize::Int
|
bufsize::Int
|
||||||
ringbuf::RingBuffer
|
buffer::Array{T, 2}
|
||||||
open::Bool
|
transbuf::Array{T, 2}
|
||||||
task::Task
|
|
||||||
|
|
||||||
function PortAudioSink(eltype, rate, channels, bufsize)
|
function PortAudioSink(eltype, rate, channels, bufsize)
|
||||||
stream = Pa_OpenDefaultStream(0, channels, type_to_fmt[eltype], float(rate), bufsize)
|
stream = Pa_OpenDefaultStream(0, channels, type_to_fmt[eltype], float(rate), bufsize)
|
||||||
writers = Condition[]
|
writers = Condition[]
|
||||||
# we want the ringbuf to output zeros to portaudio if it runs out of samples
|
buffer = Array(eltype, bufsize, channels)
|
||||||
ringbuf = RingBuffer(eltype, RINGBUF_FRAMES, channels; underflow=PAD)
|
# as of portaudio 19.20140130 (which is the HomeBrew version as of 20160319)
|
||||||
|
# noninterleaved data is not supported for the read/write interface on OSX
|
||||||
|
transbuf = Array(eltype, channels, bufsize)
|
||||||
|
|
||||||
Pa_StartStream(stream)
|
Pa_StartStream(stream)
|
||||||
|
|
||||||
this = new(stream, channels, rate, bufsize, ringbuf, true)
|
this = new(stream, channels, rate, bufsize, buffer, transbuf)
|
||||||
this.task = @schedule sinktask(this)
|
|
||||||
finalizer(this, close)
|
finalizer(this, close)
|
||||||
yield()
|
|
||||||
|
|
||||||
this
|
this
|
||||||
end
|
end
|
||||||
|
@ -64,13 +66,7 @@ PortAudioSink(eltype=Float32, rate=48000Hz, channels=2, bufsize=DEFAULT_BUFSIZE)
|
||||||
PortAudioSink{eltype, typeof(rate)}(eltype, rate, channels, bufsize)
|
PortAudioSink{eltype, typeof(rate)}(eltype, rate, channels, bufsize)
|
||||||
|
|
||||||
|
|
||||||
const DEFAULT_BUFSIZE=4096
|
|
||||||
const RINGBUF_FRAMES = 131072
|
|
||||||
|
|
||||||
function Base.close(sink::PortAudioSink)
|
function Base.close(sink::PortAudioSink)
|
||||||
sink.open = false
|
|
||||||
# no task switches inside finalizer, not sure if we'll need this or not
|
|
||||||
# wait(sink.task)
|
|
||||||
Pa_StopStream(sink.stream)
|
Pa_StopStream(sink.stream)
|
||||||
Pa_CloseStream(sink.stream)
|
Pa_CloseStream(sink.stream)
|
||||||
end
|
end
|
||||||
|
@ -85,36 +81,25 @@ Base.eltype{T, U}(sink::PortAudioSink{T, U}) = T
|
||||||
# end
|
# end
|
||||||
|
|
||||||
function SampleTypes.unsafe_write(sink::PortAudioSink, buf::SampleBuf)
|
function SampleTypes.unsafe_write(sink::PortAudioSink, buf::SampleBuf)
|
||||||
write(sink.ringbuf, buf)
|
total = nframes(buf)
|
||||||
|
written = 0
|
||||||
|
while written < total
|
||||||
|
n = min(size(sink.transbuf, 2), total-written, Pa_GetStreamWriteAvailable(sink.stream))
|
||||||
|
bufstart = 1+written
|
||||||
|
bufend = n+written
|
||||||
|
@devec sink.buffer[1:n, :] = buf[bufstart:bufend, :]
|
||||||
|
transpose!(sink.transbuf, sink.buffer)
|
||||||
|
Pa_WriteStream(sink.stream, sink.transbuf, n, false)
|
||||||
|
written += n
|
||||||
|
sleep(0.005)
|
||||||
|
end
|
||||||
|
|
||||||
|
written
|
||||||
end
|
end
|
||||||
|
|
||||||
# function SampleTypes.unsafe_read!(sink::PortAudioSource, buf::SampleBuf)
|
# function SampleTypes.unsafe_read!(sink::PortAudioSource, buf::SampleBuf)
|
||||||
# end
|
# end
|
||||||
|
|
||||||
function sinktask(sink::PortAudioSink)
|
|
||||||
buffer = Array(eltype(sink), sink.bufsize, nchannels(sink))
|
|
||||||
# as of portaudio 19.20140130 (which is the HomeBrew version as of 20160319)
|
|
||||||
# noninterleaved data is not supported for the read/write interface on OSX
|
|
||||||
transbuf = Array(eltype(sink), nchannels(sink), sink.bufsize)
|
|
||||||
try
|
|
||||||
while sink.open
|
|
||||||
total = Pa_GetStreamWriteAvailable(sink.stream)
|
|
||||||
written = 0
|
|
||||||
while(written < total)
|
|
||||||
tocopy = min(size(buffer, 1), total - written)
|
|
||||||
read!(sink.ringbuf, sub(buffer, 1:tocopy, :))
|
|
||||||
transpose!(transbuf, buffer)
|
|
||||||
Pa_WriteStream(sink.stream, transbuf, tocopy, true)
|
|
||||||
written += tocopy
|
|
||||||
end
|
|
||||||
sleep(0.005)
|
|
||||||
end
|
|
||||||
catch ex
|
|
||||||
warn("PortAudio Sink Task died with exception: $ex")
|
|
||||||
Base.show_backtrace(STDOUT, catch_backtrace())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
# function sourcetask(sink::PortAudioSource)
|
# function sourcetask(sink::PortAudioSource)
|
||||||
# while sink.open
|
# while sink.open
|
||||||
# end
|
# end
|
||||||
|
|
Loading…
Reference in a new issue