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