svcore  1.9
WavFileReader.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 "WavFileReader.h"
17 
18 #include <iostream>
19 
20 #include <QMutexLocker>
21 #include <QFileInfo>
22 
23 WavFileReader::WavFileReader(FileSource source, bool fileUpdating) :
24  m_file(0),
25  m_source(source),
26  m_path(source.getLocalFilename()),
27  m_seekable(false),
28  m_buffer(0),
29  m_bufsiz(0),
30  m_lastStart(0),
31  m_lastCount(0),
32  m_updating(fileUpdating)
33 {
34  m_frameCount = 0;
35  m_channelCount = 0;
36  m_sampleRate = 0;
37 
38  m_fileInfo.format = 0;
39  m_fileInfo.frames = 0;
40  m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
41 
42  if (!m_file || (!fileUpdating && m_fileInfo.channels <= 0)) {
43  cerr << "WavFileReader::initialize: Failed to open file at \""
44  << m_path << "\" ("
45  << sf_strerror(m_file) << ")" << endl;
46 
47  if (m_file) {
48  m_error = QString("Couldn't load audio file '%1':\n%2")
49  .arg(m_path).arg(sf_strerror(m_file));
50  } else {
51  m_error = QString("Failed to open audio file '%1'")
52  .arg(m_path);
53  }
54  return;
55  }
56 
57  if (m_fileInfo.channels > 0) {
58 
59  m_frameCount = m_fileInfo.frames;
60  m_channelCount = m_fileInfo.channels;
61  m_sampleRate = m_fileInfo.samplerate;
62 
63  m_seekable = (m_fileInfo.seekable != 0);
64 
65  // Our m_seekable reports whether a file is rapidly seekable,
66  // so things like Ogg don't qualify. We cautiously report
67  // every file type of "at least" the historical period of Ogg
68  // or FLAC as non-seekable.
69  int type = m_fileInfo.format & SF_FORMAT_TYPEMASK;
70 // cerr << "WavFileReader: format type is " << type << " (flac, ogg are " << SF_FORMAT_FLAC << ", " << SF_FORMAT_OGG << ")" << endl;
71  if (type >= SF_FORMAT_FLAC || type >= SF_FORMAT_OGG) {
72 // cerr << "WavFileReader: Recording as non-seekable" << endl;
73  m_seekable = false;
74  }
75  }
76 
77 // cerr << "WavFileReader: Frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << ", seekable " << m_seekable << endl;
78 
79 }
80 
82 {
83  if (m_file) sf_close(m_file);
84  delete[] m_buffer;
85 }
86 
87 void
89 {
90  QMutexLocker locker(&m_mutex);
91 
92  int prevCount = m_fileInfo.frames;
93 
94  if (m_file) {
95  sf_close(m_file);
96  m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
97  if (!m_file || m_fileInfo.channels <= 0) {
98  cerr << "WavFileReader::updateFrameCount: Failed to open file at \"" << m_path << "\" ("
99  << sf_strerror(m_file) << ")" << endl;
100  }
101  }
102 
103 // SVDEBUG << "WavFileReader::updateFrameCount: now " << m_fileInfo.frames << endl;
104 
105  m_frameCount = m_fileInfo.frames;
106 
107  if (m_channelCount == 0) {
108  m_channelCount = m_fileInfo.channels;
109  m_sampleRate = m_fileInfo.samplerate;
110  }
111 
112  if (m_frameCount != prevCount) {
113 // cerr << "frameCountChanged" << endl;
114  emit frameCountChanged();
115  }
116 }
117 
118 void
120 {
122  m_updating = false;
123 }
124 
125 void
127  SampleBlock &results) const
128 {
129  if (count == 0) return;
130  results.clear();
131  results.reserve(count * m_fileInfo.channels);
132 
133  QMutexLocker locker(&m_mutex);
134 
135  if (!m_file || !m_channelCount) {
136  return;
137  }
138 
139  if ((long)start >= m_fileInfo.frames) {
140 // SVDEBUG << "WavFileReader::getInterleavedFrames: " << start
141 // << " > " << m_fileInfo.frames << endl;
142  return;
143  }
144 
145  if (long(start + count) > m_fileInfo.frames) {
146  count = m_fileInfo.frames - start;
147  }
148 
149  sf_count_t readCount = 0;
150 
151  if (start != m_lastStart || count != m_lastCount) {
152 
153  if (sf_seek(m_file, start, SEEK_SET) < 0) {
154 // cerr << "sf_seek failed" << endl;
155  return;
156  }
157 
158  if (count * m_fileInfo.channels > m_bufsiz) {
159 // cerr << "WavFileReader: Reallocating buffer for " << count
160 // << " frames, " << m_fileInfo.channels << " channels: "
161 // << m_bufsiz << " floats" << endl;
162  m_bufsiz = count * m_fileInfo.channels;
163  delete[] m_buffer;
164  m_buffer = new float[m_bufsiz];
165  }
166 
167  if ((readCount = sf_readf_float(m_file, m_buffer, count)) < 0) {
168 // cerr << "sf_readf_float failed" << endl;
169  return;
170  }
171 
172  m_lastStart = start;
173  m_lastCount = readCount;
174  }
175 
176  for (int i = 0; i < count * m_fileInfo.channels; ++i) {
177  if (i >= m_bufsiz) {
178  cerr << "INTERNAL ERROR: WavFileReader::getInterleavedFrames: " << i << " >= " << m_bufsiz << endl;
179  }
180  results.push_back(m_buffer[i]);
181  }
182 
183  return;
184 }
185 
186 void
187 WavFileReader::getSupportedExtensions(std::set<QString> &extensions)
188 {
189  int count;
190 
191  if (sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count))) {
192  extensions.insert("wav");
193  extensions.insert("aiff");
194  extensions.insert("aifc");
195  extensions.insert("aif");
196  return;
197  }
198 
199  SF_FORMAT_INFO info;
200  for (int i = 0; i < count; ++i) {
201  info.format = i;
202  if (!sf_command(0, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) {
203  QString ext = QString(info.extension).toLower();
204  extensions.insert(ext);
205  if (ext == "oga") {
206  // libsndfile is awfully proper, it says it only
207  // supports .oga but lots of Ogg audio files in the
208  // wild are .ogg and it will accept that
209  extensions.insert("ogg");
210  }
211  }
212  }
213 }
214 
215 bool
217 {
218  std::set<QString> extensions;
219  getSupportedExtensions(extensions);
220  return (extensions.find(extension.toLower()) != extensions.end());
221 }
222 
223 bool
225 {
226  return (type == "audio/x-wav" ||
227  type == "audio/x-aiff" ||
228  type == "audio/basic");
229 }
230 
231 bool
233 {
234  return (supportsExtension(source.getExtension()) ||
236 }
237 
238 
QString getExtension() const
Return the file extension for this file, if any.
Definition: FileSource.cpp:619
SF_INFO m_fileInfo
Definition: WavFileReader.h:67
WavFileReader(FileSource source, bool fileUpdating=false)
std::vector< float > SampleBlock
static bool supportsExtension(QString ext)
float * m_buffer
Definition: WavFileReader.h:77
static bool supportsContentType(QString type)
static bool supports(FileSource &source)
void frameCountChanged()
FileSource is a class used to refer to the contents of a file that may be either local or at a remote...
Definition: FileSource.h:59
static void getSupportedExtensions(std::set< QString > &extensions)
QString m_path
Definition: WavFileReader.h:71
SNDFILE * m_file
Definition: WavFileReader.h:68
virtual void getInterleavedFrames(int start, int count, SampleBlock &frames) const
Must be safe to call from multiple threads with different arguments on the same object at the same ti...
void updateFrameCount()
QString getContentType() const
Return the MIME content type of this file, if known.
Definition: FileSource.cpp:613
virtual ~WavFileReader()
QString m_error
Definition: WavFileReader.h:72