1 /*
2 * sample_test.c - Sample audio conversion tests
3 *
4 * Tests every combination of audio format conversions (484 combinations).
5 * This is done by creating a double audio format triangle waveform and then
6 * for each transformation format pair, converting this waveform to the
7 * first format, then the second, then back to double again and comparing
8 * against the original.
9 *
10 * libInstPatch
11 * Copyright (C) 1999-2014 Element Green <element@elementsofsound.org>
12 *
13 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU Lesser General Public License
15 * as published by the Free Software Foundation; version 2.1
16 * of the License only.
17 *
18 * This program 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 this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 * 02110-1301, USA or on the web at http://www.gnu.org.
27 */
28 #include <libinstpatch/libinstpatch.h>
29
30 #define DEFAULT_AUDIO_SIZE (32 * 1024) /* default test waveform size in samples */
31 #define WAVEFORM_PERIOD 1684 /* something to exercise LSB bytes too */
32 #define MAX_DIFF_ALLOWED 0.016 /* maximum difference allowed */
33
34 #define WAVEFORM_QUARTER (WAVEFORM_PERIOD / 4)
35
36 /* all available sample format combinations */
37 int testformats[] =
38 {
39 IPATCH_SAMPLE_8BIT,
40 IPATCH_SAMPLE_16BIT,
41 IPATCH_SAMPLE_24BIT,
42 IPATCH_SAMPLE_32BIT,
43 IPATCH_SAMPLE_FLOAT,
44 IPATCH_SAMPLE_DOUBLE,
45 IPATCH_SAMPLE_REAL24BIT,
46
47 IPATCH_SAMPLE_8BIT | IPATCH_SAMPLE_UNSIGNED,
48 IPATCH_SAMPLE_16BIT | IPATCH_SAMPLE_UNSIGNED,
49 IPATCH_SAMPLE_24BIT | IPATCH_SAMPLE_UNSIGNED,
50 IPATCH_SAMPLE_32BIT | IPATCH_SAMPLE_UNSIGNED,
51 IPATCH_SAMPLE_REAL24BIT | IPATCH_SAMPLE_UNSIGNED,
52
53 IPATCH_SAMPLE_16BIT | IPATCH_SAMPLE_BENDIAN,
54 IPATCH_SAMPLE_24BIT | IPATCH_SAMPLE_BENDIAN,
55 IPATCH_SAMPLE_32BIT | IPATCH_SAMPLE_BENDIAN,
56 IPATCH_SAMPLE_FLOAT | IPATCH_SAMPLE_BENDIAN,
57 IPATCH_SAMPLE_DOUBLE | IPATCH_SAMPLE_BENDIAN,
58 IPATCH_SAMPLE_REAL24BIT | IPATCH_SAMPLE_BENDIAN,
59
60 IPATCH_SAMPLE_16BIT | IPATCH_SAMPLE_UNSIGNED | IPATCH_SAMPLE_BENDIAN,
61 IPATCH_SAMPLE_24BIT | IPATCH_SAMPLE_UNSIGNED | IPATCH_SAMPLE_BENDIAN,
62 IPATCH_SAMPLE_32BIT | IPATCH_SAMPLE_UNSIGNED | IPATCH_SAMPLE_BENDIAN,
63 IPATCH_SAMPLE_REAL24BIT | IPATCH_SAMPLE_UNSIGNED | IPATCH_SAMPLE_BENDIAN
64 };
65
66 #define SAMPLE_FORMAT_COUNT G_N_ELEMENTS (testformats)
67
68 static int test_size = DEFAULT_AUDIO_SIZE;
69 static gboolean verbose = FALSE;
70
71 static GOptionEntry entries[] =
72 {
73 { "size", 's', 0, G_OPTION_ARG_INT, &test_size, "Size of test waveform in samples (default=32768)", NULL },
74 { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
75 { NULL }
76 };
77
main(int argc,char * argv[])78 int main(int argc, char *argv[])
79 {
80 IpatchSampleTransform *trans;
81 gpointer srctrans, desttrans;
82 double *dwave, *fintrans;
83 guint periodpos;
84 int srcform, destform;
85 int isrc, idest;
86 double d, maxdiff;
87 int i, maxindex, failcount = 0;
88 GError *error = NULL;
89 GOptionContext *context;
90
91 context = g_option_context_new("- test libInstPatch sample format conversions");
92 g_option_context_add_main_entries(context, entries, "sample_test");
93
94 if(!g_option_context_parse(context, &argc, &argv, &error))
95 {
96 printf("Failed to parse command line arguments: %s\n",
97 ipatch_gerror_message(error));
98 return 1;
99 }
100
101 g_option_context_free(context);
102
103 ipatch_init();
104
105 dwave = g_new(double, test_size); /* allocate audio buffer (double format) */
106 srctrans = g_malloc(8 * test_size); /* source format transform buf */
107 desttrans = g_malloc(8 * test_size); /* destination format transform buf */
108 fintrans = g_malloc(8 * test_size); /* final transform buf */
109
110 /* create sample transform object and allocate its buffer */
111 trans = ipatch_sample_transform_new(0, 0, 0);
112 ipatch_sample_transform_alloc_size(trans, 32 * 1024);
113
114 /* generate triangle waveform */
115 for(i = 0; i < test_size; i++)
116 {
117 periodpos = i % WAVEFORM_PERIOD;
118
119 if(periodpos <= WAVEFORM_QUARTER)
120 {
121 dwave[i] = periodpos / (double)WAVEFORM_QUARTER;
122 }
123 else if(periodpos <= WAVEFORM_QUARTER * 3)
124 {
125 dwave[i] = -((periodpos - WAVEFORM_QUARTER) / (double)WAVEFORM_QUARTER - 1.0);
126 }
127 else
128 {
129 dwave[i] = (periodpos - WAVEFORM_QUARTER * 3) / (double)WAVEFORM_QUARTER - 1.0;
130 }
131 }
132
133 /* Convert between all possible format pairs using the following steps:
134 * - Convert double to first format of format pair
135 * - Convert from first format to second format
136 * - Convert second format back to double
137 * - Calculate maximum sample difference between new double audio and original
138 */
139
140 for(isrc = 0; isrc < SAMPLE_FORMAT_COUNT; isrc++)
141 {
142 srcform = testformats[isrc];
143
144 for(idest = 0; idest < SAMPLE_FORMAT_COUNT; idest++)
145 {
146 destform = testformats[idest];
147
148 /* convert double waveform to source format */
149 ipatch_sample_transform_set_formats(trans, IPATCH_SAMPLE_DOUBLE
150 | IPATCH_SAMPLE_ENDIAN_HOST, srcform,
151 IPATCH_SAMPLE_UNITY_CHANNEL_MAP);
152 ipatch_sample_transform_convert(trans, dwave, srctrans, test_size);
153
154 /* convert source format to destination format */
155 ipatch_sample_transform_set_formats(trans, srcform, destform,
156 IPATCH_SAMPLE_UNITY_CHANNEL_MAP);
157 ipatch_sample_transform_convert(trans, srctrans, desttrans, test_size);
158
159 /* convert destination format to final double output */
160 ipatch_sample_transform_set_formats(trans, destform, IPATCH_SAMPLE_DOUBLE
161 | IPATCH_SAMPLE_ENDIAN_HOST,
162 IPATCH_SAMPLE_UNITY_CHANNEL_MAP);
163 ipatch_sample_transform_convert(trans, desttrans, fintrans, test_size);
164
165 /* compare final waveform against original */
166 for(i = 0, maxdiff = 0.0, maxindex = 0; i < test_size; i++)
167 {
168 d = dwave[i] - fintrans[i];
169
170 if(d < 0.0)
171 {
172 d = -d;
173 }
174
175 if(d > maxdiff)
176 {
177 maxdiff = d;
178 maxindex = i;
179 }
180 }
181
182 if(verbose)
183 printf("Convert format %03x to %03x%s: maxdiff=%0.6f, sample=%d\n",
184 srcform, destform, maxdiff > MAX_DIFF_ALLOWED ? " FAILED" : "",
185 maxdiff, maxindex);
186
187 if(maxdiff > MAX_DIFF_ALLOWED)
188 {
189 if(!verbose)
190 printf("Convert format %03x to %03x FAILED: maxdiff=%0.6f, sample=%d\n",
191 srcform, destform, maxdiff, maxindex);
192
193 failcount++;
194 }
195 }
196 }
197
198 ipatch_sample_transform_free(trans);
199
200 g_free(dwave);
201 g_free(srctrans);
202 g_free(desttrans);
203 g_free(fintrans);
204
205 if(failcount > 0)
206 {
207 printf("%d of %d format conversions FAILED\n", failcount,
208 SAMPLE_FORMAT_COUNT * SAMPLE_FORMAT_COUNT);
209 return 1;
210 }
211
212 printf("All %d sample format conversions PASSED\n",
213 SAMPLE_FORMAT_COUNT * SAMPLE_FORMAT_COUNT);
214
215 return 0;
216 }
217