Audacity 3.2.0
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
32static FILE *g_raw_debug_file = NULL;
33#endif
34
35static 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
61static 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
77static 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
94static 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
106static 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
184static 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
294static 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
517static 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
665static 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
928static 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
1007int 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}
wxT("CloseDown"))
Declare abstract class AudacityException, some often-used subclasses, and GuardedCall.
@ BadUserAction
Indicates that the user performed an action that is not allowed.
int min(int a, int b)
int format
Definition: ExportPCM.cpp:56
#define XO(s)
Definition: Internat.h:31
static float AmpStat(float *data, size_t len)
static int Guess8Bit(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, unsigned *out_channels)
int RawAudioGuess(const wxString &in_fname, size_t *out_offset, unsigned *out_channels)
static int GuessIntFormats(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, 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 float SecondDStat(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 float JumpStat(float *data, size_t len)
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 RedundantStereo(float *data, size_t len)
static int GuessFloatFormats(unsigned numTests, const ArrayOf< char > rawData[], size_t dataSize, size_t *out_offset, unsigned *out_channels)
A MessageBoxException that shows a given, unvarying string.
void swap(std::unique_ptr< Alg_seq > &a, std::unique_ptr< Alg_seq > &b)
Definition: NoteTrack.cpp:753