2121
2222#include < yup_dsp/yup_dsp.h>
2323
24+ #include < array>
25+
2426#include < gtest/gtest.h>
2527
2628using namespace yup ;
@@ -29,6 +31,7 @@ namespace
2931{
3032constexpr double analogSampleRate = 44100.0 ;
3133constexpr int analogBlockSize = 128 ;
34+ constexpr std::array<double , 4 > analogResponseFrequencies { 0.0 , 100.0 , 1000.0 , 10000.0 };
3235
3336template <typename SampleType>
3437std::vector<SampleType> makeAnalogInput ()
@@ -47,6 +50,21 @@ void expectFiniteAnalogBuffer (const std::vector<SampleType>& buffer)
4750 for (auto sample : buffer)
4851 EXPECT_TRUE (std::isfinite (sample));
4952}
53+
54+ template <typename CoeffType>
55+ void expectFiniteAnalogResponse (const Complex<CoeffType>& response)
56+ {
57+ EXPECT_TRUE (std::isfinite (response.real ()));
58+ EXPECT_TRUE (std::isfinite (response.imag ()));
59+ EXPECT_TRUE (std::isfinite (std::abs (response)));
60+ }
61+
62+ template <typename FilterType>
63+ void expectFiniteAnalogResponses (const FilterType& filter)
64+ {
65+ for (auto frequency : analogResponseFrequencies)
66+ expectFiniteAnalogResponse (filter.getComplexResponse (frequency));
67+ }
5068} // namespace
5169
5270// ==============================================================================
@@ -107,6 +125,39 @@ TEST (AnalogFilterTests, TwoPoleProcessesFiniteOutput)
107125 expectFiniteAnalogBuffer (output);
108126}
109127
128+ TEST (AnalogFilterTests, TwoPoleComplexResponseCoversSupportedModes)
129+ {
130+ for (auto mode : { FilterMode::lowpass, FilterMode::highpass, FilterMode::bandpassCsg, FilterMode::bandpassCpg, FilterMode::bandstop, FilterMode::peak })
131+ {
132+ AnalogTwoPoleFilter<double > filter;
133+ filter.prepare (analogSampleRate, analogBlockSize);
134+ filter.setParameters (mode, 1000.0 , 0.65 , 0.0 , analogSampleRate);
135+
136+ expectFiniteAnalogResponses (filter);
137+ }
138+ }
139+
140+ TEST (AnalogFilterTests, TwoPoleComplexResponseMatchesModeShape)
141+ {
142+ AnalogTwoPoleFilter<double > lowpass;
143+ lowpass.prepare (analogSampleRate, analogBlockSize);
144+ lowpass.setParameters (FilterMode::lowpass, 1000.0 , 0.35 , 0.0 , analogSampleRate);
145+ EXPECT_GT (std::abs (lowpass.getComplexResponse (100.0 )), std::abs (lowpass.getComplexResponse (10000.0 )));
146+
147+ AnalogTwoPoleFilter<double > highpass;
148+ highpass.prepare (analogSampleRate, analogBlockSize);
149+ highpass.setParameters (FilterMode::highpass, 1000.0 , 0.35 , 0.0 , analogSampleRate);
150+ EXPECT_LT (std::abs (highpass.getComplexResponse (100.0 )), std::abs (highpass.getComplexResponse (10000.0 )));
151+
152+ AnalogTwoPoleFilter<double > bandpass;
153+ bandpass.prepare (analogSampleRate, analogBlockSize);
154+ bandpass.setParameters (FilterMode::bandpassCpg, 1000.0 , 0.75 , 0.0 , analogSampleRate);
155+
156+ const auto centerResponse = std::abs (bandpass.getComplexResponse (1000.0 ));
157+ EXPECT_GT (centerResponse, std::abs (bandpass.getComplexResponse (100.0 )));
158+ EXPECT_GT (centerResponse, std::abs (bandpass.getComplexResponse (10000.0 )));
159+ }
160+
110161TEST (AnalogFilterTests, VowelProcessesFiniteOutput)
111162{
112163 AnalogVowelFilter<float > filter;
@@ -121,6 +172,15 @@ TEST (AnalogFilterTests, VowelProcessesFiniteOutput)
121172 expectFiniteAnalogBuffer (output);
122173}
123174
175+ TEST (AnalogFilterTests, VowelComplexResponseIsFinite)
176+ {
177+ AnalogVowelFilter<double > filter;
178+ filter.prepare (analogSampleRate, analogBlockSize);
179+ filter.setParameters (0.5 , 0.75 , 0.0 , analogSampleRate);
180+
181+ expectFiniteAnalogResponses (filter);
182+ }
183+
124184TEST (AnalogFilterTests, Korg35ProcessesAllModes)
125185{
126186 const auto input = makeAnalogInput<float >();
@@ -138,6 +198,39 @@ TEST (AnalogFilterTests, Korg35ProcessesAllModes)
138198 }
139199}
140200
201+ TEST (AnalogFilterTests, Korg35ComplexResponseCoversAllModes)
202+ {
203+ for (auto mode : { FilterMode::lowpass, FilterMode::bandpassCsg, FilterMode::highpass })
204+ {
205+ AnalogKorg35Filter<double > filter;
206+ filter.prepare (analogSampleRate, analogBlockSize);
207+ filter.setParameters (mode, 1000.0 , 0.55 , 0.0 , analogSampleRate);
208+
209+ expectFiniteAnalogResponses (filter);
210+ }
211+ }
212+
213+ TEST (AnalogFilterTests, Korg35ComplexResponseMatchesModeShape)
214+ {
215+ AnalogKorg35Filter<double > lowpass;
216+ lowpass.prepare (analogSampleRate, analogBlockSize);
217+ lowpass.setParameters (FilterMode::lowpass, 1000.0 , 0.4 , 0.0 , analogSampleRate);
218+ EXPECT_GT (std::abs (lowpass.getComplexResponse (100.0 )), std::abs (lowpass.getComplexResponse (10000.0 )));
219+
220+ AnalogKorg35Filter<double > highpass;
221+ highpass.prepare (analogSampleRate, analogBlockSize);
222+ highpass.setParameters (FilterMode::highpass, 1000.0 , 0.4 , 0.0 , analogSampleRate);
223+ EXPECT_LT (std::abs (highpass.getComplexResponse (100.0 )), std::abs (highpass.getComplexResponse (10000.0 )));
224+
225+ AnalogKorg35Filter<double > bandpass;
226+ bandpass.prepare (analogSampleRate, analogBlockSize);
227+ bandpass.setParameters (FilterMode::bandpassCsg, 1000.0 , 0.55 , 0.0 , analogSampleRate);
228+
229+ const auto centerResponse = std::abs (bandpass.getComplexResponse (1000.0 ));
230+ EXPECT_GT (centerResponse, std::abs (bandpass.getComplexResponse (100.0 )));
231+ EXPECT_GT (centerResponse, std::abs (bandpass.getComplexResponse (10000.0 )));
232+ }
233+
141234TEST (AnalogFilterTests, MoogLadderProcessesRepresentativeModes)
142235{
143236 const auto input = makeAnalogInput<float >();
@@ -155,6 +248,48 @@ TEST (AnalogFilterTests, MoogLadderProcessesRepresentativeModes)
155248 }
156249}
157250
251+ TEST (AnalogFilterTests, MoogLadderComplexResponseCoversAllModes)
252+ {
253+ for (auto mode : { AnalogMoogLadderMode::lowpass24,
254+ AnalogMoogLadderMode::highpass24,
255+ AnalogMoogLadderMode::lowpass18,
256+ AnalogMoogLadderMode::highpass18,
257+ AnalogMoogLadderMode::lowpass12,
258+ AnalogMoogLadderMode::highpass12,
259+ AnalogMoogLadderMode::lowpass6,
260+ AnalogMoogLadderMode::highpass6,
261+ AnalogMoogLadderMode::bandpass12,
262+ AnalogMoogLadderMode::bandpass6 })
263+ {
264+ AnalogMoogLadderFilter<double > filter;
265+ filter.prepare (analogSampleRate, analogBlockSize);
266+ filter.setParameters (mode, 1000.0 , 0.55 , 0.0 , analogSampleRate);
267+
268+ expectFiniteAnalogResponses (filter);
269+ }
270+ }
271+
272+ TEST (AnalogFilterTests, MoogLadderComplexResponseMatchesModeShape)
273+ {
274+ AnalogMoogLadderFilter<double > lowpass;
275+ lowpass.prepare (analogSampleRate, analogBlockSize);
276+ lowpass.setParameters (AnalogMoogLadderMode::lowpass24, 1000.0 , 0.4 , 0.0 , analogSampleRate);
277+ EXPECT_GT (std::abs (lowpass.getComplexResponse (100.0 )), std::abs (lowpass.getComplexResponse (10000.0 )));
278+
279+ AnalogMoogLadderFilter<double > highpass;
280+ highpass.prepare (analogSampleRate, analogBlockSize);
281+ highpass.setParameters (AnalogMoogLadderMode::highpass24, 1000.0 , 0.4 , 0.0 , analogSampleRate);
282+ EXPECT_LT (std::abs (highpass.getComplexResponse (100.0 )), std::abs (highpass.getComplexResponse (10000.0 )));
283+
284+ AnalogMoogLadderFilter<double > bandpass;
285+ bandpass.prepare (analogSampleRate, analogBlockSize);
286+ bandpass.setParameters (AnalogMoogLadderMode::bandpass12, 1000.0 , 0.55 , 0.0 , analogSampleRate);
287+
288+ const auto centerResponse = std::abs (bandpass.getComplexResponse (1000.0 ));
289+ EXPECT_GT (centerResponse, std::abs (bandpass.getComplexResponse (100.0 )));
290+ EXPECT_GT (centerResponse, std::abs (bandpass.getComplexResponse (10000.0 )));
291+ }
292+
158293TEST (AnalogFilterTests, RolandDiodeProcessesFiniteOutput)
159294{
160295 AnalogRolandDiodeFilter<float > filter;
@@ -169,6 +304,16 @@ TEST (AnalogFilterTests, RolandDiodeProcessesFiniteOutput)
169304 expectFiniteAnalogBuffer (output);
170305}
171306
307+ TEST (AnalogFilterTests, RolandDiodeComplexResponseIsFiniteAndLowpass)
308+ {
309+ AnalogRolandDiodeFilter<double > filter;
310+ filter.prepare (analogSampleRate, analogBlockSize);
311+ filter.setParameters (1000.0 , 0.45 , 0.0 , analogSampleRate);
312+
313+ expectFiniteAnalogResponses (filter);
314+ EXPECT_GT (std::abs (filter.getComplexResponse (100.0 )), std::abs (filter.getComplexResponse (10000.0 )));
315+ }
316+
172317TEST (AnalogFilterTests, ResetRestoresDeterministicState)
173318{
174319 AnalogMoogLadderFilter<float > filter;
0 commit comments