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 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> 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> 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> 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; } 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); } }; */ 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>; 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); }; 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; }; 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; }; 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>; 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); }; 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; }; 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); }; }; 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>; 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(); }; 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>; 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}; }; 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>; 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}; }; 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); } 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; }; 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>; 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; }; 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>; 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}; }; 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>; 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}; }; 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; }; 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>; 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}; }; cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/CodeChunks.dbBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/CopilotIndices/17.13.439.2385/SemanticSymbols.dbBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/2575945a-65a1-431d-91d3-3d5f980cae5a.vsidxBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/3a4648d8-dd3f-46ea-993c-503c18760d34.vsidxBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/46d07015-65cb-4fe7-a056-59362f75721f.vsidxBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/FileContentIndex/9e83b5d3-8044-4e57-b6e1-3cc4afe3f3db.vsidxBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/.suoBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Browse.VC.dbBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.backup.json
ÎļþÒÑɾ³ý cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/DocumentLayout.json
ÎļþÒÑɾ³ý cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/Solution.VC.dbBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/26c6e6bc21719993/REVERB.ipchBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/60fac65e2eb3380b/REVERBHALLROOM.ipchBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c6c4be2c6e03fbf/REVERB_WRAPPER.ipchBinary files differ
cbb_RoomReverb/ReverbHallRoom/.vs/ReverbHallRoom/v17/ipch/AutoPCH/c9606fc76e9a2740/RANDOMBUFFER.ipchBinary files differ