Chris@175: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@175: Chris@175: /* Chris@175: Sonic Visualiser Chris@175: An audio file viewer and annotation editor. Chris@175: Centre for Digital Music, Queen Mary, University of London. Chris@175: This file copyright 2006 Chris Cannam. Chris@175: Chris@175: This program is free software; you can redistribute it and/or Chris@175: modify it under the terms of the GNU General Public License as Chris@175: published by the Free Software Foundation; either version 2 of the Chris@175: License, or (at your option) any later version. See the file Chris@175: COPYING included with this distribution for more information. Chris@175: */ Chris@175: Chris@175: #include "WritableWaveFileModel.h" Chris@175: Chris@175: #include "base/TempDirectory.h" Chris@175: #include "base/Exceptions.h" Chris@175: Chris@175: #include "fileio/WavFileWriter.h" Chris@175: #include "fileio/WavFileReader.h" Chris@175: Chris@175: #include Chris@175: Chris@175: #include Chris@175: #include Chris@175: Chris@187: Chris@175: WritableWaveFileModel::WritableWaveFileModel(size_t sampleRate, Chris@175: size_t channels, Chris@175: QString path) : Chris@175: m_model(0), Chris@175: m_writer(0), Chris@175: m_reader(0), Chris@175: m_sampleRate(sampleRate), Chris@175: m_channels(channels), Chris@188: m_frameCount(0), Chris@188: m_completion(0) Chris@175: { Chris@175: if (path.isEmpty()) { Chris@175: try { Chris@175: QDir dir(TempDirectory::getInstance()->getPath()); Chris@175: path = dir.filePath(QString("written_%1.wav") Chris@175: .arg((intptr_t)this)); Chris@175: } catch (DirectoryCreationFailed f) { Chris@175: std::cerr << "WritableWaveFileModel: Failed to create temporary directory" << std::endl; Chris@175: return; Chris@175: } Chris@175: } Chris@175: Chris@175: m_writer = new WavFileWriter(path, sampleRate, channels); Chris@175: if (!m_writer->isOK()) { Chris@175: std::cerr << "WritableWaveFileModel: Error in creating WAV file writer: " << m_writer->getError().toStdString() << std::endl; Chris@175: delete m_writer; Chris@175: m_writer = 0; Chris@175: return; Chris@175: } Chris@187: Chris@187: m_reader = new WavFileReader(m_writer->getPath(), true); Chris@187: if (!m_reader->getError().isEmpty()) { Chris@187: std::cerr << "WritableWaveFileModel: Error in creating wave file reader" << std::endl; Chris@187: delete m_reader; Chris@187: m_reader = 0; Chris@187: return; Chris@187: } Chris@187: Chris@187: m_model = new WaveFileModel(m_writer->getPath(), m_reader); Chris@187: if (!m_model->isOK()) { Chris@187: std::cerr << "WritableWaveFileModel: Error in creating wave file model" << std::endl; Chris@187: delete m_model; Chris@187: m_model = 0; Chris@187: delete m_reader; Chris@187: m_reader = 0; Chris@187: return; Chris@187: } Chris@187: Chris@187: connect(m_model, SLOT(modelChanged()), this, SIGNAL(modelChanged())); Chris@187: connect(m_model, SLOT(modelChanged(size_t, size_t)), Chris@187: this, SIGNAL(modelChanged(size_t, size_t))); Chris@175: } Chris@175: Chris@175: WritableWaveFileModel::~WritableWaveFileModel() Chris@175: { Chris@175: delete m_model; Chris@175: delete m_writer; Chris@175: delete m_reader; Chris@175: } Chris@175: Chris@175: bool Chris@175: WritableWaveFileModel::addSamples(float **samples, size_t count) Chris@175: { Chris@175: if (!m_writer) return false; Chris@175: Chris@175: if (!m_writer->writeSamples(samples, count)) { Chris@175: std::cerr << "ERROR: WritableWaveFileModel::addSamples: writer failed: " << m_writer->getError().toStdString() << std::endl; Chris@175: return false; Chris@175: } Chris@175: Chris@175: m_frameCount += count; Chris@175: Chris@187: static int updateCounter = 0; Chris@175: Chris@187: if (m_reader && m_reader->getChannelCount() == 0) { Chris@187: m_reader->updateFrameCount(); Chris@187: } else if (++updateCounter == 100) { Chris@175: if (m_reader) m_reader->updateFrameCount(); Chris@175: updateCounter = 0; Chris@175: } Chris@175: Chris@175: return true; Chris@175: } Chris@175: Chris@175: bool Chris@175: WritableWaveFileModel::isOK() const Chris@175: { Chris@187: bool ok = (m_writer && m_writer->isOK()); Chris@188: // std::cerr << "WritableWaveFileModel::isOK(): ok = " << ok << std::endl; Chris@175: return ok; Chris@175: } Chris@175: Chris@175: bool Chris@175: WritableWaveFileModel::isReady(int *completion) const Chris@175: { Chris@188: if (completion) *completion = m_completion; Chris@188: return (m_completion == 100); Chris@188: } Chris@188: Chris@188: void Chris@188: WritableWaveFileModel::setCompletion(int completion) Chris@188: { Chris@188: m_completion = completion; Chris@188: if (completion == 100) { Chris@188: if (m_reader) m_reader->updateDone(); Chris@188: } Chris@175: } Chris@175: Chris@175: size_t Chris@175: WritableWaveFileModel::getFrameCount() const Chris@175: { Chris@188: // std::cerr << "WritableWaveFileModel::getFrameCount: count = " << m_frameCount << std::endl; Chris@175: return m_frameCount; Chris@175: } Chris@175: Chris@175: Model * Chris@175: WritableWaveFileModel::clone() const Chris@175: { Chris@175: assert(0); //!!! Chris@188: return 0; Chris@175: } Chris@175: Chris@175: size_t Chris@175: WritableWaveFileModel::getValues(int channel, size_t start, size_t end, Chris@175: float *buffer) const Chris@175: { Chris@187: if (!m_model || m_model->getChannelCount() == 0) return 0; Chris@175: return m_model->getValues(channel, start, end, buffer); Chris@175: } Chris@175: Chris@175: size_t Chris@175: WritableWaveFileModel::getValues(int channel, size_t start, size_t end, Chris@175: double *buffer) const Chris@175: { Chris@187: if (!m_model || m_model->getChannelCount() == 0) return 0; Chris@175: // std::cerr << "WritableWaveFileModel::getValues(" << channel << ", " Chris@175: // << start << ", " << end << "): calling model" << std::endl; Chris@175: return m_model->getValues(channel, start, end, buffer); Chris@175: } Chris@175: Chris@175: WritableWaveFileModel::RangeBlock Chris@175: WritableWaveFileModel::getRanges(size_t channel, size_t start, size_t end, Chris@175: size_t &blockSize) const Chris@175: { Chris@187: if (!m_model || m_model->getChannelCount() == 0) return RangeBlock(); Chris@175: return m_model->getRanges(channel, start, end, blockSize); Chris@175: } Chris@175: Chris@175: WritableWaveFileModel::Range Chris@175: WritableWaveFileModel::getRange(size_t channel, size_t start, size_t end) const Chris@175: { Chris@187: if (!m_model || m_model->getChannelCount() == 0) return Range(); Chris@175: return m_model->getRange(channel, start, end); Chris@175: } Chris@175: Chris@175: void Chris@175: WritableWaveFileModel::toXml(QTextStream &out, Chris@175: QString indent, Chris@175: QString extraAttributes) const Chris@175: { Chris@188: // We don't actually write the data to XML. We just write a brief Chris@188: // description of the model. Any code that uses this class is Chris@188: // going to need to be aware that it will have to make separate Chris@188: // arrangements for the audio file itself. Chris@187: Chris@188: Model::toXml Chris@188: (out, indent, Chris@188: QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3") Chris@188: .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes)); Chris@175: } Chris@175: Chris@175: QString Chris@175: WritableWaveFileModel::toXmlString(QString indent, Chris@175: QString extraAttributes) const Chris@175: { Chris@188: // As above. Chris@188: Chris@188: return Model::toXmlString Chris@188: (indent, Chris@188: QString("type=\"writablewavefile\" file=\"%1\" channels=\"%2\" %3") Chris@188: .arg(m_writer->getPath()).arg(m_model->getChannelCount()).arg(extraAttributes)); Chris@175: } Chris@175: