Skip to content

Commit

Permalink
Automerge fix for v0.3.5 [skip ci] (JuliaDSP#38)
Browse files Browse the repository at this point in the history
* automerge fix for Projects.toml [skip ci]

- version changed back to 0.3.5 so versions don't skip
- add v1 compat for stdlibs (Distributed, LinearAlgebra, Statistics, Test)
- add compat for Memoization
- bump required Julia version to LTS (1.6)

* use CompatHelper and Test

testset and test macros

* dct_i with fftw

- use buffers for more stuff
- `@views` entire functions

* specify Dict type

- Dict{Symbol, Any} is the result anyway, specifying in advance reduces allocations from compilation

* collect

* don't use PolynomialRatio
  • Loading branch information
wheeheee authored Nov 20, 2023
1 parent 24e79cc commit 40c4ea5
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 92 deletions.
45 changes: 45 additions & 0 deletions .github/workflows/CompatHelper.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: CompatHelper
on:
schedule:
- cron: 0 0 * * *
workflow_dispatch:
permissions:
contents: write
pull-requests: write
jobs:
CompatHelper:
runs-on: ubuntu-latest
steps:
- name: Check if Julia is already available in the PATH
id: julia_in_path
run: which julia
continue-on-error: true
- name: Install Julia, but only if it is not already available in the PATH
uses: julia-actions/setup-julia@latest
with:
version: '1'
arch: ${{ runner.arch }}
if: steps.julia_in_path.outcome != 'success'
- name: "Add the General registry via Git"
run: |
import Pkg
ENV["JULIA_PKG_SERVER"] = ""
Pkg.Registry.add("General")
shell: julia --color=yes {0}
- name: "Install CompatHelper"
run: |
import Pkg
name = "CompatHelper"
uuid = "aa819f21-2bde-4658-8897-bab36330d9b7"
version = "3"
Pkg.add(; name, uuid, version)
shell: julia --color=yes {0}
- name: "Run CompatHelper"
run: |
import CompatHelper
CompatHelper.main()
shell: julia --color=yes {0}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }}
# COMPATHELPER_PRIV: ${{ secrets.COMPATHELPER_PRIV }}
11 changes: 8 additions & 3 deletions Project.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = "MFCC"
uuid = "ca7b5df7-6146-5dcc-89ec-36256279a339"
authors = ["David van Leeuwen"]
version = "0.3.6"
version = "0.3.5"

[deps]
DSP = "717857b8-e6f2-59f4-9121-6e50c889abd2"
Expand All @@ -18,12 +18,17 @@ WAV = "8149f6b0-98f6-5db9-b78f-408fbbb8ef88"

[compat]
DSP = "0.6, 0.7"
Distributed = "1"
FFTW = "1"
FileIO = "1"
HDF5 = "0.15 - 0.17"
SpecialFunctions = "0.8, 1, 2"
LinearAlgebra = "1"
Memoization = "0.2"
SpecialFunctions = "0.8 - 2"
Statistics = "1"
Test = "1"
WAV = "1"
julia = "1"
julia = "1.6"

