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 0c71023..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") @@ -45,38 +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) - -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 -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 -else - wavplay(data, fs) = @warn "wavplay is not currently implemented on $(Sys.KERNEL)" -end - include("AudioDisplay.jl") include("WAVChunk.jl") @@ -720,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. @@ -1079,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 new file mode 100644 index 0000000..e17aec5 --- /dev/null +++ b/src/wavplay-win32.jl @@ -0,0 +1,27 @@ +# -*- mode: julia; -*- +module WAVPlay +import WAV: wavplay, wavwrite + +# 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