⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rawaudioguess.cpp

📁 Audacity是一款用於錄音和編輯聲音的、免費的開放源碼軟體。它可以執行於Mac OS X、Microsoft Windows、GNU/Linux和其它作業系統
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/**********************************************************************  Audacity: A Digital Audio Editor  RawAudioGuess.cpp  Dominic Mazzoni  Attempts to determine the format of an audio file that doesn't  have any header information.  Returns the format as a  libsndfile-compatible format, along with the guessed number of  channels and the byte-offset.**********************************************************************/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <math.h>#include <wx/defs.h>#include <wx/ffile.h>#include "../Internat.h"#include "RawAudioGuess.h"#define RAW_GUESS_DEBUG 0#if RAW_GUESS_DEBUGstatic FILE *g_raw_debug_file = NULL;#endiffloat AmpStat(float *data, int len){   float sum, sumofsquares, avg, variance, dev;   int i;   if (len == 0)      return 1.0;   /* Calculate standard deviation of the amplitudes */   sum = 0.0;   sumofsquares = 0.0;   for (i = 0; i < len; i++) {      float x = fabs(data[i]);      sum += x;      sumofsquares += x * x;   }   avg = sum / len;   variance = sumofsquares / len - (avg * avg);   dev = sqrt(variance);   return dev;}float JumpStat(float *data, int len){   float avg;   int i;   /* Calculate 1.0 - avg jump    * A score near 1.0 means avg jump is pretty small    */   avg = 0.0;   for (i = 0; i < len - 1; i++)      avg += fabs(data[i + 1] - data[i]);   avg = 1.0 - (avg / (len - 1) / 2.0);   return avg;}float SecondDStat(float *data, int len){   int i;   float v1=0, v2=0, v3=0;   float a1=0, a2=0;   float sum=0;   for (i = 1; i < len; i++) {      a2 = a1;      v3 = v2;      v2 = v1;      v1 = data[i]-data[i-1];      a1 = v1 - v2;      sum += fabs(a1-a2);   }   return sum/len;}float RedundantStereo(float *data, int len){   int i;   int c = 0;   for (i = 1; i < len - 1; i += 2)      if (fabs(data[i + 1] - data[i]) > 2*fabs(data[i] - data[i - 1]) ||          2*fabs(data[i + 1] - data[i]) < fabs(data[i] - data[i - 1]))         c++;   return ((c * 2.0) / (len - 2));}void ExtractFloats(bool doublePrec,                   bool bigendian,                   bool stereo,                   int offset,                   char *rawData, int dataSize,                   float *data1, float *data2, int *len1, int *len2){   int rawCount = 0;   int dataCount1 = 0;   int dataCount2 = 0;   int i;   bool swap;   *len1 = 0;   *len2 = 0;   if (offset) {      rawData += offset;      dataSize -= offset;   }   #if WORDS_BIGENDIAN      swap = !bigendian;   #else   swap = bigendian;   #endif   if (doublePrec) {      union {         unsigned char c[8];         double d;      } u;      while (rawCount + 7 < dataSize) {         if (swap)            for(i=0; i<8; i++)               u.c[7-i] = rawData[rawCount+i];         else            for(i=0; i<8; i++)               u.c[i] = rawData[rawCount+i];         data1[dataCount1] = (float)u.d;         dataCount1++;         rawCount += 8;      }   }   else {      union {         unsigned char c[4];         float f;      } u;      while (rawCount + 3 < dataSize) {         if (swap)            for(i=0; i<4; i++)               u.c[3-i] = rawData[rawCount+i];         else            for(i=0; i<4; i++)               u.c[i] = rawData[rawCount+i];         data1[dataCount1] = u.f;         dataCount1++;         rawCount += 4;      }         }   if (stereo) {      dataCount1 /= 2;      for(i=0; i<dataCount1; i++) {         data2[i] = data1[2*i+1];         data1[i] = data1[2*i];      }      dataCount2 = dataCount1;   }   *len1 = dataCount1;   *len2 = dataCount2;   }void Extract(bool bits16,             bool sign,             bool stereo,             bool bigendian,             bool offset,             char *rawData, int dataSize,             float *data1, float *data2, int *len1, int *len2){   int rawCount = 0;   int dataCount1 = 0;   int dataCount2 = 0;   int i;   *len1 = 0;   *len2 = 0;   if (offset && bits16) {      /* Special case so as to not flip stereo channels during analysis */      if (stereo && !bigendian) {         rawData += 3;         dataSize -= 3;      }      else {         rawData++;         dataSize--;      }   }   if (bits16) {      if (sign && bigendian)         while (rawCount + 1 < dataSize) {            /* 16-bit signed BE */            data1[dataCount1] =               (wxINT16_SWAP_ON_LE(*((signed short *)                                     &rawData[rawCount])))               / 32768.0;            dataCount1++;            rawCount += 2;         }      if (!sign && bigendian)         while (rawCount + 1 < dataSize) {            /* 16-bit unsigned BE */            data1[dataCount1] =               (wxUINT16_SWAP_ON_LE(*((unsigned short *)                                      &rawData[rawCount])))               / 32768.0 - 1.0;            dataCount1++;            rawCount += 2;         }      if (sign && !bigendian)         while (rawCount + 1 < dataSize) {            /* 16-bit signed LE */            data1[dataCount1] =               (wxINT16_SWAP_ON_BE(*((signed short *)                                     &rawData[rawCount])))               / 32768.0;            dataCount1++;            rawCount += 2;         }      if (!sign && !bigendian)         while (rawCount + 1 < dataSize) {            /* 16-bit unsigned LE */            data1[dataCount1] =               (wxUINT16_SWAP_ON_BE(*((unsigned short *)                                      &rawData[rawCount])))               / 32768.0 - 1.0;            dataCount1++;            rawCount += 2;         }   }   else {      /* 8-bit */      if (sign) {         while (rawCount < dataSize) {            /* 8-bit signed */            data1[dataCount1++] =               (*(signed char *) (&rawData[rawCount++])) / 128.0;         }      }      else {         while (rawCount < dataSize) {            /* 8-bit unsigned */            data1[dataCount1++] =               (*(unsigned char *) &rawData[rawCount++]) / 128.0 - 1.0;         }      }   }   if (stereo) {      dataCount1 /= 2;      for(i=0; i<dataCount1; i++) {         data2[i] = data1[2*i+1];         data1[i] = data1[2*i];      }      dataCount2 = dataCount1;   }   *len1 = dataCount1;   *len2 = dataCount2;}int GuessFloatFormats(int numTests, char **rawData, int dataSize,                      int *out_offset, int *out_channels){   int format;   int bestOffset = 0;   int bestEndian = 0;   int bestPrec = 0;   float bestSmoothAvg = 1000.0;   int offset;   int endian;   int prec;   float *data1, *data2;   int len1;   int len2;   int test;   int i;   bool guessStereo = false;   int stereoVotes = 0;   int monoVotes = 0;     #if RAW_GUESS_DEBUG   FILE *af = g_raw_debug_file;   fprintf(af, "Testing float\n");  #endif   data1 = (float *)malloc((dataSize + 4) * sizeof(float));   data2 = (float *)malloc((dataSize + 4) * sizeof(float));   /*    * First determine if it is possibly in a floating-point    * format.  The nice thing about floating-point formats    * is that random bytes or even random integers are    * extremely unlikely to result in meaningful floats.    * All we do is try interpreting the raw bytes as floating-point,    * with a variety of offsets, both endiannesses, and both    * precisions (32-bit float and 64-bit double), and if any of    * them result in all finite numbers with reasonable ranges,    * we accept them.    *    * Sometimes there is more than one plausible candidate, in    * which case we take the smoothest one.  This usually happens    * because big-endian floats actually still look and act    * like floats when you interpret them as little-endian    * floats with a 1-byte offset.    */   for(prec=0; prec<2; prec++) {      for(endian=0; endian<2; endian++) {         for(offset=0; offset<(4*prec+4); offset++) {            int finiteVotes = 0;            int maxminVotes = 0;            float smoothAvg = 0;           #if RAW_GUESS_DEBUG            fprintf(af, "prec=%d endian=%d offset=%d\n",                    prec, endian, offset);           #endif            for(test=0; test<numTests; test++) {               float min, max;               ExtractFloats(prec?true:false, endian?true:false,                             true, /* stereo */                             offset,                             rawData[test], dataSize,                             data1, data2, &len1, &len2);               for(i=0; i<len1; i++)                  if (!(data1[i]>=0 || data1[i]<=0) ||                      !(data2[i]>=0 || data2[i]<=0))                     break;               if (i == len1)                  finiteVotes++;               min = data1[0];               max = data1[0];               for(i=1; i<len1; i++) {                  if (data1[i]<min)                     min = data1[i];                  if (data1[i]>max)                     max = data1[i];               }               for(i=1; i<len2; i++) {                  if (data2[i]<min)                     min = data2[i];                  if (data2[i]>max)                     max = data2[i];               }               if (min < -0.01 && min >= -100000 &&                   max > 0.01 && max <= 100000)                  maxminVotes++;               smoothAvg += SecondDStat(data1, len1) / max;            }            smoothAvg /= numTests;           #if RAW_GUESS_DEBUG                        fprintf(af, "finite: %d/%d maxmin: %d/%d smooth: %f\n",                    finiteVotes, numTests, maxminVotes, numTests,                    smoothAvg);           #endif            if (finiteVotes > numTests/2 &&                finiteVotes > numTests-2 &&                maxminVotes > numTests/2 &&                smoothAvg < bestSmoothAvg) {               bestSmoothAvg = smoothAvg;               bestOffset = offset;               bestPrec = prec;               bestEndian = endian;            }         }      }   }   /*    * If none of those tests succeeded, it's probably not    * actually floating-point data.  Return 0 so the    * main function will try guessing an integer format.    */   if (bestSmoothAvg >= 1000.0) {      free(data1);      free(data2);      return 0;   }   /*    * We still have to test for mono/stereo.  For an explanation    * of these tests, see the comments next to the stereo/mono    * tests for 8-bit or 16-bit data.    */   for (test = 0; test < numTests; test++) {      float leftChannel, rightChannel, combinedChannel;      ExtractFloats(bestPrec?true:false, bestEndian?true:false,                    true, /* stereo */                    bestOffset,                    rawData[test], dataSize,                    data1, data2, &len1, &len2);      leftChannel = JumpStat(data1, len1);      rightChannel = JumpStat(data2, len2);      ExtractFloats(bestPrec?true:false, bestEndian?true:false,                    false, /* stereo */                    bestOffset,                    rawData[test], dataSize,                    data1, data2, &len1, &len2);      combinedChannel = JumpStat(data1, len1);            if (leftChannel > combinedChannel          && rightChannel > combinedChannel)         stereoVotes++;      else         monoVotes++;   }     #if RAW_GUESS_DEBUG   fprintf(af, "stereo: %d mono: %d\n", stereoVotes, monoVotes);  #endif      if (stereoVotes > monoVotes)      guessStereo = true;   else      guessStereo = false;      if (guessStereo == false) {            /* test for repeated-byte, redundant stereo */            int rstereoVotes = 0;      int rmonoVotes = 0;            for (test = 0; test < numTests; test++) {         float redundant;         ExtractFloats(bestPrec?true:false, bestEndian?true:false,                       false, /* stereo */                       bestOffset,                       rawData[test], dataSize,                       data1, data2, &len1, &len2);         redundant = RedundantStereo(data1, len1);                 #if RAW_GUESS_DEBUG         fprintf(af, "redundant: %f\n", redundant);        #endif                  if (redundant > 0.8)            rstereoVotes++;         else            rmonoVotes++;      }     #if RAW_GUESS_DEBUG      fprintf(af, "rstereo: %d rmono: %d\n", rstereoVotes, rmonoVotes);     #endif            if (rstereoVotes > rmonoVotes)         guessStereo = true;         }  #if RAW_GUESS_DEBUG   if (guessStereo)      fprintf(af, "stereo\n");   else      fprintf(af, "mono\n");  #endif      *out_offset = bestOffset;   if (guessStereo)      *out_channels = 2;   else      *out_channels = 1;      if (bestPrec)      format = SF_FORMAT_RAW | SF_FORMAT_DOUBLE;   else      format = SF_FORMAT_RAW | SF_FORMAT_FLOAT;      if (bestEndian)      format |= SF_ENDIAN_BIG;   else      format |= SF_ENDIAN_LITTLE;   free(data1);   free(data2);      return format;}int Guess8Bit(int numTests, char **rawData, int dataSize, int *out_channels){   bool guessSigned = false;   bool guessStereo = false;   int signvotes = 0;   int unsignvotes = 0;   int stereoVotes = 0;   int monoVotes = 0;   float *data1 = (float *)malloc((dataSize + 4) * sizeof(float));   float *data2 = (float *)malloc((dataSize + 4) * sizeof(float));   int len1;   int len2;   int test;  #if RAW_GUESS_DEBUG   FILE *af = g_raw_debug_file;   fprintf(af, "8-bit\n");  #endif   /*    * Compare signed to unsigned, interpreted as if the file were    * stereo just to be safe.  If the file is actually mono, the test    * still works, and we lose a tiny bit of accuracy.  (It would not make    * sense to assume the file is mono, because if the two tracks are not    * very similar we would get inaccurate results.)    *    * The JumpTest measures the average jump between two successive samples    * and returns a value 0-1.  0 is maximally discontinuous, 1 is smooth.    */       for (test = 0; test < numTests; test++) {      float signL, signR, unsignL, unsignR;      Extract(0, 1, 1, 0, /* 8-bit signed stereo */              false, rawData[test], dataSize,              data1, data2, &len1, &len2);      signL = JumpStat(data1, len1);      signR = JumpStat(data2, len2);      Extract(0, 0, 1, 0, /* 8-bit unsigned stereo */              false, rawData[test], dataSize,              data1, data2, &len1, &len2);      unsignL = JumpStat(data1, len1);      unsignR = JumpStat(data2, len2);            if (signL > unsignL)         signvotes++;      else         unsignvotes++;            if (signR > unsignR)

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -