Merge pull request #8 from zhemao/master

Add basic support for file output
This commit is contained in:
Spencer Russell 2014-01-23 09:06:03 -08:00
commit 0fa2977889
4 changed files with 83 additions and 16 deletions

2
.gitignore vendored
View file

@ -3,3 +3,5 @@
*.o *.o
deps/usr deps/usr
deps/deps.jl deps/deps.jl
*.wav
*.flac

View file

@ -5,6 +5,20 @@ const sndfile = "libsndfile"
const SFM_READ = int32(0x10) const SFM_READ = int32(0x10)
const SFM_WRITE = int32(0x20) const SFM_WRITE = int32(0x20)
const SF_FORMAT_WAV = 0x010000
const SF_FORMAT_FLAC = 0x170000
const SF_FORMAT_OGG = 0x200060
const SF_FORMAT_PCM_S8 = 0x0001 # Signed 8 bit data
const SF_FORMAT_PCM_16 = 0x0002 # Signed 16 bit data
const SF_FORMAT_PCM_24 = 0x0003 # Signed 24 bit data
const SF_FORMAT_PCM_32 = 0x0004 # Signed 32 bit data
const EXT_TO_FORMAT = [
".wav" => SF_FORMAT_WAV,
".flac" => SF_FORMAT_FLAC
]
type SF_INFO type SF_INFO
frames::Int64 frames::Int64
samplerate::Int32 samplerate::Int32
@ -25,12 +39,30 @@ type AudioFile
sfinfo::SF_INFO sfinfo::SF_INFO
end end
function af_open(path::String, mode::String="r") function af_open(path::String, mode::String = "r",
# TODO: handle write/append modes sampleRate::Integer = 44100, channels::Integer = 1,
format::Integer = 0)
@assert channels <= 2
sfinfo = SF_INFO(0, 0, 0, 0, 0, 0) sfinfo = SF_INFO(0, 0, 0, 0, 0, 0)
file_mode = SFM_READ
if mode == "w"
file_mode = SFM_WRITE
sfinfo.samplerate = sampleRate
sfinfo.channels = channels
if format == 0
_, ext = splitext(path)
sfinfo.format = EXT_TO_FORMAT[ext] | SF_FORMAT_PCM_16
else
sfinfo.format = format
end
end
filePtr = ccall((:sf_open, sndfile), Ptr{Void}, filePtr = ccall((:sf_open, sndfile), Ptr{Void},
(Ptr{Uint8}, Int32, Ptr{SF_INFO}), (Ptr{Uint8}, Int32, Ptr{SF_INFO}),
path, SFM_READ, &sfinfo) path, file_mode, &sfinfo)
if filePtr == C_NULL if filePtr == C_NULL
errmsg = ccall((:sf_strerror, sndfile), Ptr{Uint8}, (Ptr{Void},), filePtr) errmsg = ccall((:sf_strerror, sndfile), Ptr{Uint8}, (Ptr{Void},), filePtr)
error(bytestring(errmsg)) error(bytestring(errmsg))
@ -46,8 +78,8 @@ function Base.close(file::AudioFile)
end end
end end
function af_open(f::Function, path::String) function af_open(f::Function, args...)
file = af_open(path) file = af_open(args...)
f(file) f(file)
close(file) close(file)
end end
@ -89,6 +121,29 @@ function Base.read(file::AudioFile, nframes::Integer = file.sfinfo.frames,
return arr return arr
end end
function Base.write{T}(file::AudioFile, frames::Array{T})
@assert file.sfinfo.channels <= 2
nframes = int(length(frames) / file.sfinfo.channels)
if T == Int16
return ccall((:sf_writef_short, sndfile), Int64,
(Ptr{Void}, Ptr{Int16}, Int64),
file.filePtr, frames, nframes)
elseif T == Int32
return ccall((:sf_writef_int, sndfile), Int64,
(Ptr{Void}, Ptr{Int32}, Int64),
file.filePtr, frames, nframes)
elseif T == Float32
return ccall((:sf_writef_float, sndfile), Int64,
(Ptr{Void}, Ptr{Float32}, Int64),
file.filePtr, frames, nframes)
elseif T == Float64
return ccall((:sf_writef_double, sndfile), Int64,
(Ptr{Void}, Ptr{Float64}, Int64),
file.filePtr, frames, nframes)
end
end
type FilePlayer <: AudioNode type FilePlayer <: AudioNode
active::Bool active::Bool
deactivate_cond::Condition deactivate_cond::Condition

Binary file not shown.

View file

@ -73,15 +73,25 @@ stop(node)
process(test_stream) process(test_stream)
@test process(test_stream) == zeros(AudioIO.AudioSample, TEST_BUF_SIZE) @test process(test_stream) == zeros(AudioIO.AudioSample, TEST_BUF_SIZE)
info("Testing libsndfile read") for ext in ["wav", "flac"]
info("Testing $ext file write/read")
fname = "test/sinwave.$ext"
samplerate = 44100 samplerate = 44100
freq = 440 freq = 440
t = linspace(0, 2, 2 * samplerate) t = [0 : 2 * samplerate - 1] / samplerate
phase = 2 * pi * freq * t phase = 2 * pi * freq * t
reference = int16((2 ^ 15 - 1) * sin(phase)) reference = int16((2 ^ 15 - 1) * sin(phase))
f = af_open("test/sinwave.flac") af_open(fname, "w") do f
write(f, reference)
end
af_open(fname) do f
@test f.sfinfo.channels == 1 @test f.sfinfo.channels == 1
@test f.sfinfo.frames == 2 * samplerate @test f.sfinfo.frames == 2 * samplerate
actual = read(f, 2 * samplerate) actual = read(f, 2 * samplerate)
@test_approx_eq(reference, actual) @test_approx_eq(reference, actual)
end
end