Compat Julia 0.7

This commit is contained in:
WooKyoung Noh 2018-06-21 16:59:43 +09:00
parent 03aefe619d
commit 5823404f1a
11 changed files with 102 additions and 80 deletions

1
.gitignore vendored
View file

@ -1,6 +1,7 @@
*.swp
*.o
deps/deps.jl
deps/build.log
*.wav
*.flac
*.cov

View file

@ -6,6 +6,7 @@ os:
sudo: required
julia:
- 0.6
- nightly
notifications:
email: false
script:

View file

@ -1,6 +1,7 @@
julia 0.6.0-dev.2746
BinDeps
SampledSignals 0.3.0
RingBuffers 1.0.0
julia 0.6
BinDeps 0.8.8
SampledSignals 1.1.2
RingBuffers 1.1.2
Compat 0.66.0
@osx Homebrew
@windows WinRPM

View file

@ -2,6 +2,7 @@ environment:
matrix:
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
notifications:
- provider: Email

3
deps/build.jl vendored
View file

@ -1,8 +1,9 @@
using BinDeps
using Compat
@BinDeps.setup
ENV["JULIA_ROOT"] = abspath(JULIA_HOME, "../../")
ENV["JULIA_ROOT"] = abspath(Compat.Sys.BINDIR, "../../")
# include alias for WinRPM library
libportaudio = library_dependency("libportaudio", aliases=["libportaudio-2"])

View file

