more comments

This commit is contained in:
Brandon Taylor 2021-07-04 11:40:53 -04:00
parent 8cd31c4522
commit d836fe655d

View file

@ -303,6 +303,7 @@ function get_output_type(::Type{<:Union{SampledSignalsReader, SampledSignalsWrit
Int Int
end end
# write a full chunk, starting from the middle of the julia buffer
function full_write!(buffer, julia_buffer, already) function full_write!(buffer, julia_buffer, already)
chunk_frames = buffer.chunk_frames chunk_frames = buffer.chunk_frames
@inbounds transpose!( @inbounds transpose!(
@ -318,19 +319,21 @@ function (writer::SampledSignalsWriter)(buffer, (julia_buffer, offset, frame_cou
let buffer = buffer, julia_buffer = julia_buffer let buffer = buffer, julia_buffer = julia_buffer
already -> full_write!(buffer, julia_buffer, already) already -> full_write!(buffer, julia_buffer, already)
end, end,
# keep going until there is less than a chunk left # start at the offset, keep going until there is less than a chunk left
offset:chunk_frames:(offset + frame_count - chunk_frames), offset:chunk_frames:(offset + frame_count - chunk_frames),
) )
# write what's left
left = frame_count % chunk_frames left = frame_count % chunk_frames
port_audio_range = 1:left
@inbounds transpose!( @inbounds transpose!(
view(buffer.data, :, port_audio_range), view(buffer.data, :, 1:left),
view(julia_buffer, port_audio_range .+ (offset + frame_count - left), :), # the last left frames of the julia buffer
view(julia_buffer, (1:left) .+ (offset + frame_count - left), :),
) )
write_buffer(buffer, left) write_buffer(buffer, left)
frame_count frame_count
end end
# similar to above
function full_read!(buffer, julia_buffer, already) function full_read!(buffer, julia_buffer, already)
chunk_frames = buffer.chunk_frames chunk_frames = buffer.chunk_frames
read_buffer(buffer, chunk_frames) read_buffer(buffer, chunk_frames)
@ -349,17 +352,17 @@ function (reader::SampledSignalsReader)(buffer, (julia_buffer, offset, frame_cou
offset:chunk_frames:(offset + frame_count - chunk_frames), offset:chunk_frames:(offset + frame_count - chunk_frames),
) )
left = frame_count % chunk_frames left = frame_count % chunk_frames
port_audio_range = 1:left
read_buffer(buffer, left) read_buffer(buffer, left)
@inbounds transpose!( @inbounds transpose!(
view(julia_buffer, port_audio_range .+ (offset + frame_count - left), :), view(julia_buffer, (1:left) .+ (offset + frame_count - left), :),
view(buffer.data, :, port_audio_range), view(buffer.data, :, 1:left),
) )
frame_count frame_count
end end
# a Buffer contains not just a buffer # a Buffer contains not just a buffer
# but everything you might need for a source or sink # but everything you might need for a source or sink
# hopefully, because it is immutable, the optimizer can just pass what it needs
struct Buffer{Sample, Scribe, InputType, OutputType} struct Buffer{Sample, Scribe, InputType, OutputType}
stream_lock::ReentrantLock stream_lock::ReentrantLock
pointer_to::Ptr{PaStream} pointer_to::Ptr{PaStream}
@ -415,9 +418,11 @@ function buffer_task(
run_scribe(buffer) run_scribe(buffer)
end end
end) end)
# makes it able to run on a separate thread
task.sticky = false task.sticky = false
if has_channels(buffer) if has_channels(buffer)
schedule(task) schedule(task)
# output channel will close when the task ends
bind(output_channel, task) bind(output_channel, task)
else else
close(input_channel) close(input_channel)
@ -429,11 +434,6 @@ end
nchannels(buffer::Buffer) = buffer.number_of_channels nchannels(buffer::Buffer) = buffer.number_of_channels
name(buffer::Buffer) = name(buffer.device) name(buffer::Buffer) = name(buffer.device)
function close(buffer::Buffer)
close(buffer.inputs)
close(buffer.outputs)
end
# #
# PortAudioStream # PortAudioStream
# #
@ -510,7 +510,6 @@ function combine_default_sample_rates(
output_sample_rate, output_sample_rate,
) )
if input_sample_rate != output_sample_rate if input_sample_rate != output_sample_rate
# TODO: just name
throw( throw(
ArgumentError( ArgumentError(
""" """
@ -535,7 +534,7 @@ function run_scribe(buffer)
input = try input = try
take!(inputs) take!(inputs)
catch an_error catch an_error
# if the channel is closed, the scribe knows its done # if the input channel is closed, the scribe knows its done
if an_error isa InvalidStateException && an_error.state === :closed if an_error isa InvalidStateException && an_error.state === :closed
break break
else else
@ -670,6 +669,8 @@ function PortAudioStream(
PortAudioStream( PortAudioStream(
sample_rate, sample_rate,
pointer_to, pointer_to,
# we need to keep track of the tasks
# so we can wait for them to finish and catch errors
buffer_task( buffer_task(
stream_lock, stream_lock,
pointer_to, pointer_to,
@ -746,6 +747,9 @@ end
function close(stream::PortAudioStream) function close(stream::PortAudioStream)
source_buffer = stream.source_buffer source_buffer = stream.source_buffer
sink_buffer = stream.sink_buffer sink_buffer = stream.sink_buffer
# closing is tricky, because we want to make sure we've read exactly as much as we've written
# but we have don't know exactly what the tasks are doing
# for now, just close one and then the other
if has_channels(source_buffer) if has_channels(source_buffer)
# this will shut down the channels, which will shut down the threads # this will shut down the channels, which will shut down the threads
close(source_buffer.inputs) close(source_buffer.inputs)
@ -763,11 +767,12 @@ function close(stream::PortAudioStream)
handle_status(Pa_StopStream(pointer_to)) handle_status(Pa_StopStream(pointer_to))
end end
handle_status(Pa_CloseStream(pointer_to)) handle_status(Pa_CloseStream(pointer_to))
# close the debug log and then read the file
# this will contain duplicate xrun warnings mentioned above
close(stream.debug_io) close(stream.debug_io)
debug_log = open(stream.debug_file, "r") do io debug_log = open(stream.debug_file, "r") do io
read(io, String) read(io, String)
end end
# this will contain duplicate xrun warnings mentioned above
if !isempty(debug_log) if !isempty(debug_log)
@debug debug_log @debug debug_log
end end
@ -792,6 +797,8 @@ function eltype(
Sample Sample
end end
# these defaults will error for non-sampledsignal scribes
# which is probably ok; we want these users to define new methods
read(stream::PortAudioStream, arguments...) = read(stream.source, arguments...) read(stream::PortAudioStream, arguments...) = read(stream.source, arguments...)
read!(stream::PortAudioStream, arguments...) = read!(stream.source, arguments...) read!(stream::PortAudioStream, arguments...) = read!(stream.source, arguments...)
write(stream::PortAudioStream, arguments...) = write(stream.sink, arguments...) write(stream::PortAudioStream, arguments...) = write(stream.sink, arguments...)
@ -800,7 +807,7 @@ function write(sink::PortAudioStream, source::PortAudioStream, arguments...)
end end
function show(io::IO, stream::PortAudioStream) function show(io::IO, stream::PortAudioStream)
# just show the first parameter (eltype) # just show the first type parameter (eltype)
print(io, "PortAudioStream{") print(io, "PortAudioStream{")
print(io, eltype(stream)) print(io, eltype(stream))
println(io, "}") println(io, "}")
@ -875,6 +882,7 @@ name(source_or_sink::PortAudioSink) = name(source_or_sink.stream.sink_buffer)
name(source_or_sink::PortAudioSource) = name(source_or_sink.stream.source_buffer) name(source_or_sink::PortAudioSource) = name(source_or_sink.stream.source_buffer)
# could show full type name, but the PortAudio part is probably redundant # could show full type name, but the PortAudio part is probably redundant
# because these will usually only get printed as part of show for PortAudioStream
kind(::PortAudioSink) = "sink" kind(::PortAudioSink) = "sink"
kind(::PortAudioSource) = "source" kind(::PortAudioSource) = "source"
function show(io::IO, sink_or_source::Union{PortAudioSink, PortAudioSource}) function show(io::IO, sink_or_source::Union{PortAudioSink, PortAudioSource})
@ -897,6 +905,7 @@ function exchange(buffer, arguments...)
take!(buffer.outputs) take!(buffer.outputs)
end end
# these will only work with sampledsignals scribes
function unsafe_write( function unsafe_write(
sink::PortAudioSink{<:Buffer{<:Any, <:SampledSignalsWriter}}, sink::PortAudioSink{<:Buffer{<:Any, <:SampledSignalsWriter}},
julia_buffer::Array, julia_buffer::Array,