+ Legal: use an up-to-date address of Free Software Foundation
[calf.git] / src / benchmark.cpp
blobffaa1adc3aa49edb553e4893fd23514eb2edba2d
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 #include <assert.h>
24 #include <getopt.h>
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <config.h>
29 #include <calf/audio_fx.h>
31 #ifdef BENCHMARK_PLUGINS
32 #include <calf/giface.h>
33 #include <calf/modules.h>
34 #include <calf/modules_dev.h>
35 #endif
37 #include <calf/loudness.h>
38 #include <calf/benchmark.h>
40 // #define TEST_OSC
42 using namespace std;
43 using namespace dsp;
45 #ifdef TEST_OSC
46 #include <calf/osctl.h>
47 #include <calf/osctlnet.h>
48 #include <calf/osctlserv.h>
49 using namespace osctl;
50 #endif
52 bool benchmark_globals::warned = false;
54 template<int BUF_SIZE>
55 struct empty_benchmark
57 void prepare()
60 void cleanup()
63 double scaler() { return BUF_SIZE; }
66 template<class filter_class>
67 struct filter_lp24dB_benchmark
69 enum { BUF_SIZE = 256 };
70 float buffer[BUF_SIZE];
71 float result;
72 filter_class biquad, biquad2;
73 void prepare()
75 for (int i = 0; i < BUF_SIZE; i++)
76 buffer[i] = i;
77 biquad.set_lp_rbj(2000, 0.7, 44100);
78 biquad2.set_lp_rbj(2000, 0.7, 44100);
79 result = 0;
81 void cleanup() { result = buffer[BUF_SIZE - 1]; }
82 double scaler() { return BUF_SIZE; }
85 struct filter_24dB_lp_twopass_d1: public filter_lp24dB_benchmark<biquad_d1<> >
87 void run()
89 for (int i = 0; i < BUF_SIZE; i++)
90 buffer[i] = biquad.process(buffer[i]);
91 for (int i = 0; i < BUF_SIZE; i++)
92 buffer[i] = biquad2.process(buffer[i]);
96 struct filter_24dB_lp_onepass_d1: public filter_lp24dB_benchmark<biquad_d1<> >
98 void run()
100 for (int i = 0; i < BUF_SIZE; i++)
101 buffer[i] = biquad2.process(biquad.process(buffer[i]));
105 struct filter_12dB_lp_d1: public filter_lp24dB_benchmark<biquad_d1<> >
107 void run()
109 for (int i = 0; i < BUF_SIZE; i++)
110 buffer[i] = biquad.process(buffer[i]);
114 struct filter_24dB_lp_twopass_d2: public filter_lp24dB_benchmark<biquad_d2<> >
116 void run()
118 for (int i = 0; i < BUF_SIZE; i++)
119 buffer[i] = biquad.process(buffer[i]);
120 for (int i = 0; i < BUF_SIZE; i++)
121 buffer[i] = biquad2.process(buffer[i]);
125 struct filter_24dB_lp_onepass_d2: public filter_lp24dB_benchmark<biquad_d2<> >
127 void run()
129 for (int i = 0; i < BUF_SIZE; i++)
130 buffer[i] = biquad2.process(biquad.process(buffer[i]));
134 struct filter_24dB_lp_onepass_d2_lp: public filter_lp24dB_benchmark<biquad_d2<> >
136 void run()
138 for (int i = 0; i < BUF_SIZE; i++)
139 buffer[i] = biquad2.process_lp(biquad.process_lp(buffer[i]));
143 struct filter_12dB_lp_d2: public filter_lp24dB_benchmark<biquad_d2<> >
145 void run()
147 for (int i = 0; i < BUF_SIZE; i++)
148 buffer[i] = biquad.process(buffer[i]);
152 template<int N>
153 struct fft_test_class
155 typedef fft<float, N> fft_class;
156 fft_class ffter;
157 float result;
158 complex<float> data[1 << N], output[1 << N];
159 void prepare() {
160 for (int i = 0; i < (1 << N); i++)
161 data[i] = sin(i);
162 result = 0;
164 void cleanup()
167 void run()
169 ffter.calculate(data, output, false);
171 double scaler() { return 1 << N; }
174 #define ALIGN_TEST_RUN 1024
176 struct __attribute__((aligned(8))) alignment_test: public empty_benchmark<ALIGN_TEST_RUN>
178 char __attribute__((aligned(8))) data[ALIGN_TEST_RUN * sizeof(double) + sizeof(double)];
179 float result;
181 virtual double *get_ptr()=0;
182 virtual ~alignment_test() {}
183 void prepare()
185 memset(data, 0, sizeof(data));
186 result = 0;
188 void cleanup()
190 result = 0;
191 double *p = get_ptr();
192 for (int i=0; i < ALIGN_TEST_RUN; i++)
193 result += p[i];
197 struct aligned_double: public alignment_test
199 virtual double *get_ptr() { return (double *)data; }
200 void run()
202 double *ptr = (double *)data;
203 for (int i=0; i < ALIGN_TEST_RUN; i++)
204 ptr[i] += 1 + i;
208 struct __attribute__((aligned(8))) misaligned_double: public alignment_test
210 virtual double *get_ptr() { return (double *)(data+4); }
211 void run()
213 double *ptr = (double *)(data + 4);
214 for (int i=0; i < ALIGN_TEST_RUN; i++)
215 ptr[i] += 1 + i;
219 const char *unit = NULL;
221 static struct option long_options[] = {
222 {"help", 0, 0, 'h'},
223 {"version", 0, 0, 'v'},
224 {"unit", 1, 0, 'u'},
225 {0,0,0,0},
228 void biquad_test()
230 do_simple_benchmark<filter_24dB_lp_twopass_d1>();
231 do_simple_benchmark<filter_24dB_lp_onepass_d1>();
232 do_simple_benchmark<filter_12dB_lp_d1>();
233 do_simple_benchmark<filter_24dB_lp_twopass_d2>();
234 do_simple_benchmark<filter_24dB_lp_onepass_d2>();
235 do_simple_benchmark<filter_24dB_lp_onepass_d2_lp>();
236 do_simple_benchmark<filter_12dB_lp_d2>();
239 void fft_test()
241 do_simple_benchmark<fft_test_class<17> >(5, 10);
244 void alignment_test()
246 do_simple_benchmark<misaligned_double>();
247 do_simple_benchmark<aligned_double>();
250 #ifdef BENCHMARK_PLUGINS
251 template<class Effect>
252 void get_default_effect_params(float params[Effect::param_count], uint32_t &sr);
254 template<>
255 void get_default_effect_params<calf_plugins::reverb_audio_module>(float params[3], uint32_t &sr)
257 typedef calf_plugins::reverb_audio_module mod;
258 params[mod::par_decay] = 4;
259 params[mod::par_hfdamp] = 2000;
260 params[mod::par_amount] = 2;
261 sr = 4000;
264 template<>
265 void get_default_effect_params<calf_plugins::filter_audio_module>(float params[4], uint32_t &sr)
267 typedef calf_plugins::filter_audio_module mod;
268 params[mod::par_cutoff] = 500;
269 params[mod::par_resonance] = 3;
270 params[mod::par_mode] = 2;
271 params[mod::par_inertia] = 16;
272 sr = 4000;
275 template<>
276 void get_default_effect_params<calf_plugins::flanger_audio_module>(float params[5], uint32_t &sr)
278 typedef calf_plugins::flanger_audio_module mod;
279 params[mod::par_delay] = 1;
280 params[mod::par_depth] = 2;
281 params[mod::par_rate] = 1;
282 params[mod::par_fb] = 0.9;
283 params[mod::par_amount] = 0.9;
284 sr = 44100;
287 template<>
288 void get_default_effect_params<calf_plugins::compressor_audio_module>(float params[], uint32_t &sr)
290 typedef calf_plugins::compressor_audio_module mod;
291 params[mod::param_threshold] = 10;
292 params[mod::param_ratio] = 2;
293 params[mod::param_attack] = 0.1;
294 params[mod::param_release] = 100;
295 params[mod::param_makeup] = 1;
296 params[mod::param_stereo_link] = 1;
297 params[mod::param_detection] = 0;
298 params[mod::param_knee] = 40000;
299 params[mod::param_bypass] = 0;
300 params[mod::param_aweighting] = 1;
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<float> 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<float> 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;