+ LV2: add data access extension header (by Dave Robillard) to unbreak build
[calf.git] / src / benchmark.cpp
blobd09e1e91dc47135f09fe9218fd7a0e2a2df9dd05
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., 59 Temple Place, Suite 330,
18 * Boston, MA 02111-1307, USA.
20 #include <assert.h>
21 #include <getopt.h>
22 #include <stdint.h>
23 #include <stdlib.h>
24 #include <config.h>
25 #include <calf/audio_fx.h>
26 //#include <calf/giface.h>
27 //#include <calf/modules.h>
28 //#include <calf/modules_dev.h>
29 #include <calf/loudness.h>
30 #include <calf/benchmark.h>
32 // #define TEST_OSC
34 using namespace std;
35 using namespace dsp;
37 #ifdef TEST_OSC
38 #include <calf/osctl.h>
39 #include <calf/osctlnet.h>
40 using namespace osctl;
41 #endif
43 bool benchmark_globals::warned = false;
45 template<int BUF_SIZE>
46 struct empty_benchmark
48 void prepare()
51 void cleanup()
54 double scaler() { return BUF_SIZE; }
57 template<class filter_class>
58 struct filter_lp24dB_benchmark
60 enum { BUF_SIZE = 256 };
61 float buffer[BUF_SIZE];
62 float result;
63 filter_class biquad, biquad2;
64 void prepare()
66 for (int i = 0; i < BUF_SIZE; i++)
67 buffer[i] = i;
68 biquad.set_lp_rbj(2000, 0.7, 44100);
69 biquad2.set_lp_rbj(2000, 0.7, 44100);
70 result = 0;
72 void cleanup() { result = buffer[BUF_SIZE - 1]; }
73 double scaler() { return BUF_SIZE; }
76 struct filter_24dB_lp_twopass_d1: public filter_lp24dB_benchmark<biquad_d1<> >
78 void run()
80 for (int i = 0; i < BUF_SIZE; i++)
81 buffer[i] = biquad.process(buffer[i]);
82 for (int i = 0; i < BUF_SIZE; i++)
83 buffer[i] = biquad2.process(buffer[i]);
87 struct filter_24dB_lp_onepass_d1: public filter_lp24dB_benchmark<biquad_d1<> >
89 void run()
91 for (int i = 0; i < BUF_SIZE; i++)
92 buffer[i] = biquad2.process(biquad.process(buffer[i]));
96 struct filter_12dB_lp_d1: public filter_lp24dB_benchmark<biquad_d1<> >
98 void run()
100 for (int i = 0; i < BUF_SIZE; i++)
101 buffer[i] = biquad.process(buffer[i]);
105 struct filter_24dB_lp_twopass_d2: public filter_lp24dB_benchmark<biquad_d2<> >
107 void run()
109 for (int i = 0; i < BUF_SIZE; i++)
110 buffer[i] = biquad.process(buffer[i]);
111 for (int i = 0; i < BUF_SIZE; i++)
112 buffer[i] = biquad2.process(buffer[i]);
116 struct filter_24dB_lp_onepass_d2: public filter_lp24dB_benchmark<biquad_d2<> >
118 void run()
120 for (int i = 0; i < BUF_SIZE; i++)
121 buffer[i] = biquad2.process(biquad.process(buffer[i]));
125 struct filter_24dB_lp_onepass_d2_lp: public filter_lp24dB_benchmark<biquad_d2<> >
127 void run()
129 for (int i = 0; i < BUF_SIZE; i++)
130 buffer[i] = biquad2.process_lp(biquad.process_lp(buffer[i]));
134 struct filter_12dB_lp_d2: public filter_lp24dB_benchmark<biquad_d2<> >
136 void run()
138 for (int i = 0; i < BUF_SIZE; i++)
139 buffer[i] = biquad.process(buffer[i]);
143 #define ALIGN_TEST_RUN 1024
145 struct __attribute__((aligned(8))) alignment_test: public empty_benchmark<ALIGN_TEST_RUN>
147 char __attribute__((aligned(8))) data[ALIGN_TEST_RUN * sizeof(double) + sizeof(double)];
148 float result;
150 virtual double *get_ptr()=0;
151 virtual ~alignment_test() {}
152 void prepare()
154 memset(data, 0, sizeof(data));
155 result = 0;
157 void cleanup()
159 result = 0;
160 double *p = get_ptr();
161 for (int i=0; i < ALIGN_TEST_RUN; i++)
162 result += p[i];
166 struct aligned_double: public alignment_test
168 virtual double *get_ptr() { return (double *)data; }
169 void run()
171 double *ptr = (double *)data;
172 for (int i=0; i < ALIGN_TEST_RUN; i++)
173 ptr[i] += 1 + i;
177 struct __attribute__((aligned(8))) misaligned_double: public alignment_test
179 virtual double *get_ptr() { return (double *)(data+4); }
180 void run()
182 double *ptr = (double *)(data + 4);
183 for (int i=0; i < ALIGN_TEST_RUN; i++)
184 ptr[i] += 1 + i;
188 const char *unit = NULL;
190 static struct option long_options[] = {
191 {"help", 0, 0, 'h'},
192 {"version", 0, 0, 'v'},
193 {"unit", 1, 0, 'u'},
194 {0,0,0,0},
197 void biquad_test()
199 do_simple_benchmark<filter_24dB_lp_twopass_d1>();
200 do_simple_benchmark<filter_24dB_lp_onepass_d1>();
201 do_simple_benchmark<filter_12dB_lp_d1>();
202 do_simple_benchmark<filter_24dB_lp_twopass_d2>();
203 do_simple_benchmark<filter_24dB_lp_onepass_d2>();
204 do_simple_benchmark<filter_24dB_lp_onepass_d2_lp>();
205 do_simple_benchmark<filter_12dB_lp_d2>();
208 void alignment_test()
210 do_simple_benchmark<misaligned_double>();
211 do_simple_benchmark<aligned_double>();
214 #if 0
215 template<class Effect>
216 void get_default_effect_params(float params[Effect::param_count], uint32_t &sr);
218 template<>
219 void get_default_effect_params<synth::reverb_audio_module>(float params[3], uint32_t &sr)
221 typedef synth::reverb_audio_module mod;
222 params[mod::par_decay] = 4;
223 params[mod::par_hfdamp] = 2000;
224 params[mod::par_amount] = 2;
225 sr = 4000;
228 template<>
229 void get_default_effect_params<synth::filter_audio_module>(float params[4], uint32_t &sr)
231 typedef synth::filter_audio_module mod;
232 params[mod::par_cutoff] = 500;
233 params[mod::par_resonance] = 3;
234 params[mod::par_mode] = 2;
235 params[mod::par_inertia] = 16;
236 sr = 4000;
239 template<>
240 void get_default_effect_params<synth::flanger_audio_module>(float params[5], uint32_t &sr)
242 typedef synth::flanger_audio_module mod;
243 params[mod::par_delay] = 1;
244 params[mod::par_depth] = 2;
245 params[mod::par_rate] = 1;
246 params[mod::par_fb] = 0.9;
247 params[mod::par_amount] = 0.9;
248 sr = 44100;
251 template<class Effect, unsigned int bufsize = 256>
252 class effect_benchmark: public empty_benchmark<bufsize>
254 public:
255 Effect effect;
256 float inputs[Effect::in_count][bufsize];
257 float outputs[Effect::out_count][bufsize];
258 float result;
259 float params[Effect::param_count];
261 void prepare()
263 for (int b = 0; b < Effect::out_count; b++)
265 effect.outs[b] = outputs[b];
266 dsp::zero(outputs[b], bufsize);
268 for (int b = 0; b < Effect::in_count; b++)
270 effect.ins[b] = inputs[b];
271 for (unsigned int i = 0; i < bufsize; i++)
272 inputs[b][i] = (float)(10 + i*0.3f*(b+1));
274 for (int i = 0; i < Effect::param_count; i++)
275 effect.params[i] = &params[i];
276 ::get_default_effect_params<Effect>(params, effect.srate);
277 result = 0.f;
278 effect.activate();
280 void run()
282 effect.params_changed();
283 effect.process(0, bufsize, 3, 3);
285 void cleanup()
287 for (int b = 0; b < Effect::out_count; b++)
289 for (unsigned int i = 0; i < bufsize; i++)
290 result += outputs[b][i];
295 void effect_test()
297 dsp::do_simple_benchmark<effect_benchmark<synth::flanger_audio_module> >(5, 10000);
298 dsp::do_simple_benchmark<effect_benchmark<synth::reverb_audio_module> >(5, 1000);
299 dsp::do_simple_benchmark<effect_benchmark<synth::filter_audio_module> >(5, 10000);
302 #else
303 void effect_test()
305 printf("Test temporarily removed due to refactoring\n");
307 #endif
308 void reverbir_calc()
310 enum { LEN = 1048576 };
311 static float data[2][LEN];
313 for (int t = 1; t < 38; t++)
315 dsp::reverb<float> rvb;
317 memset(data, 0, sizeof(data));
318 data[0][0] = 1;
319 data[1][0] = 0;
321 rvb.set_cutoff(22000);
322 rvb.setup(44100);
323 rvb.reset();
324 rvb.set_fb(t < 19 ? t * 0.05 : 0.905 + (t - 19) * 0.005);
326 for (int i = 0; i < LEN; i++)
327 rvb.process(data[0][i], data[1][i]);
329 int i;
330 for (i = LEN - 1; i > 0; i--)
332 // printf("[%d]=%f\n", i, data[0][i]);
333 if (fabs(data[0][i]) < 0.001 && fabs(data[1][i]) < 0.001)
334 continue;
335 break;
337 if (i < LEN - 1)
338 printf("%f\t%f\n", rvb.get_fb(), i / 44100.0);
342 void eq_calc()
344 biquad_coeffs<float> bqc;
345 bqc.set_lowshelf_rbj(2000, 2.0, 4.0, 10000);
346 for (int i = 0; i <= 5000; i += 100)
348 printf("%d %f\n", i, bqc.freq_gain(i * 1.0, 10000));
352 void aweighting_calc()
354 aweighter aw;
355 float fs = 44100;
356 aw.set(fs);
357 for (int i = 10; i < 20000; i += 10)
359 printf("%d %f\n", i, 20*log10(aw.freq_gain(i * 1.0, fs)));
363 #ifdef TEST_OSC
365 struct my_sink: public osc_message_sink<osc_strstream>
367 GMainLoop *loop;
368 osc_message_dump<osc_strstream, ostream> dump;
369 my_sink() : dump(cout) {}
370 virtual void receive_osc_message(std::string address, std::string type_tag, osc_strstream &buffer)
372 dump.receive_osc_message(address, type_tag, buffer);
373 assert(address == "/blah");
374 assert(type_tag == "bsii");
376 string_buffer blob;
377 string str;
378 uint32_t val1, val2;
379 buffer >> blob >> str >> val1 >> val2;
380 assert(blob.data == "123");
381 assert(str == "test");
382 assert(val1 == 1);
383 assert(val2 == 2);
384 g_main_loop_quit(loop);
389 void osctl_test()
391 string sdata = string("\000\000\000\003123\000test\000\000\000\000\000\000\000\001\000\000\000\002", 24);
392 string_buffer sb(sdata);
393 osc_strstream is(sb);
394 osc_inline_typed_strstream os;
396 string_buffer blob;
397 string str;
398 uint32_t val1, val2;
399 is >> blob >> str >> val1 >> val2;
400 assert(blob.data == "123");
401 assert(str == "test");
402 assert(val1 == 1);
403 assert(val2 == 2);
405 os << blob << str << val1 << val2;
406 assert(os.buf_data.data == sdata);
407 assert(os.buf_types.data == "bsii");
409 GMainLoop *main_loop = g_main_loop_new(NULL, FALSE);
410 my_sink sink;
411 sink.loop = main_loop;
412 osc_server srv;
413 srv.sink = &sink;
414 srv.bind("0.0.0.0", 4541);
416 osc_client cli;
417 cli.bind("0.0.0.0", 0);
418 cli.set_addr("0.0.0.0", 4541);
419 if (!cli.send("/blah", os))
421 g_error("Could not send the OSC message");
424 g_main_loop_run(main_loop);
426 #endif
428 int main(int argc, char *argv[])
430 while(1) {
431 int option_index;
432 int c = getopt_long(argc, argv, "u:hv", long_options, &option_index);
433 if (c == -1)
434 break;
435 switch(c) {
436 case 'h':
437 case '?':
438 printf("Benchmark suite Calf plugin pack\nSyntax: %s [--help] [--version] [--unit biquad|alignment|effects]\n", argv[0]);
439 return 0;
440 case 'v':
441 printf("%s\n", PACKAGE_STRING);
442 return 0;
443 case 'u':
444 unit = optarg;
445 break;
449 #ifdef TEST_OSC
450 if (unit && !strcmp(unit, "osc"))
451 osctl_test();
452 #endif
454 if (!unit || !strcmp(unit, "biquad"))
455 biquad_test();
457 if (!unit || !strcmp(unit, "alignment"))
458 alignment_test();
460 if (!unit || !strcmp(unit, "effects"))
461 effect_test();
463 if (unit && !strcmp(unit, "reverbir"))
464 reverbir_calc();
466 if (unit && !strcmp(unit, "eq"))
467 eq_calc();
469 if (unit && !strcmp(unit, "aweighting"))
470 aweighting_calc();
472 return 0;