annotate data/fileio/WavFileReader.cpp @ 458:f60360209e5c

* Fix race condition in FFTFileCache when reading from the same FFT model from multiple threads (e.g. when applying more than one plugin at once)
author Chris Cannam
date Wed, 15 Oct 2008 12:08:02 +0000
parents 166c22eff678
children ecef2f1bec18
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 "WavFileReader.h"
Chris@148 17
Chris@148 18 #include <iostream>
Chris@148 19
Chris@175 20 #include <QMutexLocker>
Chris@316 21 #include <QFileInfo>
Chris@175 22
Chris@317 23 WavFileReader::WavFileReader(FileSource source, bool fileUpdating) :
Chris@148 24 m_file(0),
Chris@316 25 m_source(source),
Chris@316 26 m_path(source.getLocalFilename()),
Chris@148 27 m_buffer(0),
Chris@148 28 m_bufsiz(0),
Chris@148 29 m_lastStart(0),
Chris@176 30 m_lastCount(0),
Chris@176 31 m_updating(fileUpdating)
Chris@148 32 {
Chris@148 33 m_frameCount = 0;
Chris@148 34 m_channelCount = 0;
Chris@148 35 m_sampleRate = 0;
Chris@148 36
Chris@148 37 m_fileInfo.format = 0;
Chris@148 38 m_fileInfo.frames = 0;
Chris@290 39 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
Chris@148 40
Chris@187 41 if (!m_file || (!fileUpdating && m_fileInfo.channels <= 0)) {
Chris@148 42 std::cerr << "WavFileReader::initialize: Failed to open file ("
Chris@148 43 << sf_strerror(m_file) << ")" << std::endl;
Chris@148 44
Chris@148 45 if (m_file) {
Chris@290 46 m_error = QString("Couldn't load audio file '%1':\n%2")
Chris@290 47 .arg(m_path).arg(sf_strerror(m_file));
Chris@148 48 } else {
Chris@290 49 m_error = QString("Failed to open audio file '%1'")
Chris@290 50 .arg(m_path);
Chris@148 51 }
Chris@148 52 return;
Chris@148 53 }
Chris@148 54
Chris@187 55 if (m_fileInfo.channels > 0) {
Chris@187 56 m_frameCount = m_fileInfo.frames;
Chris@187 57 m_channelCount = m_fileInfo.channels;
Chris@187 58 m_sampleRate = m_fileInfo.samplerate;
Chris@187 59 }
Chris@175 60
Chris@259 61 // std::cerr << "WavFileReader: Frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << std::endl;
Chris@175 62
Chris@148 63 }
Chris@148 64
Chris@148 65 WavFileReader::~WavFileReader()
Chris@148 66 {
Chris@148 67 if (m_file) sf_close(m_file);
Chris@148 68 }
Chris@148 69
Chris@148 70 void
Chris@175 71 WavFileReader::updateFrameCount()
Chris@175 72 {
Chris@175 73 QMutexLocker locker(&m_mutex);
Chris@175 74
Chris@175 75 size_t prevCount = m_fileInfo.frames;
Chris@175 76
Chris@175 77 if (m_file) {
Chris@175 78 sf_close(m_file);
Chris@290 79 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
Chris@175 80 if (!m_file || m_fileInfo.channels <= 0) {
Chris@175 81 std::cerr << "WavFileReader::updateFrameCount: Failed to open file ("
Chris@175 82 << sf_strerror(m_file) << ")" << std::endl;
Chris@175 83 }
Chris@175 84 }
Chris@175 85
Chris@188 86 // std::cerr << "WavFileReader::updateFrameCount: now " << m_fileInfo.frames << std::endl;
Chris@175 87
Chris@176 88 m_frameCount = m_fileInfo.frames;
Chris@176 89
Chris@187 90 if (m_channelCount == 0) {
Chris@187 91 m_channelCount = m_fileInfo.channels;
Chris@187 92 m_sampleRate = m_fileInfo.samplerate;
Chris@187 93 }
Chris@187 94
Chris@258 95 if (m_frameCount != prevCount) {
Chris@258 96 // std::cerr << "frameCountChanged" << std::endl;
Chris@258 97 emit frameCountChanged();
Chris@258 98 }
Chris@176 99 }
Chris@176 100
Chris@176 101 void
Chris@176 102 WavFileReader::updateDone()
Chris@176 103 {
Chris@176 104 updateFrameCount();
Chris@176 105 m_updating = false;
Chris@175 106 }
Chris@175 107
Chris@175 108 void
Chris@148 109 WavFileReader::getInterleavedFrames(size_t start, size_t count,
Chris@148 110 SampleBlock &results) const
Chris@148 111 {
Chris@175 112 if (count == 0) return;
Chris@148 113 results.clear();
Chris@377 114 results.reserve(count * m_fileInfo.channels);
Chris@175 115
Chris@175 116 QMutexLocker locker(&m_mutex);
Chris@175 117
Chris@175 118 if (!m_file || !m_channelCount) {
Chris@175 119 return;
Chris@175 120 }
Chris@148 121
Chris@148 122 if ((long)start >= m_fileInfo.frames) {
Chris@175 123 // std::cerr << "WavFileReader::getInterleavedFrames: " << start
Chris@175 124 // << " > " << m_fileInfo.frames << std::endl;
Chris@148 125 return;
Chris@148 126 }
Chris@148 127
Chris@148 128 if (long(start + count) > m_fileInfo.frames) {
Chris@148 129 count = m_fileInfo.frames - start;
Chris@148 130 }
Chris@148 131
Chris@148 132 sf_count_t readCount = 0;
Chris@148 133
Chris@148 134 if (start != m_lastStart || count != m_lastCount) {
Chris@148 135
Chris@148 136 if (sf_seek(m_file, start, SEEK_SET) < 0) {
Chris@175 137 // std::cerr << "sf_seek failed" << std::endl;
Chris@148 138 return;
Chris@148 139 }
Chris@148 140
Chris@148 141 if (count * m_fileInfo.channels > m_bufsiz) {
Chris@148 142 // std::cerr << "WavFileReader: Reallocating buffer for " << count
Chris@148 143 // << " frames, " << m_fileInfo.channels << " channels: "
Chris@148 144 // << m_bufsiz << " floats" << std::endl;
Chris@148 145 m_bufsiz = count * m_fileInfo.channels;
Chris@148 146 delete[] m_buffer;
Chris@148 147 m_buffer = new float[m_bufsiz];
Chris@148 148 }
Chris@148 149
Chris@148 150 if ((readCount = sf_readf_float(m_file, m_buffer, count)) < 0) {
Chris@175 151 // std::cerr << "sf_readf_float failed" << std::endl;
Chris@148 152 return;
Chris@148 153 }
Chris@148 154
Chris@148 155 m_lastStart = start;
Chris@148 156 m_lastCount = readCount;
Chris@148 157 }
Chris@148 158
Chris@148 159 for (size_t i = 0; i < count * m_fileInfo.channels; ++i) {
Chris@232 160 if (i >= m_bufsiz) {
Chris@232 161 std::cerr << "INTERNAL ERROR: WavFileReader::getInterleavedFrames: " << i << " >= " << m_bufsiz << std::endl;
Chris@232 162 }
Chris@148 163 results.push_back(m_buffer[i]);
Chris@148 164 }
Chris@148 165
Chris@148 166 return;
Chris@148 167 }
Chris@148 168
Chris@157 169 void
Chris@290 170 WavFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 171 {
Chris@157 172 int count;
Chris@157 173
Chris@157 174 if (sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count))) {
Chris@157 175 extensions.insert("wav");
Chris@157 176 extensions.insert("aiff");
Chris@316 177 extensions.insert("aifc");
Chris@157 178 extensions.insert("aif");
Chris@157 179 return;
Chris@157 180 }
Chris@157 181
Chris@157 182 SF_FORMAT_INFO info;
Chris@157 183 for (int i = 0; i < count; ++i) {
Chris@157 184 info.format = i;
Chris@157 185 if (!sf_command(0, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) {
Chris@316 186 extensions.insert(QString(info.extension).toLower());
Chris@157 187 }
Chris@157 188 }
Chris@157 189 }
Chris@316 190
Chris@316 191 bool
Chris@316 192 WavFileReader::supportsExtension(QString extension)
Chris@316 193 {
Chris@316 194 std::set<QString> extensions;
Chris@316 195 getSupportedExtensions(extensions);
Chris@316 196 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 197 }
Chris@316 198
Chris@316 199 bool
Chris@316 200 WavFileReader::supportsContentType(QString type)
Chris@316 201 {
Chris@316 202 return (type == "audio/x-wav" ||
Chris@316 203 type == "audio/x-aiff" ||
Chris@316 204 type == "audio/basic");
Chris@316 205 }
Chris@316 206
Chris@316 207 bool
Chris@317 208 WavFileReader::supports(FileSource &source)
Chris@316 209 {
Chris@316 210 return (supportsExtension(source.getExtension()) ||
Chris@316 211 supportsContentType(source.getContentType()));
Chris@316 212 }
Chris@316 213
Chris@316 214