1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /***************************************************************************
3  *            lv2.cc
4  *
5  *  Thu Feb 12 14:55:41 CET 2015
6  *  Copyright 2015 Bent Bisballe Nyeng
7  *  deva@aasimon.org
8  ****************************************************************************/
9 
10 /*
11  *  This file is part of DrumGizmo.
12  *
13  *  DrumGizmo is free software; you can redistribute it and/or modify
14  *  it under the terms of the GNU Lesser General Public License as published by
15  *  the Free Software Foundation; either version 3 of the License, or
16  *  (at your option) any later version.
17  *
18  *  DrumGizmo is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  *  GNU Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public License
24  *  along with DrumGizmo; if not, write to the Free Software
25  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
26  */
27 #include <uunit.h>
28 
29 #include <config.h>
30 
31 #include <thread>
32 #include <chrono>
33 #include <memory.h>
34 #include <stdio.h>
35 #include <arpa/inet.h>
36 
37 #include "drumkit_creator.h"
38 #include "lv2_test_host.h"
39 
40 #define DG_URI "http://drumgizmo.org/lv2"
41 
42 enum class Ports {
43 	FreeWheel = 0,
44 	Latency,
45 	MidiPort,
46 	AudioPortOffset,
47 };
48 
49 /**
50  * Tests that should be performed:
51  * -------------------------------
52  * - Run without port connects (shouldn't crash)
53  * - Run without output ports connects (shouldn't crash)
54  * - Run with buffer size 0
55  * - Run with VERY LARGE buffer size (>1MB?)
56  * - Run with buffer size a prime number (and thereby not power of 2)
57  * - Run with HUGE number of midi events in one buffer (10000)
58  */
59 class test_lv2 : public uUnit
60 {
61 public:
test_lv2()62 	test_lv2()
63 	{
64 		uUNIT_TEST(test_lv2::open_and_verify);
65 		uUNIT_TEST(test_lv2::run_no_ports_connected);
66 		uUNIT_TEST(test_lv2::run_no_output_ports_connected);
67 		uUNIT_TEST(test_lv2::test1);
68 	}
69 
70 	DrumkitCreator drumkit_creator;
71 
open_and_verify()72 	void open_and_verify()
73 	{
74 		int res;
75 
76 		LV2TestHost h(LV2_PATH);
77 
78 		res = h.open(DG_URI);
79 		uUNIT_ASSERT_EQUAL(0, res);
80 
81 		res = h.verify();
82 		uUNIT_ASSERT_EQUAL(0, res);
83 
84 		res = h.close();
85 		uUNIT_ASSERT_EQUAL(0, res);
86 	}
87 
run_no_ports_connected()88 	void run_no_ports_connected()
89 	{
90 		int res;
91 
92 		LV2TestHost h(LV2_PATH);
93 
94 		res = h.open(DG_URI);
95 		uUNIT_ASSERT_EQUAL(0, res);
96 
97 		res = h.verify();
98 		uUNIT_ASSERT_EQUAL(0, res);
99 
100 		res = h.createInstance(44100);
101 		uUNIT_ASSERT_EQUAL(0, res);
102 
103 		const char config_fmt[] =
104 			"<config>\n"
105 			"  <value name=\"drumkitfile\">%s</value>\n"
106 			"  <value name=\"midimapfile\">%s</value>\n"
107 			"  <value name=\"enable_velocity_modifier\">%s</value>\n"
108 			"  <value name=\"velocity_modifier_falloff\">%f</value>\n"
109 			"  <value name=\"velocity_modifier_weight\">%f</value>\n"
110 			"  <value name=\"enable_velocity_randomiser\">%s</value>\n"
111 			"  <value name=\"velocity_randomiser_weight\">%f</value>\n"
112 			"  <value name=\"enable_resampling\">%s</value>\n"
113 			"  <value name=\"enable_resampling\">%s</value>\n"
114 			"  <value name=\"disk_cache_upper_limit\">%d</value>\n"
115 			"  <value name=\"disk_cache_chunk_size\">%d</value>\n"
116 			"  <value name=\"disk_cache_enable\">%s</value>\n"
117 			"  <value name=\"enable_bleed_control\">%s</value>\n"
118 			"  <value name=\"master_bleed\">%f</value>\n"
119 			"  <value name=\"enable_latency_modifier\">%s</value>\n"
120 			"  <value name=\"latency_max\">%d</value>\n"
121 			"  <value name=\"latency_laid_back\">%d</value>\n"
122 			"  <value name=\"latency_stddev\">%f</value>\n"
123 			"  <value name=\"latency_regain\">%f</value>\n"
124 			"</config>";
125 
126 		// Create drumkit
127 		auto kit1_file = drumkit_creator.createStdKit("kit1");
128 
129 		auto midimapfile = drumkit_creator.createStdMidimap("midimap");
130 		bool enable_velocity_modifier = true;
131 		float velocity_modifier_falloff = 0.5;
132 		float velocity_modifier_weight = 0.25;
133 		bool enable_velocity_randomiser = false;
134 		float velocity_randomiser_weight = 0.1;
135 		bool enable_resampling = false;
136 		int disk_cache_upper_limit = 1024 * 1024;
137 		int disk_cache_chunk_size = 1024 * 1024 * 1024;
138 		bool disk_cache_enable = true;
139 		bool enable_bleed_control = false;
140 		float master_bleed = 1.0f;
141 		bool enable_latency_modifier = false;
142 		int latency_max = 0u;
143 		int latency_laid_back = 0u;
144 		float latency_stddev = 100.0f;
145 		float latency_regain = 0.9f;
146 
147 		char config[sizeof(config_fmt) * 2];
148 		sprintf(config, config_fmt,
149 		        kit1_file.c_str(),
150 		        midimapfile.c_str(),
151 		        enable_velocity_modifier?"true":"false",
152 		        velocity_modifier_falloff,
153 		        velocity_modifier_weight,
154 		        enable_velocity_randomiser?"true":"false",
155 		        velocity_randomiser_weight,
156 		        enable_resampling?"true":"false",
157 		        enable_resampling?"true":"false",
158 		        disk_cache_upper_limit,
159 		        disk_cache_chunk_size,
160 		        disk_cache_enable?"true":"false",
161 		        enable_bleed_control?"true":"false",
162 		        master_bleed,
163 		        enable_latency_modifier?"true":"false",
164 		        latency_max,
165 		        latency_laid_back,
166 		        latency_stddev,
167 		        latency_regain);
168 
169 		res = h.loadConfig(config, strlen(config));
170 		uUNIT_ASSERT_EQUAL(0, res);
171 
172 		// run for 1 samples to trigger kit loading
173 		res = h.run(1);
174 		uUNIT_ASSERT_EQUAL(0, res);
175 		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // wait for kit to get loaded (async),
176 
177 		res = h.run(100);
178 		uUNIT_ASSERT_EQUAL(0, res);
179 
180 		res = h.destroyInstance();
181 		uUNIT_ASSERT_EQUAL(0, res);
182 
183 		res = h.close();
184 		uUNIT_ASSERT_EQUAL(0, res);
185 	}
186 
run_no_output_ports_connected()187 	void run_no_output_ports_connected()
188 	{
189 		int res;
190 
191 		LV2TestHost h(LV2_PATH);
192 
193 		res = h.open(DG_URI);
194 		uUNIT_ASSERT_EQUAL(0, res);
195 
196 		res = h.verify();
197 		uUNIT_ASSERT_EQUAL(0, res);
198 
199 		res = h.createInstance(44100);
200 		uUNIT_ASSERT_EQUAL(0, res);
201 
202 		const char config_fmt[] =
203 			"<config>\n"
204 			"  <value name=\"drumkitfile\">%s</value>\n"
205 			"  <value name=\"midimapfile\">%s</value>\n"
206 			"  <value name=\"enable_velocity_modifier\">%s</value>\n"
207 			"  <value name=\"velocity_modifier_falloff\">%f</value>\n"
208 			"  <value name=\"velocity_modifier_weight\">%f</value>\n"
209 			"  <value name=\"enable_velocity_randomiser\">%s</value>\n"
210 			"  <value name=\"velocity_randomiser_weight\">%f</value>\n"
211 			"  <value name=\"enable_resampling\">%s</value>\n"
212 			"  <value name=\"enable_resampling\">%s</value>\n"
213 			"  <value name=\"disk_cache_upper_limit\">%d</value>\n"
214 			"  <value name=\"disk_cache_chunk_size\">%d</value>\n"
215 			"  <value name=\"disk_cache_enable\">%s</value>\n"
216 			"  <value name=\"enable_bleed_control\">%s</value>\n"
217 			"  <value name=\"master_bleed\">%f</value>\n"
218 			"  <value name=\"enable_latency_modifier\">%s</value>\n"
219 			"  <value name=\"latency_max\">%d</value>\n"
220 			"  <value name=\"latency_laid_back\">%d</value>\n"
221 			"  <value name=\"latency_stddev\">%f</value>\n"
222 			"  <value name=\"latency_regain\">%f</value>\n"
223 			"</config>";
224 
225 		// Create drumkit
226 		auto kit1_file = drumkit_creator.createStdKit("kit1");
227 
228 		auto midimapfile = drumkit_creator.createStdMidimap("midimap");
229 		bool enable_velocity_modifier = true;
230 		float velocity_modifier_falloff = 0.5;
231 		float velocity_modifier_weight = 0.25;
232 		bool enable_velocity_randomiser = false;
233 		float velocity_randomiser_weight = 0.1;
234 		bool enable_resampling = false;
235 		int disk_cache_upper_limit = 1024 * 1024;
236 		int disk_cache_chunk_size = 1024 * 1024 * 1024;
237 		bool disk_cache_enable = true;
238 		bool enable_bleed_control = false;
239 		float master_bleed = 1.0f;
240 		bool enable_latency_modifier = false;
241 		int latency_max = 0u;
242 		int latency_laid_back = 0u;
243 		float latency_stddev = 100.0f;
244 		float latency_regain = 0.9f;
245 
246 		char config[sizeof(config_fmt) * 2];
247 		sprintf(config, config_fmt,
248 		        kit1_file.c_str(),
249 		        midimapfile.c_str(),
250 		        enable_velocity_modifier?"true":"false",
251 		        velocity_modifier_falloff,
252 		        velocity_modifier_weight,
253 		        enable_velocity_randomiser?"true":"false",
254 		        velocity_randomiser_weight,
255 		        enable_resampling?"true":"false",
256 		        enable_resampling?"true":"false",
257 		        disk_cache_upper_limit,
258 		        disk_cache_chunk_size,
259 		        disk_cache_enable?"true":"false",
260 		        enable_bleed_control?"true":"false",
261 		        master_bleed,
262 		        enable_latency_modifier?"true":"false",
263 		        latency_max,
264 		        latency_laid_back,
265 		        latency_stddev,
266 		        latency_regain);
267 
268 		res = h.loadConfig(config, strlen(config));
269 		uUNIT_ASSERT_EQUAL(0, res);
270 
271 		// Port buffers:
272 		char sequence_buffer[4096];
273 		bool freeWheel = false;
274 
275 		// Free wheel port
276 		res = h.connectPort((int)Ports::FreeWheel, (void*)&freeWheel);
277 
278 		LV2TestHost::Sequence seq(sequence_buffer, sizeof(sequence_buffer));
279 		res = h.connectPort((int)Ports::MidiPort, seq.data());
280 		uUNIT_ASSERT_EQUAL(0, res);
281 
282 		// run for 1 samples to trigger kit loading
283 		res = h.run(1);
284 		uUNIT_ASSERT_EQUAL(0, res);
285 		std::this_thread::sleep_for(std::chrono::milliseconds(1)); // wait for kit to get loaded (async),
286 
287 		seq.addMidiNote(5, 1, 127);
288 		res = h.run(100);
289 		uUNIT_ASSERT_EQUAL(0, res);
290 
291 		res = h.destroyInstance();
292 		uUNIT_ASSERT_EQUAL(0, res);
293 
294 		res = h.close();
295 		uUNIT_ASSERT_EQUAL(0, res);
296 	}
297 
test1()298 	void test1()
299 	{
300 		int res;
301 
302 		LV2TestHost h(LV2_PATH);
303 
304 		res = h.open(DG_URI);
305 		uUNIT_ASSERT_EQUAL(0, res);
306 
307 		res = h.verify();
308 		uUNIT_ASSERT_EQUAL(0, res);
309 
310 		res = h.createInstance(44100);
311 		uUNIT_ASSERT_EQUAL(0, res);
312 
313 		const char config_fmt[] =
314 			"<config>\n"
315 			"  <value name=\"drumkitfile\">%s</value>\n"
316 			"  <value name=\"midimapfile\">%s</value>\n"
317 			"  <value name=\"enable_velocity_modifier\">%s</value>\n"
318 			"  <value name=\"velocity_modifier_falloff\">%f</value>\n"
319 			"  <value name=\"velocity_modifier_weight\">%f</value>\n"
320 			"  <value name=\"enable_velocity_randomiser\">%s</value>\n"
321 			"  <value name=\"velocity_randomiser_weight\">%f</value>\n"
322 			"  <value name=\"enable_resampling\">%s</value>\n"
323 			"  <value name=\"enable_resampling\">%s</value>\n"
324 			"  <value name=\"disk_cache_upper_limit\">%d</value>\n"
325 			"  <value name=\"disk_cache_chunk_size\">%d</value>\n"
326 			"  <value name=\"disk_cache_enable\">%s</value>\n"
327 			"  <value name=\"enable_bleed_control\">%s</value>\n"
328 			"  <value name=\"master_bleed\">%f</value>\n"
329 			"  <value name=\"enable_latency_modifier\">%s</value>\n"
330 			"  <value name=\"latency_max\">%d</value>\n"
331 			"  <value name=\"latency_laid_back\">%d</value>\n"
332 			"  <value name=\"latency_stddev\">%f</value>\n"
333 			"  <value name=\"latency_regain\">%f</value>\n"
334 			"</config>";
335 
336 		// Create drumkit
337 		auto kit1_file = drumkit_creator.createStdKit("kit1");
338 
339 		auto midimapfile = drumkit_creator.createStdMidimap("midimap");
340 		bool enable_velocity_modifier = true;
341 		float velocity_modifier_falloff = 0.5;
342 		float velocity_modifier_weight = 0.25;
343 		bool enable_velocity_randomiser = false;
344 		float velocity_randomiser_weight = 0.1;
345 		bool enable_resampling = false;
346 		int disk_cache_upper_limit = 1024 * 1024;
347 		int disk_cache_chunk_size = 1024 * 1024 * 1024;
348 		bool disk_cache_enable = true;
349 		bool enable_bleed_control = false;
350 		float master_bleed = 1.0f;
351 		bool enable_latency_modifier = false;
352 		int latency_max = 0u;
353 		int latency_laid_back = 0u;
354 		float latency_stddev = 100.0f;
355 		float latency_regain = 0.9f;
356 
357 		char config[sizeof(config_fmt) * 2];
358 		sprintf(config, config_fmt,
359 		        kit1_file.c_str(),
360 		        midimapfile.c_str(),
361 		        enable_velocity_modifier?"true":"false",
362 		        velocity_modifier_falloff,
363 		        velocity_modifier_weight,
364 		        enable_velocity_randomiser?"true":"false",
365 		        velocity_randomiser_weight,
366 		        enable_resampling?"true":"false",
367 		        enable_resampling?"true":"false",
368 		        disk_cache_upper_limit,
369 		        disk_cache_chunk_size,
370 		        disk_cache_enable?"true":"false",
371 		        enable_bleed_control?"true":"false",
372 		        master_bleed,
373 		        enable_latency_modifier?"true":"false",
374 		        latency_max,
375 		        latency_laid_back,
376 		        latency_stddev,
377 		        latency_regain);
378 
379 		res = h.loadConfig(config, strlen(config));
380 		uUNIT_ASSERT_EQUAL(0, res);
381 
382 		// Port buffers:
383 		char sequence_buffer[4096];
384 		float pcm_buffer[NUM_CHANNELS][10];
385 		bool freeWheel = true;
386 
387 		// Free wheel port
388 		res = h.connectPort((int)Ports::FreeWheel, (void*)&freeWheel);
389 
390 		LV2TestHost::Sequence seq(sequence_buffer, sizeof(sequence_buffer));
391 		res = h.connectPort((int)Ports::MidiPort, seq.data());
392 		uUNIT_ASSERT_EQUAL(0, res);
393 
394 		for(int i = 0; i < NUM_CHANNELS; ++i)
395 		{
396 			for(int j = 0; j < 10; ++j)
397 			{
398 				pcm_buffer[i][j] = 0.42;
399 			}
400 			res += h.connectPort((int)Ports::AudioPortOffset + i, pcm_buffer[i]);
401 		}
402 		uUNIT_ASSERT_EQUAL(0, res);
403 
404 		// run for 1 samples to trigger kit loading
405 		res = h.run(1);
406 		uUNIT_ASSERT_EQUAL(0, res);
407 		std::this_thread::sleep_for(std::chrono::seconds(1));  // wait for kit to get loaded (async),
408 
409 		seq.addMidiNote(5, 1, 127);
410 		for(int i = 0; i < 10; i++)
411 		{
412 			res = h.run(10);
413 			std::this_thread::sleep_for(std::chrono::milliseconds(1));
414 			uUNIT_ASSERT_EQUAL(0, res);
415 
416 			//printf("Iteration:\n");
417 			//for(int k = 0; k < 16; k++) {
418 			//	printf("#%d ", k);
419 			//	for(int j = 0; j < 10; j++) printf("[%f]", pcm_buffer[k][j]);
420 			//	printf("\n");
421 			//}
422 			//printf("\n");
423 
424 			seq.clear();
425 		}
426 
427 
428 		seq.addMidiNote(5, 1, 127);
429 		res = h.run(10);
430 		std::this_thread::sleep_for(std::chrono::milliseconds(1));
431 		uUNIT_ASSERT_EQUAL(0, res);
432 
433 		/*
434 		printf("Iteration:\n");
435 		for(int k = 0; k < 4; k++) {
436 			printf("#%d ", k);
437 			for(int j = 0; j < 10; j++) printf("[%f]", pcm_buffer[k][j]);
438 			printf("\n");
439 		}
440 		printf("\n");
441 		*/
442 
443 		union {
444 			float f;
445 			unsigned int u;
446 		} comp_val;
447 
448 		comp_val.u = 1040744448; // floating point value 0.133301....
449 
450 		for(int k = 0; k < 4; k++)
451 		{
452 			for(int j = 0; j < 10; j++)
453 			{
454 				uUNIT_ASSERT_EQUAL(((j==5)?comp_val.f:0), pcm_buffer[k][j]);
455 			}
456 		}
457 		seq.clear();
458 
459 		res = h.destroyInstance();
460 		uUNIT_ASSERT_EQUAL(0, res);
461 
462 		res = h.close();
463 		uUNIT_ASSERT_EQUAL(0, res);
464 	}
465 };
466 
467 // Registers the fixture into the 'registry'
468 static test_lv2 test;
469