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

Adding dependencies and writing tests for audio.jl #13

Merged
merged 7 commits into from
Oct 27, 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
*.jl.cov
*.jl.*.cov
*.jl.mem
Mainfest.toml
21 changes: 21 additions & 0 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
name = "MusicProcessing"
uuid = "f57c4921-e30c-5f49-b073-3f2f2ada663e"
repo = "https://github.com/JuliaMusic/MusicProcessing.jl.git"
version = "1.8.1"

[deps]
DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2"
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
FixedPointNumbers = "53c48c17-4a7d-5ca2-90c5-79b7896eea93"
Requires = "ae029012-a4dd-5104-9daa-d747884805df"
SampledSignals = "bd7594eb-a658-542f-9e75-4c4d8908c167"
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
Comment on lines +7 to +12
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

O, forgot to say this here. In the compat entry we need an entry for every package used, to allow for registration in the General registry (you can simply use the versions you tested this with in Jupyter)


[compat]
julia = "1"

[extras]
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"

[targets]
test = ["Test"]
46 changes: 21 additions & 25 deletions src/TFR.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ function spectrogram(audio::SampleBuf{T, 1},
hopsize::Int = windowsize >> 2;
window = hanning, kwargs...) where T
noverlap = windowsize - hopsize
data = map(Float32, audio.data)
DSP.spectrogram(data, windowsize, noverlap; fs = audio.samplerate.val, window = window, kwargs...)
DSP.spectrogram(audio.data, windowsize, noverlap; fs = audio.samplerate, window = window, kwargs...)
end

""""""
Expand All @@ -19,10 +18,9 @@ function spectrogram(audio::SampleBuf{T, 2},
hopsize::Int = windowsize >> 2;
window = hanning, kwargs...) where T
noverlap = windowsize - hopsize
data = map(Float32, audio.data)
(mapslices(data, 1) do data
DSP.spectrogram(data, windowsize, noverlap; fs = audio.samplerate.val, window = window, kwargs...)
end)[:]
vec(mapslices(audio.data, dims=1) do data
DSP.spectrogram(data, windowsize, noverlap; fs = audio.samplerate, window = window, kwargs...)
end)
end

""""""
Expand All @@ -42,8 +40,7 @@ function stft(audio::SampleBuf{T, 1},
hopsize::Int = windowsize >> 2;
window = hanning, kwargs...) where T
noverlap = windowsize - hopsize
data = tofloat(audio.data)
DSP.stft(data, windowsize, noverlap; window = window, kwargs...)
DSP.stft(audio.data, windowsize, noverlap; window = window, kwargs...)
end

