annotate data/fileio/WavFileWriter.cpp @ 184:5a916fee6d2d

* Handle generator transforms (plugins whose channel count isn't dependent on number of audio inputs, as they have none) * Be less keen to suspend writing FFT data in spectrogram repaint -- only do it if we find we actually need to query the FFT data (i.e. we aren't repainting an area that hasn't been generated at all yet)
author Chris Cannam
date Tue, 10 Oct 2006 19:04:57 +0000
parents f8cf055dbf34
children 91fdc752e540
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@148 7 This file copyright 2006 Chris Cannam.
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@148 20
Chris@148 21 #include <QFileInfo>
Chris@148 22
Chris@148 23 #include <iostream>
Chris@148 24
Chris@148 25 WavFileWriter::WavFileWriter(QString path,
Chris@148 26 size_t sampleRate,
Chris@174 27 size_t channels) :
Chris@148 28 m_path(path),
Chris@148 29 m_sampleRate(sampleRate),
Chris@174 30 m_channels(channels),
Chris@174 31 m_file(0)
Chris@148 32 {
Chris@174 33 SF_INFO fileInfo;
Chris@174 34 fileInfo.samplerate = m_sampleRate;
Chris@174 35 fileInfo.channels = m_channels;
Chris@174 36 fileInfo.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT;
Chris@174 37
Chris@174 38 m_file = sf_open(m_path.toLocal8Bit(), SFM_WRITE, &fileInfo);
Chris@174 39 if (!m_file) {
Chris@174 40 std::cerr << "WavFileWriter: Failed to open file ("
Chris@174 41 << sf_strerror(m_file) << ")" << std::endl;
Chris@174 42 m_error = QString("Failed to open audio file '%1' for writing")
Chris@174 43 .arg(m_path);
Chris@174 44 }
Chris@148 45 }
Chris@148 46
Chris@148 47 WavFileWriter::~WavFileWriter()
Chris@148 48 {
Chris@174 49 if (m_file) close();
Chris@148 50 }
Chris@148 51
Chris@148 52 bool
Chris@148 53 WavFileWriter::isOK() const
Chris@148 54 {
Chris@148 55 return (m_error.isEmpty());
Chris@148 56 }
Chris@148 57
Chris@148 58 QString
Chris@148 59 WavFileWriter::getError() const
Chris@148 60 {
Chris@148 61 return m_error;
Chris@148 62 }
Chris@148 63
Chris@174 64 bool
Chris@174 65 WavFileWriter::writeModel(DenseTimeValueModel *source,
Chris@174 66 MultiSelection *selection)
Chris@148 67 {
Chris@174 68 if (source->getChannelCount() != m_channels) {
Chris@174 69 std::cerr << "WavFileWriter::writeModel: Wrong number of channels ("
Chris@174 70 << source->getChannelCount() << " != " << m_channels << ")"
Chris@174 71 << std::endl;
Chris@174 72 m_error = QString("Failed to write model to audio file '%1'")
Chris@174 73 .arg(m_path);
Chris@174 74 return false;
Chris@148 75 }
Chris@148 76
Chris@174 77 if (!m_file) {
Chris@174 78 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@174 79 .arg(m_path);
Chris@174 80 return false;
Chris@174 81 }
Chris@148 82
Chris@174 83 bool ownSelection = false;
Chris@174 84 if (!selection) {
Chris@148 85 selection = new MultiSelection;
Chris@174 86 selection->setSelection(Selection(source->getStartFrame(),
Chris@174 87 source->getEndFrame()));
Chris@174 88 ownSelection = true;
Chris@148 89 }
Chris@148 90
Chris@148 91 size_t bs = 2048;
Chris@148 92 float *ub = new float[bs]; // uninterleaved buffer (one channel)
Chris@174 93 float *ib = new float[bs * m_channels]; // interleaved buffer
Chris@148 94
Chris@148 95 for (MultiSelection::SelectionList::iterator i =
Chris@148 96 selection->getSelections().begin();
Chris@148 97 i != selection->getSelections().end(); ++i) {
Chris@148 98
Chris@148 99 size_t f0(i->getStartFrame()), f1(i->getEndFrame());
Chris@148 100
Chris@148 101 for (size_t f = f0; f < f1; f += bs) {
Chris@148 102
Chris@148 103 size_t n = std::min(bs, f1 - f);
Chris@148 104
Chris@174 105 for (int c = 0; c < int(m_channels); ++c) {
Chris@174 106 source->getValues(c, f, f + n, ub);
Chris@148 107 for (size_t i = 0; i < n; ++i) {
Chris@174 108 ib[i * m_channels + c] = ub[i];
Chris@148 109 }
Chris@148 110 }
Chris@148 111
Chris@174 112 sf_count_t written = sf_writef_float(m_file, ib, n);
Chris@148 113
Chris@148 114 if (written < n) {
Chris@148 115 m_error = QString("Only wrote %1 of %2 frames at file frame %3")
Chris@148 116 .arg(written).arg(n).arg(f);
Chris@148 117 break;
Chris@148 118 }
Chris@148 119 }
Chris@148 120 }
Chris@148 121
Chris@148 122 delete[] ub;
Chris@148 123 delete[] ib;
Chris@174 124 if (ownSelection) delete selection;
Chris@174 125
Chris@174 126 return isOK();
Chris@174 127 }
Chris@174 128
Chris@174 129 bool
Chris@174 130 WavFileWriter::writeSamples(float **samples, size_t count)
Chris@174 131 {
Chris@174 132 if (!m_file) {
Chris@174 133 m_error = QString("Failed to write model to audio file '%1': File not open")
Chris@174 134 .arg(m_path);
Chris@174 135 return false;
Chris@174 136 }
Chris@174 137
Chris@174 138 float *b = new float[count * m_channels];
Chris@174 139 for (size_t i = 0; i < count; ++i) {
Chris@174 140 for (size_t c = 0; c < m_channels; ++c) {
Chris@174 141 b[i * m_channels + c] = samples[c][i];
Chris@174 142 }
Chris@174 143 }
Chris@174 144
Chris@174 145 sf_count_t written = sf_writef_float(m_file, b, count);
Chris@174 146
Chris@174 147 delete[] b;
Chris@174 148
Chris@174 149 if (written < count) {
Chris@174 150 m_error = QString("Only wrote %1 of %2 frames")
Chris@174 151 .arg(written).arg(count);
Chris@174 152 }
Chris@174 153
Chris@174 154 return isOK();
Chris@174 155 }
Chris@174 156
Chris@174 157 bool
Chris@174 158 WavFileWriter::close()
Chris@174 159 {
Chris@174 160 if (m_file) {
Chris@174 161 sf_close(m_file);
Chris@174 162 m_file = 0;
Chris@174 163 }
Chris@174 164 return true;
Chris@148 165 }
Chris@148 166