@ -1,30 +1,26 @@
__precompile__()
__precompile__(true)
module PortAudio
using SampledSignals
using RingBuffers
#using Suppressor
using Compat
import Compat: undef, fetch, @compat
import Compat.LinearAlgebra: transpose!
import Base: eltype, show
import Base: close, isopen
import Base: read, read!, write, flush
export PortAudioStream
# Get binary dependencies loaded from BinDeps
include("../deps/deps.jl")
include("suppressor.jl")
include("pa_shim.jl")
include("libportaudio.jl")
function __init__()
init_pa_shim()
global const notifycb_c = cfunction(notifycb, Cint, (Ptr{Void}, ))
# initialize PortAudio on module load
@suppress_err Pa_Initialize()
end
export PortAudioStream
# These sizes are all in frames
# the block size is what we request from portaudio if no blocksize is given.
@ -46,7 +42,7 @@ function versioninfo(io::IO=STDOUT)
println(io, "Shim Source Hash: ", shimhash()[1:10])
end
type PortAudioDevice
mutable struct PortAudioDevice
name::String
hostapi::String
maxinchans::Int
@ -76,7 +72,7 @@ devnames() = join(["\"$(dev.name)\"" for dev in devices()], "\n")
# PortAudioStream
##################
type PortAudioStream{T}
mutable struct PortAudioStream{T}
samplerate::Float64
blocksize::Int
stream::PaStream
@ -98,7 +94,7 @@ type PortAudioStream{T}
Ptr{Pa_StreamParameters}(0) :
Ref(Pa_StreamParameters(outdev.idx, outchans, type_to_fmt[T], 0.0, C_NULL))
this = new(sr, blocksize, C_NULL)
finalizer(this, close)
@compat finalizer(close, this)
this.sink = PortAudioSink{T}(outdev.name, this, outchans, blocksize*2)
this.source = PortAudioSource{T}(indev.name, this, inchans, blocksize*2)
this.errbuf = RingBuffer{pa_shim_errmsg_t}(1, ERR_BUFSIZE)
@ -127,6 +123,7 @@ type PortAudioStream{T}
end
end
# this is the top-level outer constructor that all the other outer constructors end up calling
"""
PortAudioStream(inchannels=2, outchannels=2; options...)
PortAudioStream(duplexdevice, inchannels=2, outchannels=2; options...)
@ -150,8 +147,6 @@ Options:
`false`, you are free to read and write separately, but
overflow or underflow can affect the round-trip latency.
"""
# this is the top-level outer constructor that all the other outer constructors
# end up calling
function PortAudioStream(indev::PortAudioDevice, outdev::PortAudioDevice,
inchans=2, outchans=2; eltype=Float32, samplerate=-1, blocksize=DEFAULT_BLOCKSIZE, synced=false)
if samplerate == -1
@ -226,7 +221,7 @@ end
isopen(stream::PortAudioStream) = stream.stream != C_NULL
SampledSignals.samplerate(stream::PortAudioStream) = stream.samplerate
eltype{T}(stream::PortAudioStream{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...)
@ -253,7 +248,7 @@ Handle errors coming over the error stream from PortAudio. This is run as an
independent task while the stream is active.
"""
function handle_errors(stream::PortAudioStream)
err = Vector{pa_shim_errmsg_t}(1)
err = Vector{pa_shim_errmsg_t}(undef, 1)
while true
nread = read!(stream.errbuf, err)
nread == 1 || break
@ -279,7 +274,7 @@ end
# Define our source and sink types
for (TypeName, Super) in ((:PortAudioSink, :SampleSink),
(:PortAudioSource, :SampleSource))
@eval type $TypeName{T} <: $Super
@eval mutable struct $TypeName{T} <: $Super
name::String
stream::PortAudioStream{T}
chunkbuf::Array{T, 2}
@ -319,7 +314,7 @@ function SampledSignals.unsafe_write(sink::PortAudioSink, buf::Array, frameoffse
towrite = min(framecount-nwritten, CHUNKSIZE)
# make a buffer of interleaved samples
transpose!(view(sink.chunkbuf, :, 1:towrite),
view(buf, (1:towrite)+nwritten+frameoffset, :))
view(buf, (1:towrite) .+ nwritten .+ frameoffset, :))
n = write(sink.ringbuf, sink.chunkbuf, towrite)
nwritten += n
# break early if the stream is closed
@ -335,7 +330,7 @@ function SampledSignals.unsafe_read!(source::PortAudioSource, buf::Array, frameo
toread = min(framecount-nread, CHUNKSIZE)
n = read!(source.ringbuf, source.chunkbuf, toread)
# de-interleave the samples
transpose!(view(buf, (1:toread)+nread+frameoffset, :),
transpose!(view(buf, (1:toread) .+ nread .+ frameoffset, :),
view(source.chunkbuf, :, 1:toread))
nread += toread
@ -346,9 +341,43 @@ function SampledSignals.unsafe_read!(source::PortAudioSource, buf::Array, frameo
nread
end
const libpa_shim = find_pa_shim()
"""
PortAudio.shimhash()
Return the sha256 hash(as a string) of the source file used to build the shim.
We may use this sometime to verify that the distributed binary stays in sync
with the rest of the package.
"""
shimhash() = unsafe_string(ccall((:pa_shim_getsourcehash, libpa_shim), Cstring, ()))
# this is called by the shim process callback to notify that there is new data.
# it's run in the audio context so don't do anything besides wake up the
# AsyncCondition handle associated with that ring buffer
notifycb(handle) = ccall(:uv_async_send, Cint, (Ptr{Void}, ), handle)
notifycb(handle) = ccall(:uv_async_send, Cint, (Ptr{Cvoid},), handle)
global shim_processcb_c, notifycb_c
function set_global_callbacks()
shim_dlib = Libdl.dlopen(libpa_shim)
# pointer to the shim's process callback
global shim_processcb_c = Libdl.dlsym(shim_dlib, :pa_shim_processcb)
if shim_processcb_c == C_NULL
error("Got NULL pointer loading `pa_shim_processcb`")
end
global notifycb_c = @cfunction notifycb Cint (Ptr{Cvoid},)
end
function __init__()
set_global_callbacks()
# initialize PortAudio on module load
@suppress_err Pa_Initialize()
end
end # module PortAudio

View file

@ -9,8 +9,8 @@ const PaHostApiIndex = Cint
const PaHostApiTypeId = Cint
# PaStream is always used as an opaque type, so we're always dealing
# with the pointer
const PaStream = Ptr{Void}
const PaStreamCallback = Void
const PaStream = Ptr{Cvoid}
const PaStreamCallback = Cvoid
const PaStreamFlags = Culong
const paNoFlag = PaStreamFlags(0x00)
@ -86,7 +86,7 @@ const pa_host_api_names = Dict{PaHostApiTypeId, String}(
14 => "AudioScience HPI"
)
type PaHostApiInfo
mutable struct PaHostApiInfo
struct_version::Cint
api_type::PaHostApiTypeId
name::Ptr{Cchar}
@ -100,7 +100,7 @@ Pa_GetHostApiInfo(i) = unsafe_load(ccall((:Pa_GetHostApiInfo, libportaudio),
# Device Functions
type PaDeviceInfo
mutable struct PaDeviceInfo
struct_version::Cint
name::Ptr{Cchar}
host_api::PaHostApiIndex
@ -126,15 +126,15 @@ Pa_GetDefaultOutputDevice() = ccall((:Pa_GetDefaultOutputDevice, libportaudio),
# Stream Functions
type Pa_StreamParameters
mutable struct Pa_StreamParameters
device::PaDeviceIndex
channelCount::Cint
sampleFormat::PaSampleFormat
suggestedLatency::PaTime
hostAPISpecificStreamInfo::Ptr{Void}
hostAPISpecificStreamInfo::Ptr{Cvoid}
end
type PaStreamInfo
mutable struct PaStreamInfo
structVersion::Cint
inputLatency::PaTime
outputLatency::PaTime
@ -148,7 +148,7 @@ end
# err = ccall((:Pa_OpenDefaultStream, libportaudio),
# PaError, (Ref{PaStream}, Cint, Cint,
# PaSampleFormat, Cdouble, Culong,
# Ref{Void}, Ref{Void}),
# Ref{Cvoid}, Ref{Cvoid}),
# streamPtr, inChannels, outChannels, sampleFormat, sampleRate,
# framesPerBuffer, C_NULL, C_NULL)
# handle_status(err)
@ -166,7 +166,7 @@ function Pa_OpenStream(inParams, outParams,
Ptr{Pa_StreamParameters},
Ptr{Pa_StreamParameters},
Cdouble, Culong, PaStreamFlags,
Ptr{Void}, Ptr{Void}),
Ptr{Cvoid}, Ptr{Cvoid}),
streamPtr,
inParams, outParams,
sampleRate, framesPerBuffer, flags,
@ -211,7 +211,7 @@ function Pa_ReadStream(stream::PaStream, buf::Array, frames::Integer=length(buf)
show_warnings::Bool=true)
frames <= length(buf) || error("Need a buffer at least $frames long")
err = ccall((:Pa_ReadStream, libportaudio), PaError,
(PaStream, Ptr{Void}, Culong),
(PaStream, Ptr{Cvoid}, Culong),
stream, buf, frames)
handle_status(err, show_warnings)
buf
@ -221,7 +221,7 @@ function Pa_WriteStream(stream::PaStream, buf::Array, frames::Integer=length(buf
show_warnings::Bool=true)
frames <= length(buf) || error("Need a buffer at least $frames long")
err = ccall((:Pa_WriteStream, libportaudio), PaError,
(PaStream, Ptr{Void}, Culong),
(PaStream, Ptr{Cvoid}, Culong),
stream, buf, frames)
handle_status(err, show_warnings)
nothing

View file

@ -1,16 +1,16 @@
function init_pa_shim()
function find_pa_shim()
libdir = joinpath(dirname(@__FILE__), "..", "deps", "usr", "lib")
libsuffix = ""
basename = "pa_shim"
@static if is_linux() && Sys.ARCH == :x86_64
@static if Compat.Sys.islinux() && Sys.ARCH == :x86_64
libsuffix = "x86_64-linux-gnu"
elseif is_linux() && Sys.ARCH == :i686
elseif Compat.Sys.islinux() && Sys.ARCH == :i686
libsuffix = "i686-linux-gnu"
elseif is_apple() && Sys.ARCH == :x86_64
elseif Compat.Sys.isapple() && Sys.ARCH == :x86_64
libsuffix = "x86_64-apple-darwin14"
elseif is_windows() && Sys.ARCH == :x86_64
elseif Compat.Sys.iswindows() && Sys.ARCH == :x86_64
libsuffix = "x86_64-w64-mingw32"
elseif is_windows() && Sys.ARCH == :i686
elseif Compat.Sys.iswindows() && Sys.ARCH == :i686
libsuffix = "i686-w64-mingw32"
elseif !any(
(sfx) -> isfile(joinpath(libdir, "$basename.$sfx")),
@ -19,16 +19,11 @@ function init_pa_shim()
end
# if there's a suffix-less library, it was built natively on this machine,
# so load that one first, otherwise load the pre-built one
global const libpa_shim = Base.Libdl.find_library(
libpa_shim = Libdl.find_library(
[basename, "$(basename)_$libsuffix"],
[libdir])
libpa_shim == "" && error("Could not load $basename library, please file an issue at https://github.com/JuliaAudio/RingBuffers.jl/issues with your `versioninfo()` output")
shim_dlib = Libdl.dlopen(libpa_shim)
# pointer to the shim's process callback
global const shim_processcb_c = Libdl.dlsym(shim_dlib, :pa_shim_processcb)
if shim_processcb_c == C_NULL
error("Got NULL pointer loading `pa_shim_processcb`")
end
return libpa_shim
end
const pa_shim_errmsg_t = Cint
@ -43,19 +38,10 @@ mutable struct pa_shim_info_t
outputbuf::Ptr{PaUtilRingBuffer} # ringbuffer for output
errorbuf::Ptr{PaUtilRingBuffer} # ringbuffer to send error notifications
sync::Cint # keep input/output ring buffers synchronized (0/1)
notifycb::Ptr{Void} # Julia callback to notify on updates (called from audio thread)
inputhandle::Ptr{Void} # condition to notify on new input data
outputhandle::Ptr{Void} # condition to notify when ready for output
errorhandle::Ptr{Void} # condition to notify on new errors
notifycb::Ptr{Cvoid} # Julia callback to notify on updates (called from audio thread)
inputhandle::Ptr{Cvoid} # condition to notify on new input data
outputhandle::Ptr{Cvoid} # condition to notify when ready for output
errorhandle::Ptr{Cvoid} # condition to notify on new errors
end
"""
PortAudio.shimhash()
Return the sha256 hash(as a string) of the source file used to build the shim.
We may use this sometime to verify that the distributed binary stays in sync
with the rest of the package.
"""
shimhash() = unsafe_string(
ccall((:pa_shim_getsourcehash, libpa_shim), Cstring, ()))
Base.unsafe_convert(::Type{Ptr{Void}}, info::pa_shim_info_t) = pointer_from_objref(info)
Base.unsafe_convert(::Type{Ptr{Cvoid}}, info::pa_shim_info_t) = pointer_from_objref(info)

View file

@ -4,9 +4,9 @@
macro suppress_err(block)
quote
if ccall(:jl_generating_output, Cint, ()) == 0
ORIGINAL_STDERR = STDERR
ORIGINAL_STDERR = stderr
err_rd, err_wr = redirect_stderr()
err_reader = @async readstring(err_rd)
err_reader = @async read(err_rd, String)
end
value = $(esc(block))

View file

@ -1,6 +1,8 @@
#!/usr/bin/env julia
using Base.Test
using Compat
using Compat.Test
import Compat: Cvoid
using TestSetExtensions
using PortAudio
using SampledSignals
@ -34,7 +36,7 @@ function setup_callback(inchans, outchans, nframes, synced)
function processfunc()
ccall(shim_processcb_c, Cint,
(Ptr{Float32}, Ptr{Float32}, Culong, Ptr{Void}, Culong, Ptr{Void}),
(Ptr{Float32}, Ptr{Float32}, Culong, Ptr{Cvoid}, Culong, Ptr{Cvoid}),
cb_input, cb_output, nframes, C_NULL, flags, pointer_from_objref(info))
end

View file

@ -5,13 +5,13 @@
include("runtests.jl")
# these default values are specific to my machines
if is_windows()
if Compat.Sys.iswindows()
default_indev = "Microphone Array (Realtek High "
default_outdev = "Speaker/Headphone (Realtek High"
elseif is_apple()
default_indev = "Built-in Microph"
elseif Compat.Sys.isapple()
default_indev = "Built-in Microphone"
default_outdev = "Built-in Output"
elseif is_linux()
elseif Compat.Sys.islinux()
default_indev = "default"
default_outdev = "default"
end
@ -50,12 +50,12 @@ end
write(stream, buf)
io = IOBuffer()
show(io, stream)
@test String(take!(io)) == """
PortAudio.PortAudioStream{Float32}
@test Compat.occursin("""
PortAudioStream{Float32}
Samplerate: 44100.0Hz
Buffer Size: 4096 frames
2 channel sink: "$default_outdev"
2 channel source: "$default_indev\""""
2 channel source: "$default_indev\"""", String(take!(io)))
close(stream)
end
@testset "Error on wrong name" begin
@ -68,8 +68,8 @@ end
buf = SampleBuf(rand(eltype(stream), 48000, nchannels(stream.sink))*0.1, samplerate(stream))
t1 = @async write(stream, buf)
t2 = @async write(stream, buf)
@test wait(t1) == 48000
@test wait(t2) == 48000
@test fetch(t1) == 48000
@test fetch(t2) == 48000
flush(stream)
close(stream)
end
@ -78,8 +78,8 @@ end
buf = SampleBuf(rand(eltype(stream), 48000, nchannels(stream.source))*0.1, samplerate(stream))
t1 = @async read!(stream, buf)
t2 = @async read!(stream, buf)
@test wait(t1) == 48000
@test wait(t2) == 48000
@test fetch(t1) == 48000
@test fetch(t2) == 48000
close(stream)
end
end