# HG changeset patch # User Chris Cannam # Date 1305108275 -3600 # Node ID bcca512445f34172236b68775e7983908fbeb7d9 # Parent f84f147572b91bb27b247ab2df937f60c6d8915e Provide option for WavFileWriter to write directly to target file, rather than always using a temporary; make use of it in WritableWaveFileModel so we can read from target file without having to close it first diff -r f84f147572b9 -r bcca512445f3 data/fileio/WavFileWriter.cpp --- a/data/fileio/WavFileWriter.cpp Wed May 11 11:04:02 2011 +0100 +++ b/data/fileio/WavFileWriter.cpp Wed May 11 11:04:35 2011 +0100 @@ -26,7 +26,8 @@ WavFileWriter::WavFileWriter(QString path, size_t sampleRate, - size_t channels) : + size_t channels, + FileWriteMode mode) : m_path(path), m_sampleRate(sampleRate), m_channels(channels), @@ -39,15 +40,25 @@ fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; try { - m_temp = new TempWriteFile(m_path); - m_file = sf_open(m_temp->getTemporaryFilename().toLocal8Bit(), - SFM_WRITE, &fileInfo); - if (!m_file) { - std::cerr << "WavFileWriter: Failed to open file (" - << sf_strerror(m_file) << ")" << std::endl; - m_error = QString("Failed to open audio file '%1' for writing") - .arg(m_temp->getTemporaryFilename()); - } + if (mode == WriteToTemporary) { + m_temp = new TempWriteFile(m_path); + m_file = sf_open(m_temp->getTemporaryFilename().toLocal8Bit(), + SFM_WRITE, &fileInfo); + if (!m_file) { + std::cerr << "WavFileWriter: Failed to open file (" + << sf_strerror(m_file) << ")" << std::endl; + m_error = QString("Failed to open audio file '%1' for writing") + .arg(m_temp->getTemporaryFilename()); + } + } else { + m_file = sf_open(m_path.toLocal8Bit(), SFM_WRITE, &fileInfo); + if (!m_file) { + std::cerr << "WavFileWriter: Failed to open file (" + << sf_strerror(m_file) << ")" << std::endl; + m_error = QString("Failed to open audio file '%1' for writing") + .arg(m_path); + } + } } catch (FileOperationFailed &f) { m_error = f.what(); m_temp = 0; @@ -72,27 +83,32 @@ return m_error; } +QString +WavFileWriter::getWriteFilename() const +{ + if (m_temp) { + return m_temp->getTemporaryFilename(); + } else { + return m_path; + } +} + bool WavFileWriter::writeModel(DenseTimeValueModel *source, MultiSelection *selection) { - if (!m_temp) { - m_error = QString("Failed to write model to audio file: No file open"); - return false; - } - if (source->getChannelCount() != m_channels) { std::cerr << "WavFileWriter::writeModel: Wrong number of channels (" << source->getChannelCount() << " != " << m_channels << ")" << std::endl; m_error = QString("Failed to write model to audio file '%1'") - .arg(m_temp->getTemporaryFilename()); + .arg(getWriteFilename()); return false; } if (!m_file) { m_error = QString("Failed to write model to audio file '%1': File not open") - .arg(m_temp->getTemporaryFilename()); + .arg(getWriteFilename()); return false; } @@ -145,14 +161,9 @@ bool WavFileWriter::writeSamples(float **samples, size_t count) { - if (!m_temp) { - m_error = QString("Failed to write model to audio file: No file open"); - return false; - } - if (!m_file) { m_error = QString("Failed to write model to audio file '%1': File not open") - .arg(m_temp->getTemporaryFilename()); + .arg(getWriteFilename()); return false; } @@ -182,9 +193,11 @@ sf_close(m_file); m_file = 0; } - m_temp->moveToTarget(); - delete m_temp; - m_temp = 0; + if (m_temp) { + m_temp->moveToTarget(); + delete m_temp; + m_temp = 0; + } return true; } diff -r f84f147572b9 -r bcca512445f3 data/fileio/WavFileWriter.h --- a/data/fileio/WavFileWriter.h Wed May 11 11:04:02 2011 +0100 +++ b/data/fileio/WavFileWriter.h Wed May 11 11:04:35 2011 +0100 @@ -27,7 +27,25 @@ class WavFileWriter { public: - WavFileWriter(QString path, size_t sampleRate, size_t channels); + /** + * Specify the method used to open the destination file. + * + * If WriteToTemporary, the destination will be opened as a + * temporary file which is moved to the target location when the + * WavFileWriter is closed or deleted (to avoid clobbering an + * existing file with a partially written replacement). + * + * If WriteToTarget, the target file will be opened directly + * (necessary when e.g. doing a series of incremental writes to a + * file while keeping it open for reading). + */ + enum FileWriteMode { + WriteToTemporary, + WriteToTarget + }; + + WavFileWriter(QString path, size_t sampleRate, size_t channels, + FileWriteMode mode); virtual ~WavFileWriter(); bool isOK() const; @@ -50,6 +68,8 @@ TempWriteFile *m_temp; SNDFILE *m_file; QString m_error; + + QString getWriteFilename() const; }; diff -r f84f147572b9 -r bcca512445f3 data/model/WritableWaveFileModel.cpp --- a/data/model/WritableWaveFileModel.cpp Wed May 11 11:04:02 2011 +0100 +++ b/data/model/WritableWaveFileModel.cpp Wed May 11 11:04:35 2011 +0100 @@ -52,7 +52,10 @@ } } - m_writer = new WavFileWriter(path, sampleRate, channels); + // Write directly to the target file, so that we can do + // incremental writes and concurrent reads + m_writer = new WavFileWriter(path, sampleRate, channels, + WavFileWriter::WriteToTarget); if (!m_writer->isOK()) { std::cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError().toStdString() << std::endl; delete m_writer;