From 98d1468a018bc28c5e6c7c6668b5d0b95b95527b Mon Sep 17 00:00:00 2001 From: Paul Licameli Date: Sun, 25 Dec 2016 08:42:44 -0500 Subject: [PATCH] BlockFile::ReadData overrides: on failure, pad with 0s or throw... ... as the mayThrow argument directs. --- src/BlockFile.cpp | 127 ++++++++++++++------------ src/BlockFile.h | 7 +- src/blockfile/LegacyBlockFile.cpp | 4 +- src/blockfile/LegacyBlockFile.h | 2 +- src/blockfile/ODDecodeBlockFile.cpp | 12 ++- src/blockfile/ODDecodeBlockFile.h | 2 +- src/blockfile/ODPCMAliasBlockFile.cpp | 6 +- src/blockfile/ODPCMAliasBlockFile.h | 2 +- src/blockfile/PCMAliasBlockFile.cpp | 4 +- src/blockfile/PCMAliasBlockFile.h | 2 +- src/blockfile/SilentBlockFile.cpp | 2 +- src/blockfile/SilentBlockFile.h | 2 +- src/blockfile/SimpleBlockFile.cpp | 23 +++-- src/blockfile/SimpleBlockFile.h | 2 +- 14 files changed, 113 insertions(+), 84 deletions(-) diff --git a/src/BlockFile.cpp b/src/BlockFile.cpp index 01c9d9f8b..a83b3839f 100644 --- a/src/BlockFile.cpp +++ b/src/BlockFile.cpp @@ -376,7 +376,8 @@ auto BlockFile::GetMinMaxRMS(size_t start, size_t len, bool mayThrow) { // TODO: actually use summaries SampleBuffer blockData(len, floatSample); - this->ReadData(blockData.ptr(), floatSample, start, len); + + this->ReadData(blockData.ptr(), floatSample, start, len, mayThrow); float min = FLT_MAX; float max = -FLT_MAX; @@ -485,6 +486,7 @@ bool BlockFile::Read64K(float *buffer, } size_t BlockFile::CommonReadData( + bool mayThrow, const wxFileName &fileName, bool &mSilentLog, const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel, samplePtr data, sampleFormat format, size_t start, size_t len, @@ -534,80 +536,89 @@ size_t BlockFile::CommonReadData( // 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); + mSilentLog = !sf; size_t framesRead = 0; + if (sf) { + auto seek_result = SFCall( + sf_seek, sf.get(), ( origin + start ).as_long_long(), SEEK_SET); - 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); + if (seek_result < 0) + // error + ; + else { + auto channels = info.channels; + wxASSERT(channels >= 1); + wxASSERT(channel < channels); - // 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; + 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 */); + } + } } - 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 */); + + if ( framesRead < len ) { + if (mayThrow) + //throw FileException{ FileException::Cause::Read, fileName } + ; + ClearSamples(data, format, framesRead, len - framesRead); } return framesRead; diff --git a/src/BlockFile.h b/src/BlockFile.h index 56a6cf123..1425754d0 100644 --- a/src/BlockFile.h +++ b/src/BlockFile.h @@ -67,8 +67,12 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { // Reading /// Retrieves audio data from this BlockFile + /// Returns the number of samples really read, not more than len + /// If fewer can be read than len, throws an exception if mayThrow is true, + /// otherwise fills the remainder of data with zeroes. virtual size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const = 0; + size_t start, size_t len, bool mayThrow = true) + const = 0; // Other Properties @@ -223,6 +227,7 @@ class PROFILE_DLL_API BlockFile /* not final, abstract */ { virtual void FixSummary(void *data); static size_t CommonReadData( + bool mayThrow, const wxFileName &fileName, bool &mSilentLog, const AliasBlockFile *pAliasFile, sampleCount origin, unsigned channel, samplePtr data, sampleFormat format, size_t start, size_t len, diff --git a/src/blockfile/LegacyBlockFile.cpp b/src/blockfile/LegacyBlockFile.cpp index f64ba2abf..960f25416 100644 --- a/src/blockfile/LegacyBlockFile.cpp +++ b/src/blockfile/LegacyBlockFile.cpp @@ -194,10 +194,10 @@ bool LegacyBlockFile::ReadSummary(ArrayOf &data) /// @param start The offset in this block file /// @param len The number of samples to read size_t LegacyBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { sf_count_t origin = (mSummaryInfo.totalSummaryBytes / SAMPLE_SIZE(mFormat)); - return CommonReadData( + return CommonReadData( mayThrow, mFileName, mSilentLog, nullptr, origin, 0, data, format, start, len, &mFormat, mLen ); diff --git a/src/blockfile/LegacyBlockFile.h b/src/blockfile/LegacyBlockFile.h index 549b216af..a2fe1c792 100644 --- a/src/blockfile/LegacyBlockFile.h +++ b/src/blockfile/LegacyBlockFile.h @@ -51,7 +51,7 @@ class LegacyBlockFile final : public BlockFile { bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Create a NEW block file identical to this one BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override; diff --git a/src/blockfile/ODDecodeBlockFile.cpp b/src/blockfile/ODDecodeBlockFile.cpp index c6dff23dd..141e57742 100644 --- a/src/blockfile/ODDecodeBlockFile.cpp +++ b/src/blockfile/ODDecodeBlockFile.cpp @@ -438,20 +438,22 @@ void *ODDecodeBlockFile::CalcSummary(samplePtr buffer, size_t len, /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t ODDecodeBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { - size_t ret; auto locker = LockForRead(); if(IsSummaryAvailable()) - ret = SimpleBlockFile::ReadData(data,format,start,len); + return SimpleBlockFile::ReadData(data, format, start, len, mayThrow); else { + if (mayThrow) + //throw NotYetAvailableException{ mFileName } + ; + //we should do an ODRequest to start processing the data here, and wait till it finishes. and just do a SimpleBlockFile //ReadData. ClearSamples(data, format, 0, len); - ret = len; + return 0; } - return ret; } /// Read the summary of this alias block from disk. Since the audio data diff --git a/src/blockfile/ODDecodeBlockFile.h b/src/blockfile/ODDecodeBlockFile.h index 0a98df679..042b4a6de 100644 --- a/src/blockfile/ODDecodeBlockFile.h +++ b/src/blockfile/ODDecodeBlockFile.h @@ -109,7 +109,7 @@ class ODDecodeBlockFile final : public SimpleBlockFile /// Reads the specified data from the aliased file using libsndfile size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Read the summary into a buffer bool ReadSummary(ArrayOf &data) override; diff --git a/src/blockfile/ODPCMAliasBlockFile.cpp b/src/blockfile/ODPCMAliasBlockFile.cpp index 4f14be7f6..886de43c6 100644 --- a/src/blockfile/ODPCMAliasBlockFile.cpp +++ b/src/blockfile/ODPCMAliasBlockFile.cpp @@ -414,7 +414,7 @@ void ODPCMAliasBlockFile::WriteSummary() // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data SampleBuffer sampleData(mLen, floatSample); - this->ReadData(sampleData.ptr(), floatSample, 0, mLen); + this->ReadData(sampleData.ptr(), floatSample, 0, mLen, true); ArrayOf cleanup; void *summaryData = CalcSummary(sampleData.ptr(), mLen, @@ -495,7 +495,7 @@ void *ODPCMAliasBlockFile::CalcSummary(samplePtr buffer, size_t len, /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { auto locker = LockForRead(); @@ -505,7 +505,7 @@ size_t ODPCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, return len; } - return CommonReadData( + return CommonReadData( mayThrow, mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, data, format, start, len); } diff --git a/src/blockfile/ODPCMAliasBlockFile.h b/src/blockfile/ODPCMAliasBlockFile.h index 421eadad3..04752955f 100644 --- a/src/blockfile/ODPCMAliasBlockFile.h +++ b/src/blockfile/ODPCMAliasBlockFile.h @@ -118,7 +118,7 @@ class ODPCMAliasBlockFile final : public PCMAliasBlockFile /// Reads the specified data from the aliased file using libsndfile size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Read the summary into a buffer bool ReadSummary(ArrayOf &data) override; diff --git a/src/blockfile/PCMAliasBlockFile.cpp b/src/blockfile/PCMAliasBlockFile.cpp index 8ce192ee5..35719577f 100644 --- a/src/blockfile/PCMAliasBlockFile.cpp +++ b/src/blockfile/PCMAliasBlockFile.cpp @@ -75,14 +75,14 @@ PCMAliasBlockFile::~PCMAliasBlockFile() /// @param start The offset within the block to begin reading /// @param len The number of samples to read size_t PCMAliasBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { if(!mAliasedFileName.IsOk()){ // intentionally silenced memset(data, 0, SAMPLE_SIZE(format) * len); return len; } - return CommonReadData( + return CommonReadData( mayThrow, mAliasedFileName, mSilentAliasLog, this, mAliasStart, mAliasChannel, data, format, start, len); } diff --git a/src/blockfile/PCMAliasBlockFile.h b/src/blockfile/PCMAliasBlockFile.h index 738d84091..369642919 100644 --- a/src/blockfile/PCMAliasBlockFile.h +++ b/src/blockfile/PCMAliasBlockFile.h @@ -38,7 +38,7 @@ class PCMAliasBlockFile /* not final */ : public AliasBlockFile /// Reads the specified data from the aliased file using libsndfile size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; void SaveXML(XMLWriter &xmlFile) override; BlockFilePtr Copy(wxFileNameWrapper &&fileName) override; diff --git a/src/blockfile/SilentBlockFile.cpp b/src/blockfile/SilentBlockFile.cpp index a2d33effb..3250a77c6 100644 --- a/src/blockfile/SilentBlockFile.cpp +++ b/src/blockfile/SilentBlockFile.cpp @@ -32,7 +32,7 @@ bool SilentBlockFile::ReadSummary(ArrayOf &data) } size_t SilentBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t WXUNUSED(start), size_t len) const + size_t WXUNUSED(start), size_t len, bool) const { ClearSamples(data, format, 0, len); diff --git a/src/blockfile/SilentBlockFile.h b/src/blockfile/SilentBlockFile.h index e1788bccc..5003faed1 100644 --- a/src/blockfile/SilentBlockFile.h +++ b/src/blockfile/SilentBlockFile.h @@ -36,7 +36,7 @@ class SilentBlockFile final : public BlockFile { bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Create a NEW block file identical to this one BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override; diff --git a/src/blockfile/SimpleBlockFile.cpp b/src/blockfile/SimpleBlockFile.cpp index c791a6551..9b3923a8b 100644 --- a/src/blockfile/SimpleBlockFile.cpp +++ b/src/blockfile/SimpleBlockFile.cpp @@ -315,7 +315,9 @@ void SimpleBlockFile::FillCache() // Read samples into cache mCache.sampleData.reinit(mLen * SAMPLE_SIZE(mCache.format)); - if (ReadData(mCache.sampleData.get(), mCache.format, 0, mLen) != mLen) + if (ReadData(mCache.sampleData.get(), mCache.format, 0, mLen, + // no exceptions! + false) != mLen) { // Could not read all samples mCache.sampleData.reset(); @@ -387,21 +389,30 @@ bool SimpleBlockFile::ReadSummary(ArrayOf &data) /// @param start The offset in this block file /// @param len The number of samples to read size_t SimpleBlockFile::ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const + size_t start, size_t len, bool mayThrow) const { if (mCache.active) { //wxLogDebug("SimpleBlockFile::ReadData(): Data are already in cache."); - len = std::min(len, std::max(start, mLen) - start); + auto framesRead = std::min(len, std::max(start, mLen) - start); CopySamples( (samplePtr)(mCache.sampleData.get() + start * SAMPLE_SIZE(mCache.format)), - mCache.format, data, format, len); - return len; + mCache.format, data, format, framesRead); + + if ( framesRead < len ) { + if (mayThrow) + // Not the best exception class? + //throw FileException{ FileException::Cause::Read, mFileName } + ; + ClearSamples(data, format, framesRead, len - framesRead); + } + + return framesRead; } else - return CommonReadData( + return CommonReadData( mayThrow, mFileName, mSilentLog, nullptr, 0, 0, data, format, start, len); } diff --git a/src/blockfile/SimpleBlockFile.h b/src/blockfile/SimpleBlockFile.h index a7fc761a3..14c010d2e 100644 --- a/src/blockfile/SimpleBlockFile.h +++ b/src/blockfile/SimpleBlockFile.h @@ -66,7 +66,7 @@ class PROFILE_DLL_API SimpleBlockFile /* not final */ : public BlockFile { bool ReadSummary(ArrayOf &data) override; /// Read the data section of the disk file size_t ReadData(samplePtr data, sampleFormat format, - size_t start, size_t len) const override; + size_t start, size_t len, bool mayThrow) const override; /// Create a NEW block file identical to this one BlockFilePtr Copy(wxFileNameWrapper &&newFileName) override;