Compare commits
4 commits
master
...
update_rea
Author | SHA1 | Date | |
---|---|---|---|
|
71616b1bdd | ||
|
056e88032d | ||
|
e6a9e7e070 | ||
|
896a82fe79 |
6 changed files with 54 additions and 141 deletions
2
.github/workflows/Tests.yml
vendored
2
.github/workflows/Tests.yml
vendored
|
@ -17,7 +17,7 @@ jobs:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
version:
|
version:
|
||||||
- '1.6'
|
- '1.3'
|
||||||
- '1'
|
- '1'
|
||||||
- 'nightly'
|
- 'nightly'
|
||||||
os:
|
os:
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
name = "PortAudio"
|
name = "PortAudio"
|
||||||
uuid = "80ea8bcb-4634-5cb3-8ee8-a132660d1d2d"
|
uuid = "80ea8bcb-4634-5cb3-8ee8-a132660d1d2d"
|
||||||
repo = "https://github.com/JuliaAudio/PortAudio.jl.git"
|
repo = "https://github.com/JuliaAudio/PortAudio.jl.git"
|
||||||
version = "1.3.0"
|
version = "1.2.0"
|
||||||
|
|
||||||
[deps]
|
[deps]
|
||||||
alsa_plugins_jll = "5ac2f6bb-493e-5871-9171-112d4c21a6e7"
|
alsa_plugins_jll = "5ac2f6bb-493e-5871-9171-112d4c21a6e7"
|
||||||
|
@ -11,7 +11,7 @@ SampledSignals = "bd7594eb-a658-542f-9e75-4c4d8908c167"
|
||||||
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
|
Suppressor = "fd094767-a336-5f1f-9728-57cf17d0bbfb"
|
||||||
|
|
||||||
[compat]
|
[compat]
|
||||||
julia = "1.6"
|
julia = "1.3"
|
||||||
alsa_plugins_jll = "1.2.2"
|
alsa_plugins_jll = "1.2.2"
|
||||||
libportaudio_jll = "19.6.0"
|
libportaudio_jll = "19.6.0"
|
||||||
SampledSignals = "2.1.1"
|
SampledSignals = "2.1.1"
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
#=
|
|
||||||
This example illustrates synthesizing a long tone in small pieces
|
|
||||||
and routing it to the default audio output device using `write()`.
|
|
||||||
=#
|
|
||||||
|
|
||||||
using PortAudio: PortAudioStream, write
|
|
||||||
|
|
||||||
stream = PortAudioStream(0, 1; warn_xruns=false)
|
|
||||||
|
|
||||||
function play_tone(stream, freq::Real, duration::Real; buf_size::Int = 1024)
|
|
||||||
S = stream.sample_rate
|
|
||||||
current = 1
|
|
||||||
while current < duration*S
|
|
||||||
x = 0.7 * sin.(2π * (current .+ (1:buf_size)) * freq / S)
|
|
||||||
write(stream, x)
|
|
||||||
current += buf_size
|
|
||||||
end
|
|
||||||
nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
play_tone(stream, 440, 2)
|
|
113
src/PortAudio.jl
113
src/PortAudio.jl
|
@ -48,7 +48,6 @@ using .LibPortAudio:
|
||||||
Pa_Initialize,
|
Pa_Initialize,
|
||||||
paInputOverflowed,
|
paInputOverflowed,
|
||||||
Pa_IsStreamStopped,
|
Pa_IsStreamStopped,
|
||||||
paNoDevice,
|
|
||||||
paNoFlag,
|
paNoFlag,
|
||||||
Pa_OpenStream,
|
Pa_OpenStream,
|
||||||
paOutputUnderflowed,
|
paOutputUnderflowed,
|
||||||
|
@ -196,22 +195,12 @@ function show(io::IO, device::PortAudioDevice)
|
||||||
print(io, device.output_bounds.max_channels)
|
print(io, device.output_bounds.max_channels)
|
||||||
end
|
end
|
||||||
|
|
||||||
function check_device_exists(device_index, device_type)
|
|
||||||
if device_index == paNoDevice
|
|
||||||
throw(ArgumentError("No $device_type device available"))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function get_default_input_index()
|
function get_default_input_index()
|
||||||
device_index = Pa_GetDefaultInputDevice()
|
handle_status(Pa_GetDefaultInputDevice())
|
||||||
check_device_exists(device_index, "input")
|
|
||||||
device_index
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function get_default_output_index()
|
function get_default_output_index()
|
||||||
device_index = Pa_GetDefaultOutputDevice()
|
handle_status(Pa_GetDefaultOutputDevice())
|
||||||
check_device_exists(device_index, "output")
|
|
||||||
device_index
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# we can look up devices by index or name
|
# we can look up devices by index or name
|
||||||
|
@ -241,25 +230,19 @@ function devices()
|
||||||
end
|
end
|
||||||
|
|
||||||
# we can handle reading and writing from buffers in a similar way
|
# we can handle reading and writing from buffers in a similar way
|
||||||
function read_or_write(a_function, buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
|
function read_or_write(a_function, buffer, use_frames = buffer.frames_per_buffer)
|
||||||
pointer_to = buffer.pointer_to
|
|
||||||
data = buffer.data
|
|
||||||
handle_status(
|
handle_status(
|
||||||
if acquire_lock
|
# because we're calling Pa_ReadStream and Pa_WriteStream from separate threads,
|
||||||
# because we're calling Pa_ReadStream and Pa_WriteStream from separate threads,
|
# we put a lock around these calls
|
||||||
# we put a lock around these calls
|
lock(
|
||||||
lock(
|
let a_function = a_function,
|
||||||
let a_function = a_function,
|
pointer_to = buffer.pointer_to,
|
||||||
pointer_to = pointer_to,
|
data = buffer.data,
|
||||||
data = data,
|
use_frames = use_frames
|
||||||
use_frames = use_frames
|
() -> a_function(pointer_to, data, use_frames)
|
||||||
() -> a_function(pointer_to, data, use_frames)
|
end,
|
||||||
end,
|
buffer.stream_lock,
|
||||||
buffer.stream_lock,
|
),
|
||||||
)
|
|
||||||
else
|
|
||||||
a_function(pointer_to, data, use_frames)
|
|
||||||
end;
|
|
||||||
warn_xruns = buffer.warn_xruns,
|
warn_xruns = buffer.warn_xruns,
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
@ -424,39 +407,25 @@ eltype(::Type{Buffer{Sample}}) where {Sample} = Sample
|
||||||
nchannels(buffer::Buffer) = buffer.number_of_channels
|
nchannels(buffer::Buffer) = buffer.number_of_channels
|
||||||
|
|
||||||
"""
|
"""
|
||||||
PortAudio.write_buffer(buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
|
PortAudio.write_buffer(buffer, use_frames = buffer.frames_per_buffer)
|
||||||
|
|
||||||
Write a number of frames (`use_frames`) from a [`PortAudio.Buffer`](@ref) to PortAudio.
|
Write a number of frames (`use_frames`) from a [`PortAudio.Buffer`](@ref) to PortAudio.
|
||||||
|
|
||||||
Set `acquire_lock = false` to skip acquiring the lock.
|
|
||||||
"""
|
"""
|
||||||
function write_buffer(buffer::Buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
|
function write_buffer(buffer::Buffer, use_frames = buffer.frames_per_buffer)
|
||||||
read_or_write(Pa_WriteStream, buffer, use_frames; acquire_lock = acquire_lock)
|
read_or_write(Pa_WriteStream, buffer, use_frames)
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
"""
|
||||||
PortAudio.read_buffer!(buffer::Buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
|
PortAudio.read_buffer!(buffer::Buffer, use_frames = buffer.frames_per_buffer)
|
||||||
|
|
||||||
Read a number of frames (`use_frames`) from PortAudio to a [`PortAudio.Buffer`](@ref).
|
Read a number of frames (`use_frames`) from PortAudio to a [`PortAudio.Buffer`](@ref).
|
||||||
|
|
||||||
Set `acquire_lock = false` to skip acquiring the acquire_lock.
|
|
||||||
"""
|
"""
|
||||||
function read_buffer!(buffer, use_frames = buffer.frames_per_buffer; acquire_lock = true)
|
function read_buffer!(buffer, use_frames = buffer.frames_per_buffer)
|
||||||
read_or_write(Pa_ReadStream, buffer, use_frames; acquire_lock = acquire_lock)
|
read_or_write(Pa_ReadStream, buffer, use_frames)
|
||||||
end
|
end
|
||||||
|
|
||||||
"""
|
# the messenger will send tasks to the scribe
|
||||||
Messenger{Sample, Scribe, Input, Output}
|
# the scribe will read/write from the buffer
|
||||||
|
|
||||||
A `struct` with entries
|
|
||||||
* `device_name::String`
|
|
||||||
* `buffer::Buffer{Sample}`
|
|
||||||
* `scribe::Scribe`
|
|
||||||
* `input_channel::Channel{Input}`
|
|
||||||
* `output_channel::Channel{Output}`
|
|
||||||
The messenger will send tasks to the scribe;
|
|
||||||
the scribe will read/write from the buffer.
|
|
||||||
"""
|
|
||||||
struct Messenger{Sample, Scribe, Input, Output}
|
struct Messenger{Sample, Scribe, Input, Output}
|
||||||
device_name::String
|
device_name::String
|
||||||
buffer::Buffer{Sample}
|
buffer::Buffer{Sample}
|
||||||
|
@ -528,7 +497,7 @@ function messenger_task(
|
||||||
messenger, task
|
messenger, task
|
||||||
end
|
end
|
||||||
|
|
||||||
function fetch_messenger(messenger, task)
|
function fetch_messanger(messenger, task)
|
||||||
if has_channels(messenger)
|
if has_channels(messenger)
|
||||||
# this will shut down the channels, which will shut down the thread
|
# this will shut down the channels, which will shut down the thread
|
||||||
close(messenger.input_channel)
|
close(messenger.input_channel)
|
||||||
|
@ -548,9 +517,9 @@ struct PortAudioStream{SinkMessenger, SourceMessenger}
|
||||||
sample_rate::Float64
|
sample_rate::Float64
|
||||||
# pointer to the c object
|
# pointer to the c object
|
||||||
pointer_to::Ptr{PaStream}
|
pointer_to::Ptr{PaStream}
|
||||||
sink_messenger::SinkMessenger
|
sink_messanger::SinkMessenger
|
||||||
sink_task::Task
|
sink_task::Task
|
||||||
source_messenger::SourceMessenger
|
source_messanger::SourceMessenger
|
||||||
source_task::Task
|
source_task::Task
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -615,9 +584,10 @@ function combine_default_sample_rates(
|
||||||
)
|
)
|
||||||
if input_sample_rate != output_sample_rate
|
if input_sample_rate != output_sample_rate
|
||||||
throw(
|
throw(
|
||||||
ArgumentError("""
|
ArgumentError(
|
||||||
Default sample rate $input_sample_rate for input \"$(name(input_device))\" disagrees with
|
"""
|
||||||
default sample rate $output_sample_rate for output \"$(name(output_device))\".
|
Default sample rate $input_sample_rate for input $(name(input_device)) disagrees with
|
||||||
|
default sample rate $output_sample_rate for output $(name(output_device)).
|
||||||
Please specify a sample rate.
|
Please specify a sample rate.
|
||||||
""",
|
""",
|
||||||
),
|
),
|
||||||
|
@ -904,8 +874,8 @@ function close(stream::PortAudioStream)
|
||||||
# closing is tricky, because we want to make sure we've read exactly as much as we've written
|
# 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
|
# but we have don't know exactly what the tasks are doing
|
||||||
# for now, just close one and then the other
|
# for now, just close one and then the other
|
||||||
fetch_messenger(stream.source_messenger, stream.source_task)
|
fetch_messanger(stream.source_messanger, stream.source_task)
|
||||||
fetch_messenger(stream.sink_messenger, stream.sink_task)
|
fetch_messanger(stream.sink_messanger, stream.sink_task)
|
||||||
pointer_to = stream.pointer_to
|
pointer_to = stream.pointer_to
|
||||||
# only stop if it's not already stopped
|
# only stop if it's not already stopped
|
||||||
if !Bool(handle_status(Pa_IsStreamStopped(pointer_to)))
|
if !Bool(handle_status(Pa_IsStreamStopped(pointer_to)))
|
||||||
|
@ -927,14 +897,13 @@ end
|
||||||
isopen(stream::PortAudioStream) = isopen(stream.pointer_to)
|
isopen(stream::PortAudioStream) = isopen(stream.pointer_to)
|
||||||
|
|
||||||
samplerate(stream::PortAudioStream) = stream.sample_rate
|
samplerate(stream::PortAudioStream) = stream.sample_rate
|
||||||
|
|
||||||
function eltype(
|
function eltype(
|
||||||
::Type{<:PortAudioStream{<:Messenger{Sample}, <:Messenger{Sample}}},
|
::Type{<:PortAudioStream{<:Messenger{Sample}, <:Messenger{Sample}}},
|
||||||
) where {Sample}
|
) where {Sample}
|
||||||
Sample
|
Sample
|
||||||
end
|
end
|
||||||
|
|
||||||
# these defaults will error for non-SampledSignals scribes
|
# these defaults will error for non-sampledsignal scribes
|
||||||
# which is probably ok; we want these users to define new methods
|
# 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...)
|
||||||
|
@ -948,7 +917,7 @@ function show(io::IO, stream::PortAudioStream)
|
||||||
print(io, "PortAudioStream{")
|
print(io, "PortAudioStream{")
|
||||||
print(io, eltype(stream))
|
print(io, eltype(stream))
|
||||||
println(io, "}")
|
println(io, "}")
|
||||||
print(io, " Samplerate: ", round(Int, samplerate(stream)), "Hz")
|
print(io, " Samplerate: ", samplerate(stream), "Hz")
|
||||||
# show source or sink if there's any channels
|
# show source or sink if there's any channels
|
||||||
sink = stream.sink
|
sink = stream.sink
|
||||||
if has_channels(sink)
|
if has_channels(sink)
|
||||||
|
@ -994,10 +963,10 @@ function getproperty(
|
||||||
end
|
end
|
||||||
|
|
||||||
function nchannels(source_or_sink::PortAudioSource)
|
function nchannels(source_or_sink::PortAudioSource)
|
||||||
nchannels(source_or_sink.stream.source_messenger)
|
nchannels(source_or_sink.stream.source_messanger)
|
||||||
end
|
end
|
||||||
function nchannels(source_or_sink::PortAudioSink)
|
function nchannels(source_or_sink::PortAudioSink)
|
||||||
nchannels(source_or_sink.stream.sink_messenger)
|
nchannels(source_or_sink.stream.sink_messanger)
|
||||||
end
|
end
|
||||||
function samplerate(source_or_sink::Union{PortAudioSink, PortAudioSource})
|
function samplerate(source_or_sink::Union{PortAudioSink, PortAudioSource})
|
||||||
samplerate(source_or_sink.stream)
|
samplerate(source_or_sink.stream)
|
||||||
|
@ -1015,8 +984,8 @@ end
|
||||||
function isopen(source_or_sink::Union{PortAudioSink, PortAudioSource})
|
function isopen(source_or_sink::Union{PortAudioSink, PortAudioSource})
|
||||||
isopen(source_or_sink.stream)
|
isopen(source_or_sink.stream)
|
||||||
end
|
end
|
||||||
name(source_or_sink::PortAudioSink) = name(source_or_sink.stream.sink_messenger)
|
name(source_or_sink::PortAudioSink) = name(source_or_sink.stream.sink_messanger)
|
||||||
name(source_or_sink::PortAudioSource) = name(source_or_sink.stream.source_messenger)
|
name(source_or_sink::PortAudioSource) = name(source_or_sink.stream.source_messanger)
|
||||||
|
|
||||||
# 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
|
# because these will usually only get printed as part of show for PortAudioStream
|
||||||
|
@ -1045,14 +1014,14 @@ end
|
||||||
as_matrix(matrix::Matrix) = matrix
|
as_matrix(matrix::Matrix) = matrix
|
||||||
as_matrix(vector::Vector) = reshape(vector, length(vector), 1)
|
as_matrix(vector::Vector) = reshape(vector, length(vector), 1)
|
||||||
|
|
||||||
# these will only work with SampledSignals scribes
|
# these will only work with sampledsignals scribes
|
||||||
function unsafe_write(
|
function unsafe_write(
|
||||||
sink::PortAudioSink{<:Messenger{<:Any, <:SampledSignalsWriter}},
|
sink::PortAudioSink{<:Messenger{<:Any, <:SampledSignalsWriter}},
|
||||||
julia_buffer::Array,
|
julia_buffer::Array,
|
||||||
already,
|
already,
|
||||||
frame_count,
|
frame_count,
|
||||||
)
|
)
|
||||||
exchange(sink.stream.sink_messenger, as_matrix(julia_buffer), already, frame_count)
|
exchange(sink.stream.sink_messanger, as_matrix(julia_buffer), already, frame_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function unsafe_read!(
|
function unsafe_read!(
|
||||||
|
@ -1061,9 +1030,7 @@ function unsafe_read!(
|
||||||
already,
|
already,
|
||||||
frame_count,
|
frame_count,
|
||||||
)
|
)
|
||||||
exchange(source.stream.source_messenger, as_matrix(julia_buffer), already, frame_count)
|
exchange(source.stream.source_messanger, as_matrix(julia_buffer), already, frame_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
include("precompile.jl")
|
|
||||||
|
|
||||||
end # module PortAudio
|
end # module PortAudio
|
||||||
|
|
|
@ -1,29 +0,0 @@
|
||||||
# precompile some important functions
|
|
||||||
const DEFAULT_SINK_MESSENGER_TYPE = Messenger{Float32, SampledSignalsWriter, Tuple{Matrix{Float32}, Int64, Int64}, Int64}
|
|
||||||
const DEFAULT_SOURCE_MESSENGER_TYPE = Messenger{Float32, SampledSignalsReader, Tuple{Matrix{Float32}, Int64, Int64}, Int64}
|
|
||||||
const DEFAULT_STREAM_TYPE = PortAudioStream{DEFAULT_SINK_MESSENGER_TYPE, DEFAULT_SOURCE_MESSENGER_TYPE}
|
|
||||||
const DEFAULT_SINK_TYPE = PortAudioSink{DEFAULT_SINK_MESSENGER_TYPE, DEFAULT_SOURCE_MESSENGER_TYPE}
|
|
||||||
const DEFAULT_SOURCE_TYPE = PortAudioSource{DEFAULT_SINK_MESSENGER_TYPE, DEFAULT_SOURCE_MESSENGER_TYPE}
|
|
||||||
|
|
||||||
precompile(close, (DEFAULT_STREAM_TYPE,))
|
|
||||||
precompile(devices, ())
|
|
||||||
precompile(__init__, ())
|
|
||||||
precompile(isopen, (DEFAULT_STREAM_TYPE,))
|
|
||||||
precompile(nchannels, (DEFAULT_SINK_TYPE,))
|
|
||||||
precompile(nchannels, (DEFAULT_SOURCE_TYPE,))
|
|
||||||
precompile(PortAudioStream, (Int, Int))
|
|
||||||
precompile(PortAudioStream, (String, Int, Int))
|
|
||||||
precompile(PortAudioStream, (String, String, Int, Int))
|
|
||||||
precompile(samplerate, (DEFAULT_STREAM_TYPE,))
|
|
||||||
precompile(send, (DEFAULT_SINK_MESSENGER_TYPE,))
|
|
||||||
precompile(send, (DEFAULT_SOURCE_MESSENGER_TYPE,))
|
|
||||||
precompile(unsafe_read!, (DEFAULT_SOURCE_TYPE, Vector{Float32}, Int, Int))
|
|
||||||
precompile(unsafe_read!, (DEFAULT_SOURCE_TYPE, Matrix{Float32}, Int, Int))
|
|
||||||
precompile(unsafe_write, (DEFAULT_SINK_TYPE, Vector{Float32}, Int, Int))
|
|
||||||
precompile(unsafe_write, (DEFAULT_SINK_TYPE, Matrix{Float32}, Int, Int))
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ using PortAudio:
|
||||||
get_output_type,
|
get_output_type,
|
||||||
handle_status,
|
handle_status,
|
||||||
initialize,
|
initialize,
|
||||||
name,
|
|
||||||
PortAudioException,
|
PortAudioException,
|
||||||
PortAudio,
|
PortAudio,
|
||||||
PortAudioDevice,
|
PortAudioDevice,
|
||||||
|
@ -19,7 +18,7 @@ using PortAudio:
|
||||||
safe_load,
|
safe_load,
|
||||||
seek_alsa_conf,
|
seek_alsa_conf,
|
||||||
terminate,
|
terminate,
|
||||||
write_buffer
|
name
|
||||||
using PortAudio.LibPortAudio:
|
using PortAudio.LibPortAudio:
|
||||||
Pa_AbortStream,
|
Pa_AbortStream,
|
||||||
PaError,
|
PaError,
|
||||||
|
@ -110,9 +109,7 @@ using Test: @test, @test_logs, @test_nowarn, @testset, @test_throws
|
||||||
initialize()
|
initialize()
|
||||||
end
|
end
|
||||||
|
|
||||||
if isempty(devices())
|
if !isempty(devices())
|
||||||
@test_throws ArgumentError("No input device available") get_default_input_index()
|
|
||||||
else
|
|
||||||
@testset "Tests with sound" begin
|
@testset "Tests with sound" begin
|
||||||
# these default values are specific to local machines
|
# these default values are specific to local machines
|
||||||
input_name = get_device(get_default_input_index()).name
|
input_name = get_device(get_default_input_index()).name
|
||||||
|
@ -133,16 +130,15 @@ else
|
||||||
sleep(1)
|
sleep(1)
|
||||||
println("Testing pass-through")
|
println("Testing pass-through")
|
||||||
stream = PortAudioStream(input_name, output_name, 2, 2; adjust_channels = true)
|
stream = PortAudioStream(input_name, output_name, 2, 2; adjust_channels = true)
|
||||||
write_buffer(stream.sink_messenger.buffer, acquire_lock = false)
|
|
||||||
sink = stream.sink
|
sink = stream.sink
|
||||||
source = stream.source
|
source = stream.source
|
||||||
@test sprint(show, stream) == """
|
@test sprint(show, stream) == """
|
||||||
PortAudioStream{Float32}
|
PortAudioStream{Float32}
|
||||||
Samplerate: 44100Hz
|
Samplerate: 44100.0Hz
|
||||||
2 channel sink: $(repr(output_name))
|
2 channel sink: $(repr(input_name))
|
||||||
2 channel source: $(repr(input_name))"""
|
2 channel source: $(repr(output_name))"""
|
||||||
@test sprint(show, source) == "2 channel source: $(repr(input_name))"
|
@test sprint(show, source) == "2 channel source: $(repr(output_name))"
|
||||||
@test sprint(show, sink) == "2 channel sink: $(repr(output_name))"
|
@test sprint(show, sink) == "2 channel sink: $(repr(input_name))"
|
||||||
write(stream, stream, 5s)
|
write(stream, stream, 5s)
|
||||||
@test PaErrorCode(handle_status(Pa_StopStream(stream.pointer_to))) == paNoError
|
@test PaErrorCode(handle_status(Pa_StopStream(stream.pointer_to))) == paNoError
|
||||||
@test isopen(stream)
|
@test isopen(stream)
|
||||||
|
@ -213,8 +209,8 @@ else
|
||||||
big = typemax(Int)
|
big = typemax(Int)
|
||||||
@test_throws DomainError(
|
@test_throws DomainError(
|
||||||
typemax(Int),
|
typemax(Int),
|
||||||
"$big exceeds maximum output channels for $output_name",
|
"$big exceeds maximum input channels for $output_name",
|
||||||
) PortAudioStream(input_name, output_name, 0, big)
|
) PortAudioStream(input_name, output_name, big, 0)
|
||||||
@test_throws ArgumentError("Input or output must have at least 1 channel") PortAudioStream(
|
@test_throws ArgumentError("Input or output must have at least 1 channel") PortAudioStream(
|
||||||
input_name,
|
input_name,
|
||||||
output_name,
|
output_name,
|
||||||
|
@ -223,8 +219,8 @@ else
|
||||||
adjust_channels = true,
|
adjust_channels = true,
|
||||||
)
|
)
|
||||||
@test_throws ArgumentError("""
|
@test_throws ArgumentError("""
|
||||||
Default sample rate 0 for input \"$input_name\" disagrees with
|
Default sample rate 0 for input $output_name disagrees with
|
||||||
default sample rate 1 for output \"$output_name\".
|
default sample rate 1 for output $input_name.
|
||||||
Please specify a sample rate.
|
Please specify a sample rate.
|
||||||
""") combine_default_sample_rates(
|
""") combine_default_sample_rates(
|
||||||
get_device(input_name),
|
get_device(input_name),
|
||||||
|
|
Loading…
Reference in a new issue