/// Read the summary of this alias block from disk. Since the audio data /// is elsewhere, this consists of reading the entire summary file. /// Fill with zeroes and return false if data are unavailable for any reason. /// /// @param *data The buffer where the summary data will be stored. It must /// be at least mSummaryInfo.totalSummaryBytes long. bool ODPCMAliasBlockFile::ReadSummary(ArrayOf<char> &data) { data.reinit( mSummaryInfo.totalSummaryBytes ); ODLocker locker{ &mFileNameMutex }; wxFFile summaryFile(mFileName.GetFullPath(), wxT("rb")); if( !summaryFile.IsOpened() ) { // NEW model; we need to return valid data memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); // we silence the logging for this operation in this object // after first occurrence of error; it's already reported and // spewing at the user will complicate the user's ability to // deal mSilentLog = TRUE; return false; } else mSilentLog = FALSE; // worked properly, any future error is NEW auto read = summaryFile.Read(data.get(), mSummaryInfo.totalSummaryBytes); if (read != mSummaryInfo.totalSummaryBytes) { memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); return false; } FixSummary(data.get()); return true; }
/// Write the summary to disk, using the derived ReadData() to get the data void ODPCMAliasBlockFile::WriteSummary() { // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data // Call this first, so that in case of exceptions from ReadData, there is // no NEW output file SampleBuffer sampleData(mLen, floatSample); this->ReadData(sampleData.ptr(), floatSample, 0, mLen, true); ArrayOf< char > fileNameChar; FILE *summaryFile{}; { //the mFileName path may change, for example, when the project is saved. //(it moves from /tmp/ to wherever it is saved to. ODLocker locker { &mFileNameMutex }; //wxFFile is not thread-safe - if any error occurs in opening the file, // it posts a wxlog message which WILL crash // Audacity because it goes into the wx GUI. // For this reason I left the wxFFile method commented out. (mchinen) // wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); // ...and we use fopen instead. wxString sFullPath = mFileName.GetFullPath(); fileNameChar.reinit( strlen(sFullPath.mb_str(wxConvFile)) + 1 ); strcpy(fileNameChar.get(), sFullPath.mb_str(wxConvFile)); summaryFile = fopen(fileNameChar.get(), "wb"); } // JKC ANSWER-ME: Whay is IsOpened() commented out? if (!summaryFile){//.IsOpened() ){ // Never silence the Log w.r.t write errors; they always count //however, this is going to be called from a non-main thread, //and wxLog calls are not thread safe. wxPrintf("Unable to write summary data to file: %s", fileNameChar.get()); throw FileException{ FileException::Cause::Read, wxFileName{ fileNameChar.get() } }; } ArrayOf<char> cleanup; void *summaryData = CalcSummary(sampleData.ptr(), mLen, floatSample, cleanup); //summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); fwrite(summaryData, 1, mSummaryInfo.totalSummaryBytes, summaryFile); fclose(summaryFile); // wxPrintf("write successful. filename: %s\n", fileNameChar); mSummaryAvailableMutex.Lock(); mSummaryAvailable=true; mSummaryAvailableMutex.Unlock(); }
/// Read the summary of this alias block from disk. Since the audio data /// is elsewhere, this consists of reading the entire summary file. /// Fill with zeroes and return false if data are unavailable for any reason. /// /// @param *data The buffer where the summary data will be stored. It must /// be at least mSummaryInfo.totalSummaryBytes long. bool ODDecodeBlockFile::ReadSummary(ArrayOf<char> &data) { //I dont think we need to add a mutex here because only the main thread changes filenames and calls ReadSummary if(IsSummaryAvailable()) return SimpleBlockFile::ReadSummary(data); data.reinit( mSummaryInfo.totalSummaryBytes ); memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); return false; }
bool SilentBlockFile::ReadSummary(ArrayOf<char> &data) { data.reinit( mSummaryInfo.totalSummaryBytes ); memset(data.get(), 0, mSummaryInfo.totalSummaryBytes); return true; }