Audacity  2.2.2
RawAudioGuess.cpp
Go to the documentation of this file.
1 /**********************************************************************
2 
3  Audacity: A Digital Audio Editor
4 
5  RawAudioGuess.cpp
6 
7  Dominic Mazzoni
8 
9  Attempts to determine the format of an audio file that doesn't
10  have any header information. Returns the format as a
11  libsndfile-compatible format, along with the guessed number of
12  channels and the byte-offset.
13 
14 **********************************************************************/
15 
16 #include "../Audacity.h"
17 #include "RawAudioGuess.h"
18 #include "../AudacityException.h"
19 #include "../MemoryX.h"
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 
26 #include <wx/defs.h>
27 #include <wx/ffile.h>
28 
29 #include "../Internat.h"
30 
31 #define RAW_GUESS_DEBUG 0
32 
33 #if RAW_GUESS_DEBUG
34 static FILE *g_raw_debug_file = NULL;
35 #endif
36 
37 static float AmpStat(float *data, size_t len)
38 {
39  float sum, sumofsquares, avg, variance, dev;
40 
41  if (len == 0)
42  return 1.0;
43 
44  /* Calculate standard deviation of the amplitudes */
45 
46  sum = 0.0;
47  sumofsquares = 0.0;
48 
49  for (size_t i = 0; i < len; i++) {
50  float x = fabs(data[i]);
51  sum += x;
52  sumofsquares += x * x;
53  }
54 
55  avg = sum / len;
56  variance = sumofsquares / len - (avg * avg);
57 
58  dev = sqrt(variance);
59 
60  return dev;
61 }
62 
63 static float JumpStat(float *data, size_t len)
64 {
65  float avg;
66 
67  /* Calculate 1.0 - avg jump
68  * A score near 1.0 means avg jump is pretty small
69  */
70 
71  avg = 0.0;
72  for (size_t i = 0; i + 1 < len; i++)
73  avg += fabs(data[i + 1] - data[i]);
74  avg = 1.0 - (avg / (len - 1) / 2.0);
75 
76  return avg;
77 }
78 
79 static float SecondDStat(float *data, size_t len)
80 {
81  float v1=0, v2=0;
82  float a1=0, a2=0;
83  float sum=0;
84 
85  for (size_t i = 1; i < len; i++) {
86  a2 = a1;
87  v2 = v1;
88  v1 = data[i]-data[i-1];
89  a1 = v1 - v2;
90  sum += fabs(a1-a2);
91  }
92 
93  return sum/len;
94 }
95 
96 static float RedundantStereo(float *data, size_t len)
97 {
98  int c = 0;
99 
100  for (size_t i = 1; i + 1 < len; i += 2)
101  if (fabs(data[i + 1] - data[i]) > 2*fabs(data[i] - data[i - 1]) ||
102  2*fabs(data[i + 1] - data[i]) < fabs(data[i] - data[i - 1]))
103  c++;
104 
105  return ((c * 2.0) / (len - 2));
106 }
107 
108 static void ExtractFloats(bool doublePrec,
109  bool bigendian,
110  bool stereo,
111  size_t offset,
112  char *rawData, size_t dataSize,
113  float *data1, float *data2, size_t *len1, size_t *len2)
114 {
115  size_t rawCount = 0;
116  size_t dataCount1 = 0;
117  size_t dataCount2 = 0;
118  bool swap;
119 
120  *len1 = 0;
121  *len2 = 0;
122 
123  if (offset) {
124  rawData += offset;
125  dataSize -= std::min(dataSize, offset);
126  }
127 
128  #if WORDS_BIGENDIAN
129  swap = !bigendian;
130  #else
131  swap = bigendian;
132  #endif
133 
134  if (doublePrec) {
135  union {
136  unsigned char c[8];
137  double d;
138  } u;
139 
140  u.d = 0.0f;
141  while (rawCount + 7 < dataSize) {
142  if (swap)
143  for(size_t i = 0; i < 8; i++)
144  u.c[7-i] = rawData[rawCount+i];
145  else
146  for(size_t i = 0; i < 8; i++)
147  u.c[i] = rawData[rawCount+i];
148  data1[dataCount1] = (float)u.d;
149  dataCount1++;
150  rawCount += 8;
151  }
152  }
153  else {
154  union {
155  unsigned char c[4];
156  float f;
157  } u;
158 
159  u.f = 0.0f;
160  while (rawCount + 3 < dataSize) {
161  if (swap)
162  for(size_t i = 0; i < 4; i++)
163  u.c[3-i] = rawData[rawCount+i];
164  else
165  for(size_t i = 0; i < 4; i++)
166  u.c[i] = rawData[rawCount+i];
167  data1[dataCount1] = u.f;
168  dataCount1++;
169  rawCount += 4;
170  }
171  }
172 
173  if (stereo) {
174  dataCount1 /= 2;
175  for(size_t i = 0; i < dataCount1; i++) {
176  data2[i] = data1[2*i+1];
177  data1[i] = data1[2*i];
178  }
179  dataCount2 = dataCount1;
180  }
181 
182  *len1 = dataCount1;
183  *len2 = dataCount2;
184 }
185 
186 static void Extract(bool bits16,
187  bool sign,
188  bool stereo,
189  bool bigendian,
190  bool offset,
191  char *rawData, int dataSizeIn,
192  float *data1, float *data2, size_t *len1, size_t *len2)
193 {
194  size_t rawCount = 0;
195  size_t dataCount1 = 0;
196  size_t dataCount2 = 0;
197 
198  *len1 = 0;
199  *len2 = 0;
200 
201  if (offset && bits16) {
202  /* Special case so as to not flip stereo channels during analysis */
203  if (stereo && !bigendian) {
204  rawData += 3;
205  dataSizeIn -= 3;
206  }
207  else {
208  rawData++;
209  dataSizeIn--;
210  }
211  }
212 
213  if( dataSizeIn < 1 )
214  throw SimpleMessageBoxException{_("Bad data size")};
215 
216  size_t dataSize = (size_t)dataSizeIn;
217 
218  if (bits16) {
219  if (sign && bigendian)
220  while (rawCount + 1 < dataSize) {
221  /* 16-bit signed BE */
222  data1[dataCount1] =
223  (wxINT16_SWAP_ON_LE(*((signed short *)
224  &rawData[rawCount])))
225  / 32768.0;
226  dataCount1++;
227  rawCount += 2;
228  }
229  if (!sign && bigendian)
230  while (rawCount + 1 < dataSize) {
231  /* 16-bit unsigned BE */
232  data1[dataCount1] =
233  (wxUINT16_SWAP_ON_LE(*((unsigned short *)
234  &rawData[rawCount])))
235  / 32768.0 - 1.0;
236  dataCount1++;
237  rawCount += 2;
238  }
239  if (sign && !bigendian)
240  while (rawCount + 1 < dataSize) {
241  /* 16-bit signed LE */
242  data1[dataCount1] =
243  (wxINT16_SWAP_ON_BE(*((signed short *)
244  &rawData[rawCount])))
245  / 32768.0;
246  dataCount1++;
247  rawCount += 2;
248  }
249  if (!sign && !bigendian)
250  while (rawCount + 1 < dataSize) {
251  /* 16-bit unsigned LE */
252  data1[dataCount1] =
253  (wxUINT16_SWAP_ON_BE(*((unsigned short *)
254  &rawData[rawCount])))
255  / 32768.0 - 1.0;
256  dataCount1++;
257  rawCount += 2;
258  }
259  }
260  else {
261  /* 8-bit */
262  if (sign) {
263  while (rawCount < dataSize) {
264  /* 8-bit signed */
265  data1[dataCount1++] =
266  (*(signed char *) (&rawData[rawCount++])) / 128.0;
267  }
268  }
269  else {
270  while (rawCount < dataSize) {
271  /* 8-bit unsigned */
272  data1[dataCount1++] =
273  (*(unsigned char *) &rawData[rawCount++]) / 128.0 - 1.0;
274  }
275  }
276  }
277 
278  if (stereo) {
279  dataCount1 /= 2;
280  for(size_t i = 0; i < dataCount1; i++) {
281  data2[i] = data1[2*i+1];
282  data1[i] = data1[2*i];
283  }
284  dataCount2 = dataCount1;
285  }
286 
287  *len1 = dataCount1;
288  *len2 = dataCount2;
289 }
290 
291 static int GuessFloatFormats(unsigned numTests, const ArrayOf<char> rawData[], size_t dataSize,
292  size_t *out_offset, unsigned *out_channels)
293 {
294  int format;
295  size_t bestOffset = 0;
296  int bestEndian = 0;
297  int bestPrec = 0;
298  float bestSmoothAvg = 1000.0;
299  size_t len1;
300  size_t len2;
301  bool guessStereo = false;
302  unsigned stereoVotes = 0;
303  unsigned monoVotes = 0;
304 
305  #if RAW_GUESS_DEBUG
306  FILE *af = g_raw_debug_file;
307  wxFprintf(af, "Testing float\n");
308  #endif
309 
310  ArrayOf<float> data1{ dataSize + 4 };
311  ArrayOf<float> data2{ dataSize + 4 };
312 
313  /*
314  * First determine if it is possibly in a floating-point
315  * format. The nice thing about floating-point formats
316  * is that random bytes or even random integers are
317  * extremely unlikely to result in meaningful floats.
318  * All we do is try interpreting the raw bytes as floating-point,
319  * with a variety of offsets, both endiannesses, and both
320  * precisions (32-bit float and 64-bit double), and if any of
321  * them result in all finite numbers with reasonable ranges,
322  * we accept them.
323  *
324  * Sometimes there is more than one plausible candidate, in
325  * which case we take the smoothest one. This usually happens
326  * because big-endian floats actually still look and act
327  * like floats when you interpret them as little-endian
328  * floats with a 1-byte offset.
329  */
330 
331  for(unsigned int prec = 0; prec < 2; prec++) {
332  for(int endian = 0; endian < 2; endian++) {
333  for(size_t offset = 0; offset < (4 * prec + 4); offset++) {
334  unsigned finiteVotes = 0;
335  unsigned maxminVotes = 0;
336  float smoothAvg = 0;
337 
338  #if RAW_GUESS_DEBUG
339  wxFprintf(af, "prec=%d endian=%d offset=%d\n",
340  prec, endian, (int)offset);
341  #endif
342 
343  for(unsigned test = 0; test < numTests; test++) {
344  float min, max;
345 
346  ExtractFloats(prec == 1, endian == 1,
347  true, /* stereo */
348  offset,
349  rawData[test].get(), dataSize,
350  data1.get(), data2.get(), &len1, &len2);
351 
352  size_t i = 0;
353  for(; i < len1; i++)
354  // This code is testing for NaNs.
355  // We'd like to know if all data is finite.
356  if (!(data1[i]>=0 || data1[i]<=0) ||
357  !(data2[i]>=0 || data2[i]<=0))
358  break;
359  if (i == len1)
360  // all data is finite.
361  finiteVotes++;
362 
363  min = data1[0];
364  max = data1[0];
365  for(i = 1; i < len1; i++) {
366  if (data1[i]<min)
367  min = data1[i];
368  if (data1[i]>max)
369  max = data1[i];
370  }
371  for(i = 1; i < len2; i++) {
372  if (data2[i]<min)
373  min = data2[i];
374  if (data2[i]>max)
375  max = data2[i];
376  }
377 
378  if (min < -0.01 && min >= -100000 &&
379  max > 0.01 && max <= 100000)
380  maxminVotes++;
381 
382  smoothAvg += SecondDStat(data1.get(), len1) / max;
383  }
384 
385  smoothAvg /= numTests;
386 
387  #if RAW_GUESS_DEBUG
388  wxFprintf(af, "finite: %ud/%ud maxmin: %ud/%ud smooth: %f\n",
389  finiteVotes, numTests, maxminVotes, numTests,
390  smoothAvg);
391  #endif
392 
393  if (finiteVotes > numTests/2 &&
394  finiteVotes > numTests-2 &&
395  maxminVotes > numTests/2 &&
396  smoothAvg < bestSmoothAvg) {
397 
398  bestSmoothAvg = smoothAvg;
399  bestOffset = offset;
400  bestPrec = prec;
401  bestEndian = endian;
402  }
403  }
404  }
405  }
406 
407  /*
408  * If none of those tests succeeded, it's probably not
409  * actually floating-point data. Return 0 so the
410  * main function will try guessing an integer format.
411  */
412 
413  if (bestSmoothAvg >= 1000.0)
414  return 0;
415 
416  /*
417  * We still have to test for mono/stereo. For an explanation
418  * of these tests, see the comments next to the stereo/mono
419  * tests for 8-bit or 16-bit data.
420  */
421 
422  for (unsigned test = 0; test < numTests; test++) {
423  float leftChannel, rightChannel, combinedChannel;
424 
425  ExtractFloats(bestPrec == 1, bestEndian == 1,
426  true, /* stereo */
427  bestOffset,
428  rawData[test].get(), dataSize,
429  data1.get(), data2.get(), &len1, &len2);
430  leftChannel = JumpStat(data1.get(), len1);
431  rightChannel = JumpStat(data2.get(), len2);
432  ExtractFloats(bestPrec == 1, bestEndian == 1,
433  false, /* stereo */
434  bestOffset,
435  rawData[test].get(), dataSize,
436  data1.get(), data2.get(), &len1, &len2);
437  combinedChannel = JumpStat(data1.get(), len1);
438 
439  if (leftChannel > combinedChannel
440  && rightChannel > combinedChannel)
441  stereoVotes++;
442  else
443  monoVotes++;
444  }
445 
446  #if RAW_GUESS_DEBUG
447  wxFprintf(af, "stereo: %ud mono: %ud\n", stereoVotes, monoVotes);
448  #endif
449 
450  guessStereo = (stereoVotes > monoVotes);
451 
452  if (!guessStereo) {
453 
454  /* test for repeated-byte, redundant stereo */
455 
456  unsigned rstereoVotes = 0;
457  unsigned rmonoVotes = 0;
458 
459  for (unsigned test = 0; test < numTests; test++) {
460  float redundant;
461 
462  ExtractFloats(bestPrec == 1, bestEndian == 1,
463  false, /* stereo */
464  bestOffset,
465  rawData[test].get(), dataSize,
466  data1.get(), data2.get(), &len1, &len2);
467  redundant = RedundantStereo(data1.get(), len1);
468 
469  #if RAW_GUESS_DEBUG
470  wxFprintf(af, "redundant: %f\n", redundant);
471  #endif
472 
473  if (redundant > 0.8)
474  rstereoVotes++;
475  else
476  rmonoVotes++;
477  }
478 
479  #if RAW_GUESS_DEBUG
480  wxFprintf(af, "rstereo: %ud rmono: %ud\n", rstereoVotes, rmonoVotes);
481  #endif
482 
483  guessStereo = (rstereoVotes > rmonoVotes);
484 
485  }
486 
487  #if RAW_GUESS_DEBUG
488  if (guessStereo)
489  wxFprintf(af, "stereo\n");
490  else
491  wxFprintf(af, "mono\n");
492  #endif
493 
494  *out_offset = bestOffset;
495 
496  if (guessStereo)
497  *out_channels = 2;
498  else
499  *out_channels = 1;
500 
501  if (bestPrec)
502  format = SF_FORMAT_RAW | SF_FORMAT_DOUBLE;
503  else
504  format = SF_FORMAT_RAW | SF_FORMAT_FLOAT;
505 
506  if (bestEndian)
507  format |= SF_ENDIAN_BIG;
508  else
509  format |= SF_ENDIAN_LITTLE;
510 
511  return format;
512 }
513 
514 static int Guess8Bit(unsigned numTests, const ArrayOf<char> rawData[], size_t dataSize, unsigned *out_channels)
515 {
516  bool guessSigned = false;
517  bool guessStereo = false;
518  unsigned signvotes = 0;
519  unsigned unsignvotes = 0;
520  unsigned stereoVotes = 0;
521  unsigned monoVotes = 0;
522 
523  ArrayOf<float> data1 { dataSize + 4 };
524  ArrayOf<float> data2 { dataSize + 4 };
525  size_t len1;
526  size_t len2;
527 
528  #if RAW_GUESS_DEBUG
529  FILE *af = g_raw_debug_file;
530  wxFprintf(af, "8-bit\n");
531  #endif
532 
533  /*
534  * Compare signed to unsigned, interpreted as if the file were
535  * stereo just to be safe. If the file is actually mono, the test
536  * still works, and we lose a tiny bit of accuracy. (It would not make
537  * sense to assume the file is mono, because if the two tracks are not
538  * very similar we would get inaccurate results.)
539  *
540  * The JumpTest measures the average jump between two successive samples
541  * and returns a value 0-1. 0 is maximally discontinuous, 1 is smooth.
542  */
543 
544  for (unsigned test = 0; test < numTests; test++) {
545  float signL, signR, unsignL, unsignR;
546 
547  Extract(0, 1, 1, 0, /* 8-bit signed stereo */
548  false, rawData[test].get(), dataSize,
549  data1.get(), data2.get(), &len1, &len2);
550  signL = JumpStat(data1.get(), len1);
551  signR = JumpStat(data2.get(), len2);
552  Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */
553  false, rawData[test].get(), dataSize,
554  data1.get(), data2.get(), &len1, &len2);
555  unsignL = JumpStat(data1.get(), len1);
556  unsignR = JumpStat(data2.get(), len2);
557 
558  if (signL > unsignL)
559  signvotes++;
560  else
561  unsignvotes++;
562 
563  if (signR > unsignR)
564  signvotes++;
565  else
566  unsignvotes++;
567  }
568 
569  #if RAW_GUESS_DEBUG
570  wxFprintf(af, "sign: %ud unsign: %ud\n", signvotes, unsignvotes);
571  #endif
572 
573  guessSigned = (signvotes > unsignvotes);
574 
575  #if RAW_GUESS_DEBUG
576  if (guessSigned)
577  wxFprintf(af, "signed\n");
578  else
579  wxFprintf(af, "unsigned\n");
580  #endif
581 
582  /* Finally we test stereo/mono. We use the same JumpStat, and say
583  * that the file is stereo if and only if for the majority of the
584  * tests, the left channel and the right channel are more smooth than
585  * the entire stream interpreted as one channel.
586  */
587 
588  for (unsigned test = 0; test < numTests; test++) {
589  float leftChannel, rightChannel, combinedChannel;
590 
591  Extract(0, guessSigned, 1, 0, 0, rawData[test].get(), dataSize, data1.get(),
592  data2.get(), &len1, &len2);
593  leftChannel = JumpStat(data1.get(), len1);
594  rightChannel = JumpStat(data2.get(), len2);
595  Extract(0, guessSigned, 0, 0, 0, rawData[test].get(), dataSize, data1.get(),
596  data2.get(), &len1, &len2);
597  combinedChannel = JumpStat(data1.get(), len1);
598 
599  if (leftChannel > combinedChannel
600  && rightChannel > combinedChannel)
601  stereoVotes++;
602  else
603  monoVotes++;
604  }
605 
606  #if RAW_GUESS_DEBUG
607  wxFprintf(af, "stereo: %ud mono: %ud\n", stereoVotes, monoVotes);
608  #endif
609 
610  guessStereo = (stereoVotes > monoVotes);
611 
612  if (!guessStereo) {
613 
614  /* test for repeated-byte, redundant stereo */
615 
616  unsigned rstereoVotes = 0;
617  unsigned rmonoVotes = 0;
618 
619  for (unsigned test = 0; test < numTests; test++) {
620  float redundant;
621 
622  Extract(0, guessSigned, 0, 0, 0, rawData[test].get(), dataSize,
623  data1.get(), data2.get(), &len1, &len2);
624  redundant = RedundantStereo(data1.get(), len1);
625 
626  #if RAW_GUESS_DEBUG
627  wxFprintf(af, "redundant: %f\n", redundant);
628  #endif
629 
630  if (redundant > 0.8)
631  rstereoVotes++;
632  else
633  rmonoVotes++;
634  }
635 
636  #if RAW_GUESS_DEBUG
637  wxFprintf(af, "rstereo: %ud rmono: %ud\n", rstereoVotes, rmonoVotes);
638  #endif
639 
640  guessStereo = (rstereoVotes > rmonoVotes);
641 
642  }
643 
644  #if RAW_GUESS_DEBUG
645  if (guessStereo)
646  wxFprintf(af, "stereo\n");
647  else
648  wxFprintf(af, "mono\n");
649  #endif
650 
651  if (guessStereo)
652  *out_channels = 2;
653  else
654  *out_channels = 1;
655 
656  if (guessSigned)
657  return SF_FORMAT_RAW | SF_FORMAT_PCM_S8;
658  else
659  return SF_FORMAT_RAW | SF_FORMAT_PCM_U8;
660 }
661 
662 static int Guess16Bit(unsigned numTests, const ArrayOf<char> rawData[],
663  size_t dataSize, bool evenMSB,
664  size_t *out_offset, unsigned *out_channels)
665 {
666  int format;
667  bool guessSigned = false;
668  bool guessStereo = false;
669  bool guessBigEndian = false;
670  bool guessOffset = false;
671  unsigned signvotes = 0;
672  unsigned unsignvotes = 0;
673  unsigned stereoVotes = 0;
674  unsigned monoVotes = 0;
675  unsigned formerVotes = 0;
676  unsigned latterVotes = 0;
677  ArrayOf<char> rawData2{ dataSize + 4 };
678  ArrayOf<float> data1{ dataSize + 4 };
679  ArrayOf<float> data2{ dataSize + 4 };
680  size_t len1;
681  size_t len2;
682 
683  #if RAW_GUESS_DEBUG
684  FILE *af = g_raw_debug_file;
685  wxFprintf(af, "16-bit\n");
686  #endif
687 
688  /*
689  * Do the signed/unsigned test by using only the MSB.
690  */
691 
692  for (unsigned test = 0; test < numTests; test++) {
693 
694  float signL, signR, unsignL, unsignR;
695 
696  /* Extract a NEW array of the MSBs only: */
697 
698  for (size_t i = 0; i < dataSize / 2; i++)
699  rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
700 
701  /* Test signed/unsigned of the MSB */
702 
703  Extract(0, 1, 1, 0, /* 8-bit signed stereo */
704  0, rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
705  signL = JumpStat(data1.get(), len1);
706  signR = JumpStat(data2.get(), len2);
707  Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */
708  0, rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
709  unsignL = JumpStat(data1.get(), len1);
710  unsignR = JumpStat(data2.get(), len2);
711 
712  if (signL > unsignL)
713  signvotes++;
714  else
715  unsignvotes++;
716 
717  if (signR > unsignR)
718  signvotes++;
719  else
720  unsignvotes++;
721  }
722 
723  #if RAW_GUESS_DEBUG
724  wxFprintf(af, "sign: %ud unsign: %ud\n", signvotes, unsignvotes);
725  #endif
726 
727  guessSigned = (signvotes > unsignvotes);
728 
729  #if RAW_GUESS_DEBUG
730  if (guessSigned)
731  wxFprintf(af, "signed\n");
732  else
733  wxFprintf(af, "unsigned\n");
734  #endif
735 
736  /*
737  * Test mono/stereo using only the MSB
738  */
739 
740  for (unsigned test = 0; test < numTests; test++) {
741  float leftChannel, rightChannel, combinedChannel;
742 
743  /* Extract a NEW array of the MSBs only: */
744 
745  for (size_t i = 0; i < dataSize / 2; i++)
746  rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
747 
748  Extract(0, guessSigned, 1, 0, 0,
749  rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
750  leftChannel = JumpStat(data1.get(), len1);
751  rightChannel = JumpStat(data2.get(), len2);
752  Extract(0, guessSigned, 0, 0, 0,
753  rawData2.get(), dataSize / 2, data1.get(), data2.get(), &len1, &len2);
754  combinedChannel = JumpStat(data1.get(), len1);
755 
756  if (leftChannel > combinedChannel
757  && rightChannel > combinedChannel)
758  stereoVotes++;
759  else
760  monoVotes++;
761  }
762 
763  #if RAW_GUESS_DEBUG
764  wxFprintf(af, "stereoVotes: %ud monoVotes: %ud\n", stereoVotes, monoVotes);
765  #endif
766 
767  guessStereo = (stereoVotes > monoVotes);
768 
769  if (!guessStereo) {
770 
771  /* Test for repeated-byte, redundant stereo */
772 
773  unsigned rstereoVotes = 0;
774  unsigned rmonoVotes = 0;
775 
776  for (unsigned test = 0; test < numTests; test++) {
777 
778  float redundant;
779 
780  /* Extract a NEW array of the MSBs only: */
781 
782  for (size_t i = 0; i < dataSize / 2; i++)
783  rawData2[i] = rawData[test][2 * i + (evenMSB ? 0 : 1)];
784 
785  Extract(0, guessSigned, 0, 0, 0, rawData2.get(), dataSize / 2,
786  data1.get(), data2.get(), &len1, &len2);
787 
788  redundant = RedundantStereo(data1.get(), len1);
789 
790  if (redundant > 0.8)
791  rstereoVotes++;
792  else
793  rmonoVotes++;
794  }
795 
796  #if RAW_GUESS_DEBUG
797  wxFprintf(af, "rstereoVotes: %ud rmonoVotes: %ud\n",
798  rstereoVotes, rmonoVotes);
799  #endif
800 
801  guessStereo = (rstereoVotes > rmonoVotes);
802 
803  }
804 
805  #if RAW_GUESS_DEBUG
806  if (guessStereo)
807  wxFprintf(af, "stereo\n");
808  else
809  wxFprintf(af, "mono\n");
810  #endif
811 
812  /*
813  * Finally, determine the endianness and offset.
814  *
815  * Even MSB -> BigEndian or LittleEndian with Offset
816  * Odd MSB -> LittleEndian or BigEndian with Offset
817  */
818 
819  guessBigEndian = evenMSB;
820  guessOffset = 0;
821 
822  #if RAW_GUESS_DEBUG
823  wxFprintf(af, "evenMSB: %d BE: %d\n", evenMSB, guessBigEndian);
824  #endif
825 
826  for (unsigned test = 0; test < numTests; test++) {
827 
828  float former, latter;
829  int offs;
830 
831  /* Extract a NEW array of the MSBs only: */
832 
833  if (guessStereo)
834  for (size_t i = 0; i + 1 < (dataSize / 4); i++)
835  rawData2[i] =
836  rawData[test][4 * i + (evenMSB ? 0 : 1)];
837  else
838  for (size_t i = 0; i + 1 < (dataSize / 2); i++)
839  rawData2[i] =
840  rawData[test][2 * i + (evenMSB ? 0 : 1)];
841 
842  former = 0.0;
843  Extract(1, guessSigned, guessStereo, guessBigEndian, guessOffset,
844  rawData[test].get(), dataSize-4, data1.get(), data2.get(), &len1, &len2);
845 
846  offs=(!guessBigEndian);
847 
848  for(size_t i = 3; i + 4 < len1; i++) {
849  if (rawData2[offs+i-2]==rawData2[offs+i-1] &&
850  rawData2[offs+i]==rawData2[offs+i-1]+1 &&
851  rawData2[offs+i]==rawData2[offs+i+1]) {
852  former += data1[i]-data1[i-1];
853  }
854  }
855 
856  latter = 0.0;
857  Extract(1, guessSigned, guessStereo, !guessBigEndian,
858  !guessOffset, rawData[test].get(), dataSize, data1.get(), data2.get(),
859  &len1, &len2);
860 
861  offs=(guessBigEndian);
862 
863  for(size_t i = 3; i + 4 < len1; i++) {
864  if (rawData2[offs+i-2]==rawData2[offs+i-1] &&
865  rawData2[offs+i]==rawData2[offs+i-1]+1 &&
866  rawData2[offs+i]==rawData2[offs+i+1]) {
867 
868  latter += data1[i]-data1[i-1];
869  }
870  }
871 
872  #if RAW_GUESS_DEBUG
873  wxFprintf(af, "former: %f latter: %f\n", former, latter);
874  #endif
875 
876  if (former <= latter)
877  formerVotes++;
878  else
879  latterVotes++;
880  }
881 
882  #if RAW_GUESS_DEBUG
883  wxFprintf(af, "former (BE/LE): %ud latter (LE+/BE+): %ud\n",
884  formerVotes, latterVotes);
885  #endif
886 
887  // High barrier, since odd byte offsets are very rare
888  if (latterVotes > formerVotes*2) {
889  guessBigEndian = !guessBigEndian;
890  guessOffset = !guessOffset;
891  }
892 
893  #if RAW_GUESS_DEBUG
894  if (guessBigEndian)
895  wxFprintf(af, "big endian\n");
896  else
897  wxFprintf(af, "little endian\n");
898  #endif
899 
900  #if RAW_GUESS_DEBUG
901  if (guessOffset)
902  wxFprintf(af, "offset 1 byte\n");
903  else
904  wxFprintf(af, "no byte offset\n");
905  #endif
906 
907  format = SF_FORMAT_RAW | SF_FORMAT_PCM_16;
908 
909  if (guessBigEndian)
910  format |= SF_ENDIAN_BIG;
911  else
912  format |= SF_ENDIAN_LITTLE;
913 
914  if (guessOffset)
915  *out_offset = 1;
916 
917  if (guessStereo)
918  *out_channels = 2;
919  else
920  *out_channels = 1;
921 
922  return format;
923 }
924 
925 static int GuessIntFormats(unsigned numTests, const ArrayOf<char> rawData[], size_t dataSize,
926  size_t *out_offset, unsigned *out_channels)
927 {
928  int format = SF_FORMAT_RAW;
929  bool guess16bit = false;
930  bool evenMSB;
931  ArrayOf<float> data1{ dataSize + 4 };
932  ArrayOf<float> data2{ dataSize + 4 };
933  size_t len1;
934  size_t len2;
935  unsigned vote8 = 0;
936  unsigned vote16 = 0;
937  unsigned evenMSBVotes = 0;
938  unsigned oddMSBVotes = 0;
939 
940  #if RAW_GUESS_DEBUG
941  FILE *af = g_raw_debug_file;
942  #endif
943 
944  *out_channels = 1;
945  *out_offset = 0;
946 
947  /*
948  * First test: we attempt to determine if the data is 8-bit or 16-bit.
949  * We extract the odd and even bytes interpreted as signed-valued samples,
950  * and compare their amplitude distributions. Noting that in 16-bit values,
951  * the less significant 8 bits should have roughly flat distribution, while
952  * the more significant 8 bits should have a tighter distribution, with a
953  * smaller standard deviation.
954  *
955  * Note that this correctly makes the distinction whether we are dealing
956  * with mono or stereo data.
957  */
958 
959  for (unsigned test = 0; test < numTests; test++) {
960  float even, odd;
961 
962  Extract(0, 1, 1, 0, /* 8-bit signed stereo */
963  false, rawData[test].get(), dataSize,
964  data1.get(), data2.get(), &len1, &len2);
965  even = AmpStat(data1.get(), len1);
966  odd = AmpStat(data2.get(), len2);
967  if ((even > 0.15) && (odd > 0.15)) {
968  #if RAW_GUESS_DEBUG
969  wxFprintf(af, "Both appear random: %.2f, %.2f.\n", even, odd);
970  #endif
971  }
972  else if ((even > 0.15) || (odd > 0.15))
973  vote16++;
974  else
975  vote8++;
976 
977  /* Record which of the two was the MSB for future reference */
978  if (even < odd)
979  evenMSBVotes++;
980  else
981  oddMSBVotes++;
982  }
983 
984  evenMSB = (evenMSBVotes > oddMSBVotes);
985 
986  #if RAW_GUESS_DEBUG
987  wxFprintf(af, "evenMSBVote: %ud oddMSBVote: %ud\n",
988  evenMSBVotes, oddMSBVotes);
989  wxFprintf(af, "vote8: %ud vote16: %ud\n", vote8, vote16);
990  #endif
991 
992  guess16bit = (vote8 <= vote16);
993 
994  if (!guess16bit)
995  format = Guess8Bit(numTests, rawData, dataSize, out_channels);
996  else
997  format = Guess16Bit(numTests, rawData,
998  dataSize, evenMSB,
999  out_offset, out_channels);
1000 
1001  return format;
1002 }
1003 
1004 int RawAudioGuess(const wxString &in_fname,
1005  size_t *out_offset, unsigned *out_channels)
1006 {
1007  const unsigned numTests = 11;
1008  size_t headerSkipSize = 64;
1009  size_t dataSize = 16384;
1010  int format = SF_FORMAT_RAW;
1011  FILE *inf;
1012  size_t fileLen;
1013  size_t read_data;
1014 
1015  #if RAW_GUESS_DEBUG
1016  FILE *af = fopen("raw.txt", "a");
1017  g_raw_debug_file = af;
1018  wxFprintf(af, "File: %s\n", in_fname);
1019  #endif
1020 
1021  *out_offset = 0;
1022  *out_channels = 1;
1023 
1024  wxFFile in_wxFFile(in_fname, wxT("rb"));
1025 
1026  // JKC FALSE changed to -1.
1027  if (!in_wxFFile.IsOpened())
1028  return -1;
1029  inf = in_wxFFile.fp();
1030 
1031  if (!inf) {
1032  #if RAW_GUESS_DEBUG
1033  fclose(af);
1034  g_raw_debug_file = NULL;
1035  #endif
1036 
1037  return -1;
1038  }
1039 
1040  // FIXME: TRAP_ERR fseek return in RawAudioGuess unchecked.
1041  fseek(inf, 0, SEEK_END);
1042  fileLen = ftell(inf);
1043 
1044  if (fileLen < 8)
1045  return -1;
1046 
1047  if (fileLen < headerSkipSize)
1048  headerSkipSize = 0;
1049 
1050  if (fileLen < dataSize)
1051  dataSize = fileLen / 2;
1052 
1053  wxASSERT( dataSize >= 4 );
1054  wxASSERT( dataSize <= fileLen );
1055 
1056  ArraysOf<char> rawData{ numTests, dataSize + 4 };
1057 
1058  for (unsigned test = 0; test < numTests; test++) {
1059  int startPoint;
1060 
1061  startPoint = (fileLen - dataSize) * (test + 1) / (numTests + 2);
1062 
1063  /* Make it a multiple of 16 (stereo double-precision) */
1064  startPoint = (startPoint/16)*16;
1065 
1066  // FIXME: TRAP_ERR fseek return in MultiFormatReader unchecked.
1067  fseek(inf, headerSkipSize + startPoint, SEEK_SET);
1068  read_data = fread(rawData[test].get(), 1, dataSize, inf);
1069  if (read_data != dataSize && ferror(inf)) {
1070  perror("fread error in RawAudioGuess");
1071  }
1072  }
1073 
1074  in_wxFFile.Close();
1075 
1076  /*
1077  * The floating-point tests will only return a valid format
1078  * if it's almost certainly floating-point data. On the other
1079  * hand, the integer tests will always return something, since
1080  * almost anything looks like it could be integer data...
1081  */
1082 
1083  format = GuessFloatFormats(numTests,
1084  rawData.get(),
1085  dataSize,
1086  out_offset, out_channels);
1087 
1088  if (format == 0) {
1089  format = GuessIntFormats(numTests,
1090  rawData.get(),
1091  dataSize,
1092  out_offset, out_channels);
1093  }
1094 
1095  #if RAW_GUESS_DEBUG
1096  fclose(af);
1097  g_raw_debug_file = NULL;
1098  #endif
1099 
1100  return format;
1101 }
static float SecondDStat(float *data, size_t len)
memory.h template class for making an array of arrays.
Definition: MemoryX.h:519
static void ExtractFloats(bool doublePrec, bool bigendian, bool stereo, size_t offset, char *rawData, size_t dataSize, float *data1, float *data2, size_t *len1, size_t *len2)
static float JumpStat(float *data, size_t len)
static int Guess16Bit(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, bool evenMSB, size_t *out_offset, unsigned *out_channels)
static void Extract(bool bits16, bool sign, bool stereo, bool bigendian, bool offset, char *rawData, int dataSizeIn, float *data1, float *data2, size_t *len1, size_t *len2)
static int Guess8Bit(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, unsigned *out_channels)
int format
Definition: ExportPCM.cpp:56
int min(int a, int b)
static int GuessFloatFormats(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, size_t *out_offset, unsigned *out_channels)
_("Move Track &Down")+wxT("\t")+(GetActiveProject() -> GetCommandManager() ->GetKeyFromName(wxT("TrackMoveDown"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveTopID, _("Move Track to &Top")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveTop"))), OnMoveTrack) POPUP_MENU_ITEM(OnMoveBottomID, _("Move Track to &Bottom")+wxT("\t")+(GetActiveProject() ->GetCommandManager() ->GetKeyFromName(wxT("TrackMoveBottom"))), OnMoveTrack) void TrackMenuTable::OnSetName(wxCommandEvent &)
static float AmpStat(float *data, size_t len)
static int GuessIntFormats(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, size_t *out_offset, unsigned *out_channels)
static float RedundantStereo(float *data, size_t len)
int RawAudioGuess(const wxString &in_fname, size_t *out_offset, unsigned *out_channels)