{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/plain": [ "Plots.PyPlotBackend()" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "using Plots\n", "using DataStructures\n", "using LibSndFile\n", "pyplot()" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "abstract type InternalFilter end" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "process! (generic function with 1 method)" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mutable struct CombFilter <: InternalFilter\n", " g::Float64\n", " c::Float64\n", " τ::Int\n", " buff::CircularBuffer{Float64}\n", "end\n", "\n", "function CombFilter(g, c, τsec, fs)\n", " fs = trunc(Int, fs)\n", " τ = trunc(Int, τsec * fs)\n", " τ >= fs && (τ = fs - 1)\n", " buff = CircularBuffer{Float64}(fs)\n", " append!(buff, fill(0., capacity(buff)))\n", " \n", " return CombFilter(g, c, τ, buff)\n", "end\n", "\n", "function process!(self::CombFilter, u::Float64)\n", " d = self.buff[end - self.τ]\n", " v = self.g * d + u\n", " push!(self.buff, v)\n", " y = self.c * d\n", " \n", " return y\n", "end" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "process! (generic function with 2 methods)" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mutable struct AllPassFilter <: InternalFilter\n", " g::Float64\n", " τ::Int\n", " buff::CircularBuffer{Float64}\n", "end\n", "\n", "function AllPassFilter(g, τsec, fs)\n", " fs = trunc(Int, fs)\n", " τ = trunc(Int, τsec * fs)\n", " τ >= fs && (τ = fs - 1)\n", " buff = CircularBuffer{Float64}(fs)\n", " append!(buff, fill(0., capacity(buff)))\n", " \n", " return AllPassFilter(g, τ, buff)\n", "end\n", "\n", "function process!(self::AllPassFilter, u::Float64)\n", " d = self.buff[end - self.τ]\n", " v = u + self.g * d\n", " push!(self.buff, v)\n", " y = -self.g * v + d\n", " \n", " return y\n", "end" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "clearBuff! (generic function with 1 method)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "function clearBuff!(self::InternalFilter)\n", " T = eltype(self.buff)\n", " N = capacity(self.buff)\n", " buff = CircularBuffer{T}(N)\n", " append!(buff, fill(T(0), N))\n", " self.buff = buff\n", "end" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "showIr (generic function with 2 methods)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mutable struct Reverbrator\n", " combs::Vector{CombFilter}\n", " apfs::Vector{AllPassFilter}\n", " wet::Float64\n", " fs::Float64\n", "end\n", "\n", "function Reverbrator(fs)\n", " combs = Vector{CombFilter}(0)\n", " apfs = Vector{AllPassFilter}(0)\n", " wet = 0.5\n", " \n", " return Reverbrator(combs, apfs, wet, fs)\n", "end\n", "\n", "function addComb!(self::Reverbrator, g, c, τsec)\n", " comb = CombFilter(g, c, τsec, self.fs)\n", " push!(self.combs, comb)\n", "end\n", "\n", "function addApf!(self::Reverbrator, g, τsec)\n", " apf = AllPassFilter(g, τsec, fs)\n", " push!(self.apfs, apf)\n", "end\n", "\n", "function process!(self::Reverbrator, u::Float64)\n", " y = 0.\n", " for comb in self.combs\n", " y += process!(comb, u)\n", " end\n", " \n", " for apf in self.apfs\n", " y = process!(apf, y)\n", " end\n", " \n", " self.wet * y + (1. - self.wet) * u\n", "end\n", "\n", "function process!(self::Reverbrator, u::Vector{Float64})\n", " y = Vector{Float64}(length(u))\n", " clearBuff!(self)\n", " for i=1:length(u)\n", " y[i] = process!(self, u[i])\n", " end\n", " \n", " return y\n", "end\n", "\n", "function clearBuff!(self::Reverbrator)\n", " for comb in self.combs\n", " clearBuff!(comb)\n", " end\n", " for apf in self.apfs\n", " clearBuff!(apf)\n", " end\n", "end\n", "\n", "function showIr(self::Reverbrator, tsec = 2.)\n", " N = trunc(Int, self.fs * tsec)\n", " u = fill(0., N)\n", " u[1] = 1.\n", " \n", " clearBuff!(self)\n", " y = process!(self, u)\n", " \n", " plot((0:N-1)/self.fs, y, ylims=(-0.1, 0.1), xlab=\"time[sec]\", ylab=\"Amlitude\", title=\"Impluse responce\")\n", "end" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "0.15" ], "text/plain": [ "0.15" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "#set reverb params\n", "audio = load(\".\\\\Resource\\\\SynthSample.wav\")\n", "fs = audio.samplerate\n", "reverb = Reverbrator(fs)\n", "addComb!(reverb, 0.87, 1., 39.85e-3)\n", "addComb!(reverb, 0.88, 1., 36.10e-3)\n", "addComb!(reverb, 0.89, 1., 33.27e-3)\n", "addComb!(reverb, 0.90, 1., 30.15e-3)\n", "addApf!(reverb, 0.70, 5.0e-3)\n", "addApf!(reverb, 0.70, 1.7e-3)\n", "reverb.wet = 0.15" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
To enable for the whole notebook select \"Trust Notebook\" from the\n", " \"File\" menu. You can also trust this cell by re-running it. You may\n", " also need to re-run `using SampledSignals` if the module is not yet\n", " loaded in the Julia kernel, or `SampledSignals.embed_javascript()`\n", " if the Julia module is loaded but the javascript isn't initialized.
\n", "To enable for the whole notebook select \"Trust Notebook\" from the\n", " \"File\" menu. You can also trust this cell by re-running it. You may\n", " also need to re-run `using SampledSignals` if the module is not yet\n", " loaded in the Julia kernel, or `SampledSignals.embed_javascript()`\n", " if the Julia module is loaded but the javascript isn't initialized.
\n", "