annotate data/fileio/WavFileWriter.cpp @ 1078:ce82bcdc95d0

Fail upfront if the file is going to be too large. We expect the caller to split up large data sets into several MatrixFiles
author Chris Cannam
date Wed, 10 Jun 2015 13:10:26 +0100
parents 0559f25b99f2
children 4d9816ba0ebe
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@1055 26 #include <cmath>
Chris@148 27
Chris@148 28 WavFileWriter::WavFileWriter(QString path,
Chris@1040 29 sv_samplerate_t sampleRate,
Chris@929 30 int channels,
Chris@684 31 FileWriteMode mode) :
Chris@148 32 m_path(path),
Chris@148 33 m_sampleRate(sampleRate),
Chris@174 34 m_channels(channels),
Chris@674 35 m_temp(0),
Chris@174 36 m_file(0)
Chris@148 37 {
Chris@174 38 SF_INFO fileInfo;
Chris@1040 39
Chris@1040 40 int fileRate = int(round(m_sampleRate));
Chris@1040 41 if (m_sampleRate != sv_samplerate_t(fileRate)) {
Chris@1040 42 cerr << "WavFileWriter: WARNING: Non-integer sample rate "
Chris@1040 43 << m_sampleRate << " presented, rounding to " << fileRate
Chris@1040 44 << endl;
Chris@1040 45 }
Chris@1040 46 fileInfo.samplerate = fileRate;
Chris@174 47 fileInfo.channels = m_channels;
Chris@174 48 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
Chris@674 49
Chris@674 50 try {
Chris@684 51 if (mode == WriteToTemporary) {
Chris@684 52 m_temp = new TempWriteFile(m_path);
Chris@684 53 m_file = sf_open(m_temp->getTemporaryFilename().toLocal8Bit(),
Chris@684 54 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_temp->getTemporaryFilename());
Chris@684 60 }
Chris@684 61 } else {
Chris@684 62 m_file = sf_open(m_path.toLocal8Bit(), SFM_WRITE, &fileInfo);
Chris@684 63 if (!m_file) {
Chris@843 64 cerr << "WavFileWriter: Failed to open file ("
Chris@843 65 << sf_strerror(m_file) << ")" << endl;
Chris@684 66 m_error = QString("Failed to open audio file '%1' for writing")
Chris@684 67 .arg(m_path);
Chris@684 68 }
Chris@684 69 }
Chris@674 70 } catch (FileOperationFailed &f) {
Chris@674 71 m_error = f.what();
Chris@674 72 m_temp = 0;
Chris@674 73 m_file = 0;
Chris@174 74 }
Chris@148 75 }
Chris@148 76
Chris@148 77 WavFileWriter::~WavFileWriter()
Chris@148 78 {
Chris@174 79 if (m_file) close();
Chris@148 80 }
Chris@148 81
Chris@148 82 bool
Chris@148 83 WavFileWriter::isOK() const
Chris@148 84 {
Chris@148 85 return (m_error.isEmpty());
Chris@148 86 }
Chris@148 87
Chris@148 88 QString
Chris@148 89 WavFileWriter::getError() const
Chris@148 90 {
Chris@148 91 return m_error;
Chris@148 92 }
Chris@148 93
Chris@684 94 QString
Chris@684 95 WavFileWriter::getWriteFilename() const
Chris@684 96 {
Chris@684 97 if (m_temp) {
Chris@684 98 return m_temp->getTemporaryFilename();
Chris@684 99 } else {
Chris@684 100 return m_path;
Chris@684 101 }
Chris@684 102 }
Chris@684 103
Chris@174 104 bool
Chris@174 105 WavFileWriter::writeModel(DenseTimeValueModel *source,
Chris@174 106 MultiSelection *selection)
Chris@148 107 {
Chris@174 108 if (source->getChannelCount() != m_channels) {
Chris@690 109 SVDEBUG << "WavFileWriter::writeModel: Wrong number of channels ("
Chris@174 110 << source->getChannelCount() << " != " << m_channels << ")"
Chris@687 111 << endl;
Chris@174 112 m_error = QString("Failed to write model to audio file '%1'")
Chris@684 113 .arg(getWriteFilename());
Chris@174 114 return false;
Chris@148 115 }
Chris@148 116
Chris@174 117 if (!m_file) {
Chris@174 118 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@684 119 .arg(getWriteFilename());
Chris@174 120 return false;
Chris@174 121 }
Chris@148 122
Chris@174 123 bool ownSelection = false;
Chris@174 124 if (!selection) {
Chris@148 125 selection = new MultiSelection;
Chris@174 126 selection->setSelection(Selection(source->getStartFrame(),
Chris@174 127 source->getEndFrame()));
Chris@174 128 ownSelection = true;
Chris@148 129 }
Chris@148 130
Chris@1038 131 sv_frame_t bs = 2048;
Chris@148 132 float *ub = new float[bs]; // uninterleaved buffer (one channel)
Chris@174 133 float *ib = new float[bs * m_channels]; // interleaved buffer
Chris@148 134
Chris@148 135 for (MultiSelection::SelectionList::iterator i =
Chris@148 136 selection->getSelections().begin();
Chris@148 137 i != selection->getSelections().end(); ++i) {
Chris@148 138
Chris@1038 139 sv_frame_t f0(i->getStartFrame()), f1(i->getEndFrame());
Chris@148 140
Chris@1038 141 for (sv_frame_t f = f0; f < f1; f += bs) {
Chris@148 142
Chris@1038 143 sv_frame_t n = std::min(bs, f1 - f);
Chris@148 144
Chris@174 145 for (int c = 0; c < int(m_channels); ++c) {
Chris@300 146 source->getData(c, f, n, ub);
Chris@929 147 for (int i = 0; i < n; ++i) {
Chris@174 148 ib[i * m_channels + c] = ub[i];
Chris@148 149 }
Chris@148 150 }
Chris@148 151
Chris@174 152 sf_count_t written = sf_writef_float(m_file, ib, n);
Chris@148 153
Chris@148 154 if (written < n) {
Chris@148 155 m_error = QString("Only wrote %1 of %2 frames at file frame %3")
Chris@148 156 .arg(written).arg(n).arg(f);
Chris@148 157 break;
Chris@148 158 }
Chris@148 159 }
Chris@148 160 }
Chris@148 161
Chris@148 162 delete[] ub;
Chris@148 163 delete[] ib;
Chris@174 164 if (ownSelection) delete selection;
Chris@174 165
Chris@174 166 return isOK();
Chris@174 167 }
Chris@174 168
Chris@174 169 bool
Chris@1038 170 WavFileWriter::writeSamples(float **samples, sv_frame_t count)
Chris@174 171 {
Chris@174 172 if (!m_file) {
Chris@174 173 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@684 174 .arg(getWriteFilename());
Chris@174 175 return false;
Chris@174 176 }
Chris@174 177
Chris@174 178 float *b = new float[count * m_channels];
Chris@1038 179 for (sv_frame_t i = 0; i < count; ++i) {
Chris@929 180 for (int c = 0; c < int(m_channels); ++c) {
Chris@174 181 b[i * m_channels + c] = samples[c][i];
Chris@174 182 }
Chris@174 183 }
Chris@174 184
Chris@1038 185 sv_frame_t written = sf_writef_float(m_file, b, count);
Chris@174 186
Chris@174 187 delete[] b;
Chris@174 188
Chris@1038 189 if (written < count) {
Chris@174 190 m_error = QString("Only wrote %1 of %2 frames")
Chris@174 191 .arg(written).arg(count);
Chris@174 192 }
Chris@174 193
Chris@174 194 return isOK();
Chris@174 195 }
Chris@174 196
Chris@174 197 bool
Chris@174 198 WavFileWriter::close()
Chris@174 199 {
Chris@174 200 if (m_file) {
Chris@174 201 sf_close(m_file);
Chris@174 202 m_file = 0;
Chris@174 203 }
Chris@684 204 if (m_temp) {
Chris@684 205 m_temp->moveToTarget();
Chris@684 206 delete m_temp;
Chris@684 207 m_temp = 0;
Chris@684 208 }
Chris@174 209 return true;
Chris@148 210 }
Chris@148 211