1 /*
2 * Copyright (C) 2002 2003 2004 2005 2006 2007 2008 2010 2012, Magnus Hjorth
3 *
4 * This file is part of mhWaveEdit.
5 *
6 * mhWaveEdit is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * mhWaveEdit is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with mhWaveEdit; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <config.h>
22
23 #ifndef _GNU_SOURCE
24 #define _GNU_SOURCE
25 #endif
26
27 #include <string.h>
28 #include <stdlib.h>
29 #include <math.h>
30 #include "dataformat.h"
31 #include "inifile.h"
32 #include "main.h"
33 #include "gettext.h"
34
35 Dataformat dataformat_sample_t,dataformat_single;
36 gboolean ieee_le_compatible,ieee_be_compatible;
37 gint sample_convert_mode;
38
floating_point_check(void)39 void floating_point_check(void)
40 {
41 char c[4] = { 0, 0, 0xD0, 0xC0 };
42 char d[4] = { 0xC0, 0xD0, 0, 0 };
43 float *f;
44 f = (float *)c;
45 ieee_le_compatible = (*f == -6.5);
46 f = (float *)d;
47 ieee_be_compatible = (*f == -6.5);
48
49 dataformat_sample_t.type = DATAFORMAT_FLOAT;
50 dataformat_sample_t.samplesize = sizeof(sample_t);
51 dataformat_sample_t.bigendian = ieee_be_compatible;
52 dataformat_sample_t.channels = 0;
53 dataformat_sample_t.samplebytes = 0;
54 dataformat_sample_t.samplerate = 0;
55
56 dataformat_single.type = DATAFORMAT_FLOAT;
57 dataformat_single.samplesize = sizeof(float);
58 dataformat_single.bigendian = ieee_be_compatible;
59 dataformat_single.channels = 0;
60 dataformat_single.samplebytes = 0;
61 dataformat_single.samplerate = 0;
62 }
63
dataformat_equal(Dataformat * f1,Dataformat * f2)64 gboolean dataformat_equal(Dataformat *f1, Dataformat *f2)
65 {
66 return (f1->type == f2->type && f1->samplerate==f2->samplerate &&
67 f1->samplesize==f2->samplesize &&
68 f1->channels==f2->channels &&
69 (f1->samplesize == 1 || BOOLEQ(f1->bigendian,f2->bigendian)) &&
70 (f1->type != DATAFORMAT_PCM ||
71 (BOOLEQ(f1->sign,f2->sign) &&
72 (f1->samplesize != 4 || f1->packing == f2->packing))));
73 }
74
dataformat_samples_equal(Dataformat * f1,Dataformat * f2)75 gboolean dataformat_samples_equal(Dataformat *f1, Dataformat *f2)
76 {
77 return (f1->type == f2->type && f1->samplesize==f2->samplesize &&
78 (f1->samplesize == 1 || BOOLEQ(f1->bigendian,f2->bigendian)) &&
79 (f1->type != DATAFORMAT_PCM ||
80 (BOOLEQ(f1->sign,f2->sign) &&
81 (f1->samplesize != 4 || f1->packing == f2->packing))));
82 }
83
sampletype_name(Dataformat * fmt)84 const gchar *sampletype_name(Dataformat *fmt)
85 {
86 if (fmt->type == DATAFORMAT_FLOAT) {
87 if (fmt->samplesize == sizeof(double)) return "double";
88 else return "float";
89 }
90 switch (fmt->samplesize) {
91 case 1: return "8 bit";
92 case 2: return "16 bit";
93 case 3: return "24 bit";
94 default:
95 case 4: if (fmt->packing != 0) return "24+8 bit"; else return "32 bit";
96 }
97 }
98
dataformat_get_from_inifile(gchar * ini_prefix,gboolean full,Dataformat * result)99 gboolean dataformat_get_from_inifile(gchar *ini_prefix, gboolean full,
100 Dataformat *result)
101 {
102 guint t,ss,chn,pack=0;
103 guint32 sr;
104 gboolean sign=FALSE,end=FALSE;
105 gchar *c,*d;
106 c = g_strdup_printf("%s_SampleSize",ini_prefix);
107 d = inifile_get(c,NULL);
108 g_free(c);
109 if (d == NULL) return FALSE;
110 switch (d[0]) {
111 case '1': t=DATAFORMAT_PCM; ss=1; break;
112 case '2': t=DATAFORMAT_PCM; ss=2; break;
113 case '3':
114 switch (d[1]) {
115 case 'm':
116 t=DATAFORMAT_PCM; ss=4; pack=1; break;
117 case 'l':
118 t=DATAFORMAT_PCM; ss=4; pack=2; break;
119 case 'p':
120 default:
121 t=DATAFORMAT_PCM; ss=3; break;
122 }
123 case '4': t=DATAFORMAT_PCM; ss=4; break;
124 case 's': t=DATAFORMAT_FLOAT; ss=sizeof(float); break;
125 case 'd': t=DATAFORMAT_FLOAT; ss=sizeof(double); break;
126 default: return FALSE;
127 }
128 c = g_strdup_printf("%s_BigEndian",ini_prefix);
129 end=inifile_get_gboolean(c,ieee_be_compatible && t==DATAFORMAT_FLOAT);
130 g_free(c);
131 if (t == DATAFORMAT_PCM) {
132 c = g_strdup_printf("%s_Signed",ini_prefix);
133 sign=inifile_get_gboolean(c,FALSE);
134 g_free(c);
135 }
136 result->type = t;
137 result->samplesize = ss;
138 result->packing = pack;
139 result->sign = sign;
140 result->bigendian = end;
141 if (full) {
142 c = g_strdup_printf("%s_SampleRate",ini_prefix);
143 sr = inifile_get_guint32(c,44100);
144 g_free(c);
145 c = g_strdup_printf("%s_Channels",ini_prefix);
146 chn = inifile_get_guint32(c,2);
147 g_free(c);
148 result->samplerate = sr;
149 result->channels = chn;
150 }
151 result->samplebytes = result->channels * result->samplesize;
152 return TRUE;
153 }
154
dataformat_save_to_inifile(gchar * ini_prefix,Dataformat * format,gboolean full)155 void dataformat_save_to_inifile(gchar *ini_prefix, Dataformat *format,
156 gboolean full)
157 {
158 char *s[6] = { "1","2","3p","4","3m","3l" };
159 gchar *c;
160 c = g_strdup_printf("%s_SampleSize",ini_prefix);
161 if (format->type == DATAFORMAT_PCM) {
162 inifile_set(c,s[format->samplesize+format->packing-1]);
163 g_free(c);
164 c = g_strdup_printf("%s_Signed",ini_prefix);
165 inifile_set_gboolean(c,format->sign);
166 } else if (format->samplesize == sizeof(float)) {
167 inifile_set(c,"s");
168 } else {
169 inifile_set(c,"d");
170 }
171 g_free(c);
172 c = g_strdup_printf("%s_BigEndian",ini_prefix);
173 inifile_set_gboolean(c,format->bigendian);
174 g_free(c);
175 if (full) {
176 c = g_strdup_printf("%s_SampleRate",ini_prefix);
177 inifile_set_guint32(c,format->samplerate);
178 g_free(c);
179 c = g_strdup_printf("%s_Channels",ini_prefix);
180 inifile_set_guint32(c,format->channels);
181 g_free(c);
182 }
183 }
184
185
186
187 /* PCM<->FLOAT SAMPLE CONVERSION ROUTINES */
188 /* These routines could really use some optimizing if anyone feels like it. */
189
190 /* 1) single-float, max-range */
191
192 #define FTYPE float
193 #define FTYPE_IS_FLOAT
194
195 #ifdef HAVE_LRINTF
196 #define RINT(x) lrintf(x)
197 #else
198 #define RINT(x) ((long int)((x<0)?(x-0.5000001):(x+0.5000001)))
199 #warning "Using fallback for lrintf, losing accuracy"
200 #endif
201
202 #define C_PCM8S_FLOAT convert_pcm8s_float
203 #define C_PCM8U_FLOAT convert_pcm8u_float
204 #define C_PCM16SLE_FLOAT convert_pcm16sle_float
205 #define C_PCM16SBE_FLOAT convert_pcm16sbe_float
206 #define C_PCM16ULE_FLOAT convert_pcm16ule_float
207 #define C_PCM16UBE_FLOAT convert_pcm16ube_float
208 #define C_PCM24SLE_FLOAT convert_pcm24sle_float
209 #define C_PCM24SBE_FLOAT convert_pcm24sbe_float
210 #define C_PCM24ULE_FLOAT convert_pcm24ule_float
211 #define C_PCM24UBE_FLOAT convert_pcm24ube_float
212 #define C_PCM24SLEPM_FLOAT convert_pcm24slepm_float
213 #define C_PCM24SBEPM_FLOAT convert_pcm24sbepm_float
214 #define C_PCM24ULEPM_FLOAT convert_pcm24ulepm_float
215 #define C_PCM24UBEPM_FLOAT convert_pcm24ubepm_float
216 #define C_PCM24SLEPL_FLOAT convert_pcm24slepl_float
217 #define C_PCM24SBEPL_FLOAT convert_pcm24sbepl_float
218 #define C_PCM24ULEPL_FLOAT convert_pcm24ulepl_float
219 #define C_PCM24UBEPL_FLOAT convert_pcm24ubepl_float
220 #define C_PCM32SLE_FLOAT convert_pcm32sle_float
221 #define C_PCM32SBE_FLOAT convert_pcm32sbe_float
222 #define C_PCM32ULE_FLOAT convert_pcm32ule_float
223 #define C_PCM32UBE_FLOAT convert_pcm32ube_float
224 #define C_FLOAT_PCM8S convert_float_pcm8s
225 #define C_FLOAT_PCM8U convert_float_pcm8u
226 #define C_FLOAT_PCM16SLE convert_float_pcm16sle
227 #define C_FLOAT_PCM16SBE convert_float_pcm16sbe
228 #define C_FLOAT_PCM16ULE convert_float_pcm16ule
229 #define C_FLOAT_PCM16UBE convert_float_pcm16ube
230 #define C_FLOAT_PCM24SLE convert_float_pcm24sle
231 #define C_FLOAT_PCM24SBE convert_float_pcm24sbe
232 #define C_FLOAT_PCM24ULE convert_float_pcm24ule
233 #define C_FLOAT_PCM24UBE convert_float_pcm24ube
234 #define C_FLOAT_PCM24SLEPM convert_float_pcm24slepm
235 #define C_FLOAT_PCM24SBEPM convert_float_pcm24sbepm
236 #define C_FLOAT_PCM24ULEPM convert_float_pcm24ulepm
237 #define C_FLOAT_PCM24UBEPM convert_float_pcm24ubepm
238 #define C_FLOAT_PCM24SLEPL convert_float_pcm24slepl
239 #define C_FLOAT_PCM24SBEPL convert_float_pcm24sbepl
240 #define C_FLOAT_PCM24ULEPL convert_float_pcm24ulepl
241 #define C_FLOAT_PCM24UBEPL convert_float_pcm24ubepl
242 #define C_FLOAT_PCM32SLE convert_float_pcm32sle
243 #define C_FLOAT_PCM32SBE convert_float_pcm32sbe
244 #define C_FLOAT_PCM32ULE convert_float_pcm32ule
245 #define C_FLOAT_PCM32UBE convert_float_pcm32ube
246
247 #include "convert_inc.c"
248
249 /* 2) double-float, max-range */
250
251 #define FTYPE double
252 #undef FTYPE_IS_FLOAT
253
254 #ifdef HAVE_LRINT
255 #define RINT(x) lrint(x)
256 #else
257 #define RINT(x) ((long int)((x<0)?(x-0.5000001):(x+0.5000001)))
258 #warning "Using fallback for lrint, losing accuracy"
259 #endif
260
261 #define C_PCM8S_FLOAT convert_pcm8s_double
262 #define C_PCM8U_FLOAT convert_pcm8u_double
263 #define C_PCM16SLE_FLOAT convert_pcm16sle_double
264 #define C_PCM16SBE_FLOAT convert_pcm16sbe_double
265 #define C_PCM16ULE_FLOAT convert_pcm16ule_double
266 #define C_PCM16UBE_FLOAT convert_pcm16ube_double
267 #define C_PCM24SLE_FLOAT convert_pcm24sle_double
268 #define C_PCM24SBE_FLOAT convert_pcm24sbe_double
269 #define C_PCM24ULE_FLOAT convert_pcm24ule_double
270 #define C_PCM24UBE_FLOAT convert_pcm24ube_double
271 #define C_PCM24SLEPM_FLOAT convert_pcm24slepm_double
272 #define C_PCM24SBEPM_FLOAT convert_pcm24sbepm_double
273 #define C_PCM24ULEPM_FLOAT convert_pcm24ulepm_double
274 #define C_PCM24UBEPM_FLOAT convert_pcm24ubepm_double
275 #define C_PCM24SLEPL_FLOAT convert_pcm24slepl_double
276 #define C_PCM24SBEPL_FLOAT convert_pcm24sbepl_double
277 #define C_PCM24ULEPL_FLOAT convert_pcm24ulepl_double
278 #define C_PCM24UBEPL_FLOAT convert_pcm24ubepl_double
279 #define C_PCM32SLE_FLOAT convert_pcm32sle_double
280 #define C_PCM32SBE_FLOAT convert_pcm32sbe_double
281 #define C_PCM32ULE_FLOAT convert_pcm32ule_double
282 #define C_PCM32UBE_FLOAT convert_pcm32ube_double
283 #define C_FLOAT_PCM8S convert_double_pcm8s
284 #define C_FLOAT_PCM8U convert_double_pcm8u
285 #define C_FLOAT_PCM16SLE convert_double_pcm16sle
286 #define C_FLOAT_PCM16SBE convert_double_pcm16sbe
287 #define C_FLOAT_PCM16ULE convert_double_pcm16ule
288 #define C_FLOAT_PCM16UBE convert_double_pcm16ube
289 #define C_FLOAT_PCM24SLE convert_double_pcm24sle
290 #define C_FLOAT_PCM24SBE convert_double_pcm24sbe
291 #define C_FLOAT_PCM24ULE convert_double_pcm24ule
292 #define C_FLOAT_PCM24UBE convert_double_pcm24ube
293 #define C_FLOAT_PCM24SLEPM convert_double_pcm24slepm
294 #define C_FLOAT_PCM24SBEPM convert_double_pcm24sbepm
295 #define C_FLOAT_PCM24ULEPM convert_double_pcm24ulepm
296 #define C_FLOAT_PCM24UBEPM convert_double_pcm24ubepm
297 #define C_FLOAT_PCM24SLEPL convert_double_pcm24slepl
298 #define C_FLOAT_PCM24SBEPL convert_double_pcm24sbepl
299 #define C_FLOAT_PCM24ULEPL convert_double_pcm24ulepl
300 #define C_FLOAT_PCM24UBEPL convert_double_pcm24ubepl
301 #define C_FLOAT_PCM32SLE convert_double_pcm32sle
302 #define C_FLOAT_PCM32SBE convert_double_pcm32sbe
303 #define C_FLOAT_PCM32ULE convert_double_pcm32ule
304 #define C_FLOAT_PCM32UBE convert_double_pcm32ube
305
306 #include "convert_inc.c"
307
308 /* 3) single-float, preserve-zero */
309
310 #define PZMODE
311 #define FTYPE float
312 #define FTYPE_IS_FLOAT
313
314 #ifdef HAVE_LRINTF
315 #define RINT(x) lrintf(x)
316 #else
317 #define RINT(x) ((long int)((x<0)?(x-0.5000001):(x+0.5000001)))
318 #endif
319
320 #define C_PCM8S_FLOAT convert_pcm8s_float_pz
321 #define C_PCM8U_FLOAT convert_pcm8u_float_pz
322 #define C_PCM16SLE_FLOAT convert_pcm16sle_float_pz
323 #define C_PCM16SBE_FLOAT convert_pcm16sbe_float_pz
324 #define C_PCM16ULE_FLOAT convert_pcm16ule_float_pz
325 #define C_PCM16UBE_FLOAT convert_pcm16ube_float_pz
326 #define C_PCM24SLE_FLOAT convert_pcm24sle_float_pz
327 #define C_PCM24SBE_FLOAT convert_pcm24sbe_float_pz
328 #define C_PCM24ULE_FLOAT convert_pcm24ule_float_pz
329 #define C_PCM24UBE_FLOAT convert_pcm24ube_float_pz
330 #define C_PCM24SLEPM_FLOAT convert_pcm24slepm_float_pz
331 #define C_PCM24SBEPM_FLOAT convert_pcm24sbepm_float_pz
332 #define C_PCM24ULEPM_FLOAT convert_pcm24ulepm_float_pz
333 #define C_PCM24UBEPM_FLOAT convert_pcm24ubepm_float_pz
334 #define C_PCM24SLEPL_FLOAT convert_pcm24slepl_float_pz
335 #define C_PCM24SBEPL_FLOAT convert_pcm24sbepl_float_pz
336 #define C_PCM24ULEPL_FLOAT convert_pcm24ulepl_float_pz
337 #define C_PCM24UBEPL_FLOAT convert_pcm24ubepl_float_pz
338 #define C_PCM32SLE_FLOAT convert_pcm32sle_float_pz
339 #define C_PCM32SBE_FLOAT convert_pcm32sbe_float_pz
340 #define C_PCM32ULE_FLOAT convert_pcm32ule_float_pz
341 #define C_PCM32UBE_FLOAT convert_pcm32ube_float_pz
342 #define C_FLOAT_PCM8S convert_float_pcm8s_pz
343 #define C_FLOAT_PCM8U convert_float_pcm8u_pz
344 #define C_FLOAT_PCM16SLE convert_float_pcm16sle_pz
345 #define C_FLOAT_PCM16SBE convert_float_pcm16sbe_pz
346 #define C_FLOAT_PCM16ULE convert_float_pcm16ule_pz
347 #define C_FLOAT_PCM16UBE convert_float_pcm16ube_pz
348 #define C_FLOAT_PCM24SLE convert_float_pcm24sle_pz
349 #define C_FLOAT_PCM24SBE convert_float_pcm24sbe_pz
350 #define C_FLOAT_PCM24ULE convert_float_pcm24ule_pz
351 #define C_FLOAT_PCM24UBE convert_float_pcm24ube_pz
352 #define C_FLOAT_PCM24SLEPM convert_float_pcm24slepm_pz
353 #define C_FLOAT_PCM24SBEPM convert_float_pcm24sbepm_pz
354 #define C_FLOAT_PCM24ULEPM convert_float_pcm24ulepm_pz
355 #define C_FLOAT_PCM24UBEPM convert_float_pcm24ubepm_pz
356 #define C_FLOAT_PCM24SLEPL convert_float_pcm24slepl_pz
357 #define C_FLOAT_PCM24SBEPL convert_float_pcm24sbepl_pz
358 #define C_FLOAT_PCM24ULEPL convert_float_pcm24ulepl_pz
359 #define C_FLOAT_PCM24UBEPL convert_float_pcm24ubepl_pz
360 #define C_FLOAT_PCM32SLE convert_float_pcm32sle_pz
361 #define C_FLOAT_PCM32SBE convert_float_pcm32sbe_pz
362 #define C_FLOAT_PCM32ULE convert_float_pcm32ule_pz
363 #define C_FLOAT_PCM32UBE convert_float_pcm32ube_pz
364
365 #include "convert_inc.c"
366
367 /* 4) double-float, preserve-zero */
368
369 #define PZMODE
370 #define FTYPE double
371 #undef FTYPE_IS_FLOAT
372
373 #ifdef HAVE_LRINT
374 #define RINT(x) lrint(x)
375 #else
376 #define RINT(x) ((long int)((x<0)?(x-0.5000001):(x+0.5000001)))
377 #endif
378
379 #define C_PCM8S_FLOAT convert_pcm8s_double_pz
380 #define C_PCM8U_FLOAT convert_pcm8u_double_pz
381 #define C_PCM16SLE_FLOAT convert_pcm16sle_double_pz
382 #define C_PCM16SBE_FLOAT convert_pcm16sbe_double_pz
383 #define C_PCM16ULE_FLOAT convert_pcm16ule_double_pz
384 #define C_PCM16UBE_FLOAT convert_pcm16ube_double_pz
385 #define C_PCM24SLE_FLOAT convert_pcm24sle_double_pz
386 #define C_PCM24SBE_FLOAT convert_pcm24sbe_double_pz
387 #define C_PCM24ULE_FLOAT convert_pcm24ule_double_pz
388 #define C_PCM24UBE_FLOAT convert_pcm24ube_double_pz
389 #define C_PCM24SLEPM_FLOAT convert_pcm24slepm_double_pz
390 #define C_PCM24SBEPM_FLOAT convert_pcm24sbepm_double_pz
391 #define C_PCM24ULEPM_FLOAT convert_pcm24ulepm_double_pz
392 #define C_PCM24UBEPM_FLOAT convert_pcm24ubepm_double_pz
393 #define C_PCM24SLEPL_FLOAT convert_pcm24slepl_double_pz
394 #define C_PCM24SBEPL_FLOAT convert_pcm24sbepl_double_pz
395 #define C_PCM24ULEPL_FLOAT convert_pcm24ulepl_double_pz
396 #define C_PCM24UBEPL_FLOAT convert_pcm24ubepl_double_pz
397 #define C_PCM32SLE_FLOAT convert_pcm32sle_double_pz
398 #define C_PCM32SBE_FLOAT convert_pcm32sbe_double_pz
399 #define C_PCM32ULE_FLOAT convert_pcm32ule_double_pz
400 #define C_PCM32UBE_FLOAT convert_pcm32ube_double_pz
401 #define C_FLOAT_PCM8S convert_double_pcm8s_pz
402 #define C_FLOAT_PCM8U convert_double_pcm8u_pz
403 #define C_FLOAT_PCM16SLE convert_double_pcm16sle_pz
404 #define C_FLOAT_PCM16SBE convert_double_pcm16sbe_pz
405 #define C_FLOAT_PCM16ULE convert_double_pcm16ule_pz
406 #define C_FLOAT_PCM16UBE convert_double_pcm16ube_pz
407 #define C_FLOAT_PCM24SLE convert_double_pcm24sle_pz
408 #define C_FLOAT_PCM24SBE convert_double_pcm24sbe_pz
409 #define C_FLOAT_PCM24ULE convert_double_pcm24ule_pz
410 #define C_FLOAT_PCM24UBE convert_double_pcm24ube_pz
411 #define C_FLOAT_PCM24SLEPM convert_double_pcm24slepm_pz
412 #define C_FLOAT_PCM24SBEPM convert_double_pcm24sbepm_pz
413 #define C_FLOAT_PCM24ULEPM convert_double_pcm24ulepm_pz
414 #define C_FLOAT_PCM24UBEPM convert_double_pcm24ubepm_pz
415 #define C_FLOAT_PCM24SLEPL convert_double_pcm24slepl_pz
416 #define C_FLOAT_PCM24SBEPL convert_double_pcm24sbepl_pz
417 #define C_FLOAT_PCM24ULEPL convert_double_pcm24ulepl_pz
418 #define C_FLOAT_PCM24UBEPL convert_double_pcm24ubepl_pz
419 #define C_FLOAT_PCM32SLE convert_double_pcm32sle_pz
420 #define C_FLOAT_PCM32SBE convert_double_pcm32sbe_pz
421 #define C_FLOAT_PCM32ULE convert_double_pcm32ule_pz
422 #define C_FLOAT_PCM32UBE convert_double_pcm32ube_pz
423
424 #include "convert_inc.c"
425
426 typedef void (*convert_function_pf)(void *in, void *out, guint count);
427 typedef int (*convert_function_fp)(void *in, void *out, guint count);
428
429 /* (PZ-mode) (PCM size) (PCM sign) (PCM endian) (FP isdouble) */
430 static convert_function_pf pcm_fp_functions[96] = {
431 (convert_function_pf)convert_pcm8u_float,
432 (convert_function_pf)convert_pcm8u_double,
433 (convert_function_pf)convert_pcm8u_float,
434 (convert_function_pf)convert_pcm8u_double,
435 (convert_function_pf)convert_pcm8s_float,
436 (convert_function_pf)convert_pcm8s_double,
437 (convert_function_pf)convert_pcm8s_float,
438 (convert_function_pf)convert_pcm8s_double,
439 (convert_function_pf)convert_pcm16ule_float,
440 (convert_function_pf)convert_pcm16ule_double,
441 (convert_function_pf)convert_pcm16ube_float,
442 (convert_function_pf)convert_pcm16ube_double,
443 (convert_function_pf)convert_pcm16sle_float,
444 (convert_function_pf)convert_pcm16sle_double,
445 (convert_function_pf)convert_pcm16sbe_float,
446 (convert_function_pf)convert_pcm16sbe_double,
447 (convert_function_pf)convert_pcm24ule_float,
448 (convert_function_pf)convert_pcm24ule_double,
449 (convert_function_pf)convert_pcm24ube_float,
450 (convert_function_pf)convert_pcm24ube_double,
451 (convert_function_pf)convert_pcm24sle_float,
452 (convert_function_pf)convert_pcm24sle_double,
453 (convert_function_pf)convert_pcm24sbe_float,
454 (convert_function_pf)convert_pcm24sbe_double,
455 (convert_function_pf)convert_pcm32ule_float,
456 (convert_function_pf)convert_pcm32ule_double,
457 (convert_function_pf)convert_pcm32ube_float,
458 (convert_function_pf)convert_pcm32ube_double,
459 (convert_function_pf)convert_pcm32sle_float,
460 (convert_function_pf)convert_pcm32sle_double,
461 (convert_function_pf)convert_pcm32sbe_float,
462 (convert_function_pf)convert_pcm32sbe_double,
463 (convert_function_pf)convert_pcm24ulepm_float,
464 (convert_function_pf)convert_pcm24ulepm_double,
465 (convert_function_pf)convert_pcm24ubepm_float,
466 (convert_function_pf)convert_pcm24ubepm_double,
467 (convert_function_pf)convert_pcm24slepm_float,
468 (convert_function_pf)convert_pcm24slepm_double,
469 (convert_function_pf)convert_pcm24sbepm_float,
470 (convert_function_pf)convert_pcm24sbepm_double,
471 (convert_function_pf)convert_pcm24ulepl_float,
472 (convert_function_pf)convert_pcm24ulepl_double,
473 (convert_function_pf)convert_pcm24ubepl_float,
474 (convert_function_pf)convert_pcm24ubepl_double,
475 (convert_function_pf)convert_pcm24slepl_float,
476 (convert_function_pf)convert_pcm24slepl_double,
477 (convert_function_pf)convert_pcm24sbepl_float,
478 (convert_function_pf)convert_pcm24sbepl_double,
479 (convert_function_pf)convert_pcm8u_float_pz,
480 (convert_function_pf)convert_pcm8u_double_pz,
481 (convert_function_pf)convert_pcm8u_float_pz,
482 (convert_function_pf)convert_pcm8u_double_pz,
483 (convert_function_pf)convert_pcm8s_float_pz,
484 (convert_function_pf)convert_pcm8s_double_pz,
485 (convert_function_pf)convert_pcm8s_float_pz,
486 (convert_function_pf)convert_pcm8s_double_pz,
487 (convert_function_pf)convert_pcm16ule_float_pz,
488 (convert_function_pf)convert_pcm16ule_double_pz,
489 (convert_function_pf)convert_pcm16ube_float_pz,
490 (convert_function_pf)convert_pcm16ube_double_pz,
491 (convert_function_pf)convert_pcm16sle_float_pz,
492 (convert_function_pf)convert_pcm16sle_double_pz,
493 (convert_function_pf)convert_pcm16sbe_float_pz,
494 (convert_function_pf)convert_pcm16sbe_double_pz,
495 (convert_function_pf)convert_pcm24ule_float_pz,
496 (convert_function_pf)convert_pcm24ule_double_pz,
497 (convert_function_pf)convert_pcm24ube_float_pz,
498 (convert_function_pf)convert_pcm24ube_double_pz,
499 (convert_function_pf)convert_pcm24sle_float_pz,
500 (convert_function_pf)convert_pcm24sle_double_pz,
501 (convert_function_pf)convert_pcm24sbe_float_pz,
502 (convert_function_pf)convert_pcm24sbe_double_pz,
503 (convert_function_pf)convert_pcm32ule_float_pz,
504 (convert_function_pf)convert_pcm32ule_double_pz,
505 (convert_function_pf)convert_pcm32ube_float_pz,
506 (convert_function_pf)convert_pcm32ube_double_pz,
507 (convert_function_pf)convert_pcm32sle_float_pz,
508 (convert_function_pf)convert_pcm32sle_double_pz,
509 (convert_function_pf)convert_pcm32sbe_float_pz,
510 (convert_function_pf)convert_pcm32sbe_double_pz,
511 (convert_function_pf)convert_pcm24ulepm_float_pz,
512 (convert_function_pf)convert_pcm24ulepm_double_pz,
513 (convert_function_pf)convert_pcm24ubepm_float_pz,
514 (convert_function_pf)convert_pcm24ubepm_double_pz,
515 (convert_function_pf)convert_pcm24slepm_float_pz,
516 (convert_function_pf)convert_pcm24slepm_double_pz,
517 (convert_function_pf)convert_pcm24sbepm_float_pz,
518 (convert_function_pf)convert_pcm24sbepm_double_pz,
519 (convert_function_pf)convert_pcm24ulepl_float_pz,
520 (convert_function_pf)convert_pcm24ulepl_double_pz,
521 (convert_function_pf)convert_pcm24ubepl_float_pz,
522 (convert_function_pf)convert_pcm24ubepl_double_pz,
523 (convert_function_pf)convert_pcm24slepl_float_pz,
524 (convert_function_pf)convert_pcm24slepl_double_pz,
525 (convert_function_pf)convert_pcm24sbepl_float_pz,
526 (convert_function_pf)convert_pcm24sbepl_double_pz
527 };
528
529 /* (PZ-mode) (PCM size) (PCM sign) (PCM endian) (FP isdouble) */
530 static convert_function_fp fp_pcm_functions[96] = {
531 (convert_function_fp)convert_float_pcm8u,
532 (convert_function_fp)convert_double_pcm8u,
533 (convert_function_fp)convert_float_pcm8u,
534 (convert_function_fp)convert_double_pcm8u,
535 (convert_function_fp)convert_float_pcm8s,
536 (convert_function_fp)convert_double_pcm8s,
537 (convert_function_fp)convert_float_pcm8s,
538 (convert_function_fp)convert_double_pcm8s,
539 (convert_function_fp)convert_float_pcm16ule,
540 (convert_function_fp)convert_double_pcm16ule,
541 (convert_function_fp)convert_float_pcm16ube,
542 (convert_function_fp)convert_double_pcm16ube,
543 (convert_function_fp)convert_float_pcm16sle,
544 (convert_function_fp)convert_double_pcm16sle,
545 (convert_function_fp)convert_float_pcm16sbe,
546 (convert_function_fp)convert_double_pcm16sbe,
547 (convert_function_fp)convert_float_pcm24ule,
548 (convert_function_fp)convert_double_pcm24ule,
549 (convert_function_fp)convert_float_pcm24ube,
550 (convert_function_fp)convert_double_pcm24ube,
551 (convert_function_fp)convert_float_pcm24sle,
552 (convert_function_fp)convert_double_pcm24sle,
553 (convert_function_fp)convert_float_pcm24sbe,
554 (convert_function_fp)convert_double_pcm24sbe,
555 (convert_function_fp)convert_float_pcm32ule,
556 (convert_function_fp)convert_double_pcm32ule,
557 (convert_function_fp)convert_float_pcm32ube,
558 (convert_function_fp)convert_double_pcm32ube,
559 (convert_function_fp)convert_float_pcm32sle,
560 (convert_function_fp)convert_double_pcm32sle,
561 (convert_function_fp)convert_float_pcm32sbe,
562 (convert_function_fp)convert_double_pcm32sbe,
563 (convert_function_fp)convert_float_pcm24ulepm,
564 (convert_function_fp)convert_double_pcm24ulepm,
565 (convert_function_fp)convert_float_pcm24ubepm,
566 (convert_function_fp)convert_double_pcm24ubepm,
567 (convert_function_fp)convert_float_pcm24slepm,
568 (convert_function_fp)convert_double_pcm24slepm,
569 (convert_function_fp)convert_float_pcm24sbepm,
570 (convert_function_fp)convert_double_pcm24sbepm,
571 (convert_function_fp)convert_float_pcm24ulepl,
572 (convert_function_fp)convert_double_pcm24ulepl,
573 (convert_function_fp)convert_float_pcm24ubepl,
574 (convert_function_fp)convert_double_pcm24ubepl,
575 (convert_function_fp)convert_float_pcm24slepl,
576 (convert_function_fp)convert_double_pcm24slepl,
577 (convert_function_fp)convert_float_pcm24sbepl,
578 (convert_function_fp)convert_double_pcm24sbepl,
579 (convert_function_fp)convert_float_pcm8u_pz,
580 (convert_function_fp)convert_double_pcm8u_pz,
581 (convert_function_fp)convert_float_pcm8u_pz,
582 (convert_function_fp)convert_double_pcm8u_pz,
583 (convert_function_fp)convert_float_pcm8s_pz,
584 (convert_function_fp)convert_double_pcm8s_pz,
585 (convert_function_fp)convert_float_pcm8s_pz,
586 (convert_function_fp)convert_double_pcm8s_pz,
587 (convert_function_fp)convert_float_pcm16ule_pz,
588 (convert_function_fp)convert_double_pcm16ule_pz,
589 (convert_function_fp)convert_float_pcm16ube_pz,
590 (convert_function_fp)convert_double_pcm16ube_pz,
591 (convert_function_fp)convert_float_pcm16sle_pz,
592 (convert_function_fp)convert_double_pcm16sle_pz,
593 (convert_function_fp)convert_float_pcm16sbe_pz,
594 (convert_function_fp)convert_double_pcm16sbe_pz,
595 (convert_function_fp)convert_float_pcm24ule_pz,
596 (convert_function_fp)convert_double_pcm24ule_pz,
597 (convert_function_fp)convert_float_pcm24ube_pz,
598 (convert_function_fp)convert_double_pcm24ube_pz,
599 (convert_function_fp)convert_float_pcm24sle_pz,
600 (convert_function_fp)convert_double_pcm24sle_pz,
601 (convert_function_fp)convert_float_pcm24sbe_pz,
602 (convert_function_fp)convert_double_pcm24sbe_pz,
603 (convert_function_fp)convert_float_pcm32ule_pz,
604 (convert_function_fp)convert_double_pcm32ule_pz,
605 (convert_function_fp)convert_float_pcm32ube_pz,
606 (convert_function_fp)convert_double_pcm32ube_pz,
607 (convert_function_fp)convert_float_pcm32sle_pz,
608 (convert_function_fp)convert_double_pcm32sle_pz,
609 (convert_function_fp)convert_float_pcm32sbe_pz,
610 (convert_function_fp)convert_double_pcm32sbe_pz,
611 (convert_function_fp)convert_float_pcm24ulepm_pz,
612 (convert_function_fp)convert_double_pcm24ulepm_pz,
613 (convert_function_fp)convert_float_pcm24ubepm_pz,
614 (convert_function_fp)convert_double_pcm24ubepm_pz,
615 (convert_function_fp)convert_float_pcm24slepm_pz,
616 (convert_function_fp)convert_double_pcm24slepm_pz,
617 (convert_function_fp)convert_float_pcm24sbepm_pz,
618 (convert_function_fp)convert_double_pcm24sbepm_pz,
619 (convert_function_fp)convert_float_pcm24ulepl_pz,
620 (convert_function_fp)convert_double_pcm24ulepl_pz,
621 (convert_function_fp)convert_float_pcm24ubepl_pz,
622 (convert_function_fp)convert_double_pcm24ubepl_pz,
623 (convert_function_fp)convert_float_pcm24slepl_pz,
624 (convert_function_fp)convert_double_pcm24slepl_pz,
625 (convert_function_fp)convert_float_pcm24sbepl_pz,
626 (convert_function_fp)convert_double_pcm24sbepl_pz
627 };
628
629
630 /* The values in these tables correspond to one LSB step and are used as
631 * amplitude for the dithering, adjusted to avoid numerical (double
632 * rounding) problems. These exact values were found by changing so
633 * frand/drand return constant +/- 0.5 and adjusting until the self-test
634 * passes. */
635
636 static const float dither_amp_biased_float[4] = {
637 /* (1.0/127.5), (1.0/32767.5), (1.0/8388607.5), (1.0/2147483647.5) */
638 0.007842957, 3.033876e-5, 0.0, 0.0
639 };
640 static const float dither_amp_scaled_float[4] = {
641 /* (1.0/127.0), (1.0/32767.0), (1.0/8388607.0), (1.0/2147483647.0) */
642 0.007873832, 3.033876e-5, 0.0, 0.0
643 };
644
645 static const double dither_amp_biased_double[4] = {
646 /* (1.0/127.5), (1.0/32767.5), (1.0/8388607.5), (1.0/2147483647.5) */
647 0.007843137254901598, 3.051804379305967e-05, 1.192092963231417e-07, 4.656611762854367e-10
648 };
649 static const float dither_amp_scaled_double[4] = {
650 /* (1.0/127.0), (1.0/32767.0), (1.0/8388607.0), (1.0/2147483647.0) */
651 0.007874015751697883, 3.051850948998556e-05, 1.192092966562086e-07, 4.656610513853464e-10
652 };
653
frand(void)654 static float frand(void)
655 {
656 long l;
657 float f;
658 l = rand();
659 l &= ~1;
660 f = ((float)l) / ((float)RAND_MAX);
661 f -= 0.5;
662 /* g_assert(f >= -0.5 && f <= 0.5); */
663 return f;
664 }
665
dither_convert_float(float * indata,char * outdata,int count,convert_function_fp fn,int outdata_ssize)666 static int dither_convert_float(float *indata, char *outdata, int count,
667 convert_function_fp fn, int outdata_ssize)
668 {
669 float amp_factor;
670 float databuf[4096];
671 int i,j,r=0;
672 /* amp_factor = powf(2.0f,(float)(1-outdata_ssize*8)); */
673 if (sample_convert_mode == CONVERT_MODE_BIASED)
674 amp_factor = dither_amp_biased_float[outdata_ssize-1];
675 else
676 amp_factor = dither_amp_scaled_float[outdata_ssize-1];
677 while (count > 0) {
678 i = MIN(count,ARRAY_LENGTH(databuf));
679 memcpy(databuf,indata,i*sizeof(float));
680 for (j=0; j<i; j++)
681 databuf[j] += frand() * amp_factor;
682 r += fn(databuf,outdata,i);
683 indata += i;
684 outdata += outdata_ssize * i;
685 count -= i;
686 }
687 return r;
688 }
689
drand(void)690 static double drand(void)
691 {
692 long l;
693 double d;
694 l = rand();
695 l &= ~1;
696 d = ((double)l) / ((double)RAND_MAX);
697 d -= 0.5;
698 /* g_assert (d >= -0.5 && d <= 0.5); */
699 return d;
700 }
701
dither_convert_double(double * indata,char * outdata,int count,convert_function_fp fn,int outdata_ssize)702 static int dither_convert_double(double *indata, char *outdata, int count,
703 convert_function_fp fn, int outdata_ssize)
704 {
705 double amp_factor;
706 double databuf[4096];
707 int i,j,r=0;
708 /* amp_factor = pow(2.0,(double)(1-outdata_ssize*8)); */
709 if (sample_convert_mode == CONVERT_MODE_BIASED)
710 amp_factor = dither_amp_biased_double[outdata_ssize-1];
711 else
712 amp_factor = dither_amp_scaled_double[outdata_ssize-1];
713 while (count > 0) {
714 i = MIN(count,ARRAY_LENGTH(databuf));
715 memcpy(databuf,indata,i*sizeof(double));
716 for (j=0; j<i; j++)
717 databuf[j] += drand() * amp_factor;
718 r += fn(databuf,outdata,i);
719 indata += i;
720 outdata += outdata_ssize * i;
721 count -= i;
722 }
723 return r;
724 }
725
real_ssize(Dataformat * f)726 static int real_ssize(Dataformat *f)
727 {
728 if (f->type == DATAFORMAT_PCM &&
729 f->samplesize == 4 &&
730 f->packing != 0) return 3;
731 else return f->samplesize;
732 }
733
minimum_float_value(Dataformat * x)734 sample_t minimum_float_value(Dataformat *x)
735 {
736 static const sample_t tbl[4] = {
737 (-128.0/127.0), (-32768.0/32767.0),
738 (-8388608.0/8388607.0), (-2147483648.0/2147483647.0) };
739
740 if (sample_convert_mode==0 || x->type!=DATAFORMAT_PCM)
741 return -1.0;
742 else
743 return tbl[real_ssize(x) - 1];
744 }
745
convert_factor(Dataformat * infmt,Dataformat * outfmt)746 sample_t convert_factor(Dataformat *infmt, Dataformat *outfmt)
747 {
748 sample_t fneg;
749 fneg = minimum_float_value(outfmt) / minimum_float_value(infmt);
750 return fneg;
751 }
752
apply_convert_factor(Dataformat * infmt,Dataformat * outfmt,sample_t * buffer,guint count)753 void apply_convert_factor(Dataformat *infmt, Dataformat *outfmt,
754 sample_t *buffer, guint count)
755 {
756 sample_t f;
757 guint i;
758 if (sample_convert_mode == 0 || infmt->type!=DATAFORMAT_PCM ||
759 outfmt->type!=DATAFORMAT_PCM)
760 return;
761 f = convert_factor(infmt,outfmt);
762 for (i=0; i<count; i++)
763 buffer[i] *= f;
764 }
765
convert_array(void * indata,Dataformat * indata_format,void * outdata,Dataformat * outdata_format,guint count,int dither_mode,off_t * clipcount)766 void convert_array(void *indata, Dataformat *indata_format,
767 void *outdata, Dataformat *outdata_format,
768 guint count, int dither_mode, off_t *clipcount)
769 {
770 int i,cc;
771 char *c;
772 if (dataformat_samples_equal(indata_format,outdata_format)) {
773 memcpy(outdata,indata,count*indata_format->samplesize);
774 } else if (indata_format->type == DATAFORMAT_PCM) {
775 if (outdata_format->type == DATAFORMAT_PCM) {
776 /* PCM -> PCM conversion */
777 if (real_ssize(outdata_format) >= real_ssize(indata_format) && sample_convert_mode==CONVERT_MODE_NOOFFS)
778 dither_mode = DITHER_NONE;
779 c = g_malloc(count * sizeof(sample_t));
780 convert_array(indata,indata_format,c,&dataformat_sample_t,
781 count,dither_mode,clipcount);
782 apply_convert_factor(indata_format,outdata_format,
783 (sample_t *)c, count);
784 convert_array(c,&dataformat_sample_t,outdata,outdata_format,
785 count,dither_mode,clipcount);
786 g_free(c);
787 } else {
788 /* PCM -> FP conversion */
789 i = (sample_convert_mode ? 48:0) +
790 (indata_format->samplesize-1)*8 +
791 (indata_format->sign?4:0) +
792 (indata_format->bigendian?2:0) +
793 (outdata_format->samplesize/sizeof(double));
794 if (indata_format->samplesize == 4) i += 8*indata_format->packing;
795 /* printf("convert_array: i=%d\n",i); */
796 g_assert(i<ARRAY_LENGTH(pcm_fp_functions));
797 pcm_fp_functions[i](indata,outdata,count);
798 if (XOR(outdata_format->bigendian, dataformat_sample_t.bigendian))
799 byteswap(outdata,outdata_format->samplesize,
800 count*outdata_format->samplesize);
801 }
802 } else if (outdata_format->type == DATAFORMAT_PCM) {
803 /* FP -> PCM conversion */
804 if (XOR(indata_format->bigendian, dataformat_sample_t.bigendian)) {
805 byteswap(indata,indata_format->samplesize,
806 count*indata_format->samplesize);
807 }
808 i = (sample_convert_mode ? 48:0) +
809 (outdata_format->samplesize-1)*8 +
810 (outdata_format->sign?4:0) +
811 (outdata_format->bigendian?2:0) +
812 (indata_format->samplesize/sizeof(double));
813 if (outdata_format->samplesize == 4) i += 8*outdata_format->packing;
814 g_assert(i < ARRAY_LENGTH(fp_pcm_functions));
815 if (indata_format->samplesize == sizeof(float) && outdata_format->samplesize > 2)
816 dither_mode = DITHER_NONE;
817 g_assert(dither_mode != DITHER_UNSPEC);
818 if (dither_mode != DITHER_NONE) {
819 if (indata_format->samplesize == sizeof(float))
820 cc = dither_convert_float(indata,outdata,count,
821 fp_pcm_functions[i],
822 real_ssize(outdata_format));
823 else
824 cc = dither_convert_double(indata,outdata,count,
825 fp_pcm_functions[i],
826 real_ssize(outdata_format));
827 } else
828 cc = fp_pcm_functions[i](indata,outdata,count);
829 if (XOR(indata_format->bigendian, dataformat_sample_t.bigendian)) {
830 byteswap(indata,indata_format->samplesize,
831 count*indata_format->samplesize);
832 }
833 if (clipcount != NULL) *clipcount += cc;
834 } else {
835 /* FP -> FP conversion */
836 if (indata_format->samplesize == outdata_format->samplesize) {
837 g_assert(XOR(indata_format->bigendian, outdata_format->bigendian));
838 memcpy(outdata,indata,count*indata_format->samplesize);
839 byteswap(outdata,outdata_format->samplesize,count*outdata_format->samplesize);
840 return;
841 }
842
843 if (XOR(indata_format->bigendian, dataformat_sample_t.bigendian))
844 byteswap(indata,indata_format->samplesize,
845 count*indata_format->samplesize);
846 if (indata_format->samplesize == sizeof(float)) {
847 g_assert(outdata_format->samplesize == sizeof(double));
848 float *f = indata;
849 double *d = outdata;
850 int c = count;
851 for (; c>0; c--,f++,d++)
852 *d = (double)(*f);
853 } else {
854 g_assert(outdata_format->samplesize == sizeof(float));
855 double *d = indata;
856 float *f = outdata;
857 int c = count;
858 for (; c>0; c--,f++,d++)
859 *f = (float)(*d);
860 }
861 if (XOR(indata_format->bigendian, dataformat_sample_t.bigendian))
862 byteswap(indata,indata_format->samplesize,
863 count*indata_format->samplesize);
864 if (XOR(outdata_format->bigendian, dataformat_sample_t.bigendian))
865 byteswap(outdata,outdata_format->samplesize,
866 count*outdata_format->samplesize);
867 }
868 }
869
unnormalized_count(sample_t * buf,gint count,Dataformat * target)870 gint unnormalized_count(sample_t *buf, gint count, Dataformat *target)
871 {
872 gint i,c=0;
873 sample_t maxval,minval;
874 maxval = maximum_float_value(target);
875 minval = minimum_float_value(target);
876 for (i=0; i<count; i++)
877 if (buf[i] > maxval || buf[i] < minval)
878 c++;
879 return c;
880 }
881
print_format(Dataformat * fmt)882 static void print_format(Dataformat *fmt)
883 {
884 if (fmt->type == DATAFORMAT_FLOAT) {
885 if (fmt->samplesize == sizeof(float))
886 printf(_("Floating-point (single %s)\n"),fmt->bigendian?_("Big-endian"):_("Little-endian"));
887 else
888 printf(_("Floating-point (double %s)\n"),fmt->bigendian?_("Big-endian"):_("Little-endian"));
889 } else {
890 printf(_("PCM, %d(%d) bit, %s %s\n"), real_ssize(fmt)*8, fmt->samplesize*8,
891 fmt->sign?_("Signed"):_("Unsigned"),
892 fmt->bigendian?_("Big-endian"):_("Little-endian"));
893 }
894 }
895
896 #define SBUFLEN 32
conversion_selftest(void)897 void conversion_selftest(void)
898 {
899 guint samplesizes[] = { 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
900 4, 4, 4, 4, 4, 4, 4, 4,
901 sizeof(float), sizeof(float), sizeof(double), sizeof(double) };
902 gboolean signs[] = { FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
903 FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
904 FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
905 FALSE, FALSE, FALSE, FALSE };
906 gboolean endians[] = { FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE,
907 FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE,
908 FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE,
909 FALSE, TRUE, FALSE, TRUE };
910 gint packings[] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
911 1,1,1,1,2,2,2,2,
912 0,0,0,0 };
913 gint types[] = { DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
914 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
915 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
916 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
917 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
918 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
919 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
920 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
921 DATAFORMAT_FLOAT, DATAFORMAT_FLOAT,
922 DATAFORMAT_FLOAT, DATAFORMAT_FLOAT};
923 guchar pcm_buf[SBUFLEN*8],pcm_buf2[SBUFLEN*8],pcm_buf3[SBUFLEN*8];
924 sample_t sbuf[SBUFLEN],sbuf2[SBUFLEN],sbuf3[SBUFLEN],sbuf4[SBUFLEN],s,s2;
925 guint i,j,k;
926 Dataformat fmt[2];
927 gboolean expect_fail, err=FALSE;
928 int dm,scm;
929 off_t cc;
930
931 #if 0
932 fmt[0].type = DATAFORMAT_PCM;
933 fmt[0].samplesize = 1;
934 fmt[0].sign = FALSE;
935 fmt[0].bigendian = TRUE;
936 fmt[0].packing = 0;
937 for (i=0; i<256; i++) pcm_buf[i] = i;
938 convert_array(pcm_buf,fmt,sbuf,&dataformat_sample_t,256);
939 convert_array(sbuf,&dataformat_sample_t,pcm_buf2,fmt,256);
940 for (i=0; i<256; i++)
941 printf("%d -> %f -> %d\n",pcm_buf[i],sbuf[i],pcm_buf2[i]);
942 return;
943 #endif
944
945 /* puts(""); */
946
947 /* Perform tests */
948 for (dm=0; dm<2; dm++) {
949 for (scm=0; scm<2; scm++) {
950 printf("Dither mode: %d, Convert mode: %d\n",dm,scm);
951 sample_convert_mode = scm;
952 puts(_(" Testing ranges..."));
953
954 /* Generate full range in sample_t buffer */
955 for (j=0; j<SBUFLEN; j++)
956 sbuf[j] = 2.0*(sample_t)j/(sample_t)(SBUFLEN-1) - 1.0;
957
958 for (i=0; i<ARRAY_LENGTH(samplesizes); i++) {
959 fmt[0].type = types[i];
960 fmt[0].samplesize = samplesizes[i];
961 fmt[0].sign = signs[i];
962 fmt[0].bigendian = endians[i];
963 fmt[0].samplebytes = fmt[0].samplesize;
964 fmt[0].channels = 1;
965 fmt[0].packing = packings[i];
966 convert_array(sbuf,&dataformat_sample_t,pcm_buf2,fmt,
967 SBUFLEN,dm,NULL);
968 convert_array(pcm_buf2,fmt,sbuf2,&dataformat_sample_t,
969 SBUFLEN,dm,NULL);
970 convert_array(sbuf2,&dataformat_sample_t,pcm_buf3,fmt,
971 SBUFLEN,dm,NULL);
972
973 if ((sbuf2[0] != -1.0) ||
974 (sbuf2[SBUFLEN-1] != 1.0) ||
975 memcmp(pcm_buf2,pcm_buf3,SBUFLEN*fmt[0].samplesize)) {
976 fputs(_("Range test failed for format: "),stdout);
977 print_format(fmt);
978 printf(" %.10f -> %.10f, %.10f -> %.10f\n",sbuf[0],sbuf2[0],
979 sbuf[SBUFLEN-1],sbuf2[SBUFLEN-1]);
980 for (j=0,k=0; j<SBUFLEN; j++,k+=fmt[0].samplesize) {
981 printf("%.10f %02x %02x %02x %02x %.10f %02x %02x %02x %02x %c\n",
982 sbuf [j], pcm_buf2[k], pcm_buf2[k+1], pcm_buf2[k+2], pcm_buf2[k+3],
983 sbuf2[j], pcm_buf3[k], pcm_buf3[k+1], pcm_buf3[k+2], pcm_buf3[k+3],
984 (memcmp(pcm_buf2+k,pcm_buf3+k,fmt[0].samplesize) ? '!':' '));
985 }
986 err = TRUE;
987 }
988 }
989
990 puts(_(" Testing all conversions.."));
991
992 /* Generate random numbers in sbuf vector */
993 for (i=0; i<ARRAY_LENGTH(sbuf); i++)
994 sbuf[i] = 2.0 * (float)rand() / (float)RAND_MAX - 1.0;
995
996 for (i=0; i<ARRAY_LENGTH(samplesizes); i++) {
997 fmt[0].type = types[i];
998 fmt[0].samplesize = samplesizes[i];
999 fmt[0].sign = signs[i];
1000 fmt[0].bigendian = endians[i];
1001 fmt[0].packing = packings[i];
1002 memset(pcm_buf,0,sizeof(pcm_buf));
1003 memset(pcm_buf2,0,sizeof(pcm_buf));
1004 memset(pcm_buf3,0,sizeof(pcm_buf));
1005 convert_array(sbuf,&dataformat_sample_t,pcm_buf,fmt,
1006 ARRAY_LENGTH(sbuf),dm,NULL);
1007 for (j=0; j<ARRAY_LENGTH(samplesizes); j++) {
1008 fmt[1].type = types[j];
1009 fmt[1].samplesize = samplesizes[j];
1010 fmt[1].sign = signs[j];
1011 fmt[1].bigendian = endians[j];
1012 fmt[1].packing = packings[i];
1013 if ((fmt[0].type == DATAFORMAT_PCM &&
1014 fmt[1].type == DATAFORMAT_FLOAT &&
1015 fmt[0].samplesize == 4 && fmt[1].samplesize == 4) ||
1016 (fmt[1].type == DATAFORMAT_PCM &&
1017 fmt[0].type == DATAFORMAT_FLOAT &&
1018 fmt[0].samplesize == 4 && fmt[1].samplesize == 4) ||
1019 fmt[0].samplesize > fmt[1].samplesize ||
1020 (fmt[0].samplesize != fmt[1].samplesize &&
1021 dm != 0 && scm == 0))
1022 expect_fail = TRUE;
1023 else
1024 expect_fail = FALSE;
1025 if (expect_fail) continue;
1026 convert_array(pcm_buf,fmt,pcm_buf2,fmt+1,ARRAY_LENGTH(sbuf),
1027 dm,NULL);
1028 convert_array(pcm_buf2,fmt+1,pcm_buf3,fmt,ARRAY_LENGTH(sbuf),
1029 dm,NULL);
1030 if (memcmp(pcm_buf,pcm_buf3,
1031 ARRAY_LENGTH(sbuf)*fmt[0].samplesize)) {
1032 if (expect_fail) fputs(_("(expected) "),stdout);
1033 fputs(_("Conversion test failed, between: "),stdout);
1034 print_format(fmt);
1035 fputs(_(" and: "),stdout);
1036 print_format(fmt+1);
1037 for (j=0,k=0; j<SBUFLEN; j++,k+=fmt[0].samplesize) {
1038 printf("%.10f %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %c\n",
1039 sbuf [j], pcm_buf[k], pcm_buf[k+1], pcm_buf[k+2], pcm_buf[k+3],
1040 pcm_buf2[k], pcm_buf2[k+1], pcm_buf2[k+2], pcm_buf2[k+3],
1041 pcm_buf3[k], pcm_buf3[k+1], pcm_buf3[k+2], pcm_buf3[k+3],
1042 (memcmp(pcm_buf+k,pcm_buf3+k,fmt[0].samplesize) ? '!':' '));
1043 }
1044 err = TRUE;
1045 }
1046 }
1047 }
1048
1049 puts(" Testing dithering...");
1050 for (i=0; i<ARRAY_LENGTH(samplesizes); i++) {
1051 if (types[i] != DATAFORMAT_PCM || (samplesizes[i]>2 && sizeof(sample_t)<8)) continue;
1052 fmt[0].type = types[i];
1053 fmt[0].samplesize = samplesizes[i];
1054 fmt[0].sign = signs[i];
1055 fmt[0].bigendian = endians[i];
1056 fmt[0].packing = packings[i];
1057 /* print_format(fmt); */
1058 /* Get FP values for minimum and minimum+1 */
1059 int sgnloc = (packings[i] == 2) ? 1 : 0;
1060 int lsbloc = (packings[i] == 1) ? 2 : (samplesizes[i]-1);
1061 if (!endians[i]) { sgnloc=samplesizes[i]-1-sgnloc; lsbloc=samplesizes[i]-1-lsbloc; }
1062 memset(pcm_buf,0,8);
1063 if (signs[i]) {
1064 pcm_buf[sgnloc] = 0x80;
1065 pcm_buf[samplesizes[i]+sgnloc] = 0x80;
1066 }
1067 pcm_buf[samplesizes[i]+lsbloc] += 1;
1068 convert_array(pcm_buf,fmt,sbuf,&dataformat_sample_t,2,DITHER_NONE,NULL);
1069 /* printf("%02x %02x %02x %02x %02x %02x %02x %02x %f %f\n",
1070 pcm_buf[0], pcm_buf[1], pcm_buf[2], pcm_buf[3], pcm_buf[4], pcm_buf[5], pcm_buf[6], pcm_buf[7],
1071 sbuf[0],sbuf[1]); */
1072 g_assert(sbuf[0] <= -1.0 && sbuf[1]>sbuf[0]);
1073 s = sbuf[1];
1074 sbuf[SBUFLEN-1] = s;
1075 s = (s-sbuf[0]) / ((sample_t)(SBUFLEN-1));
1076 s2 = sbuf[0];
1077 for (j=0; j<SBUFLEN-1; j++,s2+=s)
1078 sbuf[j] = s2;
1079 memset(sbuf3,0,sizeof(sbuf3));
1080 memset(sbuf4,0,sizeof(sbuf4));
1081 for (k=0; k<10000; k++) {
1082 cc = 0;
1083 convert_array(sbuf,&dataformat_sample_t,pcm_buf,fmt,SBUFLEN,dm,&cc);
1084 convert_array(pcm_buf,fmt,sbuf2,&dataformat_sample_t,SBUFLEN,dm,&cc);
1085 g_assert(cc == 0);
1086 for (j=0; j<SBUFLEN; j++) {
1087 s = (sbuf2[j]-sbuf[j])/(sbuf[SBUFLEN-1]-sbuf[0])*0.0001;
1088 sbuf3[j] += s;
1089 sbuf4[j] += s*s;
1090 }
1091 }
1092 for (j=0; j<SBUFLEN; j++) {
1093 s = sbuf4[j]-sbuf3[j]*sbuf3[j]*0.0001;
1094 if (dm == DITHER_NONE) {
1095 if (sbuf3[j] < -0.5001 || sbuf3[j] > 0.5001 || s > 1e-7) break;
1096 } else {
1097 if (sbuf3[j] < -0.02 || sbuf3[j] > 0.02 || s > 1e-4) break;
1098 }
1099 }
1100 if (j < SBUFLEN) {
1101 err = TRUE;
1102 printf("Dither test failed for mode %d format: ",dm);
1103 print_format(fmt);
1104 for (j=0; j<SBUFLEN; j++) {
1105 printf("%.10f %.10f %.10f\n",sbuf[j],sbuf3[j],(sbuf4[j]-sbuf3[j]*sbuf3[j]*0.01));
1106 }
1107 }
1108 }
1109 }
1110 }
1111
1112 if (!err) puts(_("No errors detected!"));
1113 #undef SBUFLEN
1114 }
1115
conversion_performance_test(void)1116 void conversion_performance_test(void)
1117 {
1118 #define SBUFLEN 10000
1119 #define FORMATS 16
1120 guint samplesizes[] = { 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4,
1121 sizeof(float), sizeof(double) };
1122 gboolean signs[] = { FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
1123 FALSE, TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE,
1124 FALSE, FALSE };
1125 gboolean endians[] = { FALSE, FALSE, FALSE, FALSE, TRUE, TRUE,
1126 FALSE, FALSE, TRUE, TRUE, FALSE, FALSE, TRUE, TRUE,
1127 FALSE, FALSE };
1128 gint types[] = { DATAFORMAT_PCM,
1129 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
1130 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
1131 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
1132 DATAFORMAT_PCM, DATAFORMAT_PCM, DATAFORMAT_PCM,
1133 DATAFORMAT_PCM, DATAFORMAT_FLOAT, DATAFORMAT_FLOAT };
1134 gchar *strings[] = { "8U", "8S",
1135 "16U_LE", "16S_LE", "16U_BE", "16S_BE",
1136 "24U_LE", "24S_LE", "24U_BE", "24S_BE",
1137 "32U_LE", "32S_LE", "32U_BE", "32S_BE",
1138 "FP_s", "FP_d" };
1139 GTimeVal start_time, end_time, test_times[FORMATS*FORMATS];
1140 sample_t *sbuf;
1141 gpointer buf,buf2;
1142 guint i,j;
1143 gfloat f,g;
1144 Dataformat fmt[2];
1145
1146 puts(_("Preparing tests.."));
1147 sbuf = g_malloc(SBUFLEN * sizeof(*sbuf));
1148 buf = g_malloc(SBUFLEN * 8);
1149 buf2 = g_malloc(SBUFLEN * 8);
1150
1151 for (i=0; i<SBUFLEN; i++)
1152 sbuf[i] = 2.0 * (float)rand() / (float)RAND_MAX - 1.0;
1153
1154 fputs(_("Running tests.."),stdout);
1155 fflush(stdout);
1156 for (i=0; i<FORMATS; i++) {
1157 fmt[0].type = types[i];
1158 fmt[0].samplesize = samplesizes[i];
1159 fmt[0].sign = signs[i];
1160 fmt[0].bigendian = endians[i];
1161 fmt[0].packing = 0;
1162 convert_array(sbuf,&dataformat_sample_t,buf,fmt,SBUFLEN,DITHER_NONE,NULL);
1163 for (j=0; j<FORMATS; j++) {
1164 fmt[1].type = types[j];
1165 fmt[1].samplesize = samplesizes[j];
1166 fmt[1].sign = signs[j];
1167 fmt[1].bigendian = endians[j];
1168 fmt[1].packing = 0;
1169 fputs(".",stdout);
1170 fflush(stdout);
1171 convert_array(buf,fmt,buf2,fmt+1,SBUFLEN,DITHER_NONE,NULL);
1172 g_get_current_time(&start_time);
1173 convert_array(buf,fmt,buf2,fmt+1,SBUFLEN,DITHER_NONE,NULL);
1174 g_get_current_time(&end_time);
1175 timeval_subtract(&test_times[i*FORMATS+j],&end_time,
1176 &start_time);
1177 }
1178 }
1179
1180 /* Find out which one took the longest and take that time / 100, then
1181 * "round down" to get the index */
1182 i = 0;
1183 for (j=0; j<FORMATS*FORMATS; j++) {
1184 if (test_times[j].tv_sec > test_times[i].tv_sec ||
1185 (test_times[j].tv_sec == test_times[i].tv_sec &&
1186 test_times[j].tv_usec > test_times[i].tv_usec))
1187 i = j;
1188 }
1189 f = (float)test_times[i].tv_sec +
1190 ((float)test_times[i].tv_usec) * 0.000001;
1191 f /= 100;
1192 i = 0;
1193 while (f < 1.0) { f*=10.0; i++; }
1194 f = 1.0;
1195 while (i > 0) { f/=10.0; i--; }
1196 printf(_("\n\nTest results (1 time unit = %f usec/sample)\n"),
1197 f*1000000/SBUFLEN);
1198 printf(" ");
1199 for (i=0; i<FORMATS; i++)
1200 printf("%6s ",strings[i]);
1201 for (i=0; i<FORMATS; i++) {
1202 printf("\n%6s ",strings[i]);
1203 for (j=0; j<FORMATS; j++) {
1204 g = (float)test_times[i*FORMATS+j].tv_sec +
1205 ((float)test_times[i*FORMATS+j].tv_usec) * 0.000001;
1206 g /= f;
1207 printf("%6.2f ",g);
1208
1209 }
1210 }
1211 puts("\n");
1212 }
1213