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