Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add wavplay() support for Windows, minor doc tweaks #87

Merged
merged 4 commits into from
Aug 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
68 changes: 33 additions & 35 deletions src/WAV.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand All @@ -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")

Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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
27 changes: 27 additions & 0 deletions src/wavplay-win32.jl
Original file line number Diff line number Diff line change
@@ -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
18 changes: 11 additions & 7 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -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