1 //
2 // Copyright 2011-2012 Ettus Research LLC
3 // Copyright 2018 Ettus Research, a National Instruments Company
4 //
5 // SPDX-License-Identifier: GPL-3.0-or-later
6 //
7 
8 #include <uhd/convert.hpp>
9 #include <stdint.h>
10 #include <boost/test/unit_test.hpp>
11 #include <complex>
12 #include <cstdlib>
13 #include <iostream>
14 #include <vector>
15 
16 using namespace uhd;
17 
18 // typedefs for complex types
19 typedef std::complex<int16_t> sc16_t;
20 typedef std::complex<float> fc32_t;
21 typedef std::complex<double> fc64_t;
22 
23 #define MY_CHECK_CLOSE(a, b, f)                                                     \
24     {                                                                               \
25         BOOST_CHECK_MESSAGE(std::abs((a) - (b)) < f,                                \
26             "\n\t" << #a << " (" << (a) << ") error " << #b << " (" << (b) << ")"); \
27     }
28 
29 /***********************************************************************
30  * Loopback runner:
31  *    convert input buffer into intermediate buffer
32  *    convert intermediate buffer into output buffer
33  **********************************************************************/
34 template <typename Range>
loopback(size_t nsamps,convert::id_type & in_id,convert::id_type & out_id,const Range & input,Range & output,const int prio_in=-1,const int prio_out=-1)35 static void loopback(size_t nsamps,
36     convert::id_type& in_id,
37     convert::id_type& out_id,
38     const Range& input,
39     Range& output,
40     const int prio_in  = -1,
41     const int prio_out = -1)
42 {
43     // make this buffer large enough for all test types
44     std::vector<uint64_t> interm(nsamps);
45 
46     std::vector<const void*> input0(1, &input[0]), input1(1, &interm[0]);
47     std::vector<void*> output0(1, &interm[0]), output1(1, &output[0]);
48 
49     // convert to intermediate type
50     convert::converter::sptr c0 = convert::get_converter(in_id, prio_in)();
51     c0->set_scalar(32767.);
52     c0->conv(input0, output0, nsamps);
53 
54     // convert back to host type
55     convert::converter::sptr c1 = convert::get_converter(out_id, prio_out)();
56     c1->set_scalar(1 / 32767.);
57     c1->conv(input1, output1, nsamps);
58 }
59 
60 /***********************************************************************
61  * Test short conversion
62  **********************************************************************/
test_convert_types_sc16(size_t nsamps,convert::id_type & id,const int extra_div=1,int mask=0xffff)63 static void test_convert_types_sc16(
64     size_t nsamps, convert::id_type& id, const int extra_div = 1, int mask = 0xffff)
65 {
66     // fill the input samples
67     std::vector<sc16_t> input(nsamps), output(nsamps);
68     for (sc16_t& in : input)
69         in = sc16_t(
70             short((float((std::rand()) / (double(RAND_MAX) / 2)) - 1) * 32767 / extra_div)
71                 & mask,
72             short((float((std::rand()) / (double(RAND_MAX) / 2)) - 1) * 32767 / extra_div)
73                 & mask);
74 
75     // run the loopback and test
76     convert::id_type in_id  = id;
77     convert::id_type out_id = id;
78     std::swap(out_id.input_format, out_id.output_format);
79     std::swap(out_id.num_inputs, out_id.num_outputs);
80     loopback(nsamps, in_id, out_id, input, output);
81     BOOST_CHECK_EQUAL_COLLECTIONS(
82         input.begin(), input.end(), output.begin(), output.end());
83 }
84 
BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16)85 BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16)
86 {
87     convert::id_type id;
88     id.input_format  = "sc16";
89     id.num_inputs    = 1;
90     id.output_format = "sc16_item32_be";
91     id.num_outputs   = 1;
92 
93     // try various lengths to test edge cases
94     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
95         test_convert_types_sc16(nsamps, id);
96     }
97 }
98 
BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16)99 BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16)
100 {
101     convert::id_type id;
102     id.input_format  = "sc16";
103     id.num_inputs    = 1;
104     id.output_format = "sc16_item32_le";
105     id.num_outputs   = 1;
106 
107     // try various lengths to test edge cases
108     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
109         test_convert_types_sc16(nsamps, id);
110     }
111 }
112 
BOOST_AUTO_TEST_CASE(test_convert_types_chdr_sc16)113 BOOST_AUTO_TEST_CASE(test_convert_types_chdr_sc16)
114 {
115     convert::id_type id;
116     id.input_format  = "sc16";
117     id.num_inputs    = 1;
118     id.output_format = "sc16_chdr";
119     id.num_outputs   = 1;
120 
121     // try various lengths to test edge cases
122     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
123         test_convert_types_sc16(nsamps, id);
124     }
125 }
126 
127 /***********************************************************************
128  * Test float conversion
129  **********************************************************************/
130 template <typename data_type>
test_convert_types_for_floats(size_t nsamps,convert::id_type & id,const double extra_scale=1.0)131 static void test_convert_types_for_floats(
132     size_t nsamps, convert::id_type& id, const double extra_scale = 1.0)
133 {
134     typedef typename data_type::value_type value_type;
135 
136     // fill the input samples
137     std::vector<data_type> input(nsamps), output(nsamps);
138     for (data_type& in : input)
139         in = data_type(
140             ((std::rand() / (value_type(RAND_MAX) / 2)) - 1) * float(extra_scale),
141             ((std::rand() / (value_type(RAND_MAX) / 2)) - 1) * float(extra_scale));
142 
143     // run the loopback and test
144     convert::id_type in_id  = id;
145     convert::id_type out_id = id;
146     std::swap(out_id.input_format, out_id.output_format);
147     std::swap(out_id.num_inputs, out_id.num_outputs);
148 
149     // make a list of all prio: best/generic combos
150     typedef std::pair<int, int> int_pair_t;
151     const std::vector<int_pair_t> prios{
152         int_pair_t(0, 0), int_pair_t(-1, 0), int_pair_t(0, -1), int_pair_t(-1, -1)};
153 
154     // loopback foreach prio combo (generic vs best)
155     for (const auto& prio : prios) {
156         loopback(nsamps, in_id, out_id, input, output, prio.first, prio.second);
157         for (size_t i = 0; i < nsamps; i++) {
158             MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(1. / (1 << 14)));
159             MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(1. / (1 << 14)));
160         }
161     }
162 }
163 
BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32)164 BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32)
165 {
166     convert::id_type id;
167     id.input_format  = "fc32";
168     id.num_inputs    = 1;
169     id.output_format = "sc16_item32_be";
170     id.num_outputs   = 1;
171 
172     // try various lengths to test edge cases
173     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
174         test_convert_types_for_floats<fc32_t>(nsamps, id);
175     }
176 }
177 
BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32)178 BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32)
179 {
180     convert::id_type id;
181     id.input_format  = "fc32";
182     id.num_inputs    = 1;
183     id.output_format = "sc16_item32_le";
184     id.num_outputs   = 1;
185 
186     // try various lengths to test edge cases
187     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
188         test_convert_types_for_floats<fc32_t>(nsamps, id);
189     }
190 }
191 
BOOST_AUTO_TEST_CASE(test_convert_types_chdr_fc32)192 BOOST_AUTO_TEST_CASE(test_convert_types_chdr_fc32)
193 {
194     convert::id_type id;
195     id.input_format  = "fc32";
196     id.num_inputs    = 1;
197     id.output_format = "sc16_chdr";
198     id.num_outputs   = 1;
199 
200     // try various lengths to test edge cases
201     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
202         test_convert_types_for_floats<fc32_t>(nsamps, id);
203     }
204 }
205 
BOOST_AUTO_TEST_CASE(test_convert_types_be_fc64)206 BOOST_AUTO_TEST_CASE(test_convert_types_be_fc64)
207 {
208     convert::id_type id;
209     id.input_format  = "fc64";
210     id.num_inputs    = 1;
211     id.output_format = "sc16_item32_be";
212     id.num_outputs   = 1;
213 
214     // try various lengths to test edge cases
215     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
216         test_convert_types_for_floats<fc64_t>(nsamps, id);
217     }
218 }
219 
BOOST_AUTO_TEST_CASE(test_convert_types_le_fc64)220 BOOST_AUTO_TEST_CASE(test_convert_types_le_fc64)
221 {
222     convert::id_type id;
223     id.input_format  = "fc64";
224     id.num_inputs    = 1;
225     id.output_format = "sc16_item32_le";
226     id.num_outputs   = 1;
227 
228     // try various lengths to test edge cases
229     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
230         test_convert_types_for_floats<fc64_t>(nsamps, id);
231     }
232 }
233 
BOOST_AUTO_TEST_CASE(test_convert_types_chdr_fc64)234 BOOST_AUTO_TEST_CASE(test_convert_types_chdr_fc64)
235 {
236     convert::id_type id;
237     id.input_format  = "fc64";
238     id.num_inputs    = 1;
239     id.output_format = "sc16_chdr";
240     id.num_outputs   = 1;
241 
242     // try various lengths to test edge cases
243     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
244         test_convert_types_for_floats<fc64_t>(nsamps, id);
245     }
246 }
247 
248 /***********************************************************************
249  * Test float to/from sc12 conversion loopback
250  **********************************************************************/
251 
BOOST_AUTO_TEST_CASE(test_convert_types_le_sc12_with_fc32)252 BOOST_AUTO_TEST_CASE(test_convert_types_le_sc12_with_fc32)
253 {
254     convert::id_type id;
255     id.input_format  = "fc32";
256     id.num_inputs    = 1;
257     id.output_format = "sc12_item32_le";
258     id.num_outputs   = 1;
259 
260     // try various lengths to test edge cases
261     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
262         test_convert_types_for_floats<fc32_t>(nsamps, id, 1. / 16);
263     }
264 }
265 
BOOST_AUTO_TEST_CASE(test_convert_types_be_sc12_with_fc32)266 BOOST_AUTO_TEST_CASE(test_convert_types_be_sc12_with_fc32)
267 {
268     convert::id_type id;
269     id.input_format  = "fc32";
270     id.num_inputs    = 1;
271     id.output_format = "sc12_item32_be";
272     id.num_outputs   = 1;
273 
274     // try various lengths to test edge cases
275     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
276         test_convert_types_for_floats<fc32_t>(nsamps, id, 1. / 16);
277     }
278 }
279 
BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16_and_sc12)280 BOOST_AUTO_TEST_CASE(test_convert_types_le_sc16_and_sc12)
281 {
282     convert::id_type id;
283     id.input_format = "sc16";
284     id.num_inputs   = 1;
285     id.num_outputs  = 1;
286 
287     // try various lengths to test edge cases
288     id.output_format = "sc12_item32_le";
289     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
290         test_convert_types_sc16(nsamps, id, 1, 0xfff0);
291     }
292 }
293 
BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16_and_sc12)294 BOOST_AUTO_TEST_CASE(test_convert_types_be_sc16_and_sc12)
295 {
296     convert::id_type id;
297     id.input_format = "sc16";
298     id.num_inputs   = 1;
299     id.num_outputs  = 1;
300 
301     id.output_format = "sc12_item32_be";
302     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
303         test_convert_types_sc16(nsamps, id, 1, 0xfff0);
304     }
305 }
306 
307 /***********************************************************************
308  * Test float to/from fc32 conversion loopback
309  **********************************************************************/
310 
BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32_with_fc32)311 BOOST_AUTO_TEST_CASE(test_convert_types_le_fc32_with_fc32)
312 {
313     convert::id_type id;
314     id.input_format  = "fc32";
315     id.num_inputs    = 1;
316     id.output_format = "fc32_item32_le";
317     id.num_outputs   = 1;
318 
319     // try various lengths to test edge cases
320     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
321         test_convert_types_for_floats<fc32_t>(nsamps, id);
322     }
323 }
324 
BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32_with_fc32)325 BOOST_AUTO_TEST_CASE(test_convert_types_be_fc32_with_fc32)
326 {
327     convert::id_type id;
328     id.input_format  = "fc32";
329     id.num_inputs    = 1;
330     id.output_format = "fc32_item32_be";
331     id.num_outputs   = 1;
332 
333     // try various lengths to test edge cases
334     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
335         test_convert_types_for_floats<fc32_t>(nsamps, id);
336     }
337 }
338 
BOOST_AUTO_TEST_CASE(test_convert_types_fc32_with_fc32_chdr)339 BOOST_AUTO_TEST_CASE(test_convert_types_fc32_with_fc32_chdr)
340 {
341     convert::id_type id;
342     id.input_format  = "fc32";
343     id.num_inputs    = 1;
344     id.output_format = "fc32_chdr";
345     id.num_outputs   = 1;
346 
347     // try various lengths to test edge cases
348     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
349         test_convert_types_for_floats<fc32_t>(nsamps, id);
350     }
351 }
352 
353 /***********************************************************************
354  * Test float to short conversion loopback
355  **********************************************************************/
BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16)356 BOOST_AUTO_TEST_CASE(test_convert_types_fc32_to_sc16)
357 {
358     convert::id_type in_id;
359     in_id.input_format  = "fc32";
360     in_id.num_inputs    = 1;
361     in_id.output_format = "sc16_item32_le";
362     in_id.num_outputs   = 1;
363 
364     convert::id_type out_id;
365     out_id.input_format  = "sc16_item32_le";
366     out_id.num_inputs    = 1;
367     out_id.output_format = "sc16";
368     out_id.num_outputs   = 1;
369 
370     const size_t nsamps = 13;
371     std::vector<fc32_t> input(nsamps);
372     for (fc32_t& in : input)
373         in = fc32_t(
374             (std::rand() / (RAND_MAX / 2.0)) - 1, (std::rand() / (RAND_MAX / 2.0)) - 1);
375     std::vector<uint32_t> interm(nsamps);
376     std::vector<sc16_t> output(nsamps);
377 
378     std::vector<const void*> input0(1, &input[0]), input1(1, &interm[0]);
379     std::vector<void*> output0(1, &interm[0]), output1(1, &output[0]);
380 
381     // convert float to intermediate
382     convert::converter::sptr c0 = convert::get_converter(in_id)();
383     c0->set_scalar(32767.);
384     c0->conv(input0, output0, nsamps);
385 
386     // convert intermediate to short
387     convert::converter::sptr c1 = convert::get_converter(out_id)();
388     c1->set_scalar(1 / 32767.);
389     c1->conv(input1, output1, nsamps);
390 
391     // test that the inputs and outputs match
392     for (size_t i = 0; i < nsamps; i++) {
393         MY_CHECK_CLOSE(input[i].real(), output[i].real() / float(32767), float(0.01));
394         MY_CHECK_CLOSE(input[i].imag(), output[i].imag() / float(32767), float(0.01));
395     }
396 }
397 
398 /***********************************************************************
399  * Test short to float conversion loopback
400  **********************************************************************/
BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32)401 BOOST_AUTO_TEST_CASE(test_convert_types_sc16_to_fc32)
402 {
403     convert::id_type in_id;
404     in_id.input_format  = "sc16";
405     in_id.num_inputs    = 1;
406     in_id.output_format = "sc16_item32_le";
407     in_id.num_outputs   = 1;
408 
409     convert::id_type out_id;
410     out_id.input_format  = "sc16_item32_le";
411     out_id.num_inputs    = 1;
412     out_id.output_format = "fc32";
413     out_id.num_outputs   = 1;
414 
415     const size_t nsamps = 13;
416     std::vector<sc16_t> input(nsamps);
417     for (sc16_t& in : input)
418         in = sc16_t(std::rand() - (RAND_MAX / 2), std::rand() - (RAND_MAX / 2));
419     std::vector<uint32_t> interm(nsamps);
420     std::vector<fc32_t> output(nsamps);
421 
422     std::vector<const void*> input0(1, &input[0]), input1(1, &interm[0]);
423     std::vector<void*> output0(1, &interm[0]), output1(1, &output[0]);
424 
425     // convert short to intermediate
426     convert::converter::sptr c0 = convert::get_converter(in_id)();
427     c0->set_scalar(32767.);
428     c0->conv(input0, output0, nsamps);
429 
430     // convert intermediate to float
431     convert::converter::sptr c1 = convert::get_converter(out_id)();
432     c1->set_scalar(1 / 32767.);
433     c1->conv(input1, output1, nsamps);
434 
435     // test that the inputs and outputs match
436     for (size_t i = 0; i < nsamps; i++) {
437         MY_CHECK_CLOSE(input[i].real() / float(32767), output[i].real(), float(0.01));
438         MY_CHECK_CLOSE(input[i].imag() / float(32767), output[i].imag(), float(0.01));
439     }
440 }
441 
442 /***********************************************************************
443  * Test sc8 conversions
444  **********************************************************************/
BOOST_AUTO_TEST_CASE(test_convert_types_fc64_and_sc8)445 BOOST_AUTO_TEST_CASE(test_convert_types_fc64_and_sc8)
446 {
447     convert::id_type id;
448     id.input_format = "fc64";
449     id.num_inputs   = 1;
450     id.num_outputs  = 1;
451 
452     // try various lengths to test edge cases
453     id.output_format = "sc8_item32_le";
454     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
455         test_convert_types_for_floats<fc64_t>(nsamps, id, 1. / 256);
456     }
457 
458     // try various lengths to test edge cases
459     id.output_format = "sc8_item32_be";
460     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
461         test_convert_types_for_floats<fc64_t>(nsamps, id, 1. / 256);
462     }
463 }
464 
BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_sc8)465 BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_sc8)
466 {
467     convert::id_type id;
468     id.input_format = "fc32";
469     id.num_inputs   = 1;
470     id.num_outputs  = 1;
471 
472     // try various lengths to test edge cases
473     id.output_format = "sc8_item32_le";
474     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
475         test_convert_types_for_floats<fc32_t>(nsamps, id, 1. / 256);
476     }
477 
478     // try various lengths to test edge cases
479     id.output_format = "sc8_item32_be";
480     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
481         test_convert_types_for_floats<fc32_t>(nsamps, id, 1. / 256);
482     }
483 }
484 
BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8)485 BOOST_AUTO_TEST_CASE(test_convert_types_sc16_and_sc8)
486 {
487     convert::id_type id;
488     id.input_format = "sc16";
489     id.num_inputs   = 1;
490     id.num_outputs  = 1;
491 
492     // try various lengths to test edge cases
493     id.output_format = "sc8_item32_le";
494     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
495         test_convert_types_sc16(nsamps, id, 256);
496     }
497 
498     // try various lengths to test edge cases
499     id.output_format = "sc8_item32_be";
500     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
501         test_convert_types_sc16(nsamps, id, 256);
502     }
503 }
504 
505 /***********************************************************************
506  * Test u8 conversion
507  **********************************************************************/
test_convert_types_u8(size_t nsamps,convert::id_type & id)508 static void test_convert_types_u8(size_t nsamps, convert::id_type& id)
509 {
510     // fill the input samples
511     std::vector<uint8_t> input(nsamps), output(nsamps);
512     for (uint8_t& in : input)
513         in = uint8_t(std::rand() & 0xFF);
514     // uint32_t d = 48;
515     // for(uint8_t &in:  input) in = d++;
516 
517     // run the loopback and test
518     convert::id_type in_id  = id;
519     convert::id_type out_id = id;
520     std::swap(out_id.input_format, out_id.output_format);
521     std::swap(out_id.num_inputs, out_id.num_outputs);
522     loopback(nsamps, in_id, out_id, input, output);
523     BOOST_CHECK_EQUAL_COLLECTIONS(
524         input.begin(), input.end(), output.begin(), output.end());
525 }
526 
BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8)527 BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8)
528 {
529     convert::id_type id;
530     id.input_format = "u8";
531     id.num_inputs   = 1;
532     id.num_outputs  = 1;
533 
534     // try various lengths to test edge cases
535     id.output_format = "u8_item32_le";
536     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
537         test_convert_types_u8(nsamps, id);
538     }
539 
540     // try various lengths to test edge cases
541     id.output_format = "u8_item32_be";
542     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
543         test_convert_types_u8(nsamps, id);
544     }
545 }
546 
BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8_chdr)547 BOOST_AUTO_TEST_CASE(test_convert_types_u8_and_u8_chdr)
548 {
549     convert::id_type id;
550     id.input_format  = "u8";
551     id.output_format = "u8_chdr";
552     id.num_inputs    = 1;
553     id.num_outputs   = 1;
554 
555     // try various lengths to test edge cases
556     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
557         test_convert_types_u8(nsamps, id);
558     }
559 }
560 
561 /***********************************************************************
562  * Test s8 conversion
563  **********************************************************************/
test_convert_types_s8(size_t nsamps,convert::id_type & id)564 static void test_convert_types_s8(size_t nsamps, convert::id_type& id)
565 {
566     // fill the input samples
567     std::vector<int8_t> input(nsamps), output(nsamps);
568     for (int8_t& in : input)
569         in = int8_t(std::rand() & 0xFF);
570 
571     // run the loopback and test
572     convert::id_type in_id  = id;
573     convert::id_type out_id = id;
574     std::swap(out_id.input_format, out_id.output_format);
575     std::swap(out_id.num_inputs, out_id.num_outputs);
576     loopback(nsamps, in_id, out_id, input, output);
577     BOOST_CHECK_EQUAL_COLLECTIONS(
578         input.begin(), input.end(), output.begin(), output.end());
579 }
580 
BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8)581 BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8)
582 {
583     convert::id_type id;
584     id.input_format = "s8";
585     id.num_inputs   = 1;
586     id.num_outputs  = 1;
587 
588     // try various lengths to test edge cases
589     id.output_format = "s8_item32_le";
590     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
591         test_convert_types_s8(nsamps, id);
592     }
593 
594     // try various lengths to test edge cases
595     id.output_format = "s8_item32_be";
596     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
597         test_convert_types_s8(nsamps, id);
598     }
599 }
600 
BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8_chdr)601 BOOST_AUTO_TEST_CASE(test_convert_types_s8_and_s8_chdr)
602 {
603     convert::id_type id;
604     id.input_format  = "s8";
605     id.output_format = "s8_chdr";
606     id.num_inputs    = 1;
607     id.num_outputs   = 1;
608 
609     // try various lengths to test edge cases
610     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
611         test_convert_types_s8(nsamps, id);
612     }
613 }
614 
615 /***********************************************************************
616  * Test s16 conversion
617  **********************************************************************/
test_convert_types_s16(size_t nsamps,convert::id_type & id)618 static void test_convert_types_s16(size_t nsamps, convert::id_type& id)
619 {
620     // fill the input samples
621     std::vector<int16_t> input(nsamps), output(nsamps);
622     for (int16_t& in : input)
623         in = int16_t(std::rand() & 0xFFFF);
624 
625     // run the loopback and test
626     convert::id_type in_id  = id;
627     convert::id_type out_id = id;
628     std::swap(out_id.input_format, out_id.output_format);
629     std::swap(out_id.num_inputs, out_id.num_outputs);
630     loopback(nsamps, in_id, out_id, input, output);
631     BOOST_CHECK_EQUAL_COLLECTIONS(
632         input.begin(), input.end(), output.begin(), output.end());
633 }
634 
BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16)635 BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16)
636 {
637     convert::id_type id;
638     id.input_format = "s16";
639     id.num_inputs   = 1;
640     id.num_outputs  = 1;
641 
642     // try various lengths to test edge cases
643     id.output_format = "s16_item32_le";
644     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
645         test_convert_types_s16(nsamps, id);
646     }
647 
648     // try various lengths to test edge cases
649     id.output_format = "s16_item32_be";
650     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
651         test_convert_types_s16(nsamps, id);
652     }
653 }
654 
BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16_chdr)655 BOOST_AUTO_TEST_CASE(test_convert_types_s16_and_s16_chdr)
656 {
657     convert::id_type id;
658     id.input_format  = "s16";
659     id.output_format = "s16_chdr";
660     id.num_inputs    = 1;
661     id.num_outputs   = 1;
662 
663     // try various lengths to test edge cases
664     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
665         test_convert_types_s16(nsamps, id);
666     }
667 }
668 
669 /***********************************************************************
670  * Test fc32 -> fc32 conversion
671  **********************************************************************/
test_convert_types_fc32(size_t nsamps,convert::id_type & id)672 static void test_convert_types_fc32(size_t nsamps, convert::id_type& id)
673 {
674     // fill the input samples
675     std::vector<std::complex<float>> input(nsamps), output(nsamps);
676     for (fc32_t& in : input)
677         in = fc32_t((std::rand() / float(RAND_MAX / 2)) - 1,
678             (std::rand() / float(RAND_MAX / 2)) - 1);
679 
680     // run the loopback and test
681     convert::id_type in_id  = id;
682     convert::id_type out_id = id;
683     std::swap(out_id.input_format, out_id.output_format);
684     std::swap(out_id.num_inputs, out_id.num_outputs);
685     loopback(nsamps, in_id, out_id, input, output);
686     for (size_t i = 0; i < nsamps; i++) {
687         MY_CHECK_CLOSE(input[i].real(), output[i].real(), float(1. / (1 << 16)));
688         MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), float(1. / (1 << 16)));
689     }
690 }
691 
BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32)692 BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32)
693 {
694     convert::id_type id;
695     id.input_format = "fc32";
696     id.num_inputs   = 1;
697     id.num_outputs  = 1;
698 
699     // try various lengths to test edge cases
700     id.output_format = "fc32_item32_le";
701     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
702         test_convert_types_fc32(nsamps, id);
703     }
704 
705     // try various lengths to test edge cases
706     id.output_format = "fc32_item32_be";
707     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
708         test_convert_types_fc32(nsamps, id);
709     }
710 }
711 
BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32_chdr)712 BOOST_AUTO_TEST_CASE(test_convert_types_fc32_and_fc32_chdr)
713 {
714     convert::id_type id;
715     id.input_format  = "fc32";
716     id.output_format = "fc32_chdr";
717     id.num_inputs    = 1;
718     id.num_outputs   = 1;
719 
720     // try various lengths to test edge cases
721     for (size_t nsamps = 1; nsamps < 16; nsamps++) {
722         test_convert_types_fc32(nsamps, id);
723     }
724 }
725