annotate data/fileio/WavFileReader.cpp @ 316:3a6725f285d6

* Make RemoteFile far more pervasive, and use it for local files as well so that we can handle both transparently. Make it shallow copy with reference counting, so it can be used by value without having to worry about the cache file lifetime. Use RemoteFile for MainWindow file-open functions, etc
author Chris Cannam
date Thu, 18 Oct 2007 15:31:20 +0000
parents 92e8dbde73cd
children c324d410b096
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@316 23 WavFileReader::WavFileReader(RemoteFile 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@175 114
Chris@175 115 QMutexLocker locker(&m_mutex);
Chris@175 116
Chris@175 117 if (!m_file || !m_channelCount) {
Chris@175 118 return;
Chris@175 119 }
Chris@148 120
Chris@148 121 if ((long)start >= m_fileInfo.frames) {
Chris@175 122 // std::cerr << "WavFileReader::getInterleavedFrames: " << start
Chris@175 123 // << " > " << m_fileInfo.frames << std::endl;
Chris@148 124 return;
Chris@148 125 }
Chris@148 126
Chris@148 127 if (long(start + count) > m_fileInfo.frames) {
Chris@148 128 count = m_fileInfo.frames - start;
Chris@148 129 }
Chris@148 130
Chris@148 131 sf_count_t readCount = 0;
Chris@148 132
Chris@148 133 if (start != m_lastStart || count != m_lastCount) {
Chris@148 134
Chris@148 135 if (sf_seek(m_file, start, SEEK_SET) < 0) {
Chris@175 136 // std::cerr << "sf_seek failed" << std::endl;
Chris@148 137 return;
Chris@148 138 }
Chris@148 139
Chris@148 140 if (count * m_fileInfo.channels > m_bufsiz) {
Chris@148 141 // std::cerr << "WavFileReader: Reallocating buffer for " << count
Chris@148 142 // << " frames, " << m_fileInfo.channels << " channels: "
Chris@148 143 // << m_bufsiz << " floats" << std::endl;
Chris@148 144 m_bufsiz = count * m_fileInfo.channels;
Chris@148 145 delete[] m_buffer;
Chris@148 146 m_buffer = new float[m_bufsiz];
Chris@148 147 }
Chris@148 148
Chris@148 149 if ((readCount = sf_readf_float(m_file, m_buffer, count)) < 0) {
Chris@175 150 // std::cerr << "sf_readf_float failed" << std::endl;
Chris@148 151 return;
Chris@148 152 }
Chris@148 153
Chris@148 154 m_lastStart = start;
Chris@148 155 m_lastCount = readCount;
Chris@148 156 }
Chris@148 157
Chris@148 158 for (size_t i = 0; i < count * m_fileInfo.channels; ++i) {
Chris@232 159 if (i >= m_bufsiz) {
Chris@232 160 std::cerr << "INTERNAL ERROR: WavFileReader::getInterleavedFrames: " << i << " >= " << m_bufsiz << std::endl;
Chris@232 161 }
Chris@148 162 results.push_back(m_buffer[i]);
Chris@148 163 }
Chris@148 164
Chris@148 165 return;
Chris@148 166 }
Chris@148 167
Chris@157 168 void
Chris@290 169 WavFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 170 {
Chris@157 171 int count;
Chris@157 172
Chris@157 173 if (sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count))) {
Chris@157 174 extensions.insert("wav");
Chris@157 175 extensions.insert("aiff");
Chris@316 176 extensions.insert("aifc");
Chris@157 177 extensions.insert("aif");
Chris@157 178 return;
Chris@157 179 }
Chris@157 180
Chris@157 181 SF_FORMAT_INFO info;
Chris@157 182 for (int i = 0; i < count; ++i) {
Chris@157 183 info.format = i;
Chris@157 184 if (!sf_command(0, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) {
Chris@316 185 extensions.insert(QString(info.extension).toLower());
Chris@157 186 }
Chris@157 187 }
Chris@157 188 }
Chris@316 189
Chris@316 190 bool
Chris@316 191 WavFileReader::supportsExtension(QString extension)
Chris@316 192 {
Chris@316 193 std::set<QString> extensions;
Chris@316 194 getSupportedExtensions(extensions);
Chris@316 195 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 196 }
Chris@316 197
Chris@316 198 bool
Chris@316 199 WavFileReader::supportsContentType(QString type)
Chris@316 200 {
Chris@316 201 return (type == "audio/x-wav" ||
Chris@316 202 type == "audio/x-aiff" ||
Chris@316 203 type == "audio/basic");
Chris@316 204 }
Chris@316 205
Chris@316 206 bool
Chris@316 207 WavFileReader::supports(RemoteFile &source)
Chris@316 208 {
Chris@316 209 return (supportsExtension(source.getExtension()) ||
Chris@316 210 supportsContentType(source.getContentType()));
Chris@316 211 }
Chris@316 212
Chris@316 213