From f761b6198e2e98f02adb84c83dbf59529e51b2ef Mon Sep 17 00:00:00 2001
From: chenlh <2008get@163.com>
Date: 星期五, 20 三月 2026 17:59:58 +0800
Subject: [PATCH] 新增门控混响算法(基于spring reverb)
---
cbb_ReverbGate/utils/IIRFilter.cpp | 201 +++
cbb_ReverbGate/utils/InterpolatedAllPassFilter.cpp | 64 +
cbb_ReverbGate/reverb_gate.cpp | 52
cbb_ReverbGate/utils/ModulatedAllPassFilter.cpp | 107 +
cbb_ReverbGate/Reverb_spring.vcxproj.filters | 99 +
cbb_ReverbGate/utils/ModulatedCombFilter.h | 103 +
cbb_ReverbGate/utils/EnvelopeDetector.h | 113 +
cbb_ReverbGate/utils/EffectProcessorBase.h | 38
cbb_ReverbGate/utils/Reverb.cpp | 108 +
cbb_ReverbGate/utils/LFO.cpp | 199 +++
cbb_ReverbGate/utils/Reverb.h | 65 +
cbb_ReverbGate/utils/GainUtilities.h | 30
cbb_ReverbGate/utils/Compressor.cpp | 205 +++
cbb_ReverbGate/utils/IIRFilter.h | 125 ++
cbb_ReverbGate/Reverb_spring.vcxproj.user | 4
cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.cpp | 127 ++
cbb_ReverbGate/Reverb_spring.vcxproj | 164 ++
cbb_ReverbGate/utils/FirstOrderSmoother.h | 52
cbb_ReverbGate/utils/ModulationProcessor.h | 51
cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.h | 124 ++
/dev/null | 0
cbb_ReverbGate/reverb_gate.h | 633 ++++++++++
cbb_ReverbGate/utils/InterpolatedCombFilter.h | 84 +
cbb_ReverbGate/utils/Compressor.h | 143 ++
cbb_ReverbGate/utils/ModulatedAllPassFilter.h | 103 +
cbb_ReverbGate/Reverb_gate.sln | 31
cbb_ReverbGate/utils/EnvelopeDetector.cpp | 128 ++
cbb_ReverbGate/utils/ModulatedCombFilter.cpp | 107 +
cbb_ReverbGate/utils/InterpolatedAllPassFilter.h | 84 +
cbb_ReverbGate/utils/InterpolatedCombFilter.cpp | 68 +
cbb_ReverbGate/utils/LFO.h | 127 ++
cbb_ReverbGate/utils/DynamicsProcessor.h | 45
32 files changed, 3,584 insertions(+), 0 deletions(-)
diff --git a/cbb_ReverbGate/Reverb_gate.sln b/cbb_ReverbGate/Reverb_gate.sln
new file mode 100644
index 0000000..abfafdd
--- /dev/null
+++ b/cbb_ReverbGate/Reverb_gate.sln
@@ -0,0 +1,31 @@
+锘�+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35828.75 d17.13
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Reverb_spring", "Reverb_spring.vcxproj", "{42EA330B-B03E-44F6-9D4C-9C4FD300A78C}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Debug|x64.ActiveCfg = Debug|x64
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Debug|x64.Build.0 = Debug|x64
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Debug|x86.ActiveCfg = Debug|Win32
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Debug|x86.Build.0 = Debug|Win32
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Release|x64.ActiveCfg = Release|x64
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Release|x64.Build.0 = Release|x64
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Release|x86.ActiveCfg = Release|Win32
+ {42EA330B-B03E-44F6-9D4C-9C4FD300A78C}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {B8775238-3A82-456D-AB61-D88B57B90638}
+ EndGlobalSection
+EndGlobal
diff --git a/cbb_ReverbGate/Reverb_spring.vcxproj b/cbb_ReverbGate/Reverb_spring.vcxproj
new file mode 100644
index 0000000..be15e01
--- /dev/null
+++ b/cbb_ReverbGate/Reverb_spring.vcxproj
@@ -0,0 +1,164 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <VCProjectVersion>17.0</VCProjectVersion>
+ <Keyword>Win32Proj</Keyword>
+ <ProjectGuid>{42ea330b-b03e-44f6-9d4c-9c4fd300a78c}</ProjectGuid>
+ <RootNamespace>Reverbspring</RootNamespace>
+ <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
+ <ProjectName>Reverb_gate</ProjectName>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <PlatformToolset>v143</PlatformToolset>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="Shared">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>_DEBUG;_CRT_SECURE_NO_WARNINGS;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ <AdditionalIncludeDirectories>E:\Algorithm\Effect\MoorerReverb-main\Reverb_spring\Reverb_spring\utils;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <SDLCheck>true</SDLCheck>
+ <PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <ConformanceMode>true</ConformanceMode>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="reverb_gate.cpp" />
+ <ClCompile Include="utils\Compressor.cpp" />
+ <ClCompile Include="utils\EnvelopeDetector.cpp" />
+ <ClCompile Include="utils\IIRFilter.cpp" />
+ <ClCompile Include="utils\InterpolatedAllPassFilter.cpp" />
+ <ClCompile Include="utils\InterpolatedCombFilter.cpp" />
+ <ClCompile Include="utils\LFO.cpp" />
+ <ClCompile Include="utils\LinearInterpolationCircularBuffer.cpp" />
+ <ClCompile Include="utils\ModulatedAllPassFilter.cpp" />
+ <ClCompile Include="utils\ModulatedCombFilter.cpp" />
+ <ClCompile Include="utils\Reverb.cpp" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="reverb_gate.h" />
+ <ClInclude Include="utils\Compressor.h" />
+ <ClInclude Include="utils\DynamicsProcessor.h" />
+ <ClInclude Include="utils\EffectProcessorBase.h" />
+ <ClInclude Include="utils\FirstOrderSmoother.h" />
+ <ClInclude Include="utils\GainUtilities.h" />
+ <ClInclude Include="utils\IIRFilter.h" />
+ <ClInclude Include="utils\InterpolatedAllPassFilter.h" />
+ <ClInclude Include="utils\InterpolatedCombFilter.h" />
+ <ClInclude Include="utils\LFO.h" />
+ <ClInclude Include="utils\LinearInterpolationCircularBuffer.h" />
+ <ClInclude Include="utils\ModulatedAllPassFilter.h" />
+ <ClInclude Include="utils\ModulatedCombFilter.h" />
+ <ClInclude Include="utils\ModulationProcessor.h" />
+ <ClInclude Include="utils\Reverb.h" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project>
\ No newline at end of file
diff --git a/cbb_ReverbGate/Reverb_spring.vcxproj.filters b/cbb_ReverbGate/Reverb_spring.vcxproj.filters
new file mode 100644
index 0000000..1b34960
--- /dev/null
+++ b/cbb_ReverbGate/Reverb_spring.vcxproj.filters
@@ -0,0 +1,99 @@
+锘�?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="婧愭枃浠�>
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="澶存枃浠�>
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
+ </Filter>
+ <Filter Include="璧勬簮鏂囦欢">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="reverb_gate.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\IIRFilter.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\InterpolatedAllPassFilter.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\InterpolatedCombFilter.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\LFO.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\LinearInterpolationCircularBuffer.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\ModulatedAllPassFilter.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\ModulatedCombFilter.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\Reverb.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\Compressor.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ <ClCompile Include="utils\EnvelopeDetector.cpp">
+ <Filter>婧愭枃浠�/Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="reverb_gate.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\EffectProcessorBase.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\FirstOrderSmoother.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\LFO.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\ModulatedAllPassFilter.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\ModulatedCombFilter.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\ModulationProcessor.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\IIRFilter.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\InterpolatedCombFilter.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\LinearInterpolationCircularBuffer.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\InterpolatedAllPassFilter.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\Reverb.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\Compressor.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\DynamicsProcessor.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ <ClInclude Include="utils\GainUtilities.h">
+ <Filter>澶存枃浠�/Filter>
+ </ClInclude>
+ </ItemGroup>
+</Project>
\ No newline at end of file
diff --git a/cbb_ReverbGate/Reverb_spring.vcxproj.user b/cbb_ReverbGate/Reverb_spring.vcxproj.user
new file mode 100644
index 0000000..88a5509
--- /dev/null
+++ b/cbb_ReverbGate/Reverb_spring.vcxproj.user
@@ -0,0 +1,4 @@
+锘�?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup />
+</Project>
\ No newline at end of file
diff --git a/cbb_ReverbGate/reverb_gate.cpp b/cbb_ReverbGate/reverb_gate.cpp
new file mode 100644
index 0000000..362e1e0
--- /dev/null
+++ b/cbb_ReverbGate/reverb_gate.cpp
@@ -0,0 +1,52 @@
+锘�+#include "reverb.h"
+#include "compressor.h"
+#include "reverb_gate.h"
+
+int main(void)
+{
+ Reverb<float> rvb;
+ rvb.prepare(48000);
+ rvb.setRoomSize(1.0);
+ rvb.setDecay(1.0);
+ rvb.setCutoff(5000);
+ rvb.setMix(1.0);
+
+ Compressor<float> comp;
+ comp.prepare(48000);
+ comp.setThreshold(-20.0);
+ comp.setRatio(5.0);
+ comp.setAttack(0.001);
+ comp.setRelease(0.1);
+ comp.setGain(1.0);
+
+
+ std::string output_file = "output.wav";
+ Wave w;
+ w.read_wav("E:\\music\\Voice_print\\GaoWeiDong.wav");
+ w.init_channels_maxmin();
+ w.update_channel_maxmin();
+ float gate_gain;
+
+ for (int i = 0; i < w.num_channels; ++i)
+ {
+ for (int j = 0; j < w.num_samples; ++j) {
+ gate_gain = comp.processSample(w.samples[i][j]);
+ w.samples[i][j] = rvb.processSample(w.samples[i][j]) * gate_gain;
+ }
+ }
+
+
+
+ // normalizing to db
+ LOG_INFO("normalized_volume : " << db_to_vol(-1.5f));
+ LOG_INFO("normalized_volume_db: " << -1.5f);
+ w.update_channel_maxmin();
+ w.normalize(-db_to_vol(-1.5f), db_to_vol(-1.5f));
+ w.write_wav(output_file);
+ LOG_INFO("output_file : " << output_file);
+ w.info_summary();
+
+ return 0;
+}
+
diff --git a/cbb_ReverbGate/reverb_gate.h b/cbb_ReverbGate/reverb_gate.h
new file mode 100644
index 0000000..57e3581
--- /dev/null
+++ b/cbb_ReverbGate/reverb_gate.h
@@ -0,0 +1,633 @@
+
+#pragma once
+
+#include <iostream>
+
+
+#define NUM_COMBS 4
+#define NUM_ALLPASS 2
+
+
+#define LOG_INFO(msg) std::cout<<"[INFO] "<<msg<<std::endl;
+#define LOG_WARN(msg) std::cout<<"[WARN] "<<msg<<std::endl;
+#define LOG_ERROR(msg) std::cout<<"[ERROR] "<<msg<<std::endl;
+
+float db_to_vol(float db) {
+ return pow(10, db / 20);
+}
+
+class Header {
+public:
+ uint8_t riff_label[4]; // (00) = {'R','I','F','F'}
+ uint32_t riff_size; // (04) = 36 + data_size
+ uint8_t file_tag[4]; // (08) = {'W','A','V','E'}
+ uint8_t fmt_label[4]; // (12) = {'f','m','t',' '}
+ uint32_t fmt_size; // (16) = 16
+ uint16_t audio_format; // (20) = 1
+ uint16_t channel_count; // (22) = 1 or 2
+ uint32_t sampling_rate; // (24) = (anything)
+ uint32_t bytes_per_second; // (28) = (see above)
+ uint16_t bytes_per_sample; // (32) = (see above)
+ uint16_t bits_per_sample; // (34) = 8 or 16
+ uint8_t data_label[4]; // (36) = {'d','a','t','a'}
+ uint32_t data_size; // (40) = # bytes of data
+};
+
+class Wave {
+public:
+ Header header;
+ std::vector<std::vector<float>> samples;
+ std::vector<float> max_amplitude;
+ std::vector<float> min_amplitude;
+
+ int num_samples = 0;
+ int num_channels = 0;
+
+ void read_header(std::string file_path) {
+ FILE* in = fopen(file_path.c_str(), "rb");
+ if (!in) {
+ LOG_ERROR("read : file does not exsit");
+ exit(-1);
+ }
+ fread(&header, sizeof(Header), 1, in);
+ fclose(in);
+ if (header.channel_count > 1) {
+ LOG_ERROR("read : only mono tracks supported for now");
+ exit(-1);
+ }
+ }
+
+ void write_header(std::string file_path) {
+ if (header.channel_count > 1) {
+ LOG_ERROR("write : only mono tracks supported for now");
+ exit(-1);
+ }
+ FILE* out = fopen(file_path.c_str(), "wb");
+ if (!out) {
+ LOG_ERROR("write : file does not exsit");
+ exit(-1);
+ }
+ fseek(out, 0, SEEK_SET);
+ fwrite(&header, sizeof(header), 1, out);
+ fclose(out);
+ }
+
+ void print_header(int i) {
+ printf("\n[HEADER]\n");
+ if (i) printf("riff_label: %c%c%c%c.\n", header.riff_label[0], header.riff_label[1], header.riff_label[2], header.riff_label[3]);
+ printf("riff_size: %u.\n", header.riff_size);
+ if (i) printf("file_tag: %c%c%c%c.\n", header.file_tag[0], header.file_tag[1], header.file_tag[2], header.file_tag[3]);
+ if (i) printf("fmt_label: %c%c%c%c.\n", header.fmt_label[0], header.fmt_label[1], header.fmt_label[2], header.fmt_label[3]);
+ printf("fmt_size: %u.\n", header.fmt_size);
+ printf("audio_format: %u.\n", header.audio_format);
+ printf("channel_count: %u.\n", header.channel_count);
+ printf("sampling_rate: %u.\n", header.sampling_rate);
+ printf("bytes_per_second: %u.\n", header.bytes_per_second);
+ printf("bytes_per_sample: %u.\n", header.bytes_per_sample);
+ printf("bits_per_sample: %u.\n", header.bits_per_sample);
+ if (i) printf("data_label: %c%c%c%c.\n", header.data_label[0], header.data_label[1], header.data_label[2], header.data_label[3]);
+ printf("data_size: %u.\n", header.data_size);
+ }
+
+ void read_data(std::string file_path) {
+ FILE* in = fopen(file_path.c_str(), "rb");
+ num_samples = header.data_size / (header.channel_count * header.bits_per_sample / 8);
+ num_channels = header.channel_count;
+ fseek(in, sizeof(Header), SEEK_SET);
+ uint8_t* data = new uint8_t[header.data_size];
+ fread(data, header.data_size, 1, in);
+ int16_t* data16 = (int16_t*)(data);
+ // clear all channels
+ for (int channel = 0;channel < (int)samples.size();++channel) {
+ samples[channel].clear();
+ }
+ samples.clear();
+ // resize buffer and reserve samples
+ samples.resize(num_channels);
+ for (int channel = 0;channel < (int)samples.size();++channel) {
+ samples[channel].reserve(num_samples);
+ }
+ // convert PCM data to float samples
+ for (int i = 0;i < num_samples;++i) {
+ for (int c = 0;c < num_channels;++c) {
+ if (header.bits_per_sample == 16) {
+ float sample = data16[i * num_channels + c] / (float)((1 << 15));
+ samples[c].push_back(sample);
+ }
+ else {
+ LOG_ERROR("read : only 16 bit signed pcm supported");
+ exit(-1);
+ }
+
+ }
+ }
+ delete[] data;
+ fclose(in);
+ }
+
+ void write_data(std::string file_path) {
+ FILE* out = fopen(file_path.c_str(), "ab");
+ fseek(out, sizeof(Header), SEEK_SET);
+ for (int i = 0;i < num_samples;++i) {
+ for (int c = 0;c < num_channels;++c) {
+ float sample = samples[c][i];
+ if (header.bits_per_sample == 16) {
+ int16_t bytes_2 = (sample * ((1 << 15)));
+ fwrite(&bytes_2, 2, 1, out);
+ }
+ else {
+ LOG_ERROR("write : only 16 bit signed pcm supported");
+ exit(-1);
+ }
+ }
+ }
+ fclose(out);
+ }
+
+ void read_wav(std::string file_path) {
+ read_header(file_path);
+ read_data(file_path);
+ }
+
+ void write_wav(std::string file_path) {
+ write_header(file_path.c_str());
+ write_data(file_path.c_str());
+ }
+
+ void init_channels_maxmin() {
+ // clear it
+ max_amplitude.clear();
+ min_amplitude.clear();
+ // initialize
+ for (int i = 0;i < num_channels;++i) {
+ max_amplitude.push_back(std::numeric_limits<float>::min());
+ min_amplitude.push_back(std::numeric_limits<float>::max());
+ }
+ }
+
+ void update_channel_maxmin() {
+ for (int i = 0;i < num_samples;++i) {
+ for (int c = 0;c < num_channels;++c) {
+ float sample = samples[c][i];
+ //track max min
+ if (sample > max_amplitude[c]) {
+ max_amplitude[c] = sample;
+ }
+ if (sample < min_amplitude[c]) {
+ min_amplitude[c] = sample;
+ }
+ }
+ }
+ }
+
+ void normalize(float min, float max) {
+ std::vector<float> sum;
+ sum.resize(2, 0.0f);
+ for (int i = 0; i < num_samples; i++) {
+ for (int c = 0; c < num_channels; c++) {
+ float x = samples[c][i];
+ sum[c] += x;
+ }
+ }
+
+ for (int i = 0; i < num_samples; i++) {
+ for (int c = 0; c < num_channels; c++) {
+ samples[c][i] += sum[c] / num_samples;
+ float x = samples[c][i];
+ x = ((max - min) * (x - min_amplitude[c]) / (max_amplitude[c] - min_amplitude[c])) - (max - min) / 2;
+ samples[c][i] = x;
+ }
+ }
+ }
+
+ void info_summary() {
+ LOG_INFO("sample_rate : " << header.sampling_rate);
+ LOG_INFO("bit_depth : " << header.bits_per_sample);
+ LOG_INFO("num_channels : " << num_channels);
+ LOG_INFO("num_samples : " << num_samples);
+ LOG_INFO("num_seconds : " << num_samples / header.sampling_rate);
+ }
+};
+
+
+
+/*
+#include "iostream"
+#include "fstream"
+#include "vector"
+#include "limits"
+#include "math.h"
+
+#define PI 3.14159265358979323846
+
+#define LOG_INFO(msg) std::cout<<"[INFO] "<<msg<<std::endl;
+#define LOG_WARN(msg) std::cout<<"[WARN] "<<msg<<std::endl;
+#define LOG_ERROR(msg) std::cout<<"[ERROR] "<<msg<<std::endl;
+
+float min(float a, float b){
+ if(a<b){
+ return a;
+ }
+ else{
+ return b;
+ }
+}
+
+float max(float a, float b){
+ if(a>b){
+ return a;
+ }
+ else{
+ return b;
+ }
+}
+
+float lerp(float l, float r, float t, float lo=0.0f, float hi=1.0f){
+
+ if(hi == lo){
+ return l;
+ }
+
+ t = (t-lo)/(hi-lo);
+
+ // interpolate
+ return l*(1-t) + r*(t);
+}
+
+class GainFilter{
+public:
+ float gain=1.0f;
+public:
+ void init(float g=1.0f){
+ gain = g;
+ }
+
+ void set_gain(float g){
+ gain = g;
+ }
+
+ float process(float n){
+ return n*gain;
+ }
+};
+
+class DelayFilter{
+public:
+ std::vector<float> delay_pipe;
+ float delay_samples;
+ float delay_ms;
+ float delay_frac;
+ float max_delay_ms;
+ int max_delay_samples;
+ int w_index;
+ int r_index;
+public:
+
+ void init(float ms, float delay_ms_max, int sample_rate=48000){
+
+ delay_samples = 0.0f;
+ delay_ms = ms;
+ max_delay_samples = ceil(sample_rate * delay_ms_max / 1000.0f);
+ max_delay_ms = max_delay_samples * 1000.0f / sample_rate;
+
+ // get the delay in sammples and separate out fractional parts
+ float delay_raw = sample_rate * ms / 1000.0f;
+ delay_samples = floor(delay_raw);
+ delay_frac = delay_raw - delay_samples;
+
+ // initialize the delay pipe with 0.0f data and set read write indexes
+ r_index = 0;
+ w_index = 0;
+
+ delay_pipe.resize(max_delay_samples,0.0f);
+
+ }
+
+ float process(float n){
+
+ float out=0.0f;
+ if(delay_samples == 0){
+ out = n;
+ }
+ else{
+ out = read_delay();
+ }
+ write_delay(n);
+ return out;
+ }
+
+ void set_delay_ms(float ms,int sample_rate=48000){
+
+ if(ms > max_delay_ms){
+ LOG_ERROR("Delay Filter : exceeded max_delay_ms");
+ return;
+ }
+ // delay
+ delay_ms = ms;
+
+ // get the delay in sammples and separate out fractional parts
+ float delay_raw = sample_rate * ms / 1000.0f;
+ delay_samples = floor(delay_raw);
+ delay_frac = delay_raw - delay_samples;
+
+ // read position and wrap around the buffer max size
+ r_index = w_index - delay_samples;
+ r_index = r_index<0?r_index+max_delay_samples:r_index;
+
+ }
+
+ float read_delay(){
+ float out = 0.0f;
+ out = delay_pipe[r_index];
+
+ int n_minus_one_r_index = r_index - 1;
+ n_minus_one_r_index = n_minus_one_r_index < 0? max_delay_samples - 1: n_minus_one_r_index;
+
+ float out_n_minus_one = delay_pipe[n_minus_one_r_index];
+
+ return lerp(out,out_n_minus_one,delay_frac);
+ }
+
+ void write_delay(float n){
+
+ delay_pipe[w_index++] = n;
+ w_index = w_index >= max_delay_samples ? 0 : w_index;
+
+ ++r_index;
+ r_index = r_index >= max_delay_samples ? 0 : r_index;
+
+ }
+
+ void reset(){
+ delay_pipe.clear();
+ delay_pipe.resize(max_delay_samples,0.0f);
+ r_index = 0;
+ w_index = 0;
+ set_delay_ms(delay_ms,48000);
+ }
+
+};
+
+class LowPassFilter{
+public:
+ float coeff=0.0f;
+ float n_minus_one=0.0f;
+public:
+
+ void init(float lp_coeff,int sample_rate=48000){
+ set_coeff(lp_coeff);
+ }
+
+ float process(float n){
+ n_minus_one = n * (1 - coeff) + (coeff * n_minus_one); // this was the correct one
+ return n_minus_one;
+ }
+
+ void set_coeff(float c){
+ coeff = c;
+ }
+};
+
+class CombFilter{
+public:
+ GainFilter gain_filter;
+ DelayFilter delay_filter;
+ LowPassFilter low_pass_filter;
+public:
+ void init(float ms, float delay_ms_max, float g, float lp_coeff, int sample_rate=48000){
+ delay_filter.init(ms,delay_ms_max,sample_rate);
+ low_pass_filter.init(lp_coeff,sample_rate);
+ gain_filter.init(g);
+ }
+ float process(float n){
+ // delay -> gain -> low pass -> feedback -> output
+ float delayed_n = delay_filter.read_delay();
+ float delayed_n_gain = gain_filter.process(delayed_n);
+ float delayed_n_gain_low_pass = low_pass_filter.process(delayed_n_gain);
+ float delayed_n_gain_low_pass_feedback = n + delayed_n_gain_low_pass;
+ delay_filter.write_delay(delayed_n_gain_low_pass_feedback);
+ float out = delayed_n;
+ return out;
+ }
+
+};
+
+class AllPassFilter{
+public:
+ float wet_dry_ratio=1.0f;
+ DelayFilter delay_filter;
+ GainFilter gain_filter;
+
+public:
+ void init(float ms, float delay_ms_max, float g, int sample_rate=48000){
+ delay_filter.init(ms,delay_ms_max,sample_rate);
+ gain_filter.init(g);
+ }
+
+ float process(float n){
+ float delayed_n = delay_filter.read_delay();
+ float delayed_n_gain = gain_filter.process(delayed_n);
+ float delayed_n_gain_feedback = n + delayed_n_gain;
+ float out = delayed_n + (-1.0f)*(gain_filter.process(delayed_n_gain_feedback));
+ delay_filter.write_delay(delayed_n_gain_feedback);
+ return out;
+ }
+
+};
+
+
+class Header{
+public:
+ uint8_t riff_label[4]; // (00) = {'R','I','F','F'}
+ uint32_t riff_size; // (04) = 36 + data_size
+ uint8_t file_tag[4]; // (08) = {'W','A','V','E'}
+ uint8_t fmt_label[4]; // (12) = {'f','m','t',' '}
+ uint32_t fmt_size; // (16) = 16
+ uint16_t audio_format; // (20) = 1
+ uint16_t channel_count; // (22) = 1 or 2
+ uint32_t sampling_rate; // (24) = (anything)
+ uint32_t bytes_per_second; // (28) = (see above)
+ uint16_t bytes_per_sample; // (32) = (see above)
+ uint16_t bits_per_sample; // (34) = 8 or 16
+ uint8_t data_label[4]; // (36) = {'d','a','t','a'}
+ uint32_t data_size; // (40) = # bytes of data
+};
+
+class Wave{
+public:
+ Header header;
+ std::vector<std::vector<float>> samples;
+ std::vector<float> max_amplitude;
+ std::vector<float> min_amplitude;
+
+ int num_samples=0;
+ int num_channels=0;
+
+ void read_header(std::string file_path){
+ FILE* in = fopen(file_path.c_str(),"rb");
+ if(!in){
+ LOG_ERROR("read : file does not exsit");
+ exit(-1);
+ }
+ fread(&header,sizeof(Header),1,in);
+ fclose(in);
+ if(header.channel_count > 1){
+ LOG_ERROR("read : only mono tracks supported for now");
+ exit(-1);
+ }
+ }
+
+ void write_header(std::string file_path){
+ if(header.channel_count > 1){
+ LOG_ERROR("write : only mono tracks supported for now");
+ exit(-1);
+ }
+ FILE* out = fopen(file_path.c_str(),"wb");
+ if(!out){
+ LOG_ERROR("write : file does not exsit");
+ exit(-1);
+ }
+ fseek(out,0,SEEK_SET);
+ fwrite(&header,sizeof(header),1,out);
+ fclose(out);
+ }
+
+ void print_header(int i){
+ printf("\n[HEADER]\n");
+ if(i) printf("riff_label: %c%c%c%c.\n",header.riff_label[0],header.riff_label[1],header.riff_label[2],header.riff_label[3]);
+ printf("riff_size: %u.\n",header.riff_size);
+ if(i) printf("file_tag: %c%c%c%c.\n",header.file_tag[0],header.file_tag[1],header.file_tag[2],header.file_tag[3]);
+ if(i) printf("fmt_label: %c%c%c%c.\n",header.fmt_label[0],header.fmt_label[1],header.fmt_label[2],header.fmt_label[3]);
+ printf("fmt_size: %u.\n",header.fmt_size);
+ printf("audio_format: %u.\n",header.audio_format);
+ printf("channel_count: %u.\n",header.channel_count);
+ printf("sampling_rate: %u.\n",header.sampling_rate);
+ printf("bytes_per_second: %u.\n",header.bytes_per_second);
+ printf("bytes_per_sample: %u.\n",header.bytes_per_sample);
+ printf("bits_per_sample: %u.\n",header.bits_per_sample);
+ if(i) printf("data_label: %c%c%c%c.\n",header.data_label[0],header.data_label[1],header.data_label[2],header.data_label[3]);
+ printf("data_size: %u.\n",header.data_size);
+ }
+
+ void read_data(std::string file_path){
+ FILE* in = fopen(file_path.c_str(),"rb");
+ num_samples = header.data_size/(header.channel_count*header.bits_per_sample/8);
+ num_channels = header.channel_count;
+ fseek(in,sizeof(Header),SEEK_SET);
+ uint8_t* data = new uint8_t[header.data_size];
+ fread(data,header.data_size,1,in);
+ int16_t* data16 = (int16_t*)(data);
+ // clear all channels
+ for(int channel=0;channel<(int)samples.size();++channel){
+ samples[channel].clear();
+ }
+ samples.clear();
+ // resize buffer and reserve samples
+ samples.resize(num_channels);
+ for(int channel=0;channel<(int)samples.size();++channel){
+ samples[channel].reserve(num_samples);
+ }
+ // convert PCM data to float samples
+ for(int i=0;i<num_samples;++i){
+ for(int c=0;c<num_channels;++c){
+ if(header.bits_per_sample == 16){
+ float sample = data16[i*num_channels + c]/(float)((1<<15));
+ samples[c].push_back(sample);
+ }
+ else{
+ LOG_ERROR("read : only 16 bit signed pcm supported");
+ exit(-1);
+ }
+
+ }
+ }
+ delete[] data;
+ fclose(in);
+ }
+
+ void write_data(std::string file_path){
+ FILE* out = fopen(file_path.c_str(),"ab");
+ fseek(out,sizeof(Header),SEEK_SET);
+ for(int i=0;i<num_samples;++i){
+ for(int c=0;c<num_channels;++c){
+ float sample = samples[c][i];
+ if(header.bits_per_sample == 16){
+ int16_t bytes_2 = (sample * ((1<<15)));
+ fwrite(&bytes_2,2,1,out);
+ }
+ else{
+ LOG_ERROR("write : only 16 bit signed pcm supported");
+ exit(-1);
+ }
+ }
+ }
+ fclose(out);
+ }
+
+ void read_wav(std::string file_path){
+ read_header(file_path);
+ read_data(file_path);
+ }
+
+ void write_wav(std::string file_path){
+ write_header(file_path.c_str());
+ write_data(file_path.c_str());
+ }
+
+ void init_channels_maxmin(){
+ // clear it
+ max_amplitude.clear();
+ min_amplitude.clear();
+ // initialize
+ for(int i=0;i<num_channels;++i){
+ max_amplitude.push_back(std::numeric_limits<float>::min());
+ min_amplitude.push_back(std::numeric_limits<float>::max());
+ }
+ }
+
+ void update_channel_maxmin(){
+ for(int i=0;i<num_samples;++i){
+ for(int c=0;c<num_channels;++c){
+ float sample = samples[c][i];
+ //track max min
+ if(sample > max_amplitude[c]){
+ max_amplitude[c] = sample;
+ }
+ if(sample < min_amplitude[c]){
+ min_amplitude[c] = sample;
+ }
+ }
+ }
+ }
+
+ void normalize(float min, float max){
+ std::vector<float> sum;
+ sum.resize(2,0.0f);
+ for (int i = 0; i < num_samples; i++){
+ for (int c = 0; c < num_channels; c++){
+ float x = samples[c][i];
+ sum[c] += x;
+ }
+ }
+
+ for (int i = 0; i < num_samples; i++){
+ for (int c = 0; c < num_channels; c++){
+ samples[c][i] += sum[c]/num_samples;
+ float x = samples[c][i];
+ x = ((max-min) * (x - min_amplitude[c]) / (max_amplitude[c] - min_amplitude[c])) - (max-min)/2;
+ samples[c][i] = x;
+ }
+ }
+ }
+
+ void info_summary(){
+ LOG_INFO("sample_rate : "<<header.sampling_rate);
+ LOG_INFO("bit_depth : "<<header.bits_per_sample);
+ LOG_INFO("num_channels : "<<num_channels);
+ LOG_INFO("num_samples : "<<num_samples);
+ LOG_INFO("num_seconds : "<<num_samples/header.sampling_rate);
+ }
+};
+
+*/
+
diff --git a/cbb_ReverbGate/utils/Compressor.cpp b/cbb_ReverbGate/utils/Compressor.cpp
new file mode 100644
index 0000000..09a5817
--- /dev/null
+++ b/cbb_ReverbGate/utils/Compressor.cpp
@@ -0,0 +1,205 @@
+#include "Compressor.h"
+
+template <typename SampleType>
+Compressor<SampleType>::Compressor()
+{
+
+}
+
+template <typename SampleType>
+Compressor<SampleType>::~Compressor()
+{
+
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::prepare(SampleType sampleRate)
+{
+ this->detector.prepare(sampleRate);
+ this->detector.setOutputIndB(true);
+}
+
+template <typename SampleType>
+SampleType Compressor<SampleType>::processSample(SampleType sample)
+{
+ SampleType xn = sample;
+ SampleType detect_input = 0.0;
+
+ detect_input = this->detector.processSample(xn);
+
+ //Gain Reduction Calculation
+ SampleType gainReduction = calaculateGain(detect_input);
+
+ //Make-up Gain
+ //SampleType muGain = GainUtilities<SampleType>::decibelsToGain(makeupGain);
+
+ //return xn * gainReduction * muGain;
+ return gainReduction;
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::process(SampleType* data, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ data[sample] = processSample(data[sample]);
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setThreshold(SampleType newThreshold)
+{
+ threshold = newThreshold;
+
+ //Bounds Check
+ if (threshold > 0.0)
+ threshold = 0.0;
+ if (threshold < -80.0)
+ threshold = -80.0;
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setRatio(SampleType newRatio)
+{
+ ratio = newRatio;
+
+ //Bounds Check
+ if (ratio > 100.0)
+ ratio = 100.0;
+ if (ratio < 1.0)
+ ratio = 1.0;
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setAttack(SampleType newAttack)
+{
+ attack = newAttack;
+
+ //Bounds Check
+ if (attack > 100.0)
+ attack = 100.0;
+ if (attack < 1.0)
+ attack = 1.0;
+
+ this->detector.setAttackTime(attack);
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setRelease(SampleType newRelease)
+{
+ release = newRelease;
+
+ //Bounds Check
+ if (release > 1000.0)
+ release = 1000.0;
+ if (release < 10.0)
+ release = 10.0;
+
+ this->detector.setReleaseTime(release);
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setGain(SampleType newGain)
+{
+ makeupGain = newGain;
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setParameter(int index, SampleType newValue)
+{
+ switch (index)
+ {
+ case Parameters::Threshold:
+ setThreshold(newValue);
+ break;
+ case Parameters::Ratio:
+ setRatio(newValue);
+ break;
+ case Parameters::Attack:
+ setAttack(newValue);
+ break;
+ case Parameters::Release:
+ setRelease(newValue);
+ break;
+ case Parameters::MakeupGain:
+ setGain(newValue);
+ break;
+ }
+}
+
+template <typename SampleType>
+SampleType Compressor<SampleType>::getParameter(int index)
+{
+ switch (index)
+ {
+ case Parameters::Threshold:
+ return threshold;
+ break;
+ case Parameters::Ratio:
+ return ratio;
+ break;
+ case Parameters::Attack:
+ return attack;
+ break;
+ case Parameters::Release:
+ return release;
+ break;
+ case Parameters::MakeupGain:
+ return makeupGain;
+ break;
+ }
+}
+
+template <typename SampleType>
+void Compressor<SampleType>::setKneeType(int index)
+{
+ switch (index)
+ {
+ case KneeTypes::Soft:
+ kneeType = KneeTypes::Soft;
+ break;
+ case KneeTypes::Hard:
+ kneeType = KneeTypes::Hard;
+ break;
+ }
+}
+
+template <typename SampleType>
+int Compressor<SampleType>::getKneeType()
+{
+ return kneeType;
+}
+
+template <typename SampleType>
+SampleType Compressor<SampleType>::calaculateGain(SampleType input)
+{
+ SampleType output = 0.0;
+
+ switch (kneeType)
+ {
+ case KneeTypes::Soft:
+
+ if (2.0 * (input - threshold) < -(kneeWidth))
+ output = input;
+ else if (2.0 * (std::fabs(input - threshold)) <= kneeWidth)
+ output = input + (((1.0 / ratio) - 1.0) * std::pow((input - threshold + (kneeWidth/ 2.0)), 2.0)) / (2.0 * kneeWidth);
+ else if (2.0 * (input - threshold) > kneeWidth)
+ output = threshold + (input - threshold) / ratio;
+
+ break;
+ case KneeTypes::Hard:
+
+ if (input <= threshold)
+ output = input;
+ else
+ output = threshold + (input - threshold) / ratio;
+
+ break;
+ }
+
+ SampleType gainReduction_dB = output - input;
+ SampleType gainReduction_Linear = std::pow(10.0, (gainReduction_dB) / 20.0);
+
+ return gainReduction_Linear;
+}
+
+template class Compressor<float>;
+template class Compressor<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/Compressor.h b/cbb_ReverbGate/utils/Compressor.h
new file mode 100644
index 0000000..b087d5f
--- /dev/null
+++ b/cbb_ReverbGate/utils/Compressor.h
@@ -0,0 +1,143 @@
+#pragma once
+
+#include <DynamicsProcessor.h>
+#include <GainUtilities.h>
+
+/**
+ * Basic Compressor Effect
+ */
+template <typename SampleType>
+class Compressor : public DynamicsProcessor<SampleType>
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ Compressor();
+
+ /**
+ * @brief Destructor
+ */
+ ~Compressor();
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate) override;
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input) override;
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param data Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* data, int startSample, int endSample) override;
+
+ /**
+ * @brief Sets the compressor threshold
+ *
+ * @param newThreshold New threshold value in decibels
+ */
+ void setThreshold(SampleType newThreshold) override;
+
+ /**
+ * @brief Sets the compression ratio
+ *
+ * @param newRatio New ratio value
+ */
+ void setRatio(SampleType newRatio);
+
+ /**
+ * @brief Sets the compressor attack time
+ *
+ * @param newAttack New attack time value in milliseconds
+ */
+ void setAttack(SampleType newAttack) override;
+
+ /**
+ * @brief Sets the compressor release time
+ *
+ * @param newRelease New release time value in milliseconds
+ */
+ void setRelease(SampleType newRelease) override;
+
+ /**
+ * @brief Sets the compressor make-up gain
+ *
+ * @param newGain New gain value in decibels
+ */
+ void setGain(SampleType newGain) override;
+
+ /**
+ * @brief Sets one of the compressor's parameters
+ *
+ * @param index Parameter index
+ * @param newValue New parameter value
+ */
+ void setParameter(int index, SampleType newValue);
+
+ /**
+ * @brief Returns one of the compressor's parameters
+ *
+ * @param index Parameter index
+ */
+ SampleType getParameter(int index);
+
+ /**
+ * @brief Sets the compressor knee type
+ *
+ * @param index Knee type index
+ */
+ void setKneeType(int index);
+
+ /**
+ * @brief Returns the compressor knee type index
+ */
+ int getKneeType();
+
+ enum Parameters
+ {
+ Threshold = 0, //-80 | 0 dB
+ Ratio, //
+ Attack, //1ms | 100ms
+ Release, //10ms | 1000ms
+ MakeupGain
+ };
+
+ enum KneeTypes
+ {
+ Soft = 0,
+ Hard
+ };
+
+private:
+
+ SampleType sampleRate;
+
+ // User Parameters
+ SampleType threshold{ -10.0 }; //in dB
+ SampleType ratio{ 50.0 };
+ SampleType makeupGain{ 0.0 }; //in dB
+ SampleType attack{ 10.0 }; //in ms
+ SampleType release{ 100.0 }; //in ms
+ int kneeType{ KneeTypes::Soft };
+
+ //=============================================
+
+ SampleType kneeWidth{ 30.0 }; //in dB
+
+ //============================================
+
+ SampleType calaculateGain(SampleType input);
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/DynamicsProcessor.h b/cbb_ReverbGate/utils/DynamicsProcessor.h
new file mode 100644
index 0000000..4089cfd
--- /dev/null
+++ b/cbb_ReverbGate/utils/DynamicsProcessor.h
@@ -0,0 +1,45 @@
+#pragma once
+
+#include <EffectProcessorBase.h>
+#include <EnvelopeDetector.h>
+
+/**
+ * Base Class for Dynamics Effects Processors
+ */
+template <typename SampleType>
+class DynamicsProcessor : public EffectProcessorBase<SampleType>
+{
+public:
+
+ /**
+ * @brief Sets the detection threshold
+ *
+ * @param newThreshold New threshold value in decibels
+ */
+ virtual void setThreshold(SampleType newThreshold) = 0;
+
+ /**
+ * @brief Sets the detector attack time
+ *
+ * @param newRatio New ratio value
+ */
+ virtual void setAttack(SampleType newAttack) = 0;
+
+ /**
+ * @brief Sets the detector release time
+ *
+ * @param newRelease New release time value in milliseconds
+ */
+ virtual void setRelease(SampleType newRelease) = 0;
+
+ /**
+ * @brief Sets the processor make-up gain
+ *
+ * @param newGain New gain value in decibels
+ */
+ virtual void setGain(SampleType newGain) = 0;
+
+
+protected:
+ EnvelopeDetector<SampleType> detector;
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/EffectProcessorBase.h b/cbb_ReverbGate/utils/EffectProcessorBase.h
new file mode 100644
index 0000000..e02de2e
--- /dev/null
+++ b/cbb_ReverbGate/utils/EffectProcessorBase.h
@@ -0,0 +1,38 @@
+#pragma once
+
+
+/**
+ * Base Class for Audio Effect Processors
+ *
+ */
+template <typename SampleType>
+class EffectProcessorBase
+{
+public:
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ virtual void prepare(SampleType sampleRate) = 0;
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ virtual SampleType processSample(SampleType input) = 0;
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param data Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ virtual void process(SampleType* channelData, int startSample, int endSample) = 0;
+
+protected:
+ SampleType sampleRate;
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/EnvelopeDetector.cpp b/cbb_ReverbGate/utils/EnvelopeDetector.cpp
new file mode 100644
index 0000000..8f5fee0
--- /dev/null
+++ b/cbb_ReverbGate/utils/EnvelopeDetector.cpp
@@ -0,0 +1,128 @@
+#include "EnvelopeDetector.h"
+
+template <typename SampleType>
+EnvelopeDetector<SampleType>::EnvelopeDetector()
+{
+}
+
+template <typename SampleType>
+void EnvelopeDetector<SampleType>::prepare(SampleType sampleRate)
+{
+ setSampleRate(sampleRate);
+ previousValue = 0.0;
+}
+
+template <typename SampleType>
+SampleType EnvelopeDetector<SampleType>::processSample(SampleType input)
+{
+ SampleType xn = std::fabs(input);
+ SampleType currentValue = 0.0; //Envelope value for the current sample
+
+ if(detectionMode == DetectionModes::MS || detectionMode == DetectionModes::RMS)
+ xn = xn*xn;
+
+ if(xn > previousValue)
+ currentValue = attackTimeCoeff * (previousValue - xn) + xn;
+ else
+ currentValue = releaseTimeCoeff * (previousValue - xn) + xn;
+
+ if (currentValue > 0.0 && currentValue < 1.175494351e-38)
+ {
+ currentValue = 0;
+
+ }
+ else if (currentValue < 0.0 && currentValue > -1.175494351e-38)
+ {
+ currentValue = 0;
+
+ }
+
+ currentValue = std::fmax(currentValue, 0.0);
+ previousValue = currentValue;
+
+ //Check if RMS Mode is selected
+ if(getDetectionMode() == DetectionModes::RMS)
+ currentValue = std::pow(currentValue, 0.5);
+
+ //Check if output is linear
+ if(!output_In_dB)
+ return currentValue;
+
+ if (currentValue <= 0)
+ return -96.0;
+
+ //If output is in dB...
+ return 20*(std::log10(currentValue));
+}
+
+template <typename SampleType>
+void EnvelopeDetector<SampleType>::setAttackTime(SampleType newValue)
+{
+ attackTimeCoeff = std::exp(rc_atc / (newValue * sampleRate * 0.001));
+}
+
+template <typename SampleType>
+SampleType EnvelopeDetector<SampleType>::getAttackTime()
+{
+ return attackTime;
+}
+
+template <typename SampleType>
+void EnvelopeDetector<SampleType>::setReleaseTime(SampleType newValue)
+{
+ releaseTimeCoeff = std::exp(rc_atc / (newValue * sampleRate * 0.001));
+}
+
+template <typename SampleType>
+SampleType EnvelopeDetector<SampleType>::getReleaseTime()
+{
+ return releaseTimeCoeff;
+}
+
+template <typename SampleType>
+void EnvelopeDetector<SampleType>::setDetectionMode(int index)
+{
+ switch(index)
+ {
+ case DetectionModes::Peak:
+ detectionMode = DetectionModes::Peak;
+ break;
+ case DetectionModes::MS:
+ detectionMode = DetectionModes::MS;
+ break;
+ case DetectionModes::RMS:
+ detectionMode = DetectionModes::RMS;
+ break;
+ default:
+ detectionMode = DetectionModes::Peak;
+ }
+}
+
+template <typename SampleType>
+int EnvelopeDetector<SampleType>::getDetectionMode()
+{
+ return detectionMode;
+}
+
+template <typename SampleType>
+void EnvelopeDetector<SampleType>::setOutputIndB(bool outputIndB)
+{
+ output_In_dB = outputIndB;
+}
+
+template <typename SampleType>
+bool EnvelopeDetector<SampleType>::isOutputIndB()
+{
+ return output_In_dB;
+}
+
+template <typename SampleType>
+void EnvelopeDetector<SampleType>::setSampleRate(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+ setAttackTime(attackTime);
+ setReleaseTime(releaseTime);
+}
+
+template class EnvelopeDetector<float>;
+template class EnvelopeDetector<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/EnvelopeDetector.h b/cbb_ReverbGate/utils/EnvelopeDetector.h
new file mode 100644
index 0000000..769f690
--- /dev/null
+++ b/cbb_ReverbGate/utils/EnvelopeDetector.h
@@ -0,0 +1,113 @@
+#pragma once
+#include <cmath>
+
+/**
+ * Envelope Detector Class
+ */
+template <typename SampleType>
+class EnvelopeDetector
+{
+public:
+
+ /**
+ * @brief Constructor
+ *
+ */
+ EnvelopeDetector();
+
+ /**
+ * @brief Prepares object for processing
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate);
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input);
+
+ /**
+ * @brief Sets the attack time of the Envelope Detector object
+ *
+ * @param newValue New attack time in milliseconds
+ */
+ void setAttackTime(SampleType newValue);
+
+ /**
+ * @brief Returns the attack time parameter value of the Envelope Detector object
+ */
+ SampleType getAttackTime();
+
+ /**
+ * @brief Sets the release time of the Envelope Detector object
+ *
+ * @param newValue New Release time in milliseconds
+ */
+ void setReleaseTime(SampleType newValue);
+
+ /**
+ * @brief Returns the release time parameter value of the Envelope Detector object
+ *
+ * @return SampleType
+ */
+ SampleType getReleaseTime();
+
+ /**
+ * @brief Sets the detection mode of the Envelope Detector object
+ *
+ * @param index Detection mode index
+ */
+ void setDetectionMode(int index);
+
+ /**
+ * @brief Returns the detection mode index of the Envelope Detector object
+ */
+ int getDetectionMode();
+
+ /**
+ * @brief Sets the envelope detector in dB or linear output mode
+ *
+ * @param outputIndB Should output be in dB boolean.
+ * True = db Output, False = Linear Output
+ */
+ void setOutputIndB(bool outputIndB);
+
+ /**
+ * @brief Returns Envelope Detector detection mode
+ *
+ * @return true dB output
+ * @return false Linear output
+ */
+ bool isOutputIndB();
+
+ enum DetectionModes
+ {
+ Peak = 0,
+ MS, //Mean Square
+ RMS //Root Mean Square
+ };
+
+
+private:
+
+ SampleType sampleRate{ 44100.0 };
+
+ //User Parameters
+ SampleType attackTime{ 0.0 }; //In ms
+ SampleType releaseTime{ 0.0 }; //In ms
+ int detectionMode{DetectionModes::Peak};
+
+
+ SampleType attackTimeCoeff{ 0.0 };
+ SampleType releaseTimeCoeff{ 0.0 };
+ bool output_In_dB{false};
+
+ const double rc_atc = -0.99967234081320612357829304641019; //RC filter analog time constant
+
+ SampleType previousValue{0.0}; //Envelope value for the previous sample
+
+ void setSampleRate(SampleType sampleRate);
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/FirstOrderSmoother.h b/cbb_ReverbGate/utils/FirstOrderSmoother.h
new file mode 100644
index 0000000..35a5eef
--- /dev/null
+++ b/cbb_ReverbGate/utils/FirstOrderSmoother.h
@@ -0,0 +1,52 @@
+#pragma once
+
+#include <cmath>
+
+/**
+ * First order filter for smoothing parameter changes
+ *
+ */
+class FirstOrderSmoother
+{
+public:
+ FirstOrderSmoother()
+ {
+
+ }
+
+ ~FirstOrderSmoother()
+ {
+
+ }
+
+ /**
+ * @brief Prepares filter for playback
+ *
+ * @param smoothingTimeInMs Amount of time to reach target value in milliseconds
+ * @param samplingRate Current sampling rate
+ */
+ void prepare(float smoothingTimeInMs, float samplingRate)
+ {
+ const float c_twoPi = 6.283185307179586476925286766559f;
+
+ a = exp(-c_twoPi / (smoothingTimeInMs * 0.001f * samplingRate));
+ b = 1.0f - a;
+ z = 0.0f;
+ };
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param in Target value to reach
+ */
+ inline float process(float in)
+ {
+ z = (in * b) + (z * a);
+ return z;
+ }
+
+private:
+ float a;
+ float b;
+ float z;
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/GainUtilities.h b/cbb_ReverbGate/utils/GainUtilities.h
new file mode 100644
index 0000000..e1932c7
--- /dev/null
+++ b/cbb_ReverbGate/utils/GainUtilities.h
@@ -0,0 +1,30 @@
+#pragma once
+
+#include <cmath>
+
+/**
+ * Struct wrapping inline functions for manipulating Audio Buffer sample levels.
+ */
+template <typename SampleType>
+struct GainUtilities
+{
+ /**
+ * @brief Converts linear gain values to decibels
+ *
+ * @param gainValue Linear gain value
+ */
+ static inline SampleType gainToDecibels(SampleType gainValue)
+ {
+ return 20.0 * log10(gainValue);
+ };
+
+ /**
+ * @brief Converts decibel values to linear gain
+ *
+ * @param dbValue Decibel value
+ */
+ static inline SampleType decibelsToGain(SampleType dbValue)
+ {
+ return pow(10.0, dbValue / 20.0);
+ };
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/IIRFilter.cpp b/cbb_ReverbGate/utils/IIRFilter.cpp
new file mode 100644
index 0000000..985b158
--- /dev/null
+++ b/cbb_ReverbGate/utils/IIRFilter.cpp
@@ -0,0 +1,201 @@
+#include "IIRFilter.h"
+
+template <typename SampleType>
+IIRFilter<SampleType>::IIRFilter()
+{
+
+}
+
+template <typename SampleType>
+IIRFilter<SampleType>::~IIRFilter()
+{
+
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::prepare(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+ calculateCoeffs();
+}
+
+template <typename SampleType>
+SampleType IIRFilter<SampleType>::processSample(SampleType input)
+{
+ auto yn = d0*input + c0*(a0 * input + a1 * xn_1 + a2 * xn_2 - b1 * yn_1 - b2 * yn_2);
+
+ xn_2 = xn_1;
+ xn_1 = input;
+
+ yn_2 = yn_1;
+ yn_1 = yn;
+
+ return yn;
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::process(SampleType* data, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ data[sample] = processSample(data[sample]);
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::setCutoff(SampleType newValue)
+{
+ if (newValue < 20.0f)
+ fc = 20.0f;
+ else if (newValue > 20000.0f)
+ fc = 20000.0f;
+ else
+ fc = newValue;
+
+ calculateCoeffs();
+}
+
+template <typename SampleType>
+SampleType IIRFilter<SampleType>::getCutoff()
+{
+ return fc;
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::setFilterType(int type)
+{
+ if (type < 0)
+ type = 0;
+ else if (type > 4)
+ type = 4;
+
+ filterType = type;
+
+ calculateCoeffs();
+}
+
+template <typename SampleType>
+int IIRFilter<SampleType>::getFilterType()
+{
+ return filterType;
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::setQ(SampleType newValue)
+{
+ SampleType this_q = newValue;
+
+ if (this_q > 20.0)
+ this_q = 20.0;
+ else if (this_q < 0.2)
+ this_q = 0.2;
+
+ Q = this_q;
+
+ calculateCoeffs();
+}
+
+template <typename SampleType>
+SampleType IIRFilter<SampleType>::getQ()
+{
+ return Q;
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::setGain(SampleType newValue)
+{
+ notchGain = newValue;
+ calculateCoeffs();
+}
+
+template <typename SampleType>
+SampleType IIRFilter<SampleType>::getGain()
+{
+ return notchGain;
+}
+
+template <typename SampleType>
+void IIRFilter<SampleType>::calculateCoeffs()
+{
+ switch (filterType)
+ {
+ case FilterTypes::LPF : //2nd Order Butterworth LPF
+ r = std::sqrt(2);
+ C = SampleType(1.0f / tan(PI * fc / (SampleType)this->sampleRate));
+ a0 = 1.0f / (1.0f + r * C + C * C);
+ a1 = 2 * a0;
+ a2 = a0;
+ b1 = 2.0f * a0 * (1.0f - C * C);
+ b2 = a0 * (1.0f - r * C + C * C);
+ c0 = 1.0f;
+ d0 = 0.0;
+ break;
+
+ case FilterTypes::HPF : //2nd Order Butterworth HPF
+ r = std::sqrt(2);
+ C = SampleType(tan(PI * fc / (SampleType)this->sampleRate));
+ a0 = 1.0f / (1.0f + r * C + C * C);
+ a1 = -2 * a0;
+ a2 = a0;
+ b1 = 2.0f * a0 * (C * C - 1.0f);
+ b2 = a0 * (1.0f - r * C + C * C);
+ c0 = 1.0f;
+ d0 = 0.0;
+ break;
+
+ case FilterTypes::Parametric :
+
+ K = tan(PI*fc/SampleType(this->sampleRate));
+ V0 = std::pow(10, notchGain / 20);
+ D0 = 1 + (K/Q)+K*K;
+ e0 = 1 + (K/(V0*Q)) + K*K;
+ alpha = 1 + ((V0*K) / Q) + K*K;
+ beta = 2*(K*K - 1);
+ gamma = 1 - ((V0*K) / Q) + K*K;
+ delta = 1 - (K / Q) + K*K;
+ heta = 1 - (K / V0*Q) + K*K;
+
+ if(notchGain >= 0)
+ {
+ //Calcualte boost coefficients
+
+ a0 = alpha/D0;
+ a1 = beta/D0;
+ a2 = gamma/D0;
+ b1 = beta/D0;
+ b2 = delta/D0;
+ c0 = 1.0f;
+ d0 = 0.0f;
+
+ }else
+ {
+ //Calculate cut coefficients
+
+ a0 = D0/e0;
+ a1 = beta/e0;
+ a2 = delta/e0;
+ b1 = beta/e0;
+ b2 = heta/e0;
+ c0 = 1.0f;
+ d0 = 0.0f;
+
+ }
+
+ /*theta_c = (2 * PI * fc) / SampleType(this->sampleRate);
+ u = std::pow(10, notchGain / 20);
+ zeta = 4.0 / (1.0 + u);
+ beta = 0.5 * (1.0f - (zeta * tan(theta_c / (2.0 * Q)))) / (1.0f + (zeta * tan(theta_c / (2.0 * Q))));
+ gamma = (0.5 + beta) * cos(theta_c);
+
+ a0 = 0.5 - beta;
+ a1 = 0.0;
+ a2 = beta - 0.5;
+ b1 = -2.0 * gamma;
+ b2 = 2.0 * beta;
+ c0 = u - 1.0f;
+ d0 = 1.0f;*/
+ break;
+
+ }
+}
+
+template class IIRFilter<float>;
+template class IIRFilter<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/IIRFilter.h b/cbb_ReverbGate/utils/IIRFilter.h
new file mode 100644
index 0000000..6d08f58
--- /dev/null
+++ b/cbb_ReverbGate/utils/IIRFilter.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include <cmath>
+#include <EffectProcessorBase.h>
+
+#define PI 3.14159265358979323846
+
+/**
+ * IIR Filter Class
+ *
+ */
+template <typename SampleType>
+class IIRFilter : public EffectProcessorBase<SampleType>
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ IIRFilter();
+
+ /**
+ * @brief Destructor
+ */
+ ~IIRFilter();
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate) override;
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input) override;
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param data Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* data, int startSample, int endSample) override;
+
+ /**
+ * @brief Sets filter cutoff frequency
+ *
+ * @param newValue New cutoff frequency value
+ *
+ * When the filter mode is set to Parametric it sets the center frequency instead.
+ */
+ void setCutoff(SampleType newValue);
+
+ /**
+ * @brief Sets the filter type
+ *
+ * @param filterType Filter type index
+ */
+ void setFilterType(int filterType);
+
+ /**
+ * @brief Sets the filter quality factor
+ *
+ * @param newValue New filter quality factor
+ */
+ void setQ(SampleType newValue);
+
+ /**
+ * @brief Sets the amount of boost/attenuation of the parametric mode
+ *
+ * @param newValue New boost/attention value in decibels
+ */
+ void setGain(SampleType newValue);
+
+ /**
+ * @brief Returns the cutoff/center frequency of the filter
+ */
+ SampleType getCutoff();
+
+ /**
+ * @brief Returns the quality factor of the filter
+ */
+ SampleType getQ();
+
+ /**
+ * @brief Returns the boost/cut value of the parametric filter mode
+ */
+ SampleType getGain();
+
+ /**
+ * @brief Returns the filter type index
+ */
+ int getFilterType();
+
+ enum FilterTypes
+ {
+ LPF = 0, // Low Pass Fitler
+ HPF, // High Pass Filter
+ Parametric,
+ };
+
+
+private:
+
+ SampleType a0, a1, a2, b1, b2, c0, d0, r, C;
+
+ // Paremetric EQ Filter Variables
+ SampleType K, V0, e0, D0, alpha, beta, gamma, delta, heta;
+ SampleType theta_c, u, zeta;
+
+ // Previous in/out values
+ SampleType xn_1 = 0, xn_2 = 0, yn_1 = 0, yn_2 = 0;
+
+ // User Parameters
+ SampleType fc {500.0}, Q {1.0}, notchGain {0.0};
+ int filterType {FilterTypes::LPF};
+
+ void calculateCoeffs();
+
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/InterpolatedAllPassFilter.cpp b/cbb_ReverbGate/utils/InterpolatedAllPassFilter.cpp
new file mode 100644
index 0000000..5dc577c
--- /dev/null
+++ b/cbb_ReverbGate/utils/InterpolatedAllPassFilter.cpp
@@ -0,0 +1,64 @@
+#include "InterpolatedAllPassFilter.h"
+
+template <typename SampleType>
+InterpolatedAllPassFilter<SampleType>::InterpolatedAllPassFilter()
+{
+
+}
+
+template <typename SampleType>
+InterpolatedAllPassFilter<SampleType>::~InterpolatedAllPassFilter()
+{
+
+}
+
+template <typename SampleType>
+void InterpolatedAllPassFilter<SampleType>::prepare(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+ circularBuffer.prepare(sampleRate);
+ circularBuffer.setSize(2*sampleRate);
+ circularBuffer.setDelayInMs(delayTime);
+
+}
+
+template <typename SampleType>
+void InterpolatedAllPassFilter<SampleType>::setDelayMs(SampleType delayInMs)
+{
+ circularBuffer.setDelayInMs(delayInMs);
+}
+
+template <typename SampleType>
+void InterpolatedAllPassFilter<SampleType>::setDelaySamples(SampleType delayInSamples)
+{
+ circularBuffer.setDelayInSamples(delayInSamples);
+}
+
+template <typename SampleType>
+void InterpolatedAllPassFilter<SampleType>::setFeedback(SampleType newFeedback)
+{
+ newFeedback >= FEEDBACK_LIMIT ? newFeedback = FEEDBACK_LIMIT : newFeedback = newFeedback;
+ newFeedback <= 0.0 ? newFeedback = 0.0 : newFeedback = newFeedback;
+
+ this->feedback = newFeedback;
+}
+
+template <typename SampleType>
+SampleType InterpolatedAllPassFilter<SampleType>::processSample(SampleType input)
+{
+ lastOutput = circularBuffer.popSample();
+ circularBuffer.pushSample(input + (feedback * lastOutput));
+ lastInput = input * -feedback;
+
+ return (lastOutput + lastInput);
+}
+
+template <typename SampleType>
+void InterpolatedAllPassFilter<SampleType>::process(SampleType* channelData, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ channelData[sample] = processSample(channelData[sample]);
+}
+
+template class InterpolatedAllPassFilter<float>;
+template class InterpolatedAllPassFilter<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/InterpolatedAllPassFilter.h b/cbb_ReverbGate/utils/InterpolatedAllPassFilter.h
new file mode 100644
index 0000000..c6b5900
--- /dev/null
+++ b/cbb_ReverbGate/utils/InterpolatedAllPassFilter.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <LinearInterpolationCircularBuffer.h>
+
+#define FEEDBACK_LIMIT 0.99
+
+/**
+ * First Order All-Pass Filter that utilizes linear interpolation when poping samples.
+ *
+ * Allows for smoother delay time changes and modulation.
+ *
+ */
+template <typename SampleType>
+class InterpolatedAllPassFilter
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ InterpolatedAllPassFilter();
+
+ /**
+ * @brief Destructor
+ */
+ ~InterpolatedAllPassFilter();
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate);
+
+ /**
+ * @brief Sets the delay time in milliseconds
+ *
+ * @param delayInMs Delay time in milliseconds
+ */
+ void setDelayMs(SampleType delayInMs);
+
+ /**
+ * @brief Sets the delay time in samples
+ *
+ * @param delayInMs Delay time in samples
+ */
+ void setDelaySamples(SampleType delayInSamples);
+
+ /**
+ * @brief Sets the amount of feedback.
+ *
+ * Values must range between 0 and 1
+ *
+ * @param newFeedback Feedback amount
+ */
+ void setFeedback(SampleType newFeedback);
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input);
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param channelData Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* channelData, int startSample, int endSample);
+
+
+private:
+
+ SampleType sampleRate;
+ LinearInterpolationCircularBuffer<SampleType> circularBuffer;
+ SampleType delayTime {0.0};
+ SampleType feedback {0.0};
+
+ SampleType lastOutput {0.0};
+ SampleType lastInput {0.0};
+
+};
diff --git a/cbb_ReverbGate/utils/InterpolatedCombFilter.cpp b/cbb_ReverbGate/utils/InterpolatedCombFilter.cpp
new file mode 100644
index 0000000..7c9cbde
--- /dev/null
+++ b/cbb_ReverbGate/utils/InterpolatedCombFilter.cpp
@@ -0,0 +1,68 @@
+#include "InterpolatedCombFilter.h"
+
+template <typename SampleType>
+InterpolatedCombFilter<SampleType>::InterpolatedCombFilter()
+{
+
+}
+
+template <typename SampleType>
+InterpolatedCombFilter<SampleType>::~InterpolatedCombFilter()
+{
+
+}
+
+template <typename SampleType>
+void InterpolatedCombFilter<SampleType>::prepare(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+ circularBuffer.prepare(sampleRate);
+ circularBuffer.setSize(2*sampleRate);
+ circularBuffer.setDelayInSamples(delaySamples);
+}
+
+template <typename SampleType>
+void InterpolatedCombFilter<SampleType>::setDelayMs(SampleType delayInMs)
+{
+ this->delaySamples = (delayInMs / 1000) * sampleRate;
+ circularBuffer.setDelayInSamples(this->delaySamples);
+}
+
+template <typename SampleType>
+void InterpolatedCombFilter<SampleType>::setDelaySamples(SampleType delayInSamples)
+{
+ this->delaySamples = delayInSamples;
+ circularBuffer.setDelayInSamples(delaySamples);
+}
+
+template <typename SampleType>
+void InterpolatedCombFilter<SampleType>::setFeedback(SampleType newFeedback)
+{
+ newFeedback >= FEEDBACK_LIMIT ? newFeedback = FEEDBACK_LIMIT : newFeedback = newFeedback;
+ //newFeedback <= 0.0 ? newFeedback = 0.0 : newFeedback = newFeedback;
+
+ this->feedback = newFeedback;
+}
+
+template <typename SampleType>
+SampleType InterpolatedCombFilter<SampleType>::processSample(SampleType input)
+{
+ SampleType in = input + feedback*lastOutput;
+
+ SampleType out = circularBuffer.popSample();
+ circularBuffer.pushSample(in);
+
+ lastOutput = out;
+
+ return out;
+}
+
+template <typename SampleType>
+void InterpolatedCombFilter<SampleType>::process(SampleType* channelData, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ channelData[sample] = processSample(channelData[sample]);
+}
+
+template class InterpolatedCombFilter<float>;
+template class InterpolatedCombFilter<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/InterpolatedCombFilter.h b/cbb_ReverbGate/utils/InterpolatedCombFilter.h
new file mode 100644
index 0000000..fd5869a
--- /dev/null
+++ b/cbb_ReverbGate/utils/InterpolatedCombFilter.h
@@ -0,0 +1,84 @@
+#pragma once
+
+#include <LinearInterpolationCircularBuffer.h>
+
+#define FEEDBACK_LIMIT 0.99
+
+/**
+ * Comb Filter that utilizes linear interpolation when poping samples.
+ *
+ * Allows for smoother delay time changes and modulation.
+ *
+ */
+template <typename SampleType>
+class InterpolatedCombFilter
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ InterpolatedCombFilter();
+
+ /**
+ * @brief Destructor
+ */
+ ~InterpolatedCombFilter();
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate);
+
+ /**
+ * @brief Sets the delay time in milliseconds
+ *
+ * @param delayInMs Delay time in milliseconds
+ */
+ void setDelayMs(SampleType delayInMs);
+
+ /**
+ * @brief Sets the delay time in samples
+ *
+ * @param delayInSamples Delay time in samples
+ */
+ void setDelaySamples(SampleType delayInSamples);
+
+ /**
+ * @brief Sets the amount of feedback.
+ *
+ * Values must range between 0 and 1
+ *
+ * @param newFeedback Feedback amount
+ */
+ void setFeedback(SampleType newFeedback);
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input);
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param channelData Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* channelData, int startSample, int endSample);
+
+private:
+
+ SampleType sampleRate;
+
+ LinearInterpolationCircularBuffer<SampleType> circularBuffer;
+
+ SampleType delaySamples {0.0};
+ SampleType feedback {0.0};
+ SampleType lastOutput {0.0};
+
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/LFO.cpp b/cbb_ReverbGate/utils/LFO.cpp
new file mode 100644
index 0000000..cd6d5c3
--- /dev/null
+++ b/cbb_ReverbGate/utils/LFO.cpp
@@ -0,0 +1,199 @@
+#include "LFO.h"
+
+
+LFO::LFO()
+{
+
+}
+
+LFO::LFO(int waveformType)
+{
+ setWaveformType(waveformType);
+}
+
+void LFO::prepare(double sampleRate)
+{
+ setSampleRate(sampleRate);
+ modCounter = 0.0;
+ modCounter90 = 0.25;
+ setFrequency(frequency);
+}
+
+double LFO::getNextOutputSample(int phaseType)
+{
+ generateNextOutputSample();
+
+ switch(phaseType)
+ {
+ case LFOPhase::Normal:
+ return outNormal;
+ break;
+ case LFOPhase::Inverted:
+ return outInverted;
+ break;
+ case LFOPhase::QuadPhase:
+ return outQuadPhase;
+ break;
+ case LFOPhase::QuadPhaseInverted:
+ return outQuadPhaseInverted;
+ break;
+ default:
+ return outNormal;
+ break;
+ }
+}
+
+void LFO::setWaveformType(int waveformType)
+{
+ switch(waveformType)
+ {
+ case Waveforms::Triangle:
+ waveformType = Waveforms::Triangle;
+ break;
+ case Waveforms::Sine:
+ waveformType = Waveforms::Sine;
+ break;
+ case Waveforms::Saw:
+ waveformType = Waveforms::Saw;
+ break;
+ }
+}
+
+int LFO::getWaveformType()
+{
+ return waveformType;
+}
+
+void LFO::setFrequency(double freq)
+{
+ frequency = freq;
+ phaseInc = frequency / sampleRate;
+}
+
+double LFO::getFrequency()
+{
+ return frequency;
+}
+
+void LFO::setSampleRate(double sampleRate)
+{
+ this->sampleRate = sampleRate;
+}
+
+double LFO::getSampleRate()
+{
+ return sampleRate;
+}
+
+double LFO::unipolarToBipolar(double value)
+{
+ return 2.0*value - 1.0;
+}
+
+void LFO::generateNextOutputSample()
+{
+ moduloWrap(modCounter, phaseInc);
+
+ modCounter90 = modCounter;
+
+ moduloAdvanceAndWrap(modCounter90, 0.25);
+
+ outNormal = 0.0;
+ outInverted = 0.0;
+ outQuadPhase = 0.0;
+ outQuadPhaseInverted = 0.0;
+
+ switch(waveformType)
+ {
+ case Waveforms::Triangle:
+ // Normal Output
+ outNormal = unipolarToBipolar(modCounter);
+ outNormal = 2.0*fabs(outNormal) - 1.0;
+
+ // 90 Degree phase shift
+ outQuadPhase = unipolarToBipolar(modCounter90);
+ outQuadPhase = 2.0*fabs(outQuadPhase) - 1.0;
+
+ break;
+
+ case Waveforms::Sine:
+ double angle;
+
+ // Angle Calculation
+ angle = modCounter*2.0*PI - PI;
+
+ // Normal Output
+ outNormal = parabolicSine(-angle);
+
+ // 90 Degree shift angle calculation
+ angle = modCounter90*2.0*PI - PI;
+
+ // 90 Degree phase shift
+ outQuadPhase = parabolicSine(-angle);
+
+ break;
+
+ case Waveforms::Saw:
+ // Normal Output
+ outNormal = unipolarToBipolar(modCounter);
+
+ // 90 Degree Shift
+ outQuadPhase = unipolarToBipolar(modCounter90);
+
+ break;
+
+ }
+
+ // Inverted Outputs
+
+ // Inverted Normal Output
+ outInverted = -outNormal;
+
+ // Inverted 90 Degree
+ outQuadPhaseInverted = -outQuadPhase;
+
+ moduloAdvance(modCounter, phaseInc);
+}
+
+void LFO::moduloAdvance(double& modCounter, double phaseInc)
+{
+ modCounter += phaseInc;
+}
+
+void LFO::moduloWrap(double& modCounter, double phaseInc)
+{
+ // Positive Frequencies
+ if(phaseInc > 0 && modCounter >= 1.0)
+ modCounter -= 1.0;
+
+ // Negative Frequencies
+ if(phaseInc < 0 && modCounter <= 0.0)
+ modCounter += 1.0;
+}
+
+void LFO::moduloAdvanceAndWrap(double& modCounter, double phaseInc)
+{
+ // Advance
+ modCounter += phaseInc;
+
+ // Check if Wrap is needed
+
+ // Positive Frequencies
+ if(phaseInc > 0 && modCounter >= 1.0)
+ modCounter -= 1.0;
+
+ // Negative Frequencies
+ if(phaseInc < 0 && modCounter <= 0.0)
+ modCounter += 1.0;
+}
+
+double LFO::parabolicSine(double angle)
+{
+ const double B = 4.0 / PI;
+ const double C = -4.0 / (PI* PI);
+ const double P = 0.225;
+
+ double y = B * angle + C * angle * fabs(angle);
+
+ return (P * (y * fabs(y) - y) + y);
+}
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/LFO.h b/cbb_ReverbGate/utils/LFO.h
new file mode 100644
index 0000000..a43bb22
--- /dev/null
+++ b/cbb_ReverbGate/utils/LFO.h
@@ -0,0 +1,127 @@
+#pragma once
+
+#include <iostream>
+#include <cmath>
+
+#define PI 3.14159265358979323846
+
+/**
+ * Low Frequency Oscillator Class
+ *
+ */
+class LFO
+{
+public:
+
+ /**
+ * @brief Contructor
+ *
+ */
+ LFO();
+
+ /**
+ * @brief Constructor
+ *
+ * Sets waveform type during object declaration
+ *
+ * @param waveformType Waveform type index
+ */
+ LFO(int waveformType);
+
+ /**
+ * @brief Prepares object for processing
+ *
+ * @param sampleRate Current sample rate
+ */
+ void prepare(double sampleRate);
+
+ /**
+ * @brief Generates and returns the next oscillator sample
+ *
+ * @param phaseType Oscillator phase
+ */
+ double getNextOutputSample(int phaseType);
+
+ /**
+ * @brief Sets oscillator waveform type
+ *
+ * @param waveformType Waveform type index
+ */
+ void setWaveformType(int waveformType);
+
+ /**
+ * @brief Returns waveform type index
+ */
+ int getWaveformType();
+
+ /**
+ * @brief Sets oscillation rate
+ *
+ * @param freq New Rate
+ */
+ void setFrequency(double freq);
+
+ /**
+ * @brief Returns oscillation rate
+ */
+ double getFrequency();
+
+ /**
+ * @brief Sets the Sample Rate
+ *
+ * @param sampleRate New sample rate
+ */
+ void setSampleRate(double sampleRate);
+
+ /**
+ * @brief Returns the current sample rate the object is operating on
+ */
+ double getSampleRate();
+
+ /**
+ * @brief Converts unipolar oscilation type to bipolar
+ *
+ * @param value Value to convert
+ */
+ double unipolarToBipolar(double value);
+
+ enum Waveforms
+ {
+ Triangle = 0,
+ Sine,
+ Saw
+ };
+
+ enum LFOPhase
+ {
+ Normal = 0,
+ Inverted,
+ QuadPhase,
+ QuadPhaseInverted
+ };
+
+
+private:
+ void generateNextOutputSample();
+
+ // Advabce the mod counter
+ void moduloAdvance(double& modCounter, double phaceInc);
+
+ // Check the mod counter and wrap
+ void moduloWrap(double& modCounter, double phaceInc);
+ // Advance the mod counter and wrap
+ void moduloAdvanceAndWrap(double& modCounter, double phaceInc);
+
+ // Parabolic Sine Calculation Function (Angle ragnes from -pi to pi)
+ double parabolicSine(double angle);
+
+ // Oscillator Parameters
+ double modCounter, modCounter90, phaseInc;
+
+
+ double frequency {1.0}, sampleRate;
+ int waveformType {Waveforms::Sine};
+
+ // Output Values
+ double outNormal, outInverted, outQuadPhase, outQuadPhaseInverted;
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.cpp b/cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.cpp
new file mode 100644
index 0000000..0a87ab3
--- /dev/null
+++ b/cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.cpp
@@ -0,0 +1,127 @@
+#include "LinearInterpolationCircularBuffer.h"
+
+template <typename SampleType>
+LinearInterpolationCircularBuffer<SampleType>::LinearInterpolationCircularBuffer()
+{
+ buffer.reset(new std::vector<SampleType>);
+}
+
+template <typename SampleType>
+LinearInterpolationCircularBuffer<SampleType>::~LinearInterpolationCircularBuffer()
+{
+ buffer->clear();
+ buffer.reset(nullptr);
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::prepare(int sampleRate)
+{
+ this->sampleRate = sampleRate;
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::clear()
+{
+ buffer->clear();
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::setSize(int newBufferSize)
+{
+ clear();
+ buffer->resize(newBufferSize);
+ this->bufferSize = newBufferSize;
+ writePointer = 0;
+ readPointer = 0;
+}
+
+template <typename SampleType>
+int LinearInterpolationCircularBuffer<SampleType>::getNumSamples()
+{
+ return buffer->size();
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::setDelayInSamples(SampleType delayInSamples)
+{
+ delay = limitWithinRange(SampleType(0), SampleType(bufferSize - 1), delayInSamples);
+ delayInt = static_cast<int> (std::floor (delay));
+ delayFrac = delay - (SampleType) delayInt;
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::setDelayInMs(SampleType delayInMs)
+{
+ setDelayInSamples((delayInMs / 1000) * sampleRate);
+}
+
+template <typename SampleType>
+SampleType LinearInterpolationCircularBuffer<SampleType>::processSample(SampleType input)
+{
+ pushSample(input);
+
+ return popSample();
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::process(SampleType* channelData, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ channelData[sample] = processSample(channelData[sample]);
+}
+
+template <typename SampleType>
+void LinearInterpolationCircularBuffer<SampleType>::pushSample(SampleType sample)
+{
+ (*buffer)[writePointer] = sample;
+ writePointer = (writePointer + bufferSize - 1) % bufferSize;
+}
+
+template <typename SampleType>
+SampleType LinearInterpolationCircularBuffer<SampleType>::popSample()
+{
+ SampleType returnValue = interpolateSample();
+ readPointer = (readPointer + bufferSize - 1) % bufferSize;
+
+ return returnValue;
+}
+
+template <typename SampleType>
+SampleType LinearInterpolationCircularBuffer<SampleType>::interpolateSample()
+{
+ auto index1 = readPointer + delayInt;
+ auto index2 = index1 + 1;
+
+ if(index2 >= bufferSize)
+ {
+ index1 %= bufferSize;
+ index2 %= bufferSize;
+ }
+
+ SampleType value1 = (*buffer)[index1];
+ SampleType value2 = (*buffer)[index2];
+
+ return value1 + delayFrac * (value2 - value1);
+}
+
+template <typename SampleType>
+int LinearInterpolationCircularBuffer<SampleType>::getReadPointerIndex()
+{
+ return readPointer;
+}
+
+template <typename SampleType>
+int LinearInterpolationCircularBuffer<SampleType>::getWritePointerIndex()
+{
+ return writePointer;
+}
+
+template <typename SampleType>
+SampleType LinearInterpolationCircularBuffer<SampleType>::limitWithinRange(SampleType lowerLimit, SampleType upperLimit, SampleType value)
+{
+ return value < lowerLimit ? lowerLimit : (upperLimit < value ? upperLimit : value);
+}
+
+template class LinearInterpolationCircularBuffer<float>;
+template class LinearInterpolationCircularBuffer<double>;
+
diff --git a/cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.h b/cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.h
new file mode 100644
index 0000000..af0d445
--- /dev/null
+++ b/cbb_ReverbGate/utils/LinearInterpolationCircularBuffer.h
@@ -0,0 +1,124 @@
+#pragma once
+
+#include <iostream>
+#include <vector>
+#include <memory>
+#include <cmath>
+
+/**
+ * Circular buffer that utilizes linear interpolation when reading samples, allowing for fractional delay lines.
+ */
+template <typename SampleType>
+class LinearInterpolationCircularBuffer
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ LinearInterpolationCircularBuffer();
+
+ /**
+ * @brief Destructor
+ */
+ ~LinearInterpolationCircularBuffer();
+
+ /**
+ * @brief Prepares buffer for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(int sampleRate);
+
+ void reset();
+
+ /**
+ * @brief Clears the buffer
+ *
+ */
+ void clear();
+
+ /**
+ * @brief Sets buffer size
+ *
+ * @param newBufferSize New buffer size in samples
+ */
+ void setSize(int newBufferSize);
+
+ /**
+ * @brief Returns buffer size
+ */
+ int getNumSamples();
+
+ /**
+ * @brief Sets delay time in samples
+ *
+ * @param delayInSamples New delay time in samples
+ */
+ void setDelayInSamples(SampleType delayInSamples);
+
+ /**
+ * @brief Sets delay time in milliseconds
+ *
+ * @param delayInMs New delay time in milliseconds
+ */
+ void setDelayInMs(SampleType delayInMs);
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input);
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param channelData Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* channelData, int startSample, int endSample);
+
+ /**
+ * @brief Returns read pointer index
+ */
+ int getReadPointerIndex();
+
+ /**
+ * @brief Returns write pointer index
+ */
+ int getWritePointerIndex();
+
+ /**
+ * @brief Pushes a sample to the buffer and advances the write pointer by an index of 1
+ *
+ * @warning Meant to be used in a sample by sample processing context
+ *
+ * @param sample input sample
+ */
+ void pushSample(SampleType sample);
+
+ /**
+ * @brief Returns a sample from the buffer read position and advances the read pointer by an index of 1
+ *
+ * The return value is linearly interpolated
+ *
+ * @warning Meant to be used in a sample by sample processing context
+ */
+ SampleType popSample();
+
+private:
+ SampleType interpolateSample();
+ SampleType limitWithinRange(SampleType lowerLimit, SampleType upperLimit, SampleType value);
+
+private:
+
+ SampleType sampleRate;
+ std::unique_ptr<std::vector<SampleType>> buffer;
+ SampleType delayFrac {0.0}, delay {0.0};
+ int readPointer, writePointer, delayInt, bufferSize;
+};
+
+
+
diff --git a/cbb_ReverbGate/utils/ModulatedAllPassFilter.cpp b/cbb_ReverbGate/utils/ModulatedAllPassFilter.cpp
new file mode 100644
index 0000000..6d1b36e
--- /dev/null
+++ b/cbb_ReverbGate/utils/ModulatedAllPassFilter.cpp
@@ -0,0 +1,107 @@
+#include "ModulatedAllPassFilter.h"
+
+template <typename SampleType>
+ModulatedAllPassFilter<SampleType>::ModulatedAllPassFilter()
+{
+
+}
+
+template <typename SampleType>
+ModulatedAllPassFilter<SampleType>::~ModulatedAllPassFilter()
+{
+
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::prepare(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+ allPassFilter.prepare(sampleRate);
+ allPassFilter.setDelayMs(delayTime);
+ allPassFilter.setFeedback(feedback);
+
+ lfo.prepare(sampleRate);
+ lfo.setWaveformType(LFO::Waveforms::Sine);
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::setDelayMs(SampleType delayInMs)
+{
+ this->delayTime = delayInMs;
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::setDelayInSamples(SampleType delayInSamples)
+{
+ this->delayTime = (delayInSamples / sampleRate) * 1000.0;
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::setFeedback(SampleType newFeedback)
+{
+ this->feedback = newFeedback;
+ allPassFilter.setFeedback(this->feedback);
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::setRate(SampleType newRate)
+{
+ this->rate = newRate;
+ lfo.setFrequency(this->rate);
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::setDepth(SampleType newDepth)
+{
+ this->depth = newDepth;
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::setWidth(SampleType newWidth)
+{
+ this->width = newWidth;
+}
+
+template <typename SampleType>
+SampleType ModulatedAllPassFilter<SampleType>::processSample(SampleType input)
+{
+ SampleType minDelay = ((this->delayTime / 1000) * sampleRate) - width;
+ SampleType maxDelay = ((this->delayTime / 1000) * sampleRate) + width;
+ SampleType modMin = minDelay;
+ SampleType modMax = maxDelay;
+
+ SampleType newDelTime = (doUnipolarModulationFromMin(bipolarToUnipolar(depth * lfo.getNextOutputSample(LFO::LFOPhase::Normal)), modMin, modMax));
+
+ allPassFilter.setDelaySamples(newDelTime);
+
+ SampleType output = allPassFilter.processSample(input);
+
+ return output;
+}
+
+template <typename SampleType>
+void ModulatedAllPassFilter<SampleType>::process(SampleType* data, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ data[sample] = processSample(data[sample]);
+}
+
+template <typename SampleType>
+SampleType ModulatedAllPassFilter<SampleType>::doUnipolarModulationFromMin(SampleType unipolarModulatorValue, SampleType minValue, SampleType maxValue)
+{
+ // --- UNIPOLAR bound
+ unipolarModulatorValue = fmin(unipolarModulatorValue, 1.0f);
+ unipolarModulatorValue = fmax(unipolarModulatorValue, 0.0f);
+
+ // --- modulate from minimum value upwards
+ return unipolarModulatorValue * (maxValue - minValue) + minValue;
+}
+
+template <typename SampleType>
+SampleType ModulatedAllPassFilter<SampleType>::bipolarToUnipolar(SampleType value)
+{
+ return 0.5 * value + 0.5;
+}
+
+template class ModulatedAllPassFilter<float>;
+template class ModulatedAllPassFilter<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/ModulatedAllPassFilter.h b/cbb_ReverbGate/utils/ModulatedAllPassFilter.h
new file mode 100644
index 0000000..12567ea
--- /dev/null
+++ b/cbb_ReverbGate/utils/ModulatedAllPassFilter.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <InterpolatedAllPassFilter.h>
+#include <LFO.h>
+
+/**
+ * First Order All-Pass Filter with modulating delay time
+ *
+ */
+template <typename SampleType>
+class ModulatedAllPassFilter
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ ModulatedAllPassFilter();
+
+ /**
+ * @brief Destructor
+ */
+ ~ModulatedAllPassFilter();
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate);
+
+ /**
+ * @brief Sets the delay time in milliseconds
+ *
+ * @param delayInMs Delay time in milliseconds
+ */
+ void setDelayMs(SampleType delayInMs);
+
+ /**
+ * @brief Sets the delay time in samples
+ *
+ * @param delayInSamples Delay time in samples
+ */
+ void setDelayInSamples(SampleType delayInSamples);
+
+ /**
+ * @brief Sets the amount of feedback.
+ *
+ * Values must range between 0 and 1
+ *
+ * @param newFeedback Feedback amount
+ */
+ void setFeedback(SampleType newFeedback);
+
+ /**
+ * @brief Sets the delay time modulation rate
+ *
+ * @param newRate New modulation rate value in Hz
+ */
+ void setRate(SampleType newRate);
+
+ /**
+ * @brief Sets the delay time modulation depth
+ *
+ * @param newDepth New modulation depth value
+ *
+ * Values must range between 0.0 to 1.0
+ */
+ void setDepth(SampleType newDepth);
+
+ /**
+ * @brief Sets the bounds the delay time values can modulate between
+ *
+ * @param newWidth New modulation width in samples
+ */
+ void setWidth(SampleType newWidth);
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input);
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param data Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* data, int startSample, int endSample);
+
+private:
+ SampleType doUnipolarModulationFromMin(SampleType unipolarModulatorValue, SampleType minValue, SampleType maxValue);
+ SampleType bipolarToUnipolar(SampleType value);
+
+private:
+ SampleType sampleRate;
+ InterpolatedAllPassFilter<SampleType> allPassFilter;
+ LFO lfo;
+ SampleType delayTime {0.0}, feedback {0.0}, rate {0.0}, depth {0.0}, width {0.0};
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/ModulatedCombFilter.cpp b/cbb_ReverbGate/utils/ModulatedCombFilter.cpp
new file mode 100644
index 0000000..63a7207
--- /dev/null
+++ b/cbb_ReverbGate/utils/ModulatedCombFilter.cpp
@@ -0,0 +1,107 @@
+#include "ModulatedCombFilter.h"
+
+template <typename SampleType>
+ModulatedCombFilter<SampleType>::ModulatedCombFilter()
+{
+
+}
+
+template <typename SampleType>
+ModulatedCombFilter<SampleType>::~ModulatedCombFilter()
+{
+
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::prepare(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+ combFilter.prepare(sampleRate);
+ combFilter.setDelayMs(delayTime);
+ combFilter.setFeedback(feedback);
+
+ lfo.prepare(sampleRate);
+ lfo.setWaveformType(LFO::Waveforms::Sine);
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::setDelayMs(SampleType delayInMs)
+{
+ this->delayTime = delayInMs;
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::setDelayInSamples(SampleType delayInSamples)
+{
+ this->delayTime = (delayInSamples / sampleRate) * 1000.0;
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::setFeedback(SampleType newFeedback)
+{
+ this->feedback = newFeedback;
+ combFilter.setFeedback(this->feedback);
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::setRate(SampleType newRate)
+{
+ this->rate = newRate;
+ lfo.setFrequency(this->rate);
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::setDepth(SampleType newDepth)
+{
+ this->depth = newDepth;
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::setWidth(SampleType newWidth)
+{
+ this->width = newWidth;
+}
+
+template <typename SampleType>
+SampleType ModulatedCombFilter<SampleType>::processSample(SampleType input)
+{
+ SampleType minDelay = ((this->delayTime / 1000) * sampleRate) - width;
+ SampleType maxDelay = ((this->delayTime / 1000) * sampleRate) + width;
+ SampleType modMin = minDelay;
+ SampleType modMax = maxDelay;
+
+ SampleType newDelTime = (doUnipolarModulationFromMin(bipolarToUnipolar(depth * lfo.getNextOutputSample(LFO::LFOPhase::Normal)), modMin, modMax));
+
+ combFilter.setDelaySamples(newDelTime);
+
+ SampleType output = combFilter.processSample(input);
+
+ return output;
+}
+
+template <typename SampleType>
+void ModulatedCombFilter<SampleType>::process(SampleType* data, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ data[sample] = processSample(data[sample]);
+}
+
+template <typename SampleType>
+SampleType ModulatedCombFilter<SampleType>::doUnipolarModulationFromMin(SampleType unipolarModulatorValue, SampleType minValue, SampleType maxValue)
+{
+ // --- UNIPOLAR bound
+ unipolarModulatorValue = fmin(unipolarModulatorValue, 1.0f);
+ unipolarModulatorValue = fmax(unipolarModulatorValue, 0.0f);
+
+ // --- modulate from minimum value upwards
+ return unipolarModulatorValue * (maxValue - minValue) + minValue;
+}
+
+template <typename SampleType>
+SampleType ModulatedCombFilter<SampleType>::bipolarToUnipolar(SampleType value)
+{
+ return 0.5 * value + 0.5;
+}
+
+template class ModulatedCombFilter<float>;
+template class ModulatedCombFilter<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/ModulatedCombFilter.h b/cbb_ReverbGate/utils/ModulatedCombFilter.h
new file mode 100644
index 0000000..566e955
--- /dev/null
+++ b/cbb_ReverbGate/utils/ModulatedCombFilter.h
@@ -0,0 +1,103 @@
+#pragma once
+
+#include <InterpolatedCombFilter.h>
+#include <LFO.h>
+
+/**
+ * Comb Filter with modulating delay time
+ *
+ */
+template <typename SampleType>
+class ModulatedCombFilter
+{
+public:
+
+ /**
+ * @brief Constructor
+ */
+ ModulatedCombFilter();
+
+ /**
+ * @brief Destructor
+ */
+ ~ModulatedCombFilter();
+
+ /**
+ * @brief Prepares object for playback
+ *
+ * @param sampleRate Current sampling rate
+ */
+ void prepare(SampleType sampleRate);
+
+ /**
+ * @brief Sets the delay time in milliseconds
+ *
+ * @param delayInMs Delay time in milliseconds
+ */
+ void setDelayMs(SampleType delayInMs);
+
+ /**
+ * @brief Sets the delay time in samples
+ *
+ * @param delayInSamples Delay time in samples
+ */
+ void setDelayInSamples(SampleType delayInSamples);
+
+ /**
+ * @brief Sets the amount of feedback.
+ *
+ * Values must range between 0 and 1
+ *
+ * @param newFeedback Feedback amount
+ */
+ void setFeedback(SampleType newFeedback);
+
+ /**
+ * @brief Sets the delay time modulation rate
+ *
+ * @param newRate New modulation rate value in Hz
+ */
+ void setRate(SampleType newRate);
+
+ /**
+ * @brief Sets the delay time modulation depth
+ *
+ * @param newDepth New modulation depth value
+ *
+ * Values must range between 0.0 to 1.0
+ */
+ void setDepth(SampleType newDepth);
+
+ /**
+ * @brief Sets the bounds the delay time values can modulate between
+ *
+ * @param newWidth New modulation width in samples
+ */
+ void setWidth(SampleType newWidth);
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input);
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param data Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* data, int startSample, int endSample);
+
+private:
+ SampleType doUnipolarModulationFromMin(SampleType unipolarModulatorValue, SampleType minValue, SampleType maxValue);
+ SampleType bipolarToUnipolar(SampleType value);
+
+private:
+ SampleType sampleRate;
+ InterpolatedCombFilter<SampleType> combFilter;
+ LFO lfo;
+ SampleType delayTime {0.0}, feedback {0.0}, rate {0.0}, depth {0.0}, width {0.0};
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/ModulationProcessor.h b/cbb_ReverbGate/utils/ModulationProcessor.h
new file mode 100644
index 0000000..0fd58f5
--- /dev/null
+++ b/cbb_ReverbGate/utils/ModulationProcessor.h
@@ -0,0 +1,51 @@
+#pragma once
+
+#include <EffectProcessorBase.h>
+#include <LinearInterpolationCircularBuffer.h>
+#include <LFO.h>
+
+/**
+ * Base Class for Modulation Effect Processors
+ *
+ */
+template <typename SampleType>
+class ModulationProcessor : public EffectProcessorBase<SampleType>
+{
+public:
+
+ /**
+ * @brief Sets modulation rate
+ *
+ * @param newRate New rate value
+ */
+ virtual void setRate(SampleType newRate) = 0;
+
+ /**
+ * @brief Sets modulation depth
+ *
+ * @param newDepth New depth value
+ */
+ virtual void setDepth(SampleType newDepth) = 0;
+
+protected:
+
+ SampleType doUnipolarModulationFromMin(SampleType unipolarModulatorValue, SampleType minValue, SampleType maxValue)
+ {
+ // --- UNIPOLAR bound
+ unipolarModulatorValue = fmin(unipolarModulatorValue, 1.0f);
+ unipolarModulatorValue = fmax(unipolarModulatorValue, 0.0f);
+
+ // --- modulate from minimum value upwards
+ return unipolarModulatorValue * (maxValue - minValue) + minValue;
+ };
+
+ SampleType bipolarToUnipolar(SampleType value)
+ {
+ return 0.5 * value + 0.5;
+ };
+
+protected:
+ SampleType sampleRate;
+ LinearInterpolationCircularBuffer<SampleType> delayLine;
+ LFO lfo;
+};
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/Reverb.cpp b/cbb_ReverbGate/utils/Reverb.cpp
new file mode 100644
index 0000000..85b7198
--- /dev/null
+++ b/cbb_ReverbGate/utils/Reverb.cpp
@@ -0,0 +1,108 @@
+#include "Reverb.h"
+
+template <typename SampleType>
+Reverb<SampleType>::Reverb()
+{
+
+}
+
+template <typename SampleType>
+Reverb<SampleType>::~Reverb()
+{
+
+}
+
+template <typename SampleType>
+void Reverb<SampleType>::prepare(SampleType sampleRate)
+{
+ this->sampleRate = sampleRate;
+
+ for(int comb = 0; comb < NUM_COMBS; ++comb)
+ {
+ combFilters[comb].prepare(sampleRate);
+ combFilters[comb].setDelayMs(combDelayTimeValues[comb]);
+ combFilters[comb].setFeedback(combFeedbackValues[comb]);
+ combFilters[comb].setWidth(8);
+ combFilters[comb].setRate(combModRates[comb]);
+ combFilters[comb].setDepth(1.0);
+
+ valueSmoothers[comb].prepare(450.0, sampleRate);
+ }
+
+ for(int allpass = 0; allpass < NUM_ALLPASS; ++allpass)
+ {
+ allPassFilters[allpass].prepare(sampleRate);
+ allPassFilters[allpass].setDelayMs(allPassDelayTimeValues[allpass]);
+ allPassFilters[allpass].setFeedback(allPassFeedbackValues[allpass]);
+ allPassFilters[allpass].setWidth(8);
+ allPassFilters[allpass].setRate(allPassModRates[allpass]);
+ allPassFilters[allpass].setDepth(0.4);
+ }
+
+ filter.prepare(sampleRate);
+ filter.setFilterType(IIRFilter<SampleType>::FilterTypes::LPF);
+ filter.setCutoff(this->filterCutoff);
+}
+
+template <typename SampleType>
+SampleType Reverb<SampleType>::processSample(SampleType input)
+{
+ SampleType combOutput = 0.0;
+ SampleType output = 0.0;
+
+ // Comb Filters
+ for(int comb = 0; comb < NUM_COMBS; ++comb)
+ {
+ combFilters[comb].setDelayMs(valueSmoothers[comb].process(roomSize) * combDelayTimeValues[comb]);
+ combOutput += combFilters[comb].processSample(input);
+ }
+
+ combOutput = combOutput / NUM_COMBS;
+
+ // All-Pass Filters
+ output = allPassFilters[0].processSample(combOutput);
+ output = allPassFilters[1].processSample(output);
+
+ // Low-Pass Filter
+ output = filter.processSample(output);
+
+ return (mix * output) + ((1.0 - mix) * input);
+}
+
+template <typename SampleType>
+void Reverb<SampleType>::process(SampleType* data, int startSample, int endSample)
+{
+ for(int sample = startSample; sample < endSample; ++sample)
+ data[sample] = processSample(data[sample]);
+}
+
+template <typename SampleType>
+void Reverb<SampleType>::setRoomSize(SampleType newRoomSize)
+{
+ this->roomSize = newRoomSize;
+}
+
+template <typename SampleType>
+void Reverb<SampleType>::setDecay(SampleType newDecay)
+{
+ this->decay = newDecay;
+
+ for(int comb = 0; comb < NUM_COMBS; ++comb)
+ combFilters[comb].setFeedback(decay * combFeedbackValues[comb]);
+}
+
+template <typename SampleType>
+void Reverb<SampleType>::setCutoff(SampleType newCutoff)
+{
+ this->filterCutoff = newCutoff;
+ filter.setCutoff(this->filterCutoff);
+}
+
+template <typename SampleType>
+void Reverb<SampleType>::setMix(SampleType newMix)
+{
+ this->mix = newMix;
+}
+
+template class Reverb<float>;
+template class Reverb<double>;
\ No newline at end of file
diff --git a/cbb_ReverbGate/utils/Reverb.h b/cbb_ReverbGate/utils/Reverb.h
new file mode 100644
index 0000000..9873f2e
--- /dev/null
+++ b/cbb_ReverbGate/utils/Reverb.h
@@ -0,0 +1,65 @@
+#pragma once
+
+#include <EffectProcessorBase.h>
+#include <ModulatedCombFilter.h>
+#include <ModulatedAllPassFilter.h>
+#include <LFO.h>
+#include <IIRFilter.h>
+#include <FirstOrderSmoother.h>
+
+#define NUM_COMBS 4
+#define NUM_ALLPASS 2
+
+template <typename SampleType>
+class Reverb : public EffectProcessorBase<SampleType>
+{
+public:
+ Reverb();
+ ~Reverb();
+
+ void prepare(SampleType sampleRate) override;
+
+ /**
+ * @brief Processes a single sample
+ *
+ * @param input Input sample
+ */
+ SampleType processSample(SampleType input) override;
+
+ /**
+ * @brief Processes a memory block that holds audio samples
+ *
+ * @param data Memory block start pointer
+ * @param startSample Sample index to start processing from
+ * @param endSample Number of samples to process
+ */
+ void process(SampleType* data, int startSample, int endSample) override;
+
+ void setRoomSize(SampleType newRoomSize);
+ void setDecay(SampleType newDecay);
+ void setCutoff(SampleType newCutoff);
+ void setMix(SampleType newMix);
+
+private:
+
+ ModulatedCombFilter<SampleType> combFilters[NUM_COMBS];
+ ModulatedAllPassFilter<SampleType> allPassFilters[NUM_ALLPASS];
+
+ LFO combLFO[NUM_COMBS];
+ LFO allPassLFO[NUM_ALLPASS];
+
+ SampleType combDelayTimeValues[NUM_COMBS] {43.7, 41.1, 37.1, 29.7}; // CombFilter Delay times in ms
+ SampleType combFeedbackValues[NUM_COMBS] {0.9, -0.9, 0.9, -0.9};
+ SampleType combModRates[NUM_COMBS] {0.6, 0.71, 0.83, 0.95};
+
+ SampleType allPassDelayTimeValues[NUM_ALLPASS] {5.0, 1.7}; // AllPass Delay times in ms
+ SampleType allPassFeedbackValues[NUM_ALLPASS] {0.7, 0.7};
+ SampleType allPassModRates[NUM_ALLPASS] {0.6, 0.83};
+
+ FirstOrderSmoother valueSmoothers[NUM_COMBS];
+
+ IIRFilter<SampleType> filter;
+
+ // User Parameters
+ SampleType roomSize {1.0}, decay {0.5}, filterCutoff {20000.0}, mix {0.5};
+};
\ No newline at end of file
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/CodeChunks.db b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/CodeChunks.db
deleted file mode 100644
index 5b9c325..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/CodeChunks.db
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/SemanticSymbols.db b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/SemanticSymbols.db
deleted file mode 100644
index 395bee4..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/SemanticSymbols.db
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/2575945a-65a1-431d-91d3-3d5f980cae5a.vsidx b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/2575945a-65a1-431d-91d3-3d5f980cae5a.vsidx
deleted file mode 100644
index f248ac3..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/2575945a-65a1-431d-91d3-3d5f980cae5a.vsidx
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/3a4648d8-dd3f-46ea-993c-503c18760d34.vsidx b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/3a4648d8-dd3f-46ea-993c-503c18760d34.vsidx
deleted file mode 100644
index 86f7593..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/3a4648d8-dd3f-46ea-993c-503c18760d34.vsidx
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/46d07015-65cb-4fe7-a056-59362f75721f.vsidx b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/46d07015-65cb-4fe7-a056-59362f75721f.vsidx
deleted file mode 100644
index 95a9720..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/46d07015-65cb-4fe7-a056-59362f75721f.vsidx
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/9e83b5d3-8044-4e57-b6e1-3cc4afe3f3db.vsidx b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/9e83b5d3-8044-4e57-b6e1-3cc4afe3f3db.vsidx
deleted file mode 100644
index 901ab07..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/9e83b5d3-8044-4e57-b6e1-3cc4afe3f3db.vsidx
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/.suo b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/.suo
deleted file mode 100644
index 473a08c..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/.suo
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Browse.VC.db b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Browse.VC.db
deleted file mode 100644
index 8a68a50..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Browse.VC.db
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.backup.json b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.backup.json
deleted file mode 100644
index 8cf0b44..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.backup.json
+++ /dev/null
@@ -1,195 +0,0 @@
-{
- "Version": 1,
- "WorkspaceRootPath": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\",
- "Documents": [
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\ReverbHallRoom.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
- "RelativeMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|solutionrelative:ReverbHallRoom.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\ReverbChannel.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\Programs.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- }
- ],
- "DocumentGroupContainers": [
- {
- "Orientation": 0,
- "VerticalTabListWidth": 256,
- "DocumentGroups": [
- {
- "DockedWidth": 220,
- "SelectedChildIndex": 10,
- "Children": [
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{a0c5197d-0ac7-4b63-97cd-8872a789d233}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:129:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{53d10d51-d2d8-3452-ab88-12f687ed0782}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{3ae79031-e1bc-11d0-8f78-00a0c9110057}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{40ea2e6b-2121-4bb8-a43e-c83c04b51041}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
- },
- {
- "$type": "Document",
- "DocumentIndex": 5,
- "Title": "ReverbChannel.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\ReverbChannel.h",
- "RelativeDocumentMoniker": "..\\reverb_utils\\ReverbChannel.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\ReverbChannel.h",
- "RelativeToolTip": "..\\reverb_utils\\ReverbChannel.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-13T10:43:19.161Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 7,
- "Title": "RandomBuffer.cpp",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.cpp",
- "RelativeDocumentMoniker": "..\\reverb_utils\\RandomBuffer.cpp",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.cpp",
- "RelativeToolTip": "..\\reverb_utils\\RandomBuffer.cpp",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
- "WhenOpened": "2026-03-10T09:35:50.55Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 8,
- "Title": "RandomBuffer.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.h",
- "RelativeDocumentMoniker": "..\\reverb_utils\\RandomBuffer.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.h",
- "RelativeToolTip": "..\\reverb_utils\\RandomBuffer.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:35:49.431Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 0,
- "Title": "ReverbHallRoom.cpp",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\ReverbHallRoom.cpp",
- "RelativeDocumentMoniker": "ReverbHallRoom.cpp",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\ReverbHallRoom.cpp",
- "RelativeToolTip": "ReverbHallRoom.cpp",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAABsAAAArAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
- "WhenOpened": "2026-03-10T09:03:46.843Z",
- "EditorCaption": ""
- },
- {
- "$type": "Document",
- "DocumentIndex": 3,
- "Title": "reverb_wrapper.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.h",
- "RelativeDocumentMoniker": "..\\reverb_wrapper.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.h",
- "RelativeToolTip": "..\\reverb_wrapper.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:37:03.415Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 6,
- "Title": "Programs.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\Programs.h",
- "RelativeDocumentMoniker": "..\\reverb_utils\\Programs.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\Programs.h",
- "RelativeToolTip": "..\\reverb_utils\\Programs.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAEAAAAMAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:14:17.518Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 1,
- "Title": "reverb.cpp",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.cpp",
- "RelativeDocumentMoniker": "..\\reverb.cpp",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.cpp",
- "RelativeToolTip": "..\\reverb.cpp",
- "ViewState": "AgIAABoAAAAAAAAAAAD4v0UAAAATAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
- "WhenOpened": "2026-03-10T09:06:15.139Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 2,
- "Title": "reverb_wrapper.c",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.c",
- "RelativeDocumentMoniker": "..\\reverb_wrapper.c",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.c",
- "RelativeToolTip": "..\\reverb_wrapper.c",
- "ViewState": "AgIAAFQAAAAAAAAAAAD4v2gAAAAQAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000423|",
- "WhenOpened": "2026-03-10T09:36:48.616Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 4,
- "Title": "reverb.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.h",
- "RelativeDocumentMoniker": "..\\reverb.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.h",
- "RelativeToolTip": "..\\reverb.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:38:04.142Z"
- }
- ]
- },
- {
- "DockedWidth": 58,
- "SelectedChildIndex": -1,
- "Children": [
- {
- "$type": "Bookmark",
- "Name": "ST:283709:0:{1a46fd64-28d5-0019-8eb3-17a02d419b53}"
- }
- ]
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.json b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.json
deleted file mode 100644
index 8cf0b44..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.json
+++ /dev/null
@@ -1,195 +0,0 @@
-{
- "Version": 1,
- "WorkspaceRootPath": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\",
- "Documents": [
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\ReverbHallRoom.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}",
- "RelativeMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|solutionrelative:ReverbHallRoom.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.c||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\ReverbChannel.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\Programs.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.cpp||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- },
- {
- "AbsoluteMoniker": "D:0:0:{1400541B-B713-435F-95FB-9F7F15065495}|ReverbHallRoom.vcxproj|E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.h||{D0E1A5C6-B359-4E41-9B60-3365922C2A22}"
- }
- ],
- "DocumentGroupContainers": [
- {
- "Orientation": 0,
- "VerticalTabListWidth": 256,
- "DocumentGroups": [
- {
- "DockedWidth": 220,
- "SelectedChildIndex": 10,
- "Children": [
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{a0c5197d-0ac7-4b63-97cd-8872a789d233}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:128:0:{116d2292-e37d-41cd-a077-ebacac4c8cc4}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:129:0:{1fc202d4-d401-403c-9834-5b218574bb67}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{53d10d51-d2d8-3452-ab88-12f687ed0782}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{3ae79031-e1bc-11d0-8f78-00a0c9110057}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{40ea2e6b-2121-4bb8-a43e-c83c04b51041}"
- },
- {
- "$type": "Bookmark",
- "Name": "ST:0:0:{aa2115a1-9712-457b-9047-dbb71ca2cdd2}"
- },
- {
- "$type": "Document",
- "DocumentIndex": 5,
- "Title": "ReverbChannel.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\ReverbChannel.h",
- "RelativeDocumentMoniker": "..\\reverb_utils\\ReverbChannel.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\ReverbChannel.h",
- "RelativeToolTip": "..\\reverb_utils\\ReverbChannel.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-13T10:43:19.161Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 7,
- "Title": "RandomBuffer.cpp",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.cpp",
- "RelativeDocumentMoniker": "..\\reverb_utils\\RandomBuffer.cpp",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.cpp",
- "RelativeToolTip": "..\\reverb_utils\\RandomBuffer.cpp",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
- "WhenOpened": "2026-03-10T09:35:50.55Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 8,
- "Title": "RandomBuffer.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.h",
- "RelativeDocumentMoniker": "..\\reverb_utils\\RandomBuffer.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\RandomBuffer.h",
- "RelativeToolTip": "..\\reverb_utils\\RandomBuffer.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:35:49.431Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 0,
- "Title": "ReverbHallRoom.cpp",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\ReverbHallRoom.cpp",
- "RelativeDocumentMoniker": "ReverbHallRoom.cpp",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\ReverbHallRoom\\ReverbHallRoom.cpp",
- "RelativeToolTip": "ReverbHallRoom.cpp",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAABsAAAArAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
- "WhenOpened": "2026-03-10T09:03:46.843Z",
- "EditorCaption": ""
- },
- {
- "$type": "Document",
- "DocumentIndex": 3,
- "Title": "reverb_wrapper.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.h",
- "RelativeDocumentMoniker": "..\\reverb_wrapper.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.h",
- "RelativeToolTip": "..\\reverb_wrapper.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAwAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:37:03.415Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 6,
- "Title": "Programs.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\Programs.h",
- "RelativeDocumentMoniker": "..\\reverb_utils\\Programs.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_utils\\Programs.h",
- "RelativeToolTip": "..\\reverb_utils\\Programs.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAEAAAAMAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:14:17.518Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 1,
- "Title": "reverb.cpp",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.cpp",
- "RelativeDocumentMoniker": "..\\reverb.cpp",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.cpp",
- "RelativeToolTip": "..\\reverb.cpp",
- "ViewState": "AgIAABoAAAAAAAAAAAD4v0UAAAATAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000677|",
- "WhenOpened": "2026-03-10T09:06:15.139Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 2,
- "Title": "reverb_wrapper.c",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.c",
- "RelativeDocumentMoniker": "..\\reverb_wrapper.c",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb_wrapper.c",
- "RelativeToolTip": "..\\reverb_wrapper.c",
- "ViewState": "AgIAAFQAAAAAAAAAAAD4v2gAAAAQAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000423|",
- "WhenOpened": "2026-03-10T09:36:48.616Z"
- },
- {
- "$type": "Document",
- "DocumentIndex": 4,
- "Title": "reverb.h",
- "DocumentMoniker": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.h",
- "RelativeDocumentMoniker": "..\\reverb.h",
- "ToolTip": "E:\\ADI_Prj\\z_git_fold_temp\\03-audio_process\\cbb_RoomReverb\\reverb.h",
- "RelativeToolTip": "..\\reverb.h",
- "ViewState": "AgIAAAAAAAAAAAAAAAAAAAkAAAAAAAAAAAAAAA==",
- "Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000680|",
- "WhenOpened": "2026-03-10T09:38:04.142Z"
- }
- ]
- },
- {
- "DockedWidth": 58,
- "SelectedChildIndex": -1,
- "Children": [
- {
- "$type": "Bookmark",
- "Name": "ST:283709:0:{1a46fd64-28d5-0019-8eb3-17a02d419b53}"
- }
- ]
- }
- ]
- }
- ]
-}
\ No newline at end of file
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Solution.VC.db b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Solution.VC.db
deleted file mode 100644
index 699679b..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Solution.VC.db
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/26c6e6bc21719993/REVERB.ipch b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/26c6e6bc21719993/REVERB.ipch
deleted file mode 100644
index 15c8e01..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/26c6e6bc21719993/REVERB.ipch
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/60fac65e2eb3380b/REVERBHALLROOM.ipch b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/60fac65e2eb3380b/REVERBHALLROOM.ipch
deleted file mode 100644
index 24f22c7..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/60fac65e2eb3380b/REVERBHALLROOM.ipch
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c6c4be2c6e03fbf/REVERB_WRAPPER.ipch b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c6c4be2c6e03fbf/REVERB_WRAPPER.ipch
deleted file mode 100644
index d00c04a..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c6c4be2c6e03fbf/REVERB_WRAPPER.ipch
+++ /dev/null
Binary files differ
diff --git a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c9606fc76e9a2740/RANDOMBUFFER.ipch b/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c9606fc76e9a2740/RANDOMBUFFER.ipch
deleted file mode 100644
index 369f4ff..0000000
--- a/cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c9606fc76e9a2740/RANDOMBUFFER.ipch
+++ /dev/null
Binary files differ
--
Gitblit v1.9.3