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