diff --git a/src/Makefile.am b/src/Makefile.am index da6bd1522..beb6b1c2c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -409,6 +409,12 @@ audacity_SOURCES = \ import/ImportRaw.h \ import/RawAudioGuess.cpp \ import/RawAudioGuess.h \ + import/FormatClassifier.cpp \ + import/FormatClassifier.h \ + import/MultiFormatReader.cpp \ + import/MultiFormatReader.h \ + import/SpecPowerMeter.cpp \ + import/SpecPowerMeter.h \ ondemand/ODComputeSummaryTask.cpp \ ondemand/ODComputeSummaryTask.h \ ondemand/ODDecodeFFmpegTask.cpp \ diff --git a/src/Makefile.in b/src/Makefile.in index bdcbe43d0..3ceb8ef3f 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -398,7 +398,10 @@ am__audacity_SOURCES_DIST = BlockFile.cpp BlockFile.h DirManager.cpp \ import/ImportOGG.cpp import/ImportOGG.h import/ImportPCM.cpp \ import/ImportPCM.h import/ImportPlugin.h import/ImportRaw.cpp \ import/ImportRaw.h import/RawAudioGuess.cpp \ - import/RawAudioGuess.h ondemand/ODComputeSummaryTask.cpp \ + import/RawAudioGuess.h import/FormatClassifier.cpp \ + import/FormatClassifier.h import/MultiFormatReader.cpp \ + import/MultiFormatReader.h import/SpecPowerMeter.cpp \ + import/SpecPowerMeter.h ondemand/ODComputeSummaryTask.cpp \ ondemand/ODComputeSummaryTask.h \ ondemand/ODDecodeFFmpegTask.cpp ondemand/ODDecodeFFmpegTask.h \ ondemand/ODDecodeTask.cpp ondemand/ODDecodeTask.h \ @@ -643,6 +646,9 @@ am_audacity_OBJECTS = $(am__objects_1) audacity-AboutDialog.$(OBJEXT) \ import/audacity-ImportPCM.$(OBJEXT) \ import/audacity-ImportRaw.$(OBJEXT) \ import/audacity-RawAudioGuess.$(OBJEXT) \ + import/audacity-FormatClassifier.$(OBJEXT) \ + import/audacity-MultiFormatReader.$(OBJEXT) \ + import/audacity-SpecPowerMeter.$(OBJEXT) \ ondemand/audacity-ODComputeSummaryTask.$(OBJEXT) \ ondemand/audacity-ODDecodeFFmpegTask.$(OBJEXT) \ ondemand/audacity-ODDecodeTask.$(OBJEXT) \ @@ -1253,7 +1259,10 @@ audacity_SOURCES = $(libaudacity_la_SOURCES) AboutDialog.cpp \ import/ImportOGG.cpp import/ImportOGG.h import/ImportPCM.cpp \ import/ImportPCM.h import/ImportPlugin.h import/ImportRaw.cpp \ import/ImportRaw.h import/RawAudioGuess.cpp \ - import/RawAudioGuess.h ondemand/ODComputeSummaryTask.cpp \ + import/RawAudioGuess.h import/FormatClassifier.cpp \ + import/FormatClassifier.h import/MultiFormatReader.cpp \ + import/MultiFormatReader.h import/SpecPowerMeter.cpp \ + import/SpecPowerMeter.h ondemand/ODComputeSummaryTask.cpp \ ondemand/ODComputeSummaryTask.h \ ondemand/ODDecodeFFmpegTask.cpp ondemand/ODDecodeFFmpegTask.h \ ondemand/ODDecodeTask.cpp ondemand/ODDecodeTask.h \ @@ -1688,6 +1697,12 @@ import/audacity-ImportRaw.$(OBJEXT): import/$(am__dirstamp) \ import/$(DEPDIR)/$(am__dirstamp) import/audacity-RawAudioGuess.$(OBJEXT): import/$(am__dirstamp) \ import/$(DEPDIR)/$(am__dirstamp) +import/audacity-FormatClassifier.$(OBJEXT): import/$(am__dirstamp) \ + import/$(DEPDIR)/$(am__dirstamp) +import/audacity-MultiFormatReader.$(OBJEXT): import/$(am__dirstamp) \ + import/$(DEPDIR)/$(am__dirstamp) +import/audacity-SpecPowerMeter.$(OBJEXT): import/$(am__dirstamp) \ + import/$(DEPDIR)/$(am__dirstamp) ondemand/$(am__dirstamp): @$(MKDIR_P) ondemand @: > ondemand/$(am__dirstamp) @@ -2139,6 +2154,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@export/$(DEPDIR)/audacity-ExportMultiple.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@export/$(DEPDIR)/audacity-ExportOGG.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@export/$(DEPDIR)/audacity-ExportPCM.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-FormatClassifier.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-Import.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-ImportFFmpeg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-ImportFLAC.Po@am__quote@ @@ -2150,7 +2166,9 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-ImportPCM.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-ImportQT.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-ImportRaw.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-MultiFormatReader.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-RawAudioGuess.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@import/$(DEPDIR)/audacity-SpecPowerMeter.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ondemand/$(DEPDIR)/audacity-ODComputeSummaryTask.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ondemand/$(DEPDIR)/audacity-ODDecodeFFmpegTask.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@ondemand/$(DEPDIR)/audacity-ODDecodeFlacTask.Po@am__quote@ @@ -4733,6 +4751,48 @@ import/audacity-RawAudioGuess.obj: import/RawAudioGuess.cpp @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-RawAudioGuess.obj `if test -f 'import/RawAudioGuess.cpp'; then $(CYGPATH_W) 'import/RawAudioGuess.cpp'; else $(CYGPATH_W) '$(srcdir)/import/RawAudioGuess.cpp'; fi` +import/audacity-FormatClassifier.o: import/FormatClassifier.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT import/audacity-FormatClassifier.o -MD -MP -MF import/$(DEPDIR)/audacity-FormatClassifier.Tpo -c -o import/audacity-FormatClassifier.o `test -f 'import/FormatClassifier.cpp' || echo '$(srcdir)/'`import/FormatClassifier.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) import/$(DEPDIR)/audacity-FormatClassifier.Tpo import/$(DEPDIR)/audacity-FormatClassifier.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='import/FormatClassifier.cpp' object='import/audacity-FormatClassifier.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-FormatClassifier.o `test -f 'import/FormatClassifier.cpp' || echo '$(srcdir)/'`import/FormatClassifier.cpp + +import/audacity-FormatClassifier.obj: import/FormatClassifier.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT import/audacity-FormatClassifier.obj -MD -MP -MF import/$(DEPDIR)/audacity-FormatClassifier.Tpo -c -o import/audacity-FormatClassifier.obj `if test -f 'import/FormatClassifier.cpp'; then $(CYGPATH_W) 'import/FormatClassifier.cpp'; else $(CYGPATH_W) '$(srcdir)/import/FormatClassifier.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) import/$(DEPDIR)/audacity-FormatClassifier.Tpo import/$(DEPDIR)/audacity-FormatClassifier.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='import/FormatClassifier.cpp' object='import/audacity-FormatClassifier.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-FormatClassifier.obj `if test -f 'import/FormatClassifier.cpp'; then $(CYGPATH_W) 'import/FormatClassifier.cpp'; else $(CYGPATH_W) '$(srcdir)/import/FormatClassifier.cpp'; fi` + +import/audacity-MultiFormatReader.o: import/MultiFormatReader.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT import/audacity-MultiFormatReader.o -MD -MP -MF import/$(DEPDIR)/audacity-MultiFormatReader.Tpo -c -o import/audacity-MultiFormatReader.o `test -f 'import/MultiFormatReader.cpp' || echo '$(srcdir)/'`import/MultiFormatReader.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) import/$(DEPDIR)/audacity-MultiFormatReader.Tpo import/$(DEPDIR)/audacity-MultiFormatReader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='import/MultiFormatReader.cpp' object='import/audacity-MultiFormatReader.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-MultiFormatReader.o `test -f 'import/MultiFormatReader.cpp' || echo '$(srcdir)/'`import/MultiFormatReader.cpp + +import/audacity-MultiFormatReader.obj: import/MultiFormatReader.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT import/audacity-MultiFormatReader.obj -MD -MP -MF import/$(DEPDIR)/audacity-MultiFormatReader.Tpo -c -o import/audacity-MultiFormatReader.obj `if test -f 'import/MultiFormatReader.cpp'; then $(CYGPATH_W) 'import/MultiFormatReader.cpp'; else $(CYGPATH_W) '$(srcdir)/import/MultiFormatReader.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) import/$(DEPDIR)/audacity-MultiFormatReader.Tpo import/$(DEPDIR)/audacity-MultiFormatReader.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='import/MultiFormatReader.cpp' object='import/audacity-MultiFormatReader.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-MultiFormatReader.obj `if test -f 'import/MultiFormatReader.cpp'; then $(CYGPATH_W) 'import/MultiFormatReader.cpp'; else $(CYGPATH_W) '$(srcdir)/import/MultiFormatReader.cpp'; fi` + +import/audacity-SpecPowerMeter.o: import/SpecPowerMeter.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT import/audacity-SpecPowerMeter.o -MD -MP -MF import/$(DEPDIR)/audacity-SpecPowerMeter.Tpo -c -o import/audacity-SpecPowerMeter.o `test -f 'import/SpecPowerMeter.cpp' || echo '$(srcdir)/'`import/SpecPowerMeter.cpp +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) import/$(DEPDIR)/audacity-SpecPowerMeter.Tpo import/$(DEPDIR)/audacity-SpecPowerMeter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='import/SpecPowerMeter.cpp' object='import/audacity-SpecPowerMeter.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-SpecPowerMeter.o `test -f 'import/SpecPowerMeter.cpp' || echo '$(srcdir)/'`import/SpecPowerMeter.cpp + +import/audacity-SpecPowerMeter.obj: import/SpecPowerMeter.cpp +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT import/audacity-SpecPowerMeter.obj -MD -MP -MF import/$(DEPDIR)/audacity-SpecPowerMeter.Tpo -c -o import/audacity-SpecPowerMeter.obj `if test -f 'import/SpecPowerMeter.cpp'; then $(CYGPATH_W) 'import/SpecPowerMeter.cpp'; else $(CYGPATH_W) '$(srcdir)/import/SpecPowerMeter.cpp'; fi` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) import/$(DEPDIR)/audacity-SpecPowerMeter.Tpo import/$(DEPDIR)/audacity-SpecPowerMeter.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='import/SpecPowerMeter.cpp' object='import/audacity-SpecPowerMeter.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -c -o import/audacity-SpecPowerMeter.obj `if test -f 'import/SpecPowerMeter.cpp'; then $(CYGPATH_W) 'import/SpecPowerMeter.cpp'; else $(CYGPATH_W) '$(srcdir)/import/SpecPowerMeter.cpp'; fi` + ondemand/audacity-ODComputeSummaryTask.o: ondemand/ODComputeSummaryTask.cpp @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(audacity_CPPFLAGS) $(CPPFLAGS) $(audacity_CXXFLAGS) $(CXXFLAGS) -MT ondemand/audacity-ODComputeSummaryTask.o -MD -MP -MF ondemand/$(DEPDIR)/audacity-ODComputeSummaryTask.Tpo -c -o ondemand/audacity-ODComputeSummaryTask.o `test -f 'ondemand/ODComputeSummaryTask.cpp' || echo '$(srcdir)/'`ondemand/ODComputeSummaryTask.cpp @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ondemand/$(DEPDIR)/audacity-ODComputeSummaryTask.Tpo ondemand/$(DEPDIR)/audacity-ODComputeSummaryTask.Po diff --git a/src/import/FormatClassifier.cpp b/src/import/FormatClassifier.cpp new file mode 100644 index 000000000..da8b5d7ec --- /dev/null +++ b/src/import/FormatClassifier.cpp @@ -0,0 +1,384 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + FormatClassifier.cpp + + Philipp Sibler + +******************************************************************//** + +\class FormatClassifier +\brief FormatClassifier classifies the sample format and endianness of +raw audio files. + +The classifier operates in the frequency domain and exploits +the low-pass-like spectral behaviour of natural audio signals +for classification of the sample format and the used endianness. + +*//*******************************************************************/ +#include +#include +#include +#include +#include + +#include + +#include "MultiFormatReader.h" +#include "SpecPowerMeter.h" +#include "sndfile.h" + +#include "FormatClassifier.h" + +FormatClassifier::FormatClassifier(const char* filename) : + mReader(filename), + mMeter(cSiglen) +{ + FormatClassT fClass; + + // Build buffers + mSigBuffer = new float[cSiglen]; + mAuxBuffer = new float[cSiglen]; + mRawBuffer = new uint8_t[cSiglen * 8]; + + // Define the classification classes + fClass.endian = MachineEndianness::Little; + fClass.format = MultiFormatReader::Int8; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Int16; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Int32; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Uint8; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Float; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Double; + mClasses.push_back(fClass); + + fClass.endian = MachineEndianness::Big; + fClass.format = MultiFormatReader::Int8; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Int16; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Int32; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Uint8; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Float; + mClasses.push_back(fClass); + fClass.format = MultiFormatReader::Double; + mClasses.push_back(fClass); + + // Build feature vectors + mMonoFeat = new float[mClasses.size()]; + mStereoFeat = new float[mClasses.size()]; + +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + // Build a debug writer + char dfile [1024]; + sprintf(dfile, "%s.sig", filename); + mpWriter = new DebugWriter(dfile); +#endif + + // Run it + Run(); + +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + for (unsigned int n = 0; n < mClasses.size(); n++) + { + printf("Class [%i] Machine [%i]: Mono: %3.7f Stereo: %3.7f\n", mClasses[n].format, mClasses[n].endian, mMonoFeat[n], mStereoFeat[n]); + } +#endif + +} + +FormatClassifier::~FormatClassifier() +{ + delete[] mSigBuffer; + delete[] mAuxBuffer; + delete[] mRawBuffer; + + delete[] mMonoFeat; + delete[] mStereoFeat; + +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + delete mpWriter; +#endif +} + +FormatClassifier::FormatClassT FormatClassifier::GetResultFormat() +{ + return mResultFormat; +} + +int FormatClassifier::GetResultFormatLibSndfile() +{ + int format = SF_FORMAT_RAW; + + switch(mResultFormat.format) + { + case MultiFormatReader::Int8: + format |= SF_FORMAT_PCM_S8; + break; + case MultiFormatReader::Int16: + format |= SF_FORMAT_PCM_16; + break; + case MultiFormatReader::Int32: + format |= SF_FORMAT_PCM_32; + break; + case MultiFormatReader::Uint8: + format |= SF_FORMAT_PCM_U8; + break; + case MultiFormatReader::Float: + format |= SF_FORMAT_FLOAT; + break; + case MultiFormatReader::Double: + format |= SF_FORMAT_DOUBLE; + break; + default: + format |= SF_FORMAT_PCM_16; + break; + } + + switch(mResultFormat.endian) + { + case MachineEndianness::Little: + format |= SF_ENDIAN_LITTLE; + break; + case MachineEndianness::Big: + format |= SF_ENDIAN_BIG; + break; + } + + return format; +} + +int FormatClassifier::GetResultChannels() +{ + return mResultChannels; +} + +void FormatClassifier::Run() +{ + // Calc the mono feature vector + for (unsigned int n = 0; n < mClasses.size(); n++) + { + // Read the signal + ReadSignal(mClasses[n], 1); +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + mpWriter->WriteSignal(mSigBuffer, cSiglen); +#endif + + // Do some simple preprocessing + // Remove DC offset + float smean = Mean(mSigBuffer, cSiglen); + Sub(mSigBuffer, smean, cSiglen); + // Normalize to +- 1.0 + Abs(mSigBuffer, mAuxBuffer, cSiglen); + float smax = Max(mAuxBuffer, cSiglen); + Div(mSigBuffer, smax, cSiglen); + + // Now actually fill the feature vector + // Low to high band power ratio + float pLo = mMeter.CalcPower(mSigBuffer, 0.15f, 0.3f); + float pHi = mMeter.CalcPower(mSigBuffer, 0.45f, 0.1f); + mMonoFeat[n] = pLo / pHi; + } + + // Calc the stereo feature vector + for (unsigned int n = 0; n < mClasses.size(); n++) + { + // Read the signal + ReadSignal(mClasses[n], 2); +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + mpWriter->WriteSignal(mSigBuffer, cSiglen); +#endif + + // Do some simple preprocessing + // Remove DC offset + float smean = Mean(mSigBuffer, cSiglen); + Sub(mSigBuffer, smean, cSiglen); + // Normalize to +- 1.0 + Abs(mSigBuffer, mAuxBuffer, cSiglen); + float smax = Max(mAuxBuffer, cSiglen); + Div(mSigBuffer, smax, cSiglen); + + // Now actually fill the feature vector + // Low to high band power ratio + float pLo = mMeter.CalcPower(mSigBuffer, 0.15f, 0.3f); + float pHi = mMeter.CalcPower(mSigBuffer, 0.45f, 0.1f); + mStereoFeat[n] = pLo / pHi; + } + + // Get the results + size_t midx, sidx; + float monoMax = Max(mMonoFeat, mClasses.size(), &midx); + float stereoMax = Max(mStereoFeat, mClasses.size(), &sidx); + + if (monoMax > stereoMax) + { + mResultChannels = 1; + mResultFormat = mClasses[midx]; + } + else + { + mResultChannels = 2; + mResultFormat = mClasses[sidx]; + } + +} + +void FormatClassifier::ReadSignal(FormatClassT format, size_t stride) +{ + size_t actRead = 0; + unsigned int n = 0; + + mReader.Reset(); + + // Do a dummy read of 1024 bytes to skip potential header information + mReader.ReadSamples(mRawBuffer, 1024, MultiFormatReader::Uint8, MachineEndianness::Little); + + do + { + actRead = mReader.ReadSamples(mRawBuffer, cSiglen, stride, format.format, format.endian); + + if (n == 0) + { + ConvertSamples(mRawBuffer, mSigBuffer, format); + } + else + { + if (actRead == cSiglen) + { + ConvertSamples(mRawBuffer, mAuxBuffer, format); + + // Integrate signals + Add(mSigBuffer, mAuxBuffer, cSiglen); + + // Do some dummy reads to break signal coherence + mReader.ReadSamples(mRawBuffer, n + 1, stride, format.format, format.endian); + } + } + + n++; + + } while ((n < cNumInts) && (actRead == cSiglen)); + +} + +void FormatClassifier::ConvertSamples(void* in, float* out, FormatClassT format) +{ + switch(format.format) + { + case MultiFormatReader::Int8: + ToFloat((int8_t*) in, out, cSiglen); + break; + case MultiFormatReader::Int16: + ToFloat((int16_t*) in, out, cSiglen); + break; + case MultiFormatReader::Int32: + ToFloat((int32_t*) in, out, cSiglen); + break; + case MultiFormatReader::Uint8: + ToFloat((uint8_t*) in, out, cSiglen); + break; + case MultiFormatReader::Uint16: + ToFloat((uint16_t*) in, out, cSiglen); + break; + case MultiFormatReader::Uint32: + ToFloat((uint32_t*) in, out, cSiglen); + break; + case MultiFormatReader::Float: + ToFloat((float*) in, out, cSiglen); + break; + case MultiFormatReader::Double: + ToFloat((double*) in, out, cSiglen); + break; + } +} + +void FormatClassifier::Add(float* in1, float* in2, size_t len) +{ + for (unsigned int n = 0; n < len; n++) + { + in1[n] += in2[n]; + } +} + +void FormatClassifier::Sub(float* in, float subt, size_t len) +{ + for (unsigned int n = 0; n < len; n++) + { + in[n] -= subt; + } +} + +void FormatClassifier::Div(float* in, float div, size_t len) +{ + for (unsigned int n = 0; n < len; n++) + { + in[n] /= div; + } +} + + +void FormatClassifier::Abs(float* in, float* out, size_t len) +{ + for (unsigned int n = 0; n < len; n++) + { + if (in[n] < 0.0f) + { + out[n] = -in[n]; + } + else + { + out[n] = in[n]; + } + } +} + +float FormatClassifier::Mean(float* in, size_t len) +{ + float mean = 0.0f; + + for (unsigned int n = 0; n < len; n++) + { + mean += in[n]; + } + + mean /= len; + + return mean; +} + +float FormatClassifier::Max(float* in, size_t len) +{ + size_t dummyidx; + return Max(in, len, &dummyidx); +} + +float FormatClassifier::Max(float* in, size_t len, size_t* maxidx) +{ + float max = -FLT_MAX; + + for (unsigned int n = 0; n < len; n++) + { + if (in[n] > max) + { + max = in[n]; + *maxidx = n; + } + } + + return max; +} + +template void FormatClassifier::ToFloat(T* in, float* out, size_t len) +{ + for(unsigned int n = 0; n < len; n++) + { + out[n] = (float) in[n]; + } +} diff --git a/src/import/FormatClassifier.h b/src/import/FormatClassifier.h new file mode 100644 index 000000000..271c18060 --- /dev/null +++ b/src/import/FormatClassifier.h @@ -0,0 +1,111 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + FormatClassifier.h + + Philipp Sibler + +**********************************************************************/ + +#ifndef __AUDACITY_FORMATCLASSIFIER_H_ +#define __AUDACITY_FORMATCLASSIFIER_H_ + +#ifndef SNDFILE_1 +#error Requires libsndfile 1.0.3 or higher +#endif + +// #define FORMATCLASSIFIER_SIGNAL_DEBUG 1 + +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + +#include + +class DebugWriter +{ + FILE* mpFid; + +public: + DebugWriter(const char* filename) + { + mpFid = fopen(filename, "wb"); + } + + ~DebugWriter() + { + if (mpFid) fclose(mpFid); + } + + void WriteSignal(float* buffer, size_t len) + { + WriteSignal(buffer, 4, len); + } + + void WriteSignal(void* buffer, size_t size, size_t len) + { + fwrite(buffer, size, len, mpFid); + } +}; + +#endif + +class FormatClassifier +{ +public: + + typedef struct + { + MultiFormatReader::FormatT format; + MachineEndianness::EndiannessT endian; + } FormatClassT; + + typedef std::vector FormatVectorT; + typedef std::vector::iterator FormatVectorIt; + +private: + + static const size_t cSiglen = 512; + static const size_t cNumInts = 32; + + FormatVectorT mClasses; + MultiFormatReader mReader; + SpecPowerMeter mMeter; + +#ifdef FORMATCLASSIFIER_SIGNAL_DEBUG + DebugWriter* mpWriter; +#endif + + float* mSigBuffer; + float* mAuxBuffer; + uint8_t* mRawBuffer; + + float* mMonoFeat; + float* mStereoFeat; + + FormatClassT mResultFormat; + int mResultChannels; + +public: + FormatClassifier(const char* filename); + ~FormatClassifier(); + + FormatClassT GetResultFormat(); + int GetResultFormatLibSndfile(); + int GetResultChannels(); +private: + void Run(); + void ReadSignal(FormatClassT format, size_t stride); + void ConvertSamples(void* in, float* out, FormatClassT format); + + void Add(float* in1, float* in2, size_t len); + void Sub(float* in, float subt, size_t len); + void Div(float* in, float div, size_t len); + void Abs(float* in, float* out, size_t len); + float Mean(float* in, size_t len); + float Max(float* in, size_t len); + float Max(float* in, size_t len, size_t* maxidx); + + template void ToFloat(T* in, float* out, size_t len); +}; + +#endif diff --git a/src/import/ImportRaw.cpp b/src/import/ImportRaw.cpp index 6e56b4715..03279f0e7 100644 --- a/src/import/ImportRaw.cpp +++ b/src/import/ImportRaw.cpp @@ -26,8 +26,6 @@ and sample size to help you importing data of an unknown format. #include "ImportRaw.h" #include "Import.h" -#include "RawAudioGuess.h" - #include "../DirManager.h" #include "../FileFormats.h" #include "../Internat.h" @@ -35,7 +33,10 @@ and sample size to help you importing data of an unknown format. #include "../ShuttleGui.h" #include "../WaveTrack.h" -#include +#include +#include +#include +#include #include #include @@ -49,6 +50,11 @@ and sample size to help you importing data of an unknown format. #include #include +#include "RawAudioGuess.h" +#include "MultiFormatReader.h" +#include "SpecPowerMeter.h" +#include "FormatClassifier.h" + #include "sndfile.h" class ImportRawDialog:public wxDialog { @@ -94,7 +100,6 @@ int ImportRaw(wxWindow *parent, wxString fileName, int numChannels = 0; sampleFormat format; sf_count_t offset = 0; - int int_offset = 0; sampleCount totalFrames; double rate = 44100.0; double percent = 100.0; @@ -102,9 +107,17 @@ int ImportRaw(wxWindow *parent, wxString fileName, SF_INFO sndInfo; int result; - encoding = RawAudioGuess(fileName, - &int_offset, &numChannels); - offset = (sf_count_t)int_offset; + try { + // Yes, FormatClassifier currently handles filenames in UTF8 format only, that's + // a TODO ... + FormatClassifier theClassifier(fileName.utf8_str()); + encoding = theClassifier.GetResultFormatLibSndfile(); + numChannels = theClassifier.GetResultChannels(); + offset = 0; + } catch (...) { + // Something went wrong in FormatClassifier, use defaults instead. + encoding = 0; + } if (encoding <= 0) { // Unable to guess. Use mono, 16-bit samples with CPU endianness diff --git a/src/import/MultiFormatReader.cpp b/src/import/MultiFormatReader.cpp new file mode 100644 index 000000000..b323d9b35 --- /dev/null +++ b/src/import/MultiFormatReader.cpp @@ -0,0 +1,143 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + MultiFormatReader.cpp + + Philipp Sibler + +******************************************************************//** + +\class MultiFormatReader +\brief MultiFormatReader reads raw audio files in different formats and +machine endianness representations. + +*//*******************************************************************/ + +#include +#include +#include +#include +#include + +#include + +#include "MultiFormatReader.h" + +MultiFormatReader::MultiFormatReader(const char* filename) + : mpFid(NULL) +{ + mpFid = fopen(filename, "rb"); + + if (mpFid == NULL) + { + throw std::runtime_error("Error opening file"); + } +} + +MultiFormatReader::~MultiFormatReader() +{ + if (mpFid != NULL) + { + fclose(mpFid); + } +} + +void MultiFormatReader::Reset() +{ + if (mpFid != NULL) + { + rewind(mpFid); + } +} + +size_t MultiFormatReader::ReadSamples(void* buffer, size_t len, + MultiFormatReader::FormatT format, + MachineEndianness::EndiannessT end) +{ + return ReadSamples(buffer, len, 1, format, end); +} + + +size_t MultiFormatReader::ReadSamples(void* buffer, size_t len, size_t stride, + MultiFormatReader::FormatT format, + MachineEndianness::EndiannessT end) +{ + bool swapflag = (mEnd.Which() != end); + size_t actRead; + + switch(format) + { + case Int8: + case Uint8: + actRead = Read(buffer, 1, len, stride); + break; + case Int16: + case Uint16: + actRead = Read(buffer, 2, len, stride); + if(swapflag) SwapBytes(buffer, 2, len); + break; + case Int32: + case Uint32: + case Float: + actRead = Read(buffer, 4, len, stride); + if(swapflag) SwapBytes(buffer, 4, len); + break; + case Double: + actRead = Read(buffer, 8, len, stride); + if(swapflag) SwapBytes(buffer, 8, len); + break; + default: + break; + } + + return actRead; +} + +size_t MultiFormatReader::Read(void* buffer, size_t size, size_t len, size_t stride) +{ + size_t actRead = 0; + uint8_t* pWork = (uint8_t*) buffer; + + if (stride > 1) + { + // There are gaps between consecutive samples, + // so do a scattered read + for (size_t n = 0; n < len; n++) + { + actRead += fread(&(pWork[n*size]), size, 1, mpFid); + fseek(mpFid, (stride - 1) * size, SEEK_CUR); + } + } + else + { + // Just do a linear read + actRead = fread(buffer, size, len, mpFid); + } + + return actRead; +} + + +void MultiFormatReader::SwapBytes(void* buffer, size_t size, size_t len) +{ + uint8_t* pResBuffer = (uint8_t*) buffer; + uint8_t* pCurBuffer; + + if (size > 8) + { + throw std::runtime_error("SwapBytes Exception: Format width exceeding 8 bytes."); + } + + for (size_t i = 0; i < len; i++) + { + pCurBuffer = &(pResBuffer[i*size]); + memcpy(mSwapBuffer, &(pCurBuffer[0]), size); + + for (size_t n = 0; n < size; n++) + { + pCurBuffer[n] = mSwapBuffer[size - n - 1]; + } + } +} + diff --git a/src/import/MultiFormatReader.h b/src/import/MultiFormatReader.h new file mode 100644 index 000000000..3026d09d5 --- /dev/null +++ b/src/import/MultiFormatReader.h @@ -0,0 +1,91 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + MultiFormatReader.h + + Philipp Sibler + +**********************************************************************/ + +#ifndef __AUDACITY_MULTIFORMATREADER_H__ +#define __AUDACITY_MULTIFORMATREADER_H__ + +class MachineEndianness +{ +public: + typedef enum + { + Little = 0, + Big + } EndiannessT; + + MachineEndianness() + { + if (wxBYTE_ORDER == wxLITTLE_ENDIAN) + { + mFlag = MachineEndianness::Little; + } + else + { + mFlag = MachineEndianness::Big; + } + } + ~MachineEndianness() + {} + + int IsLittle() + { + return (mFlag == MachineEndianness::Little) ? 1 : 0; + } + + int IsBig() + { + return (mFlag == MachineEndianness::Big) ? 1 : 0; + } + + EndiannessT Which() + { + return mFlag; + } + +private: + EndiannessT mFlag; +}; + +class MultiFormatReader +{ + FILE* mpFid; + MachineEndianness mEnd; + uint8_t mSwapBuffer[8]; + +public: + typedef enum + { + Int8 = 0, + Int16, + Int32, + Uint8, + Uint16, + Uint32, + Float, + Double + } FormatT; + + MultiFormatReader(const char* filename); + ~MultiFormatReader(); + + void Reset(); + size_t ReadSamples(void* buffer, size_t len, + MultiFormatReader::FormatT format, + MachineEndianness::EndiannessT end); + size_t ReadSamples(void* buffer, size_t len, size_t stride, + MultiFormatReader::FormatT format, + MachineEndianness::EndiannessT end); + +private: + size_t Read(void* buffer, size_t size, size_t len, size_t stride); + void SwapBytes(void* buffer, size_t size, size_t len); +}; + +#endif diff --git a/src/import/SpecPowerMeter.cpp b/src/import/SpecPowerMeter.cpp new file mode 100644 index 000000000..546525be8 --- /dev/null +++ b/src/import/SpecPowerMeter.cpp @@ -0,0 +1,91 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + SpecPowerMeter.cpp + + Philipp Sibler + +******************************************************************//** + +\class SpecPowerMeter +\brief SpecPowerMeter is a simple spectral power level meter. + +SpecPowerMeter operates in the Fourier domain and allows power level +measurements in subbands or in the entire signal band. + +*//*******************************************************************/ + +#include +#include +#include + +#include "../FFT.h" +#include "SpecPowerMeter.h" + +SpecPowerMeter::SpecPowerMeter(int sigLen) +{ + mSigLen = sigLen; + + // Init buffers + mSigI = new float[sigLen]; + mSigFR = new float[sigLen]; + mSigFI = new float[sigLen]; + for (int n = 0; n < sigLen; n++) + { + mSigI[n] = 0.0f; + } +} + +SpecPowerMeter::~SpecPowerMeter() +{ + delete[] mSigI; + delete[] mSigFR; + delete[] mSigFI; +} + +float SpecPowerMeter::CalcPower(float* sig, float fc, float bw) +{ + float pwr; + int loBin, hiBin; + + // Given the bandwidth bw, get the boundary bin numbers + loBin = Freq2Bin(fc - (bw / 2.0f)); + hiBin = Freq2Bin(fc + (bw / 2.0f)); + if (loBin == hiBin) + { + hiBin = loBin + 1; + } + + // Calc the FFT + FFT(mSigLen, 0, sig, mSigI, mSigFR, mSigFI); + + // Calc the in-band power + pwr = CalcBinPower(mSigFR, mSigFI, loBin, hiBin); + + return pwr; +} + +float SpecPowerMeter::CalcBinPower(float* sig_f_r, float* sig_f_i, int loBin, int hiBin) +{ + float pwr = 0.0f; + + for (int n = loBin; n < hiBin; n++) + { + pwr += ((sig_f_r[n]*sig_f_r[n])+(sig_f_i[n]*sig_f_i[n])); + } + + return pwr; +} + +int SpecPowerMeter::Freq2Bin(float fc) +{ + int bin; + + // There is no round() in (older) MSVSs ... + bin = floor((double)fc * mSigLen); + bin %= mSigLen; + + return bin; +} + diff --git a/src/import/SpecPowerMeter.h b/src/import/SpecPowerMeter.h new file mode 100644 index 000000000..e5dec9cbf --- /dev/null +++ b/src/import/SpecPowerMeter.h @@ -0,0 +1,32 @@ +/********************************************************************** + + Audacity: A Digital Audio Editor + + SpecPowerMeter.h + + Philipp Sibler + +**********************************************************************/ + +#ifndef __AUDACITY_SPECPOWERMETER_H_ +#define __AUDACITY_SPECPOWERMETER_H_ + +class SpecPowerMeter +{ + int mSigLen; + + float* mSigI; + float* mSigFR; + float* mSigFI; + + float CalcBinPower(float* sig_f_r, float* sig_f_i, int loBin, int hiBin); + int Freq2Bin(float fc); +public: + SpecPowerMeter(int sigLen); + ~SpecPowerMeter(); + + float CalcPower(float* sig, float fc, float bw); +}; + +#endif +