mirror of
https://github.com/cookiengineer/audacity
synced 2025-10-13 22:21:11 +02:00
commit patch greatly improving the detection of format of raw audio files, by Philipp Sibler
This commit is contained in:
384
src/import/FormatClassifier.cpp
Normal file
384
src/import/FormatClassifier.cpp
Normal file
@@ -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 <stdint.h>
|
||||
#include <cmath>
|
||||
#include <cfloat>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
|
||||
#include <wx/defs.h>
|
||||
|
||||
#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<class T> void FormatClassifier::ToFloat(T* in, float* out, size_t len)
|
||||
{
|
||||
for(unsigned int n = 0; n < len; n++)
|
||||
{
|
||||
out[n] = (float) in[n];
|
||||
}
|
||||
}
|
111
src/import/FormatClassifier.h
Normal file
111
src/import/FormatClassifier.h
Normal file
@@ -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 <cstdio>
|
||||
|
||||
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<FormatClassT> FormatVectorT;
|
||||
typedef std::vector<FormatClassT>::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<class T> void ToFloat(T* in, float* out, size_t len);
|
||||
};
|
||||
|
||||
#endif
|
@@ -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 <math.h>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/defs.h>
|
||||
#include <wx/button.h>
|
||||
@@ -49,6 +50,11 @@ and sample size to help you importing data of an unknown format.
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/timer.h>
|
||||
|
||||
#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
|
||||
|
143
src/import/MultiFormatReader.cpp
Normal file
143
src/import/MultiFormatReader.cpp
Normal file
@@ -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 <exception>
|
||||
#include <stdexcept>
|
||||
#include <cstring>
|
||||
#include <stdint.h>
|
||||
#include <cstdio>
|
||||
|
||||
#include <wx/defs.h>
|
||||
|
||||
#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];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
91
src/import/MultiFormatReader.h
Normal file
91
src/import/MultiFormatReader.h
Normal file
@@ -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
|
91
src/import/SpecPowerMeter.cpp
Normal file
91
src/import/SpecPowerMeter.cpp
Normal file
@@ -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 <cmath>
|
||||
#include <cstdlib>
|
||||
#include <wx/defs.h>
|
||||
|
||||
#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;
|
||||
}
|
||||
|
32
src/import/SpecPowerMeter.h
Normal file
32
src/import/SpecPowerMeter.h
Normal file
@@ -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
|
||||
|
Reference in New Issue
Block a user