mirror of
https://github.com/cookiengineer/audacity
synced 2026-02-16 15:57:52 +01:00
Locate and position the current Audacity source code, and clear a variety of old junk out of the way into junk-branches
This commit is contained in:
370
src/blockfile/LegacyBlockFile.cpp
Normal file
370
src/blockfile/LegacyBlockFile.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/**********************************************************************
|
||||
|
||||
Audacity: A Digital Audio Editor
|
||||
|
||||
LegacyBlockFile.cpp
|
||||
|
||||
Dominic Mazzoni
|
||||
|
||||
******************************************************************//**
|
||||
|
||||
\class LegacyBlockFile
|
||||
\brief Audacity 1.1.0 block file format:
|
||||
|
||||
- Header tag: 20 bytes "AudacityBlockFile110"
|
||||
- 64K summaries (min, max, RMS, each a 4-byte float)
|
||||
- 256 summaries (min, max, RMS, each a 4-byte float)
|
||||
|
||||
*//******************************************************************/
|
||||
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
|
||||
#include <wx/filefn.h>
|
||||
#include <wx/file.h>
|
||||
#include <wx/ffile.h>
|
||||
#include <wx/utils.h>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "LegacyBlockFile.h"
|
||||
#include "../FileFormats.h"
|
||||
#include "../Internat.h"
|
||||
|
||||
#include "sndfile.h"
|
||||
|
||||
void ComputeLegacySummaryInfo(wxFileName fileName,
|
||||
int summaryLen,
|
||||
sampleFormat format,
|
||||
SummaryInfo *info,
|
||||
bool noRMS,bool Silent,
|
||||
float *min, float *max, float *rms)
|
||||
{
|
||||
int fields = 3; /* min, max, rms */
|
||||
|
||||
if (noRMS)
|
||||
fields = 2;
|
||||
|
||||
info->fields = fields;
|
||||
info->format = format;
|
||||
info->bytesPerFrame =
|
||||
SAMPLE_SIZE(info->format) * fields;
|
||||
info->totalSummaryBytes = summaryLen;
|
||||
info->offset64K = 20; /* legacy header tag len */
|
||||
info->frames64K = (summaryLen-20) /
|
||||
(info->bytesPerFrame * 256);
|
||||
info->offset256 = info->offset64K +
|
||||
(info->frames64K * info->bytesPerFrame);
|
||||
info->frames256 =
|
||||
(summaryLen - 20 -
|
||||
(info->frames64K * info->bytesPerFrame)) /
|
||||
info->bytesPerFrame;
|
||||
|
||||
//
|
||||
// Compute the min, max, and RMS of the block from the
|
||||
// 64K summary data
|
||||
//
|
||||
|
||||
float *summary = new float[info->frames64K * fields];
|
||||
samplePtr data = NewSamples(info->frames64K * fields,
|
||||
info->format);
|
||||
|
||||
wxLogNull *silence=0;
|
||||
wxFFile summaryFile(fileName.GetFullPath(), wxT("rb"));
|
||||
int read;
|
||||
if(Silent)silence= new wxLogNull();
|
||||
|
||||
if( !summaryFile.IsOpened() ) {
|
||||
wxLogWarning(wxT("Unable to access summary file %s; substituting silence for remainder of session"),
|
||||
fileName.GetFullPath().c_str());
|
||||
|
||||
read=info->frames64K * info->bytesPerFrame;
|
||||
memset(data,0,read);
|
||||
}else{
|
||||
summaryFile.Seek(info->offset64K);
|
||||
read = summaryFile.Read(data,
|
||||
info->frames64K *
|
||||
info->bytesPerFrame);
|
||||
}
|
||||
|
||||
if(silence) delete silence;
|
||||
|
||||
int count = read / info->bytesPerFrame;
|
||||
|
||||
CopySamples(data, info->format,
|
||||
(samplePtr)summary, floatSample, count);
|
||||
|
||||
(*min) = FLT_MAX;
|
||||
(*max) = FLT_MIN;
|
||||
float sumsq = 0;
|
||||
|
||||
for(int i=0; i<count; i++) {
|
||||
if (summary[fields*i] < (*min))
|
||||
(*min) = summary[fields*i];
|
||||
if (summary[fields*i+1] > (*max))
|
||||
(*max) = summary[fields*i+1];
|
||||
if (fields >= 3)
|
||||
sumsq += summary[fields*i+2]*summary[fields*i+2];
|
||||
}
|
||||
if (fields >= 3)
|
||||
(*rms) = sqrt(sumsq / count);
|
||||
else
|
||||
(*rms) = 0;
|
||||
|
||||
DeleteSamples(data);
|
||||
delete[] summary;
|
||||
}
|
||||
|
||||
/// Construct a LegacyBlockFile memory structure that will point to an
|
||||
/// existing block file. This file must exist and be a valid block file.
|
||||
///
|
||||
/// @param existingFile The disk file this LegacyBlockFile should use.
|
||||
LegacyBlockFile::LegacyBlockFile(wxFileName existingFile,
|
||||
sampleFormat format,
|
||||
sampleCount summaryLen,
|
||||
sampleCount len,
|
||||
bool noRMS):
|
||||
BlockFile(existingFile, len),
|
||||
mFormat(format)
|
||||
{
|
||||
|
||||
sampleFormat summaryFormat;
|
||||
|
||||
if (noRMS)
|
||||
summaryFormat = int16Sample;
|
||||
else
|
||||
summaryFormat = floatSample;
|
||||
|
||||
ComputeLegacySummaryInfo(existingFile,
|
||||
summaryLen, summaryFormat,
|
||||
&mSummaryInfo, noRMS, FALSE,
|
||||
&mMin, &mMax, &mRMS);
|
||||
}
|
||||
|
||||
LegacyBlockFile::~LegacyBlockFile()
|
||||
{
|
||||
}
|
||||
|
||||
/// Read the summary section of the disk file.
|
||||
///
|
||||
/// @param *data The buffer to write the data to. It must be at least
|
||||
/// mSummaryinfo.totalSummaryBytes long.
|
||||
bool LegacyBlockFile::ReadSummary(void *data)
|
||||
{
|
||||
wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb"));
|
||||
wxLogNull *silence=0;
|
||||
if(mSilentLog)silence= new wxLogNull();
|
||||
|
||||
if( !summaryFile.IsOpened() ){
|
||||
|
||||
memset(data,0,(size_t)mSummaryInfo.totalSummaryBytes);
|
||||
|
||||
if(silence) delete silence;
|
||||
mSilentLog=TRUE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int read = summaryFile.Read(data, (size_t)mSummaryInfo.totalSummaryBytes);
|
||||
|
||||
if(silence) delete silence;
|
||||
mSilentLog=FALSE;
|
||||
|
||||
return (read == mSummaryInfo.totalSummaryBytes);
|
||||
}
|
||||
|
||||
/// Read the data portion of the block file using libsndfile. Convert it
|
||||
/// to the given format if it is not already.
|
||||
///
|
||||
/// @param data The buffer where the data will be stored
|
||||
/// @param format The format the data will be stored in
|
||||
/// @param start The offset in this block file
|
||||
/// @param len The number of samples to read
|
||||
int LegacyBlockFile::ReadData(samplePtr data, sampleFormat format,
|
||||
sampleCount start, sampleCount len)
|
||||
{
|
||||
SF_INFO info;
|
||||
|
||||
memset(&info, 0, sizeof(info));
|
||||
|
||||
switch(mFormat) {
|
||||
case int16Sample:
|
||||
info.format =
|
||||
SF_FORMAT_RAW | SF_FORMAT_PCM_16 | SF_ENDIAN_CPU;
|
||||
break;
|
||||
default:
|
||||
case floatSample:
|
||||
info.format =
|
||||
SF_FORMAT_RAW | SF_FORMAT_FLOAT | SF_ENDIAN_CPU;
|
||||
break;
|
||||
case int24Sample:
|
||||
info.format = SF_FORMAT_RAW | SF_FORMAT_PCM_32 | SF_ENDIAN_CPU;
|
||||
break;
|
||||
}
|
||||
info.samplerate = 44100; // Doesn't matter
|
||||
info.channels = 1;
|
||||
info.frames = mLen + (mSummaryInfo.totalSummaryBytes /
|
||||
SAMPLE_SIZE(mFormat));
|
||||
|
||||
wxFile f; // will be closed when it goes out of scope
|
||||
SNDFILE *sf = NULL;
|
||||
|
||||
if (f.Open(mFileName.GetFullPath())) {
|
||||
// Even though there is an sf_open() that takes a filename, use the one that
|
||||
// takes a file descriptor since wxWidgets can open a file with a Unicode name and
|
||||
// libsndfile can't (under Windows).
|
||||
sf = sf_open_fd(f.fd(), SFM_READ, &info, FALSE);
|
||||
}
|
||||
|
||||
wxLogNull *silence=0;
|
||||
if(mSilentLog)silence= new wxLogNull();
|
||||
|
||||
if (!sf){
|
||||
|
||||
memset(data,0,SAMPLE_SIZE(format)*len);
|
||||
|
||||
if(silence) delete silence;
|
||||
mSilentLog=TRUE;
|
||||
|
||||
return len;
|
||||
}
|
||||
if(silence) delete silence;
|
||||
mSilentLog=FALSE;
|
||||
|
||||
sf_count_t seekstart = start +
|
||||
(mSummaryInfo.totalSummaryBytes / SAMPLE_SIZE(mFormat));
|
||||
sf_seek(sf, seekstart , SEEK_SET);
|
||||
|
||||
samplePtr buffer = NewSamples(len, floatSample);
|
||||
int framesRead = 0;
|
||||
|
||||
// If both the src and dest formats are integer formats,
|
||||
// read integers from the file (otherwise we would be
|
||||
// converting to float and back, which is unneccesary)
|
||||
if (format == int16Sample &&
|
||||
sf_subtype_is_integer(info.format)) {
|
||||
framesRead = sf_readf_short(sf, (short *)data, len);
|
||||
}else if (format == int24Sample &&
|
||||
sf_subtype_is_integer(info.format)) {
|
||||
framesRead = sf_readf_int(sf, (int *)data, len);
|
||||
|
||||
// libsndfile gave us the 3 byte sample in the 3 most
|
||||
// significant bytes -- we want it in the 3 least
|
||||
// significant bytes.
|
||||
int *intPtr = (int *)data;
|
||||
for( int i = 0; i < framesRead; i++ )
|
||||
intPtr[i] = intPtr[i] >> 8;
|
||||
} else {
|
||||
// Otherwise, let libsndfile handle the conversion and
|
||||
// scaling, and pass us normalized data as floats. We can
|
||||
// then convert to whatever format we want.
|
||||
framesRead = sf_readf_float(sf, (float *)buffer, len);
|
||||
CopySamples(buffer, floatSample,
|
||||
(samplePtr)data, format, framesRead);
|
||||
}
|
||||
|
||||
sf_close(sf);
|
||||
|
||||
DeleteSamples(buffer);
|
||||
|
||||
return framesRead;
|
||||
}
|
||||
|
||||
void LegacyBlockFile::SaveXML(XMLWriter &xmlFile)
|
||||
{
|
||||
xmlFile.StartTag(wxT("legacyblockfile"));
|
||||
|
||||
xmlFile.WriteAttr(wxT("name"), mFileName.GetFullName());
|
||||
xmlFile.WriteAttr(wxT("len"), mLen);
|
||||
if (mSummaryInfo.fields < 3)
|
||||
xmlFile.WriteAttr(wxT("norms"), 1);
|
||||
xmlFile.WriteAttr(wxT("summarylen"), mSummaryInfo.totalSummaryBytes);
|
||||
|
||||
xmlFile.EndTag(wxT("legacyblockfile"));
|
||||
}
|
||||
|
||||
/// static
|
||||
BlockFile *LegacyBlockFile::BuildFromXML(wxString projDir, const wxChar **attrs,
|
||||
sampleCount len, sampleFormat format)
|
||||
{
|
||||
wxFileName fileName;
|
||||
sampleCount summaryLen = 0;
|
||||
bool noRMS = false;
|
||||
long nValue;
|
||||
|
||||
while(*attrs)
|
||||
{
|
||||
const wxChar *attr = *attrs++;
|
||||
const wxChar *value = *attrs++;
|
||||
|
||||
if (!value)
|
||||
break;
|
||||
|
||||
const wxString strValue = value;
|
||||
if( !wxStrcmp(attr, wxT("name")) )
|
||||
{
|
||||
if (!XMLValueChecker::IsGoodFileName(strValue, projDir))
|
||||
return NULL;
|
||||
fileName.Assign(projDir, strValue);
|
||||
}
|
||||
else if (XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
|
||||
{ // integer parameters
|
||||
if( !wxStrcmp(attr, wxT("len")) )
|
||||
len = nValue;
|
||||
if( !wxStrcmp(attr, wxT("norms")) )
|
||||
noRMS = (nValue != 0);
|
||||
if( !wxStrcmp(attr, wxT("format")) )
|
||||
{
|
||||
if (!XMLValueChecker::IsValidSampleFormat(nValue))
|
||||
return NULL;
|
||||
format = (sampleFormat)nValue;
|
||||
}
|
||||
if( !wxStrcmp(attr, wxT("summarylen")) )
|
||||
summaryLen = nValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!XMLValueChecker::IsGoodFileName(fileName.GetFullName(),
|
||||
fileName.GetPath(wxPATH_GET_VOLUME)) ||
|
||||
(len <= 0) || (summaryLen <= 0))
|
||||
return NULL;
|
||||
|
||||
return new LegacyBlockFile(fileName, format, summaryLen, len, noRMS);
|
||||
}
|
||||
|
||||
/// Create a copy of this BlockFile, but using a different disk file.
|
||||
///
|
||||
/// @param newFileName The name of the new file to use.
|
||||
BlockFile *LegacyBlockFile::Copy(wxFileName newFileName)
|
||||
{
|
||||
BlockFile *newBlockFile = new LegacyBlockFile(newFileName,
|
||||
mFormat,
|
||||
mSummaryInfo.totalSummaryBytes,
|
||||
mLen,
|
||||
mSummaryInfo.fields < 3);
|
||||
|
||||
return newBlockFile;
|
||||
}
|
||||
|
||||
wxLongLong LegacyBlockFile::GetSpaceUsage()
|
||||
{
|
||||
wxFFile dataFile(mFileName.GetFullPath());
|
||||
return dataFile.Length();
|
||||
}
|
||||
|
||||
void LegacyBlockFile::Recover()
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
// Indentation settings for Vim and Emacs and unique identifier for Arch, a
|
||||
// version control system. Please do not modify past this point.
|
||||
//
|
||||
// Local Variables:
|
||||
// c-basic-offset: 3
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
//
|
||||
// vim: et sts=3 sw=3
|
||||
// arch-tag: e84a3cdf-2140-43b4-98fa-ca8b22ec1df8
|
||||
|
||||
Reference in New Issue
Block a user