annotate data/fileio/WavFileWriter.cpp @ 1346:75ad55315db4 3.0-integration

More work on getting tests (especially file encoding ones) running on Windows. Various problems here to do with interaction with test filenames in Hg repos
author Chris Cannam
date Fri, 06 Jan 2017 15:44:55 +0000
parents 54af1e21705c
children b3cb0edc25cd
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@1096 28 using namespace std;
Chris@1096 29
Chris@148 30 WavFileWriter::WavFileWriter(QString path,
Chris@1040 31 sv_samplerate_t sampleRate,
Chris@929 32 int channels,
Chris@684 33 FileWriteMode mode) :
Chris@148 34 m_path(path),
Chris@148 35 m_sampleRate(sampleRate),
Chris@174 36 m_channels(channels),
Chris@674 37 m_temp(0),
Chris@174 38 m_file(0)
Chris@148 39 {
Chris@174 40 SF_INFO fileInfo;
Chris@1040 41
Chris@1040 42 int fileRate = int(round(m_sampleRate));
Chris@1040 43 if (m_sampleRate != sv_samplerate_t(fileRate)) {
Chris@1040 44 cerr << "WavFileWriter: WARNING: Non-integer sample rate "
Chris@1040 45 << m_sampleRate << " presented, rounding to " << fileRate
Chris@1040 46 << endl;
Chris@1040 47 }
Chris@1040 48 fileInfo.samplerate = fileRate;
Chris@174 49 fileInfo.channels = m_channels;
Chris@174 50 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
Chris@674 51
Chris@674 52 try {
Chris@684 53 if (mode == WriteToTemporary) {
Chris@684 54 m_temp = new TempWriteFile(m_path);
Chris@684 55 m_file = sf_open(m_temp->getTemporaryFilename().toLocal8Bit(),
Chris@684 56 SFM_WRITE, &fileInfo);
Chris@684 57 if (!m_file) {
Chris@843 58 cerr << "WavFileWriter: Failed to open file ("
Chris@843 59 << sf_strerror(m_file) << ")" << endl;
Chris@684 60 m_error = QString("Failed to open audio file '%1' for writing")
Chris@684 61 .arg(m_temp->getTemporaryFilename());
Chris@684 62 }
Chris@684 63 } else {
Chris@684 64 m_file = sf_open(m_path.toLocal8Bit(), SFM_WRITE, &fileInfo);
Chris@684 65 if (!m_file) {
Chris@843 66 cerr << "WavFileWriter: Failed to open file ("
Chris@843 67 << sf_strerror(m_file) << ")" << endl;
Chris@684 68 m_error = QString("Failed to open audio file '%1' for writing")
Chris@684 69 .arg(m_path);
Chris@684 70 }
Chris@684 71 }
Chris@674 72 } catch (FileOperationFailed &f) {
Chris@674 73 m_error = f.what();
Chris@674 74 m_temp = 0;
Chris@674 75 m_file = 0;
Chris@174 76 }
Chris@148 77 }
Chris@148 78
Chris@148 79 WavFileWriter::~WavFileWriter()
Chris@148 80 {
Chris@174 81 if (m_file) close();
Chris@148 82 }
Chris@148 83
Chris@148 84 bool
Chris@148 85 WavFileWriter::isOK() const
Chris@148 86 {
Chris@148 87 return (m_error.isEmpty());
Chris@148 88 }
Chris@148 89
Chris@148 90 QString
Chris@148 91 WavFileWriter::getError() const
Chris@148 92 {
Chris@148 93 return m_error;
Chris@148 94 }
Chris@148 95
Chris@684 96 QString
Chris@684 97 WavFileWriter::getWriteFilename() const
Chris@684 98 {
Chris@684 99 if (m_temp) {
Chris@684 100 return m_temp->getTemporaryFilename();
Chris@684 101 } else {
Chris@684 102 return m_path;
Chris@684 103 }
Chris@684 104 }
Chris@684 105
Chris@174 106 bool
Chris@174 107 WavFileWriter::writeModel(DenseTimeValueModel *source,
Chris@174 108 MultiSelection *selection)
Chris@148 109 {
Chris@174 110 if (source->getChannelCount() != m_channels) {
Chris@690 111 SVDEBUG << "WavFileWriter::writeModel: Wrong number of channels ("
Chris@174 112 << source->getChannelCount() << " != " << m_channels << ")"
Chris@687 113 << endl;
Chris@174 114 m_error = QString("Failed to write model to audio file '%1'")
Chris@684 115 .arg(getWriteFilename());
Chris@174 116 return false;
Chris@148 117 }
Chris@148 118
Chris@174 119 if (!m_file) {
Chris@174 120 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@684 121 .arg(getWriteFilename());
Chris@174 122 return false;
Chris@174 123 }
Chris@148 124
Chris@174 125 bool ownSelection = false;
Chris@174 126 if (!selection) {
Chris@148 127 selection = new MultiSelection;
Chris@174 128 selection->setSelection(Selection(source->getStartFrame(),
Chris@174 129 source->getEndFrame()));
Chris@174 130 ownSelection = true;
Chris@148 131 }
Chris@148 132
Chris@1038 133 sv_frame_t bs = 2048;
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@1096 143 sv_frame_t n = min(bs, f1 - f);
Chris@1326 144 floatvec_t interleaved(n * m_channels, 0.f);
Chris@148 145
Chris@174 146 for (int c = 0; c < int(m_channels); ++c) {
Chris@1326 147 auto chanbuf = source->getData(c, f, n);
Chris@1096 148 for (int i = 0; in_range_for(chanbuf, i); ++i) {
Chris@1096 149 interleaved[i * m_channels + c] = chanbuf[i];
Chris@148 150 }
Chris@148 151 }
Chris@148 152
Chris@1096 153 sf_count_t written = sf_writef_float(m_file, interleaved.data(), n);
Chris@148 154
Chris@148 155 if (written < n) {
Chris@148 156 m_error = QString("Only wrote %1 of %2 frames at file frame %3")
Chris@148 157 .arg(written).arg(n).arg(f);
Chris@148 158 break;
Chris@148 159 }
Chris@148 160 }
Chris@148 161 }
Chris@148 162
Chris@174 163 if (ownSelection) delete selection;
Chris@174 164
Chris@174 165 return isOK();
Chris@174 166 }
Chris@174 167
Chris@174 168 bool
Chris@1325 169 WavFileWriter::writeSamples(const float *const *samples, sv_frame_t count)
Chris@174 170 {
Chris@174 171 if (!m_file) {
Chris@174 172 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@684 173 .arg(getWriteFilename());
Chris@174 174 return false;
Chris@174 175 }
Chris@174 176
Chris@174 177 float *b = new float[count * m_channels];
Chris@1038 178 for (sv_frame_t i = 0; i < count; ++i) {
Chris@929 179 for (int c = 0; c < int(m_channels); ++c) {
Chris@174 180 b[i * m_channels + c] = samples[c][i];
Chris@174 181 }
Chris@174 182 }
Chris@174 183
Chris@1038 184 sv_frame_t written = sf_writef_float(m_file, b, count);
Chris@174 185
Chris@174 186 delete[] b;
Chris@174 187
Chris@1038 188 if (written < count) {
Chris@174 189 m_error = QString("Only wrote %1 of %2 frames")
Chris@174 190 .arg(written).arg(count);
Chris@174 191 }
Chris@174 192
Chris@174 193 return isOK();
Chris@174 194 }
Chris@174 195
Chris@174 196 bool
Chris@174 197 WavFileWriter::close()
Chris@174 198 {
Chris@174 199 if (m_file) {
Chris@174 200 sf_close(m_file);
Chris@174 201 m_file = 0;
Chris@174 202 }
Chris@684 203 if (m_temp) {
Chris@684 204 m_temp->moveToTarget();
Chris@684 205 delete m_temp;
Chris@684 206 m_temp = 0;
Chris@684 207 }
Chris@174 208 return true;
Chris@148 209 }
Chris@148 210