diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index c472a2149..c4b8bcea6 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -55,6 +55,9 @@ out. #include "Internat.h" #include "MemoryX.h" +#include "sndfile.h" +#include "FileFormats.h" +#include "AudacityApp.h" // msmeyer: Define this to add debug output via printf() //#define DEBUG_BLOCKFILE @@ -498,6 +501,135 @@ bool BlockFile::Read64K(float *buffer, return true; } +size_t BlockFile::CommonReadData( + const wxFileName &fileName, bool &mSilentLog, + const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel, + samplePtr data, sampleFormat format, size_t start, size_t len, + const sampleFormat *pLegacyFormat, size_t legacyLen) +{ + // Third party library has its own type alias, check it before + // adding origin + size_t + static_assert(sizeof(sampleCount::type) <= sizeof(sf_count_t), + "Type sf_count_t is too narrow to hold a sampleCount"); + + SF_INFO info; + memset(&info, 0, sizeof(info)); + + if ( pLegacyFormat ) { + switch( *pLegacyFormat ) { + 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 = legacyLen + origin.as_long_long(); + } + + + wxFile f; // will be closed when it goes out of scope + SFFile sf; + + { + Maybe silence{}; + if (mSilentLog) + silence.create(); + + const auto fullPath = fileName.GetFullPath(); + if (wxFile::Exists(fullPath) && f.Open(fullPath)) { + // 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.reset(SFCall(sf_open_fd, f.fd(), SFM_READ, &info, FALSE)); + } + // FIXME: TRAP_ERR failure of wxFile open incompletely handled in BlockFile::CommonReadData. + + if (!sf) { + + memset(data, 0, SAMPLE_SIZE(format)*len); + + mSilentLog = TRUE; + + if (pAliasFile) { + // Set a marker to display an error message for the silence + if (!wxGetApp().ShouldShowMissingAliasedFileWarning()) + wxGetApp().MarkAliasedFilesMissingWarning(pAliasFile); + } + + return len; + } + } + mSilentLog=FALSE; + + SFCall( + sf_seek, sf.get(), ( origin + start ).as_long_long(), SEEK_SET); + + auto channels = info.channels; + wxASSERT(channels >= 1); + wxASSERT(channel < channels); + + size_t framesRead = 0; + + if (channels == 1 && + format == int16Sample && + sf_subtype_is_integer(info.format)) { + // If both the src and dest formats are integer formats, + // read integers directly from the file, comversions not needed + framesRead = SFCall( + sf_readf_short, sf.get(), (short *)data, len); + } + else if (channels == 1 && + format == int24Sample && + sf_subtype_is_integer(info.format)) { + framesRead = SFCall(sf_readf_int, sf.get(), (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 if (format == int16Sample && + !sf_subtype_more_than_16_bits(info.format)) { + // Special case: if the file is in 16-bit (or less) format, + // and the calling method wants 16-bit data, go ahead and + // read 16-bit data directly. This is a pretty common + // case, as most audio files are 16-bit. + SampleBuffer buffer(len * channels, int16Sample); + framesRead = SFCall( + sf_readf_short, sf.get(), (short *)buffer.ptr(), len); + for (int i = 0; i < framesRead; i++) + ((short *)data)[i] = + ((short *)buffer.ptr())[(channels * i) + channel]; + } + 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. + SampleBuffer buffer(len * channels, floatSample); + framesRead = SFCall( + sf_readf_float, sf.get(), (float *)buffer.ptr(), len); + auto bufferPtr = (samplePtr)((float *)buffer.ptr() + channel); + CopySamples(bufferPtr, floatSample, + (samplePtr)data, format, + framesRead, + true /* high quality by default */, + channels /* source stride */); + } + + return framesRead; +} + /// Constructs an AliasBlockFile based on the given information about /// the aliased file. /// diff --git a/src/BlockFile.h b/src/BlockFile.h index 61e843795..7a142f7ab 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -44,6 +44,7 @@ class SummaryInfo { class BlockFile; +class AliasBlockFile; using BlockFilePtr = std::shared_ptr; template< typename Result, typename... Args > @@ -185,6 +186,12 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { /// on a different platform virtual void FixSummary(void *data); + static size_t CommonReadData( + const wxFileName &fileName, bool &mSilentLog, + const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel, + samplePtr data, sampleFormat format, size_t start, size_t len, + const sampleFormat *pLegacyFormat = nullptr, size_t legacyLen = 0); + private: int mLockCount; @@ -247,7 +254,7 @@ class AliasBlockFile /* not final */ : public BlockFile wxFileNameWrapper mAliasedFileName; sampleCount mAliasStart; - int mAliasChannel; + const int mAliasChannel; mutable bool mSilentAliasLog; }; diff --git a/src/blockfile/LegacyBlockFile.cpp b/src/blockfile/LegacyBlockFile.cpp index b33c75731..df10fa6e5 100644 --- a/src/blockfile/LegacyBlockFile.cpp +++ b/src/blockfile/LegacyBlockFile.cpp @@ -191,90 +191,11 @@ bool LegacyBlockFile::ReadSummary(void *data) size_t LegacyBlockFile::ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const { - 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 - SFFile sf; - - 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.reset(SFCall(sf_open_fd, f.fd(), SFM_READ, &info, FALSE)); - } - // FIXME: TRAP_ERR failure of wxFile open incompletely handled in LegacyBlockfile::ReadData. - - { - Maybe silence{}; - if (mSilentLog) - silence.create(); - - if (!sf){ - - memset(data, 0, SAMPLE_SIZE(format)*len); - - mSilentLog = TRUE; - - return len; - } - } - mSilentLog=FALSE; - - sf_count_t seekstart = start + - (mSummaryInfo.totalSummaryBytes / SAMPLE_SIZE(mFormat)); - SFCall(sf_seek, sf.get(), seekstart , SEEK_SET); - - SampleBuffer buffer(len, floatSample); - size_t 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 = SFCall(sf_readf_short, sf.get(), (short *)data, len); - } - else if (format == int24Sample && - sf_subtype_is_integer(info.format)) { - framesRead = SFCall(sf_readf_int, sf.get(), (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 = SFCall(sf_readf_float, sf.get(), (float *)buffer.ptr(), len); - CopySamples(buffer.ptr(), floatSample, - (samplePtr)data, format, framesRead); - } - - return framesRead; + sf_count_t origin = (mSummaryInfo.totalSummaryBytes / SAMPLE_SIZE(mFormat)); + return CommonReadData( + mFileName, mSilentLog, nullptr, origin, 0, data, format, start, len, + &mFormat, mLen + ); } void LegacyBlockFile::SaveXML(XMLWriter &xmlFile) diff --git a/src/blockfile/ODDecodeBlockFile.h b/src/blockfile/ODDecodeBlockFile.h index 9753720bb..0ec7150da 100644 --- a/src/blockfile/ODDecodeBlockFile.h +++ b/src/blockfile/ODDecodeBlockFile.h @@ -185,7 +185,7 @@ class ODDecodeBlockFile final : public SimpleBlockFile sampleFormat mFormat; sampleCount mAliasStart;//where in the encoded audio file this block corresponds to. - int mAliasChannel;//The channel number in the encoded file.. + const int mAliasChannel;//The channel number in the encoded file.. }; diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index c7f544f7b..11107144a 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -490,81 +490,18 @@ size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, LockRead(); - SF_INFO info; - if(!mAliasedFileName.IsOk()){ // intentionally silenced memset(data,0,SAMPLE_SIZE(format)*len); UnlockRead(); return len; } - memset(&info, 0, sizeof(info)); - - wxString aliasPath = mAliasedFileName.GetFullPath(); - - wxFile f; // will be closed when it goes out of scope - SFFile sf; - - if (f.Exists(aliasPath) && f.Open(aliasPath)) { - // 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.reset(SFCall(sf_open_fd, f.fd(), SFM_READ, &info, FALSE)); - } - // FIXME: TRAP_ERR failure of wxFile open incompletely handled in ODPCMAliasBlockFile::ReadData. - - - if (!sf) { - - memset(data,0,SAMPLE_SIZE(format)*len); - - mSilentAliasLog = TRUE; - // Set a marker to display an error message - if (!wxGetApp().ShouldShowMissingAliasedFileWarning()) - wxGetApp().MarkAliasedFilesMissingWarning(this); - - UnlockRead(); - return len; - } - - mSilentAliasLog=FALSE; - - // Third party library has its own type alias, check it - static_assert(sizeof(sampleCount::type) <= sizeof(sf_count_t), - "Type sf_count_t is too narrow to hold a sampleCount"); - SFCall(sf_seek, sf.get(), - ( mAliasStart + start ).as_long_long(), SEEK_SET); - - wxASSERT(info.channels >= 0); - SampleBuffer buffer(len * info.channels, floatSample); - - size_t framesRead = 0; - - if (format == int16Sample && - !sf_subtype_more_than_16_bits(info.format)) { - // Special case: if the file is in 16-bit (or less) format, - // and the calling method wants 16-bit data, go ahead and - // read 16-bit data directly. This is a pretty common - // case, as most audio files are 16-bit. - framesRead = SFCall(sf_readf_short, sf.get(), (short *)buffer.ptr(), len); - - for (int i = 0; i < framesRead; i++) - ((short *)data)[i] = - ((short *)buffer.ptr())[(info.channels * i) + mAliasChannel]; - } - 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 = SFCall(sf_readf_float, sf.get(), (float *)buffer.ptr(), len); - float *bufferPtr = &((float *)buffer.ptr())[mAliasChannel]; - CopySamples((samplePtr)bufferPtr, floatSample, - (samplePtr)data, format, - framesRead, true, info.channels); - } + auto result = CommonReadData( + mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, + data, format, start, len); UnlockRead(); - return framesRead; + return result; } /// Read the summary of this alias block from disk. Since the audio data diff --git a/src/blockfile/PCMAliasBlockFile.cpp b/src/blockfile/PCMAliasBlockFile.cpp index 80b970b5d..da95aa8f1 100644 --- a/src/blockfile/PCMAliasBlockFile.cpp +++ b/src/blockfile/PCMAliasBlockFile.cpp @@ -77,79 +77,14 @@ PCMAliasBlockFile::~PCMAliasBlockFile() size_t PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, size_t start, size_t len) const { - SF_INFO info; - if(!mAliasedFileName.IsOk()){ // intentionally silenced - memset(data,0,SAMPLE_SIZE(format)*len); + memset(data, 0, SAMPLE_SIZE(format) * len); return len; } - wxFile f; // will be closed when it goes out of scope - SFFile sf; - { - Maybe silence{}; - if (mSilentAliasLog) - silence.create(); - - memset(&info, 0, sizeof(info)); - - if (f.Exists(mAliasedFileName.GetFullPath())) { // Don't use Open if file does not exits - if (f.Open(mAliasedFileName.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.reset(SFCall(sf_open_fd, f.fd(), SFM_READ, &info, FALSE)); - } - // FIXME: TRAP_ERR failure of wxFile open incompletely handled in PCMAliasBlockFile::ReadData. - - } - - if (!sf) { - memset(data, 0, SAMPLE_SIZE(format)*len); - silence.reset(); - mSilentAliasLog = TRUE; - - // Set a marker to display an error message for the silence - if (!wxGetApp().ShouldShowMissingAliasedFileWarning()) - wxGetApp().MarkAliasedFilesMissingWarning(this); - return len; - } - } - mSilentAliasLog=FALSE; - - // Third party library has its own type alias, check it - static_assert(sizeof(sampleCount::type) <= sizeof(sf_count_t), - "Type sf_count_t is too narrow to hold a sampleCount"); - SFCall(sf_seek, sf.get(), - ( mAliasStart + start ).as_long_long(), SEEK_SET); - wxASSERT(info.channels >= 0); - SampleBuffer buffer(len * info.channels, floatSample); - - size_t framesRead = 0; - - if (format == int16Sample && - !sf_subtype_more_than_16_bits(info.format)) { - // Special case: if the file is in 16-bit (or less) format, - // and the calling method wants 16-bit data, go ahead and - // read 16-bit data directly. This is a pretty common - // case, as most audio files are 16-bit. - framesRead = SFCall(sf_readf_short, sf.get(), (short *)buffer.ptr(), len); - for (int i = 0; i < framesRead; i++) - ((short *)data)[i] = - ((short *)buffer.ptr())[(info.channels * i) + mAliasChannel]; - } - 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 = SFCall(sf_readf_float, sf.get(), (float *)buffer.ptr(), len); - float *bufferPtr = &((float *)buffer.ptr())[mAliasChannel]; - CopySamples((samplePtr)bufferPtr, floatSample, - (samplePtr)data, format, - framesRead, true, info.channels); - } - - return framesRead; + return CommonReadData( + mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, + data, format, start, len); } /// Construct a NEW PCMAliasBlockFile based on this one, but writing diff --git a/src/blockfile/SimpleBlockFile.cpp b/src/blockfile/SimpleBlockFile.cpp index 4e008875e..36f93cb4e 100644 --- a/src/blockfile/SimpleBlockFile.cpp +++ b/src/blockfile/SimpleBlockFile.cpp @@ -402,76 +402,9 @@ size_t SimpleBlockFile::ReadData(samplePtr data, sampleFormat format, mCache.format, data, format, len); return len; } - else { - //wxLogDebug("SimpleBlockFile::ReadData(): Reading data from disk."); - - SF_INFO info; - wxFile f; // will be closed when it goes out of scope - SFFile sf; - { - Maybe silence{}; - if (mSilentLog) - silence.create(); - - memset(&info, 0, sizeof(info)); - - 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.reset(SFCall(sf_open_fd, f.fd(), SFM_READ, &info, FALSE)); - } - // FIXME: TRAP_ERR failure of wxFile open incompletely handled in SimpleBlockFile::ReadData. - // FIXME: Too much cut and paste code between the different block file types. - - - if (!sf) { - - memset(data, 0, SAMPLE_SIZE(format)*len); - - mSilentLog = TRUE; - - return len; - } - } - mSilentLog=FALSE; - - SFCall(sf_seek, sf.get(), start, SEEK_SET); - SampleBuffer buffer(len, floatSample); - - size_t 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 = SFCall(sf_readf_short, sf.get(), (short *)data, len); - } - else - if (format == int24Sample && - sf_subtype_is_integer(info.format)) - { - framesRead = SFCall(sf_readf_int, sf.get(), (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 = SFCall(sf_readf_float, sf.get(), (float *)buffer.ptr(), len); - CopySamples(buffer.ptr(), floatSample, - (samplePtr)data, format, framesRead); - } - - return framesRead; - } + else + return CommonReadData( + mFileName, mSilentLog, nullptr, 0, 0, data, format, start, len); } void SimpleBlockFile::SaveXML(XMLWriter &xmlFile)