[extras]
Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2"
Expand Down
10 changes: 6 additions & 4 deletions src/feacalc.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ ncol(x) = size(x, 2)
compute features according to standard settings directly from a wav file.
this does channel at the time.
"""
function feacalc(wavfile::AbstractString; method=:wav, kwargs...)
function feacalc(wavfile; method=:wav, kwargs...)
x, sr = if method == :wav
wavread(wavfile)
elseif method == :sox
Expand Down Expand Up @@ -48,8 +48,10 @@ function feacalc(x::AbstractVecOrMat; augtype=:ddelta, normtype=:warp, sadtype=:
nsamples, nchan = length(x), 1
end
## save some metadata
meta = Dict(:nsamples => nsamples, :sr => sr, :source => source,
:nchan => nchan, :chan => chan)
meta = Dict{Symbol, Any}(
:nsamples => nsamples, :sr => sr, :source => source,
:nchan => nchan, :chan => chan
)
preemph = 0.97
preemph ^= 16000. / sr

Expand Down Expand Up @@ -103,7 +105,7 @@ function feacalc(x::AbstractVecOrMat; augtype=:ddelta, normtype=:warp, sadtype=:
end

## When called with a specific application in mind, call with two arguments
function feacalc(wavfile::AbstractString, application::Symbol; kwargs...)
function feacalc(wavfile, application::Symbol; kwargs...)
if application in (:speaker, :nbspeaker)
feacalc(wavfile; defaults=:nbspeaker, kwargs...)
elseif application == :wbspeaker
Expand Down
4 changes: 2 additions & 2 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ import HDF5
HDF5.write(fd::HDF5.File, s::AbstractString, sym::Symbol) = write(fd, string(s,":Symbol"), string(sym))

## always save data in Float32
## the functiona arguments are the same as the output of feacalc
## the function arguments are the same as the output of feacalc
## x: the MFCC data
## meta: a dict with parameters anout the data, nsamples, nframes, totnframes (before sad), ...
## meta: a dict with parameters about the data, nsamples, nframes, totnframes (before sad), ...
## params: a dict with parameters about the feature extraction itself.
function feasave(file::AbstractString, x::AbstractMatrix{<:AbstractFloat}; meta::Dict=Dict(), params::Dict=Dict())
dir = dirname(file)
Expand Down
18 changes: 10 additions & 8 deletions src/mfccs.jl
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ function mfcc(x::AbstractVector{T}, sr::Real=16000.0; wintime=0.025, steptime=0.
fbtype=:htkmel, bwidth=1.0, modelorder=0, dcttype=3, dither::Real=false,
sumpower::Bool=false, usecmp::Bool=false) where {T<:AbstractFloat}
if !iszero(preemph)
x = filt(PolynomialRatio([1., -preemph], [1.]), x)
x = filt([1., -preemph], 1., x)
end
pspec = powspec(x, sr; wintime=wintime, steptime=steptime, dither=dither)
aspec = audspec(pspec, sr; nfilts=nbands, fbtype=fbtype, minfreq=minfreq,
Expand All @@ -40,11 +40,13 @@ function mfcc(x::AbstractVector{T}, sr::Real=16000.0; wintime=0.025, steptime=0.
cepstra = spec2cep(aspec, numcep, dcttype)
end
cepstra = lifter(cepstra, lifterexp)
meta = Dict(:sr => sr, :wintime => wintime, :steptime => steptime, :numcep => numcep,
:lifterexp => lifterexp, :sumpower => sumpower, :preemph => preemph,
:dither => dither, :minfreq => minfreq, :maxfreq => maxfreq, :nbands => nbands,
:bwidth => bwidth, :dcttype => dcttype, :fbtype => fbtype,
:usecmp => usecmp, :modelorder => modelorder)
meta = Dict{Symbol, Any}(
:sr => sr, :wintime => wintime, :steptime => steptime, :numcep => numcep,
:lifterexp => lifterexp, :sumpower => sumpower, :preemph => preemph,
:dither => dither, :minfreq => minfreq, :maxfreq => maxfreq, :nbands => nbands,
:bwidth => bwidth, :dcttype => dcttype, :fbtype => fbtype,
:usecmp => usecmp, :modelorder => modelorder
)
return (cepstra, pspec', meta)
end

Expand Down Expand Up @@ -75,12 +77,12 @@ function deltas(x::AbstractMatrix{T}, w::Integer=9) where {T<:AbstractFloat}
end
hlen = w ÷ 2
w = 2hlen + 1 # make w odd
win = collect(convert(T, hlen):-1:-hlen)
win = collect(T, hlen:-1:-hlen)
x1 = x[begin:begin, :]
xend = x[end:end, :]
xx = vcat(repeat(x1, hlen), x, repeat(xend, hlen)) ## take care of boundaries
norm = 3 / (hlen * w * (hlen + 1))
delta_v = filt(PolynomialRatio(win, [1.]), xx)[begin+2hlen:end, :]
delta_v = filt(win, 1., xx)[begin+2hlen:end, :]
@. delta_v *= norm
return delta_v
end
Expand Down
50 changes: 26 additions & 24 deletions src/rasta.jl
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,8 @@ function audspec(x::AbstractMatrix{<:AbstractFloat}, sr::Real=16000.0;
if sumpower
return wts_v * x
else
return (wts_v * sqrt.(x)).^2
aspec = wts_v * sqrt.(x)
return map!(x->x^2, aspec, aspec)
end
end

Expand Down Expand Up @@ -179,37 +180,38 @@ function postaud(x::AbstractMatrix{<:AbstractFloat}, fmax::Real, fbtype=:bark, b
if broaden
z = z[[begin; begin:end; end], :];
else
z = z[[begin+1; begin+1:end-1; end-1], :]
@views z[[begin, end], :] = z[[begin+1, end-1], :]
end
return z
end

function dolpc(x::AbstractMatrix{<:AbstractFloat}, modelorder::Int=8)
nbands, nframes = size(x)
r = real(ifft(x[[begin:end; end-1:-1:begin+1], :], 1)[begin:begin+nbands-1, :])
r = FFTW.r2r(x, FFTW.REDFT00, 1)
r ./= 2(nbands - 1)
# Find LPC coeffs by durbin
y, e = levinson(r, modelorder)
# Normalize each poly by gain
y ./= e
end

function lpc2cep(a::AbstractMatrix{T}, ncep::Int=0) where {T<:AbstractFloat}
@views function lpc2cep(a::AbstractMatrix{T}, ncep::Int=0) where {T<:AbstractFloat}
nlpc, nc = size(a)
order = nlpc - 1
if iszero(ncep)
ncep = nlpc
end
c = zeros(nc, ncep)
a = copy(a')
sum_var = collect(T, a[:, begin])
# Code copied from HSigP.c: LPC2Cepstrum
# First cep is log(Error) from Durbin
@views @. c[:, begin] = -log(a[:, begin])
@. c[:, begin] = -log(sum_var)
# Renormalize lpc A coeffs
@. a /= a[:, begin]
sum_var = Vector{T}(undef, nc)
@views for i in 2:ncep
@. a /= sum_var
for i in 2:ncep
fill!(sum_var, zero(T))
for m in 2:i
for m in 2:i-1
@. sum_var += (i - m) * a[:, m] * c[:, i - m + 1]
end
@. c[:, i] = -a[:, i] - sum_var / (i - 1)
Expand Down Expand Up @@ -284,35 +286,33 @@ end
## "You are welcome to move my octave code from GPL to MIT like core Julia."
## untested
## only returns a, v
function levinson(acf::AbstractVector{<:Number}, p::Int)
@views function levinson(acf::AbstractVector{<:Number}, p::Int)
if isempty(acf)
throw(ArgumentError("Empty autocorrelation function"))
end
if p < 0
elseif p < 0
throw(DomainError(p, "Negative model order"))
end
if p < 100
elseif p < 100
## direct solution [O(p^3), but no loops so slightly faster for small p]
## Kay & Marple Eqn (2.39)
R = toeplitz(@view acf[begin:begin+p-1])
a = R \ @view acf[begin+1:begin+p]
R = toeplitz(acf[begin:begin+p-1])
a = R \ acf[begin+1:begin+p]
@. a = -a
pushfirst!(a, 1)
v = @. real(a*conj(@view acf[begin:begin+p]))
v = @. real(a*conj(acf[begin:begin+p]))
else
## durbin-levinson [O(p^2), so significantly faster for large p]
## Kay & Marple Eqns (2.42-2.46)
# ref = zeros(p)
g = -acf[begin+1] / acf[begin]
a = [1, g]; sizehint!(a, p+1)
a = zeros(p+1); a[1] = 1; a[2] = g
buf = similar(a)
v = real((1 - abs2(g)) * acf[begin])
# ref[begin] = g # is not used???
for t in 2:p
g = -(acf[begin+t] + @views a[2:end] acf[begin+t-1:-1:begin+1]) / v
for i in 2:t
a[i] = a[i] + g * conj(a[end-i+2])
end
push!(a, g)
g = -(acf[begin+t] + a[2:t] acf[begin+t-1:-1:begin+1]) / v
@. buf[2:t] = g * conj(a[t:-1:2])
@. a[2:t] += buf[2:t]
a[t+1] = g
v *= 1 - abs2(g)
# ref[t] = g
end
Expand All @@ -325,7 +325,9 @@ function levinson(acf::AbstractMatrix{<:Number}, p::Integer)
a = zeros(p + 1, nc)
v = zeros(p + 1, nc)
for i in axes(acf, 2)
a[:, i], v[:, i] = levinson(view(acf, :, i), p)
a_i, v_i = levinson(view(acf, :, i), p)
a[:, i] = a_i
v[:, i] .= v_i
end
return a, v
end
Expand Down
Loading

0 comments on commit 40c4ea5

Please sign in to comment.