annotate data/fileio/WavFileWriter.cpp @ 875:3e6ed8a8577b tonioni

Use a sparse time-value model only for outputs with fixed bin count of 1, not for those with unknown bin count. (Precursor to using more than one model for outputs with unknown bin count)
author Chris Cannam
date Tue, 28 Jan 2014 18:52:22 +0000
parents e802e550a1f2
children 59e7fe1b1003
rev   line source
Chris@148 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@148 2
Chris@148 3 /*
Chris@148 4 Sonic Visualiser
Chris@148 5 An audio file viewer and annotation editor.
Chris@148 6 Centre for Digital Music, Queen Mary, University of London.
Chris@202 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@148 8
Chris@148 9 This program is free software; you can redistribute it and/or
Chris@148 10 modify it under the terms of the GNU General Public License as
Chris@148 11 published by the Free Software Foundation; either version 2 of the
Chris@148 12 License, or (at your option) any later version. See the file
Chris@148 13 COPYING included with this distribution for more information.
Chris@148 14 */
Chris@148 15
Chris@148 16 #include "WavFileWriter.h"
Chris@148 17
Chris@148 18 #include "model/DenseTimeValueModel.h"
Chris@148 19 #include "base/Selection.h"
Chris@674 20 #include "base/TempWriteFile.h"
Chris@674 21 #include "base/Exceptions.h"
Chris@148 22
Chris@148 23 #include <QFileInfo>
Chris@148 24
Chris@148 25 #include <iostream>
Chris@148 26
Chris@148 27 WavFileWriter::WavFileWriter(QString path,
Chris@148 28 size_t sampleRate,
Chris@684 29 size_t channels,
Chris@684 30 FileWriteMode mode) :
Chris@148 31 m_path(path),
Chris@148 32 m_sampleRate(sampleRate),
Chris@174 33 m_channels(channels),
Chris@674 34 m_temp(0),
Chris@174 35 m_file(0)
Chris@148 36 {
Chris@174 37 SF_INFO fileInfo;
Chris@174 38 fileInfo.samplerate = m_sampleRate;
Chris@174 39 fileInfo.channels = m_channels;
Chris@174 40 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
Chris@674 41
Chris@674 42 try {
Chris@684 43 if (mode == WriteToTemporary) {
Chris@684 44 m_temp = new TempWriteFile(m_path);
Chris@684 45 m_file = sf_open(m_temp->getTemporaryFilename().toLocal8Bit(),
Chris@684 46 SFM_WRITE, &fileInfo);
Chris@684 47 if (!m_file) {
Chris@843 48 cerr << "WavFileWriter: Failed to open file ("
Chris@843 49 << sf_strerror(m_file) << ")" << endl;
Chris@684 50 m_error = QString("Failed to open audio file '%1' for writing")
Chris@684 51 .arg(m_temp->getTemporaryFilename());
Chris@684 52 }
Chris@684 53 } else {
Chris@684 54 m_file = sf_open(m_path.toLocal8Bit(), SFM_WRITE, &fileInfo);
Chris@684 55 if (!m_file) {
Chris@843 56 cerr << "WavFileWriter: Failed to open file ("
Chris@843 57 << sf_strerror(m_file) << ")" << endl;
Chris@684 58 m_error = QString("Failed to open audio file '%1' for writing")
Chris@684 59 .arg(m_path);
Chris@684 60 }
Chris@684 61 }
Chris@674 62 } catch (FileOperationFailed &f) {
Chris@674 63 m_error = f.what();
Chris@674 64 m_temp = 0;
Chris@674 65 m_file = 0;
Chris@174 66 }
Chris@148 67 }
Chris@148 68
Chris@148 69 WavFileWriter::~WavFileWriter()
Chris@148 70 {
Chris@174 71 if (m_file) close();
Chris@148 72 }
Chris@148 73
Chris@148 74 bool
Chris@148 75 WavFileWriter::isOK() const
Chris@148 76 {
Chris@148 77 return (m_error.isEmpty());
Chris@148 78 }
Chris@148 79
Chris@148 80 QString
Chris@148 81 WavFileWriter::getError() const
Chris@148 82 {
Chris@148 83 return m_error;
Chris@148 84 }
Chris@148 85
Chris@684 86 QString
Chris@684 87 WavFileWriter::getWriteFilename() const
Chris@684 88 {
Chris@684 89 if (m_temp) {
Chris@684 90 return m_temp->getTemporaryFilename();
Chris@684 91 } else {
Chris@684 92 return m_path;
Chris@684 93 }
Chris@684 94 }
Chris@684 95
Chris@174 96 bool
Chris@174 97 WavFileWriter::writeModel(DenseTimeValueModel *source,
Chris@174 98 MultiSelection *selection)
Chris@148 99 {
Chris@174 100 if (source->getChannelCount() != m_channels) {
Chris@690 101 SVDEBUG << "WavFileWriter::writeModel: Wrong number of channels ("
Chris@174 102 << source->getChannelCount() << " != " << m_channels << ")"
Chris@687 103 << endl;
Chris@174 104 m_error = QString("Failed to write model to audio file '%1'")
Chris@684 105 .arg(getWriteFilename());
Chris@174 106 return false;
Chris@148 107 }
Chris@148 108
Chris@174 109 if (!m_file) {
Chris@174 110 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@684 111 .arg(getWriteFilename());
Chris@174 112 return false;
Chris@174 113 }
Chris@148 114
Chris@174 115 bool ownSelection = false;
Chris@174 116 if (!selection) {
Chris@148 117 selection = new MultiSelection;
Chris@174 118 selection->setSelection(Selection(source->getStartFrame(),
Chris@174 119 source->getEndFrame()));
Chris@174 120 ownSelection = true;
Chris@148 121 }
Chris@148 122
Chris@148 123 size_t bs = 2048;
Chris@148 124 float *ub = new float[bs]; // uninterleaved buffer (one channel)
Chris@174 125 float *ib = new float[bs * m_channels]; // interleaved buffer
Chris@148 126
Chris@148 127 for (MultiSelection::SelectionList::iterator i =
Chris@148 128 selection->getSelections().begin();
Chris@148 129 i != selection->getSelections().end(); ++i) {
Chris@148 130
Chris@148 131 size_t f0(i->getStartFrame()), f1(i->getEndFrame());
Chris@148 132
Chris@148 133 for (size_t f = f0; f < f1; f += bs) {
Chris@148 134
Chris@148 135 size_t n = std::min(bs, f1 - f);
Chris@148 136
Chris@174 137 for (int c = 0; c < int(m_channels); ++c) {
Chris@300 138 source->getData(c, f, n, ub);
Chris@148 139 for (size_t i = 0; i < n; ++i) {
Chris@174 140 ib[i * m_channels + c] = ub[i];
Chris@148 141 }
Chris@148 142 }
Chris@148 143
Chris@174 144 sf_count_t written = sf_writef_float(m_file, ib, n);
Chris@148 145
Chris@148 146 if (written < n) {
Chris@148 147 m_error = QString("Only wrote %1 of %2 frames at file frame %3")
Chris@148 148 .arg(written).arg(n).arg(f);
Chris@148 149 break;
Chris@148 150 }
Chris@148 151 }
Chris@148 152 }
Chris@148 153
Chris@148 154 delete[] ub;
Chris@148 155 delete[] ib;
Chris@174 156 if (ownSelection) delete selection;
Chris@174 157
Chris@174 158 return isOK();
Chris@174 159 }
Chris@174 160
Chris@174 161 bool
Chris@174 162 WavFileWriter::writeSamples(float **samples, size_t count)
Chris@174 163 {
Chris@174 164 if (!m_file) {
Chris@174 165 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@684 166 .arg(getWriteFilename());
Chris@174 167 return false;
Chris@174 168 }
Chris@174 169
Chris@174 170 float *b = new float[count * m_channels];
Chris@174 171 for (size_t i = 0; i < count; ++i) {
Chris@174 172 for (size_t c = 0; c < m_channels; ++c) {
Chris@174 173 b[i * m_channels + c] = samples[c][i];
Chris@174 174 }
Chris@174 175 }
Chris@174 176
Chris@174 177 sf_count_t written = sf_writef_float(m_file, b, count);
Chris@174 178
Chris@174 179 delete[] b;
Chris@174 180
Chris@174 181 if (written < count) {
Chris@174 182 m_error = QString("Only wrote %1 of %2 frames")
Chris@174 183 .arg(written).arg(count);
Chris@174 184 }
Chris@174 185
Chris@174 186 return isOK();
Chris@174 187 }
Chris@174 188
Chris@174 189 bool
Chris@174 190 WavFileWriter::close()
Chris@174 191 {
Chris@174 192 if (m_file) {
Chris@174 193 sf_close(m_file);
Chris@174 194 m_file = 0;
Chris@174 195 }
Chris@684 196 if (m_temp) {
Chris@684 197 m_temp->moveToTarget();
Chris@684 198 delete m_temp;
Chris@684 199 m_temp = 0;
Chris@684 200 }
Chris@174 201 return true;
Chris@148 202 }
Chris@148 203