From c817e280cf241746ea7af08bda1e29b38b6e38ed Mon Sep 17 00:00:00 2001 From: Markus Kuhn Date: Sat, 1 Aug 2020 00:26:40 +0100 Subject: [PATCH 1/4] remove compile-time find_library() checks for presence of shared library If this package gets precompiled and cached before the user has installed a pre-requisite shared library, then installing said library will not fix the problem if the check for the presence happened at compile time. Likewise, if PackageCompiler.jl is used to compile an app on another machine, then absence of a required shared library at compile time there cannot be rectified later by a user who downloaded a pre-compiled app containing this package. Dropping the compile-time check for the presence of the required shared libraries fixes this. The exception raised by ccall() if the required library is missing is anyway more informative than the warning messages removed here. https://julialang.github.io/PackageCompiler.jl/dev/devdocs/relocatable_part_3/ --- src/WAV.jl | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/WAV.jl b/src/WAV.jl index 0c71023..1d91e48 100644 --- a/src/WAV.jl +++ b/src/WAV.jl @@ -61,18 +61,9 @@ There is not a native backend for Windows yet. function wavplay end wavplay(fname) = wavplay(wavread(fname)[1:2]...) @static if Sys.islinux() - @static if Libdl.find_library(["libpulse-simple", "libpulse-simple.so.0"]) != "" - include("wavplay-pulse.jl") - else - wavplay(data, fs) = @warn "libpulse-simple not found, wavplay will not work" - end + include("wavplay-pulse.jl") elseif Sys.isapple() - @static if Libdl.find_library(["AudioToolbox"], - ["/System/Library/Frameworks/AudioToolbox.framework/Versions/A"]) != "" - include("wavplay-audioqueue.jl") - else - wavplay(data, fs) = @warn "AudioToolbox.framework not found, wavplay will not work" - end + include("wavplay-audioqueue.jl") else wavplay(data, fs) = @warn "wavplay is not currently implemented on $(Sys.KERNEL)" end From dffe83925bee57d04ee483c5785b8e5460e40cb5 Mon Sep 17 00:00:00 2001 From: Markus Kuhn Date: Sat, 1 Aug 2020 00:37:28 +0100 Subject: [PATCH 2/4] add wavplay() support for Windows --- src/WAV.jl | 5 +++-- src/wavplay-win32.jl | 27 +++++++++++++++++++++++++++ test/runtests.jl | 18 +++++++++++------- 3 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 src/wavplay-win32.jl diff --git a/src/WAV.jl b/src/WAV.jl index 1d91e48..d848688 100644 --- a/src/WAV.jl +++ b/src/WAV.jl @@ -55,8 +55,7 @@ both from the WAV file named `filename`. The supported backends are: * AudioQueue (macOS) * PulseAudio (Linux, libpulse-simple) - -There is not a native backend for Windows yet. +* PlaySound (Windows) """ function wavplay end wavplay(fname) = wavplay(wavread(fname)[1:2]...) @@ -64,6 +63,8 @@ wavplay(fname) = wavplay(wavread(fname)[1:2]...) include("wavplay-pulse.jl") elseif Sys.isapple() include("wavplay-audioqueue.jl") +elseif Sys.iswindows() + include("wavplay-win32.jl") else wavplay(data, fs) = @warn "wavplay is not currently implemented on $(Sys.KERNEL)" end diff --git a/src/wavplay-win32.jl b/src/wavplay-win32.jl new file mode 100644 index 0000000..6c74183 --- /dev/null +++ b/src/wavplay-win32.jl @@ -0,0 +1,27 @@ +# -*- mode: julia; -*- +module WAVPlay +import ..wavplay + +# some standard Win32 API types and constants, see [MS-DTYP] +const BOOL = Cint +const DWORD = Culong +const TRUE = 1 +# PlaySound flags from Winmm.h +const SND_SYNC = 0x0 +const SND_ASYNC = 0x1 +const SND_NODEFAULT = 0x2 +const SND_MEMORY = 0x4 +const SND_FILENAME = 0x20000 + +function wavplay(data, fs) + # produce an in-memory WAV file ... + buf=IOBuffer() + wavwrite(data, buf, Fs=fs) + wav = take!(buf) + # ... and pass it to PlaySound + success = ccall((:PlaySoundA, "Winmm.dll"), stdcall, BOOL, + (Ptr{Cvoid}, Ptr{Cvoid}, DWORD), + wav, C_NULL, SND_MEMORY | SND_SYNC | SND_NODEFAULT) + Base.windowserror("PlaySound", success != TRUE) +end +end # module diff --git a/test/runtests.jl b/test/runtests.jl index ceaad5f..d2361ef 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -638,11 +638,15 @@ end end ### playback -# The playback tests don't work on travis. -@testset "13" begin - fs = 44100.0 - t = 1:44100; - in_data = sin.(5.0 * t / fs) * 1e-6; - #WAV.wavplay(in_data, fs); - #WAV.wavplay([in_data in_data], fs); +if !haskey(ENV, "CI") + @testset "13" begin + fs = 44100.0 + t = 0.0:fs-1.0; + left_data = sin.(2pi * 500.0 * t / fs) * 1e-1; + right_data = sin.(2pi * 800.0 * t / fs) * 1e-1; + # 500 Hz mono + @test WAV.wavplay(left_data, fs) === nothing; + # 500 Hz left, 800 Hz right stereo + @test WAV.wavplay([left_data right_data], fs) === nothing; + end end From 18af523752737713c06a2fb95377fa9423d2b7aa Mon Sep 17 00:00:00 2001 From: Markus Kuhn Date: Sat, 1 Aug 2020 20:09:59 +0100 Subject: [PATCH 3/4] move WAVPlay module near end, so it can include wavwrite --- src/WAV.jl | 54 ++++++++++++++++++++++++-------------------- src/wavplay-win32.jl | 2 +- 2 files changed, 31 insertions(+), 25 deletions(-) diff --git a/src/WAV.jl b/src/WAV.jl index d848688..1239532 100644 --- a/src/WAV.jl +++ b/src/WAV.jl @@ -45,30 +45,6 @@ import Libdl using FileIO using Logging -""" - wavplay(data, fs) - wavplay(filename) - -Plays the audio waveform `data` at sampling frequency `fs`, or read -both from the WAV file named `filename`. - -The supported backends are: -* AudioQueue (macOS) -* PulseAudio (Linux, libpulse-simple) -* PlaySound (Windows) -""" -function wavplay end -wavplay(fname) = wavplay(wavread(fname)[1:2]...) -@static if Sys.islinux() - include("wavplay-pulse.jl") -elseif Sys.isapple() - include("wavplay-audioqueue.jl") -elseif Sys.iswindows() - include("wavplay-win32.jl") -else - wavplay(data, fs) = @warn "wavplay is not currently implemented on $(Sys.KERNEL)" -end - include("AudioDisplay.jl") include("WAVChunk.jl") @@ -1071,4 +1047,34 @@ save(s::Stream{format"WAV"}, data; kwargs...) = wavwrite(data, s.io; kwargs...) load(f::File{format"WAV"}; kwargs...) = wavread(f.filename; kwargs...) save(f::File{format"WAV"}, data; kwargs...) = wavwrite(data, f.filename; kwargs...) +""" + wavplay(data, fs) + wavplay(filename::AbstractString) + +Plays the audio waveform `data` at sampling frequency `fs` (in hertz). +To play a stereo signal, provide two columns in array `data` (left and +right channel), as in [`wavwrite`](@ref). + +The `filename` form reads both waveform data and sampling frequency +from the named WAV file to play it. + +The supported backends are: +* AudioQueue (macOS) +* PulseAudio (Linux, libpulse-simple) +* PlaySound (Windows) + +See also: [`wavwrite`](@ref) +""" +function wavplay end +wavplay(fname::AbstractString) = wavplay(wavread(fname)[1:2]...) +@static if Sys.islinux() + include("wavplay-pulse.jl") +elseif Sys.isapple() + include("wavplay-audioqueue.jl") +elseif Sys.iswindows() + include("wavplay-win32.jl") +else + wavplay(data, fs) = @warn "wavplay is not currently implemented on $(Sys.KERNEL)" +end + end # module diff --git a/src/wavplay-win32.jl b/src/wavplay-win32.jl index 6c74183..e17aec5 100644 --- a/src/wavplay-win32.jl +++ b/src/wavplay-win32.jl @@ -1,6 +1,6 @@ # -*- mode: julia; -*- module WAVPlay -import ..wavplay +import WAV: wavplay, wavwrite # some standard Win32 API types and constants, see [MS-DTYP] const BOOL = Cint From 0f22f338e076d118928c3a815d8661e169cb9b8a Mon Sep 17 00:00:00 2001 From: Markus Kuhn Date: Sat, 1 Aug 2020 20:11:13 +0100 Subject: [PATCH 4/4] avoid full-scale audio volume in examples --- README.md | 4 ++-- src/WAV.jl | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index e4a68dd..6ac027d 100644 --- a/README.md +++ b/README.md @@ -34,11 +34,11 @@ using WAV fs = 8e3 t = 0.0:1/fs:prevfloat(1.0) f = 1e3 -y = sin.(2pi * f * t) +y = sin.(2pi * f * t) * 0.1 wavwrite(y, "example.wav", Fs=fs) y, fs = wavread("example.wav") -y = sin.(2pi * 2f * t) +y = sin.(2pi * 2f * t) * 0.1 wavappend(y, "example.wav") y, fs = wavread("example.wav") diff --git a/src/WAV.jl b/src/WAV.jl index 1239532..d2e4b73 100644 --- a/src/WAV.jl +++ b/src/WAV.jl @@ -24,11 +24,11 @@ using WAV fs = 8e3 t = 0.0:1/fs:prevfloat(1.0) f = 1e3 -y = sin.(2pi * f * t) +y = sin.(2pi * f * t) * 0.1 wavwrite(y, "example.wav", Fs=fs) y, fs = wavread("example.wav") -y = sin.(2pi * 2f * t) +y = sin.(2pi * 2f * t) * 0.1 wavappend(y, "example.wav") y, fs = wavread("example.wav") @@ -688,7 +688,7 @@ make_range(subrange::Number) = 1:convert(Int, subrange) """ wavread(io::IO; subrange=:, format="double") - wavread(filename::String; subrange=:, format="double") + wavread(filename::AbstractString; subrange=:, format="double") Reads the samples from a WAV file. The samples are converted to floating point values in the range −1.0 to 1.0 by default.