/// 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(); }
/// Write the summary to disk, using the derived ReadData() to get the data void ODPCMAliasBlockFile::WriteSummary() { //the mFileName path may change, for example, when the project is saved. //(it moves from /tmp/ to wherever it is saved to. mFileNameMutex.Lock(); //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(); char* fileNameChar = new char[strlen(sFullPath.mb_str(wxConvFile)) + 1]; strcpy(fileNameChar, sFullPath.mb_str(wxConvFile)); FILE* summaryFile = fopen(fileNameChar, "wb"); mFileNameMutex.Unlock(); 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. printf("Unable to write summary data to file: %s", fileNameChar); delete [] fileNameChar; return; } delete [] fileNameChar; // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = CalcSummary(sampleData, mLen, floatSample); //summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); fwrite(summaryData, 1, mSummaryInfo.totalSummaryBytes, summaryFile); fclose(summaryFile); DeleteSamples(sampleData); delete [] (char *) summaryData; // printf("write successful. filename: %s\n", fileNameChar); mSummaryAvailableMutex.Lock(); mSummaryAvailable=true; mSummaryAvailableMutex.Unlock(); }
/// Write the summary to disk, using the derived ReadData() to get the data void ODPCMAliasBlockFile::WriteSummary() { //Below from BlockFile.cpp's method. We need to delete the data returned by //CalcSummary, because it uses local info. In the future we might do something //smarter and thread-dependant like a static thread context. wxFFile summaryFile(mFileName.GetFullPath(), wxT("wb")); if( !summaryFile.IsOpened() ){ // Never silence the Log w.r.t write errors; they always count // as new errors //however, this is going to be called from a non-main thread, //and wxLog calls are not thread safe. printf("Unable to write summary data to file %s", mFileName.GetFullPath().c_str()); // If we can't write, there's nothing to do. return; } // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = CalcSummary(sampleData, mLen, floatSample); summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); DeleteSamples(sampleData); delete [] summaryData; //above from BlockFiles.cpps method mSummaryAvailableMutex.Lock(); mSummaryAvailable=true; mSummaryAvailableMutex.Unlock(); }
/// Write the summary to disk, using the derived ReadData() to get the data /// Here, the decoder ODTask associated with this file must fetch the samples with /// the ODDecodeTask::Decode() method. void ODDecodeBlockFile::WriteODDecodeBlockFile() { // To build the summary data, call ReadData (implemented by the // derived classes) to get the sample data samplePtr sampleData = NewSamples(mLen, floatSample); //use the decoder here. mDecoderMutex.Lock(); if(!mDecoder) { mDecoderMutex.Unlock(); return; } mDecoder->Decode(sampleData, mFormat, mDecodeFileStart, mLen); mDecoderMutex.Unlock(); this->ReadData(sampleData, floatSample, 0, mLen); void *summaryData = CalcSummary(sampleData, mLen, floatSample); //OD TODO: use new write() // summaryFile.Write(summaryData, mSummaryInfo.totalSummaryBytes); WriteSimpleBlockFile( sampleData, mLen, mFormat, summaryData); DeleteSamples(sampleData); delete [] (char *) summaryData; mDataAvailableMutex.Lock(); mDataAvailable=true; mDataAvailableMutex.Unlock(); }
bool SimpleBlockFile::WriteSimpleBlockFile( samplePtr sampleData, sampleCount sampleLen, sampleFormat format, void* summaryData) { wxFFile file(mFileName.GetFullPath(), wxT("wb")); if( !file.IsOpened() ){ // Can't do anything else. return false; } auHeader header; // AU files can be either big or little endian. Which it is is // determined implicitly by the byte-order of the magic 0x2e736e64 // (.snd). We want it to be native-endian, so we write the magic // to memory and then let it write that to a file in native // endianness header.magic = 0x2e736e64; // We store the summary data at the end of the header, so the data // offset is the length of the summary data plus the length of the header header.dataOffset = sizeof(auHeader) + mSummaryInfo.totalSummaryBytes; // dataSize is optional, and we opt out header.dataSize = 0xffffffff; switch(format) { case int16Sample: header.encoding = AU_SAMPLE_FORMAT_16; break; case int24Sample: header.encoding = AU_SAMPLE_FORMAT_24; break; case floatSample: header.encoding = AU_SAMPLE_FORMAT_FLOAT; break; } // TODO: don't fabricate header.sampleRate = 44100; // BlockFiles are always mono header.channels = 1; // Write the file ArrayOf<char> cleanup; if (!summaryData) summaryData = /*BlockFile::*/CalcSummary(sampleData, sampleLen, format, cleanup); //mchinen:allowing virtual override of calc summary for ODDecodeBlockFile. // PRL: cleanup fixes a possible memory leak! size_t nBytesToWrite = sizeof(header); size_t nBytesWritten = file.Write(&header, nBytesToWrite); if (nBytesWritten != nBytesToWrite) { wxLogDebug(wxT("Wrote %lld bytes, expected %lld."), (long long) nBytesWritten, (long long) nBytesToWrite); return false; } nBytesToWrite = mSummaryInfo.totalSummaryBytes; nBytesWritten = file.Write(summaryData, nBytesToWrite); if (nBytesWritten != nBytesToWrite) { wxLogDebug(wxT("Wrote %lld bytes, expected %lld."), (long long) nBytesWritten, (long long) nBytesToWrite); return false; } if( format == int24Sample ) { // we can't write the buffer directly to disk, because 24-bit samples // on disk need to be packed, not padded to 32 bits like they are in // memory int *int24sampleData = (int*)sampleData; for( int i = 0; i < sampleLen; i++ ) { nBytesToWrite = 3; nBytesWritten = #if wxBYTE_ORDER == wxBIG_ENDIAN file.Write((char*)&int24sampleData[i] + 1, nBytesToWrite); #else file.Write((char*)&int24sampleData[i], nBytesToWrite); #endif if (nBytesWritten != nBytesToWrite) { wxLogDebug(wxT("Wrote %lld bytes, expected %lld."), (long long) nBytesWritten, (long long) nBytesToWrite); return false; } } } else { // for all other sample formats we can write straight from the buffer // to disk nBytesToWrite = sampleLen * SAMPLE_SIZE(format); nBytesWritten = file.Write(sampleData, nBytesToWrite); if (nBytesWritten != nBytesToWrite) { wxLogDebug(wxT("Wrote %lld bytes, expected %lld."), (long long) nBytesWritten, (long long) nBytesToWrite); return false; } } return true; }
bool SimpleBlockFile::WriteSimpleBlockFile( samplePtr sampleData, sampleCount sampleLen, sampleFormat format, void* summaryData) { // Now checked in the DirManager //wxASSERT( !wxFileExists(FILENAME(mFileName.GetFullPath())) ); DEBUG_OUTPUT("Writing simple block file"); // Open and write the file wxFFile file(mFileName.GetFullPath(), wxT("wb")); if( !file.IsOpened() ){ // Can't do anything else. return false; } auHeader header; // AU files can be either big or little endian. Which it is is // determined implicitly by the byte-order of the magic 0x2e736e64 // (.snd). We want it to be native-endian, so we write the magic // to memory and then let it write that to a file in native // endianness header.magic = 0x2e736e64; // We store the summary data at the end of the header, so the data // offset is the length of the summary data plus the length of the header header.dataOffset = sizeof(auHeader) + mSummaryInfo.totalSummaryBytes; // dataSize is optional, and we opt out header.dataSize = 0xffffffff; switch(format) { case int16Sample: header.encoding = AU_SAMPLE_FORMAT_16; break; case int24Sample: header.encoding = AU_SAMPLE_FORMAT_24; break; case floatSample: header.encoding = AU_SAMPLE_FORMAT_FLOAT; break; } // TODO: don't fabricate header.sampleRate = 44100; // BlockFiles are always mono header.channels = 1; // Write the file if (!summaryData) summaryData = /*BlockFile::*/CalcSummary(sampleData, sampleLen, format); //mchinen:allowing virtual override of calc summary for ODDecodeBlockFile. file.Write(&header, sizeof(header)); file.Write(summaryData, mSummaryInfo.totalSummaryBytes); if( format == int24Sample ) { // we can't write the buffer directly to disk, because 24-bit samples // on disk need to be packed, not padded to 32 bits like they are in // memory int *int24sampleData = (int*)sampleData; for( int i = 0; i < sampleLen; i++ ) #if wxBYTE_ORDER == wxBIG_ENDIAN file.Write((char*)&int24sampleData[i] + 1, 3); #else file.Write((char*)&int24sampleData[i], 3); #endif } else { // for all other sample formats we can write straight from the buffer // to disk file.Write(sampleData, sampleLen * SAMPLE_SIZE(format)); } DEBUG_OUTPUT("Wrote simple block file"); return true; }