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