""""""
Expand All @@ -53,12 +50,11 @@ function stft(audio::SampleBuf{T, 2},
nchannels = SampledSignals.nchannels(audio)
noverlap = windowsize - hopsize

stft = Array(Matrix, nchannels)
data = tofloat(audio.data)
stft = Array{Matrix{Complex{Float32}}}(undef, nchannels) # type that DSP.stft outputs
for i in 1:nchannels
stft[i] = DSP.stft(data[:, i], windowsize, noverlap; kwargs...)
stft[i] = DSP.stft(audio.data[:, i], windowsize, noverlap; kwargs...)
end
cat(3, stft...)
cat(stft..., dims=3)
end

""""""
Expand Down Expand Up @@ -110,7 +106,7 @@ function istft(stft::Array{Complex{T}, 2},

columns = size(stft, 2)
audio = zeros(T, windowsize + hopsize * (columns - 1))
weights = zeros(audio)
weights = zeros(T, windowsize + hopsize * (columns - 1))
spectrum = zeros(T, nfft)

nbins = size(stft, 1)
Expand Down Expand Up @@ -169,15 +165,15 @@ function istft(stft::Array{Complex{T}, 3},
windowsize::Int = 2 * (size(stft, 1) - 1),
hopsize::Int = windowsize >> 2; kwargs...) where {T <: AbstractFloat}
nchannels = size(stft, 3)
buffers = cell(nchannels)
buffers = Vector{SampleBuf}(undef, nchannels)

# run ISTFT for each channel
for i = 1:nchannels
buffers[i] = istft(stft[:, :, i], samplerate, windowsize, hopsize; kwargs...)
end

nsamples = size(buffers[1], 1)
audio = Array(T, nsamples, nchannels)
audio = Array{T}(undef, nsamples, nchannels)

for i = 1:nchannels
audio[:, i] = buffers[i].data
Expand Down Expand Up @@ -216,13 +212,13 @@ function phase_vocoder(stft::Array{Complex{T}, 2},
nfft = (nbins - 1) * 2
timesteps = 1f0:speed:nframes
stretched = zeros(Complex{T}, nbins, length(timesteps))
phase_advance = collect(linspace(0f0, T(π * hopsize), nbins))
phase_acc = angle(stft[:, 1])
cis_phase = Array(Complex{T}, size(phase_acc))
angle1 = Array(T, nbins)
angle2 = Array(T, nbins)
dphase = Array(T, nbins)
mag = Array(T, nbins)
phase_advance = collect(range(0f0, T(π * hopsize), length=nbins))
phase_acc = map(angle, stft[:,1])
cis_phase = Array{Complex{T}}(undef,size(phase_acc))
angle1 = Array{T}(undef, nbins)
angle2 = Array{T}(undef, nbins)
dphase = Array{T}(undef, nbins)
mag = Array{T}(undef, nbins)
twopi = T(2π)

@inbounds for (t, step) in enumerate(timesteps)
Expand Down Expand Up @@ -254,8 +250,8 @@ function phase_vocoder(stft::Array{Complex{T}, 2},
end

for i in 1:nbins
angle1[i] = angle(stft[i, left])
angle2[i] = angle(stft[i, right])
angle1[i] = map(angle, stft[i, left])
angle2[i] = map(angle,stft[i, right])
# compute phase advance
dphase[i] = angle2[i] - angle1[i] - phase_advance[i]
# wrap to -pi:pi range
Expand All @@ -276,7 +272,7 @@ Phase vocoder. Given an STFT matrix, speed it up by a factor.
function phase_vocoder(stft::Array{Complex{T}, 3},
speed::Real,
hopsize::Int = (size(stft, 1) - 1) >> 1) where {T <: AbstractFloat}
mapslices(stft, 1:2) do stft
mapslices(stft, dims=1:2) do stft
phase_vocoder(stft, speed, hopsize)
end
end
16 changes: 8 additions & 8 deletions src/audio.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ convert a multichannel audio to mono
"""
function mono(audio::SampleBuf{T, 2}) where {T <: AbstractFloat}
SampleBuf{T, 1}(
mean(audio.data, 2)[:],
vec(SampledSignals.mono(audio).data),
audio.samplerate
)
end
Expand All @@ -19,10 +19,10 @@ end
function mono(audio::SampleBuf{T, 2}) where {T <: Fixed}
nchannels = SampledSignals.nchannels(audio)
if nchannels == 1
SampleBuf{T, 1}(audio.data[:], audio.samplerate)
SampleBuf{T, 1}(vec(audio.data), audio.samplerate)
elseif nchannels == 2
nsamples = SampledSignals.nframes(audio)
buffer = Array(T, nsamples)
buffer = Array{T}(undef, nsamples)
for i = 1:nsamples
@inbounds a = audio.data[i, 1].i
@inbounds b = audio.data[i, 2].i
Expand All @@ -32,7 +32,7 @@ function mono(audio::SampleBuf{T, 2}) where {T <: Fixed}
SampleBuf{T, 1}(buffer, audio.samplerate)
else
SampleBuf{T, 1}(
map(T, mean(map(Float32, audio.data))[:]),
map(T, vec(mean(map(Float32, audio.data)))),
audio.samplerate
)
end
Expand All @@ -43,7 +43,7 @@ function resample(audio::SampleBuf{T, 2}, samplerate::Real) where T
rate = samplerate / audio.samplerate
filter = DSP.resample_filter(rate, 512, 1.0, 140)
SampleBuf{T, 2}(
mapslices(audio.data, 1) do data
mapslices(audio.data, dims=1) do data
DSP.resample(data, rate, filter)
end,
samplerate
Expand All @@ -60,7 +60,7 @@ end

"""returns the duration of given audio, in seconds"""
function duration(audio::SampleBuf)
nframes(audio) / samplerate(audio)
SampledSignals.nframes(audio) / SampledSignals.samplerate(audio)
end

"""
Expand Down Expand Up @@ -107,13 +107,13 @@ end
""""""
function zero_crossing_rate(audio::SampleBuf{T, 1}, framesize::Int = 1024, hopsize::Int = framesize >> 2) where T
nframes = MusicProcessing.nframes(length(audio.data), framesize, hopsize)
result = Array(Float32, nframes)
result = Array{Float32}(undef,nframes)

offset = 0
for i = 1:nframes
result[i] = zero_crossings(audio.data, framesize, offset) / framesize
offset += hopsize
end

SampleBuf{T, 1}(result, audio.samplerate / Float32(hopsize))
result
end
2 changes: 1 addition & 1 deletion src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ end
function zero_crossings(array::AbstractVector{T}, size::Int = length(array), offset::Int = 0) where {T<:Real}
result = 0
previous = 0
for i in offset + (1:size)
for i in offset .+ (1:size)
number = array[i]
sgn = number == 0 ? 0 : number > 0 ? 1 : -1
if sgn != previous
Expand Down
36 changes: 33 additions & 3 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,5 +1,35 @@
using MusicProcessing
using Base.Test
using SampledSignals: SampleBuf
using Test

# write your own tests here
@test 1 == 1
# Example audio
audio_one_channel = SampleBuf(rand(1000), 10)
audio_two_channel = SampleBuf(rand(1000,2), 10)
audio_multi_channel = SampleBuf(rand(1000,2), 10)

# audio.jl

@testset "audio.jl" begin
@test size(mono(audio_two_channel)) == (1000,)
@test size(mono(audio_multi_channel)) == (1000,)

@test size(resample(audio_one_channel, 5))[1] == 500
@test size(resample(audio_two_channel, 5))[1] == 500
@test size(resample(audio_multi_channel, 5))[1] == 500

@test duration(audio_one_channel) == 100
@test duration(audio_two_channel) == 100
@test duration(audio_multi_channel) == 100

@test duration(pitchshift(audio_one_channel)) == duration(audio_one_channel)
@test duration(pitchshift(audio_two_channel)) == duration(audio_two_channel)
@test duration(pitchshift(audio_multi_channel)) == duration(audio_multi_channel)

@test duration(speedup(audio_one_channel, 2)) ≈ duration(audio_one_channel) // 2
@test duration(speedup(audio_two_channel, 2)) ≈ duration(audio_two_channel) // 2
@test duration(speedup(audio_multi_channel, 2)) ≈ duration(audio_multi_channel) // 2

@test duration(slowdown(audio_one_channel, 2)) ≈ duration(audio_one_channel) * 2
@test duration(slowdown(audio_two_channel, 2)) ≈ duration(audio_two_channel) * 2
@test duration(slowdown(audio_multi_channel, 2)) ≈ duration(audio_multi_channel) * 2
end