Little speed improvement
[calf.git] / src / benchmark.cpp
blob69cf3fe5fa9d0b72e1e2e01192fdad4c053c4822
1 /* Calf DSP Library
2 * Benchmark for selected parts of the library.
3 * Copyright (C) 2007 Krzysztof Foltman
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301 USA
21 #define BENCHMARK_PLUGINS
23 #ifdef BENCHMARK_PLUGINS
24 #include <calf/giface.h>
25 #include <calf/modules_tools.h>
26 #include <calf/modules_delay.h>
27 #include <calf/modules_comp.h>
28 #include <calf/modules_dev.h>
29 #include <calf/modules_filter.h>
30 #include <calf/modules_mod.h>
31 #else
32 #include <config.h>
33 #endif
35 #include <calf/audio_fx.h>
36 #include <calf/fft.h>
37 #include <calf/loudness.h>
38 #include <calf/benchmark.h>
39 #include <getopt.h>
41 // #define TEST_OSC
43 using namespace std;
44 using namespace dsp;
46 #ifdef TEST_OSC
47 #include <calf/osctl.h>
48 #include <calf/osctlnet.h>
49 #include <calf/osctl_glib.h>
50 using namespace osctl;
51 #endif
53 bool benchmark_globals::warned = false;
55 template<int BUF_SIZE>
56 struct empty_benchmark
58 void prepare()
61 void cleanup()
64 double scaler() { return BUF_SIZE; }
67 template<class filter_class>
68 struct filter_lp24dB_benchmark
70 enum { BUF_SIZE = 256 };
71 float buffer[BUF_SIZE];
72 float result;
73 filter_class biquad, biquad2;
74 void prepare()
76 for (int i = 0; i < BUF_SIZE; i++)
77 buffer[i] = i;
78 biquad.set_lp_rbj(2000, 0.7, 44100);
79 biquad2.set_lp_rbj(2000, 0.7, 44100);
80 result = 0;
82 void cleanup() { result = buffer[BUF_SIZE - 1]; }
83 double scaler() { return BUF_SIZE; }
86 struct filter_24dB_lp_twopass_d1: public filter_lp24dB_benchmark<biquad_d1>
88 void run()
90 for (int i = 0; i < BUF_SIZE; i++)
91 buffer[i] = biquad.process(buffer[i]);
92 for (int i = 0; i < BUF_SIZE; i++)
93 buffer[i] = biquad2.process(buffer[i]);
97 struct filter_24dB_lp_onepass_d1: public filter_lp24dB_benchmark<biquad_d1>
99 void run()
101 for (int i = 0; i < BUF_SIZE; i++)
102 buffer[i] = biquad2.process(biquad.process(buffer[i]));
106 struct filter_12dB_lp_d1: public filter_lp24dB_benchmark<biquad_d1>
108 void run()
110 for (int i = 0; i < BUF_SIZE; i++)
111 buffer[i] = biquad.process(buffer[i]);
115 struct filter_24dB_lp_twopass_d2: public filter_lp24dB_benchmark<biquad_d2 >
117 void run()
119 for (int i = 0; i < BUF_SIZE; i++)
120 buffer[i] = biquad.process(buffer[i]);
121 for (int i = 0; i < BUF_SIZE; i++)
122 buffer[i] = biquad2.process(buffer[i]);
126 struct filter_24dB_lp_onepass_d2: public filter_lp24dB_benchmark<biquad_d2 >
128 void run()
130 for (int i = 0; i < BUF_SIZE; i++)
131 buffer[i] = biquad2.process(biquad.process(buffer[i]));
135 struct filter_24dB_lp_onepass_d2_lp: public filter_lp24dB_benchmark<biquad_d2 >
137 void run()
139 for (int i = 0; i < BUF_SIZE; i++)
140 buffer[i] = biquad2.process_lp(biquad.process_lp(buffer[i]));
144 struct filter_12dB_lp_d2: public filter_lp24dB_benchmark<biquad_d2 >
146 void run()
148 for (int i = 0; i < BUF_SIZE; i++)
149 buffer[i] = biquad.process(buffer[i]);
153 template<int N>
154 struct fft_test_class
156 typedef fft<float, N> fft_class;
157 fft_class ffter;
158 float result;
159 complex<float> data[1 << N], output[1 << N];
160 void prepare() {
161 for (int i = 0; i < (1 << N); i++)
162 data[i] = sin(i);
163 result = 0;
165 void cleanup()
168 void run()
170 ffter.calculate(data, output, false);
172 double scaler() { return 1 << N; }
175 #define ALIGN_TEST_RUN 1024
177 struct __attribute__((aligned(8))) alignment_test: public empty_benchmark<ALIGN_TEST_RUN>
179 char __attribute__((aligned(8))) data[ALIGN_TEST_RUN * sizeof(double) + sizeof(double)];
180 float result;
182 virtual double *get_ptr()=0;
183 virtual ~alignment_test() {}
184 void prepare()
186 memset(data, 0, sizeof(data));
187 result = 0;
189 void cleanup()
191 result = 0;
192 double *p = get_ptr();
193 for (int i=0; i < ALIGN_TEST_RUN; i++)
194 result += p[i];
198 struct aligned_double: public alignment_test
200 virtual double *get_ptr() { return (double *)data; }
201 void run()
203 double *ptr = (double *)data;
204 for (int i=0; i < ALIGN_TEST_RUN; i++)
205 ptr[i] += 1 + i;
209 struct __attribute__((aligned(8))) misaligned_double: public alignment_test
211 virtual double *get_ptr() { return (double *)(data+4); }
212 void run()
214 double *ptr = (double *)(data + 4);
215 for (int i=0; i < ALIGN_TEST_RUN; i++)
216 ptr[i] += 1 + i;
220 const char *unit = NULL;
222 static struct option long_options[] = {
223 {"help", 0, 0, 'h'},
224 {"version", 0, 0, 'v'},
225 {"unit", 1, 0, 'u'},
226 {0,0,0,0},
229 void biquad_test()
231 do_simple_benchmark<filter_24dB_lp_twopass_d1>();
232 do_simple_benchmark<filter_24dB_lp_onepass_d1>();
233 do_simple_benchmark<filter_12dB_lp_d1>();
234 do_simple_benchmark<filter_24dB_lp_twopass_d2>();
235 do_simple_benchmark<filter_24dB_lp_onepass_d2>();
236 do_simple_benchmark<filter_24dB_lp_onepass_d2_lp>();
237 do_simple_benchmark<filter_12dB_lp_d2>();
240 void fft_test()
242 do_simple_benchmark<fft_test_class<17> >(5, 10);
245 void alignment_test()
247 do_simple_benchmark<misaligned_double>();
248 do_simple_benchmark<aligned_double>();
251 #ifdef BENCHMARK_PLUGINS
252 template<class Effect>
253 void get_default_effect_params(float params[Effect::param_count], uint32_t &sr);
255 template<>
256 void get_default_effect_params<calf_plugins::reverb_audio_module>(float params[3], uint32_t &sr)
258 typedef calf_plugins::reverb_audio_module mod;
259 params[mod::par_decay] = 4;
260 params[mod::par_hfdamp] = 2000;
261 params[mod::par_amount] = 2;
262 sr = 4000;
265 template<>
266 void get_default_effect_params<calf_plugins::filter_audio_module>(float params[4], uint32_t &sr)
268 typedef calf_plugins::filter_audio_module mod;
269 params[mod::par_cutoff] = 500;
270 params[mod::par_resonance] = 3;
271 params[mod::par_mode] = 2;
272 params[mod::par_inertia] = 16;
273 sr = 4000;
276 template<>
277 void get_default_effect_params<calf_plugins::flanger_audio_module>(float params[5], uint32_t &sr)
279 typedef calf_plugins::flanger_audio_module mod;
280 params[mod::par_delay] = 1;
281 params[mod::par_depth] = 2;
282 params[mod::par_rate] = 1;
283 params[mod::par_fb] = 0.9;
284 params[mod::par_amount] = 0.9;
285 sr = 44100;
288 template<>
289 void get_default_effect_params<calf_plugins::compressor_audio_module>(float params[], uint32_t &sr)
291 typedef calf_plugins::compressor_audio_module mod;
292 params[mod::param_threshold] = 10;
293 params[mod::param_ratio] = 2;
294 params[mod::param_attack] = 0.1;
295 params[mod::param_release] = 100;
296 params[mod::param_makeup] = 1;
297 params[mod::param_stereo_link] = 1;
298 params[mod::param_detection] = 0;
299 params[mod::param_knee] = 40000;
300 params[mod::param_bypass] = 0;
301 sr = 44100;
304 template<>
305 void get_default_effect_params<calf_plugins::multichorus_audio_module>(float params[], uint32_t &sr)
307 typedef calf_plugins::multichorus_audio_module mod;
308 params[mod::par_delay] = 10;
309 params[mod::par_depth] = 10;
310 params[mod::par_rate] = 1;
311 params[mod::par_voices] = 6;
312 params[mod::par_stereo] = 180;
313 params[mod::par_vphase] = 20;
314 params[mod::par_amount] = 0.9;
315 sr = 44100;
318 template<class Effect, unsigned int bufsize = 256>
319 class effect_benchmark: public empty_benchmark<bufsize>
321 public:
322 Effect effect;
323 float inputs[Effect::in_count][bufsize];
324 float outputs[Effect::out_count][bufsize];
325 float result;
326 float params[Effect::param_count];
328 void prepare()
330 for (int b = 0; b < Effect::out_count; b++)
332 effect.outs[b] = outputs[b];
333 dsp::zero(outputs[b], bufsize);
335 for (int b = 0; b < Effect::in_count; b++)
337 effect.ins[b] = inputs[b];
338 for (unsigned int i = 0; i < bufsize; i++)
339 inputs[b][i] = (float)(10 + i*0.3f*(b+1));
341 for (int i = 0; i < Effect::param_count; i++)
342 effect.params[i] = &params[i];
343 ::get_default_effect_params<Effect>(params, effect.srate);
344 result = 0.f;
345 effect.activate();
347 void run()
349 effect.params_changed();
350 effect.process(0, bufsize, 3, 3);
352 void cleanup()
354 for (int b = 0; b < Effect::out_count; b++)
356 for (unsigned int i = 0; i < bufsize; i++)
357 result += outputs[b][i];
362 void effect_test()
364 dsp::do_simple_benchmark<effect_benchmark<calf_plugins::flanger_audio_module> >(5, 10000);
365 dsp::do_simple_benchmark<effect_benchmark<calf_plugins::reverb_audio_module> >(5, 1000);
366 dsp::do_simple_benchmark<effect_benchmark<calf_plugins::filter_audio_module> >(5, 10000);
367 dsp::do_simple_benchmark<effect_benchmark<calf_plugins::compressor_audio_module> >(5, 10000);
368 dsp::do_simple_benchmark<effect_benchmark<calf_plugins::multichorus_audio_module> >(5, 10000);
371 #else
372 void effect_test()
374 printf("Test temporarily removed due to refactoring\n");
376 #endif
377 void reverbir_calc()
379 enum { LEN = 1048576 };
380 static float data[2][LEN];
382 for (int t = 1; t < 38; t++)
384 dsp::reverb rvb;
386 memset(data, 0, sizeof(data));
387 data[0][0] = 1;
388 data[1][0] = 0;
390 rvb.set_cutoff(22000);
391 rvb.setup(44100);
392 rvb.reset();
393 rvb.set_fb(t < 19 ? t * 0.05 : 0.905 + (t - 19) * 0.005);
395 for (int i = 0; i < LEN; i++)
396 rvb.process(data[0][i], data[1][i]);
398 int i;
399 for (i = LEN - 1; i > 0; i--)
401 // printf("[%d]=%f\n", i, data[0][i]);
402 if (fabs(data[0][i]) < 0.001 && fabs(data[1][i]) < 0.001)
403 continue;
404 break;
406 if (i < LEN - 1)
407 printf("%f\t%f\n", rvb.get_fb(), i / 44100.0);
411 void eq_calc()
413 biquad_coeffs bqc;
414 bqc.set_lowshelf_rbj(2000, 2.0, 4.0, 10000);
415 for (int i = 0; i <= 5000; i += 100)
417 printf("%d %f\n", i, bqc.freq_gain(i * 1.0, 10000));
421 void aweighting_calc()
423 aweighter aw;
424 float fs = 44100;
425 aw.set(fs);
426 for (int i = 10; i < 20000; i += 10)
428 printf("%d %f\n", i, 20*log10(aw.freq_gain(i * 1.0, fs)));
432 #ifdef TEST_OSC
434 struct my_sink: public osc_message_sink<osc_strstream>
436 GMainLoop *loop;
437 osc_message_dump<osc_strstream, ostream> dump;
438 my_sink() : dump(cout) {}
439 virtual void receive_osc_message(std::string address, std::string type_tag, osc_strstream &buffer)
441 dump.receive_osc_message(address, type_tag, buffer);
442 assert(address == "/blah");
443 assert(type_tag == "bsii");
445 string_buffer blob;
446 string str;
447 uint32_t val1, val2;
448 buffer >> blob >> str >> val1 >> val2;
449 assert(blob.data == "123");
450 assert(str == "test");
451 assert(val1 == 1);
452 assert(val2 == 2);
453 g_main_loop_quit(loop);
458 void osctl_test()
460 string sdata = string("\000\000\000\003123\000test\000\000\000\000\000\000\000\001\000\000\000\002", 24);
461 string_buffer sb(sdata);
462 osc_strstream is(sb);
463 osc_inline_typed_strstream os;
465 string_buffer blob;
466 string str;
467 uint32_t val1, val2;
468 is >> blob >> str >> val1 >> val2;
469 assert(blob.data == "123");
470 assert(str == "test");
471 assert(val1 == 1);
472 assert(val2 == 2);
474 os << blob << str << val1 << val2;
475 assert(os.buf_data.data == sdata);
476 assert(os.buf_types.data == "bsii");
478 GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);
479 my_sink sink;
480 sink.loop = main_loop;
481 osc_server srv;
482 srv.sink = &sink;
483 srv.bind("0.0.0.0", 4541);
485 osc_client cli;
486 cli.bind("0.0.0.0", 0);
487 cli.set_addr("0.0.0.0", 4541);
488 if (!cli.send("/blah", os))
490 g_error("Could not send the OSC message");
493 g_main_loop_run(main_loop);
495 #endif
497 int main(int argc, char *argv[])
499 while(1) {
500 int option_index;
501 int c = getopt_long(argc, argv, "u:hv", long_options, &option_index);
502 if (c == -1)
503 break;
504 switch(c) {
505 case 'h':
506 case '?':
507 printf("Benchmark suite Calf plugin pack\nSyntax: %s [--help] [--version] [--unit biquad|alignment|effects]\n", argv[0]);
508 return 0;
509 case 'v':
510 printf("%s\n", PACKAGE_STRING);
511 return 0;
512 case 'u':
513 unit = optarg;
514 break;
518 #ifdef TEST_OSC
519 if (unit && !strcmp(unit, "osc"))
520 osctl_test();
521 #endif
523 if (!unit || !strcmp(unit, "biquad"))
524 biquad_test();
526 if (!unit || !strcmp(unit, "alignment"))
527 alignment_test();
529 if (!unit || !strcmp(unit, "effects"))
530 effect_test();
532 if (unit && !strcmp(unit, "reverbir"))
533 reverbir_calc();
535 if (unit && !strcmp(unit, "eq"))
536 eq_calc();
538 if (unit && !strcmp(unit, "aweighting"))
539 aweighting_calc();
541 if (!unit || !strcmp(unit, "fft"))
542 fft_test();
544 return 0;