In [1]:
using Plots
using DataStructures
using LibSndFile
pyplot()

Out[1]:
Plots.PyPlotBackend()
In [2]:
abstract type InternalFilter end

In [3]:
mutable struct CombFilter <: InternalFilter
g::Float64
c::Float64
τ::Int
buff::CircularBuffer{Float64}
end

function CombFilter(g, c, τsec, fs)
fs = trunc(Int, fs)
τ = trunc(Int, τsec * fs)
τ >= fs && (τ = fs - 1)
buff = CircularBuffer{Float64}(fs)
append!(buff, fill(0., capacity(buff)))

return CombFilter(g, c, τ, buff)
end

function process!(self::CombFilter, u::Float64)
d = self.buff[end - self.τ]
v = self.g * d + u
push!(self.buff, v)
y = self.c * d

return y
end

Out[3]:
process! (generic function with 1 method)
In [4]:
mutable struct AllPassFilter <: InternalFilter
g::Float64
τ::Int
buff::CircularBuffer{Float64}
end

function AllPassFilter(g, τsec, fs)
fs = trunc(Int, fs)
τ = trunc(Int, τsec * fs)
τ >= fs && (τ = fs - 1)
buff = CircularBuffer{Float64}(fs)
append!(buff, fill(0., capacity(buff)))

return AllPassFilter(g, τ, buff)
end

function process!(self::AllPassFilter, u::Float64)
d = self.buff[end - self.τ]
v = u + self.g * d
push!(self.buff, v)
y = -self.g * v + d

return y
end

Out[4]:
process! (generic function with 2 methods)
In [5]:
function clearBuff!(self::InternalFilter)
T    = eltype(self.buff)
N    = capacity(self.buff)
buff = CircularBuffer{T}(N)
append!(buff, fill(T(0), N))
self.buff = buff
end

Out[5]:
clearBuff! (generic function with 1 method)
In [6]:
mutable struct Reverbrator
combs::Vector{CombFilter}
apfs::Vector{AllPassFilter}
wet::Float64
fs::Float64
end

function Reverbrator(fs)
combs = Vector{CombFilter}(0)
apfs  = Vector{AllPassFilter}(0)
wet   = 0.5

return Reverbrator(combs, apfs, wet, fs)
end

comb = CombFilter(g, c, τsec, self.fs)
push!(self.combs, comb)
end

apf = AllPassFilter(g, τsec, fs)
push!(self.apfs, apf)
end

function process!(self::Reverbrator, u::Float64)
y = 0.
for comb in self.combs
y += process!(comb, u)
end

for apf in self.apfs
y = process!(apf, y)
end

self.wet * y + (1. - self.wet) * u
end

function process!(self::Reverbrator, u::Vector{Float64})
y = Vector{Float64}(length(u))
clearBuff!(self)
for i=1:length(u)
y[i] = process!(self, u[i])
end

return y
end

function clearBuff!(self::Reverbrator)
for comb in self.combs
clearBuff!(comb)
end
for apf in self.apfs
clearBuff!(apf)
end
end

function showIr(self::Reverbrator, tsec = 2.)
N = trunc(Int, self.fs * tsec)
u = fill(0., N)
u[1] = 1.

clearBuff!(self)
y = process!(self, u)

plot((0:N-1)/self.fs, y, ylims=(-0.1, 0.1), xlab="time[sec]", ylab="Amlitude", title="Impluse responce")
end

Out[6]:
showIr (generic function with 2 methods)
In [7]:
#set reverb params
fs     = audio.samplerate
reverb = Reverbrator(fs)
reverb.wet = 0.15

Out[7]:
0.15
In [8]:
# test data
audio

Out[8]:

#### SampleBuf display requires javascript

To enable for the whole notebook select "Trust Notebook" from the "File" menu. You can also trust this cell by re-running it. You may also need to re-run using SampledSignals if the module is not yet loaded in the Julia kernel, or SampledSignals.embed_javascript() if the Julia module is loaded but the javascript isn't initialized.