annotate data/fileio/WavFileReader.cpp @ 588:d04b8674b710

* Try to identify the properly conformant audio file structure written out by Sonic Annotator (but we still don't actually import it yet)
author Chris Cannam
date Wed, 13 May 2009 13:30:08 +0000
parents ecef2f1bec18
children bd527db65d20
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@564 68 delete[] m_buffer;
Chris@148 69 }
Chris@148 70
Chris@148 71 void
Chris@175 72 WavFileReader::updateFrameCount()
Chris@175 73 {
Chris@175 74 QMutexLocker locker(&m_mutex);
Chris@175 75
Chris@175 76 size_t prevCount = m_fileInfo.frames;
Chris@175 77
Chris@175 78 if (m_file) {
Chris@175 79 sf_close(m_file);
Chris@290 80 m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
Chris@175 81 if (!m_file || m_fileInfo.channels <= 0) {
Chris@175 82 std::cerr << "WavFileReader::updateFrameCount: Failed to open file ("
Chris@175 83 << sf_strerror(m_file) << ")" << std::endl;
Chris@175 84 }
Chris@175 85 }
Chris@175 86
Chris@188 87 // std::cerr << "WavFileReader::updateFrameCount: now " << m_fileInfo.frames << std::endl;
Chris@175 88
Chris@176 89 m_frameCount = m_fileInfo.frames;
Chris@176 90
Chris@187 91 if (m_channelCount == 0) {
Chris@187 92 m_channelCount = m_fileInfo.channels;
Chris@187 93 m_sampleRate = m_fileInfo.samplerate;
Chris@187 94 }
Chris@187 95
Chris@258 96 if (m_frameCount != prevCount) {
Chris@258 97 // std::cerr << "frameCountChanged" << std::endl;
Chris@258 98 emit frameCountChanged();
Chris@258 99 }
Chris@176 100 }
Chris@176 101
Chris@176 102 void
Chris@176 103 WavFileReader::updateDone()
Chris@176 104 {
Chris@176 105 updateFrameCount();
Chris@176 106 m_updating = false;
Chris@175 107 }
Chris@175 108
Chris@175 109 void
Chris@148 110 WavFileReader::getInterleavedFrames(size_t start, size_t count,
Chris@148 111 SampleBlock &results) const
Chris@148 112 {
Chris@175 113 if (count == 0) return;
Chris@148 114 results.clear();
Chris@377 115 results.reserve(count * m_fileInfo.channels);
Chris@175 116
Chris@175 117 QMutexLocker locker(&m_mutex);
Chris@175 118
Chris@175 119 if (!m_file || !m_channelCount) {
Chris@175 120 return;
Chris@175 121 }
Chris@148 122
Chris@148 123 if ((long)start >= m_fileInfo.frames) {
Chris@175 124 // std::cerr << "WavFileReader::getInterleavedFrames: " << start
Chris@175 125 // << " > " << m_fileInfo.frames << std::endl;
Chris@148 126 return;
Chris@148 127 }
Chris@148 128
Chris@148 129 if (long(start + count) > m_fileInfo.frames) {
Chris@148 130 count = m_fileInfo.frames - start;
Chris@148 131 }
Chris@148 132
Chris@148 133 sf_count_t readCount = 0;
Chris@148 134
Chris@148 135 if (start != m_lastStart || count != m_lastCount) {
Chris@148 136
Chris@148 137 if (sf_seek(m_file, start, SEEK_SET) < 0) {
Chris@175 138 // std::cerr << "sf_seek failed" << std::endl;
Chris@148 139 return;
Chris@148 140 }
Chris@148 141
Chris@148 142 if (count * m_fileInfo.channels > m_bufsiz) {
Chris@148 143 // std::cerr << "WavFileReader: Reallocating buffer for " << count
Chris@148 144 // << " frames, " << m_fileInfo.channels << " channels: "
Chris@148 145 // << m_bufsiz << " floats" << std::endl;
Chris@148 146 m_bufsiz = count * m_fileInfo.channels;
Chris@148 147 delete[] m_buffer;
Chris@148 148 m_buffer = new float[m_bufsiz];
Chris@148 149 }
Chris@148 150
Chris@148 151 if ((readCount = sf_readf_float(m_file, m_buffer, count)) < 0) {
Chris@175 152 // std::cerr << "sf_readf_float failed" << std::endl;
Chris@148 153 return;
Chris@148 154 }
Chris@148 155
Chris@148 156 m_lastStart = start;
Chris@148 157 m_lastCount = readCount;
Chris@148 158 }
Chris@148 159
Chris@148 160 for (size_t i = 0; i < count * m_fileInfo.channels; ++i) {
Chris@232 161 if (i >= m_bufsiz) {
Chris@232 162 std::cerr << "INTERNAL ERROR: WavFileReader::getInterleavedFrames: " << i << " >= " << m_bufsiz << std::endl;
Chris@232 163 }
Chris@148 164 results.push_back(m_buffer[i]);
Chris@148 165 }
Chris@148 166
Chris@148 167 return;
Chris@148 168 }
Chris@148 169
Chris@157 170 void
Chris@290 171 WavFileReader::getSupportedExtensions(std::set<QString> &extensions)
Chris@157 172 {
Chris@157 173 int count;
Chris@157 174
Chris@157 175 if (sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count))) {
Chris@157 176 extensions.insert("wav");
Chris@157 177 extensions.insert("aiff");
Chris@316 178 extensions.insert("aifc");
Chris@157 179 extensions.insert("aif");
Chris@157 180 return;
Chris@157 181 }
Chris@157 182
Chris@157 183 SF_FORMAT_INFO info;
Chris@157 184 for (int i = 0; i < count; ++i) {
Chris@157 185 info.format = i;
Chris@157 186 if (!sf_command(0, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) {
Chris@316 187 extensions.insert(QString(info.extension).toLower());
Chris@157 188 }
Chris@157 189 }
Chris@157 190 }
Chris@316 191
Chris@316 192 bool
Chris@316 193 WavFileReader::supportsExtension(QString extension)
Chris@316 194 {
Chris@316 195 std::set<QString> extensions;
Chris@316 196 getSupportedExtensions(extensions);
Chris@316 197 return (extensions.find(extension.toLower()) != extensions.end());
Chris@316 198 }
Chris@316 199
Chris@316 200 bool
Chris@316 201 WavFileReader::supportsContentType(QString type)
Chris@316 202 {
Chris@316 203 return (type == "audio/x-wav" ||
Chris@316 204 type == "audio/x-aiff" ||
Chris@316 205 type == "audio/basic");
Chris@316 206 }
Chris@316 207
Chris@316 208 bool
Chris@317 209 WavFileReader::supports(FileSource &source)
Chris@316 210 {
Chris@316 211 return (supportsExtension(source.getExtension()) ||
Chris@316 212 supportsContentType(source.getContentType()));
Chris@316 213 }
Chris@316 214
Chris@316 215