add basic support for file output
This commit is contained in:
parent
83c4199096
commit
d3ae48dd09
4 changed files with 80 additions and 16 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@
|
||||||
*.o
|
*.o
|
||||||
deps/usr
|
deps/usr
|
||||||
deps/deps.jl
|
deps/deps.jl
|
||||||
|
*.wav
|
||||||
|
*.flac
|
||||||
|
|
|
@ -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,28 @@ 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)
|
||||||
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 +76,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 +119,28 @@ 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})
|
||||||
|
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
|
||||||
file::AudioFile
|
file::AudioFile
|
||||||
|
|
Binary file not shown.
|
@ -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
|
||||||
|
|
Loading…
Reference in a new issue