svcore  1.9
WavFileReader.cpp
Go to the documentation of this file.
00001 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
00002 
00003 /*
00004     Sonic Visualiser
00005     An audio file viewer and annotation editor.
00006     Centre for Digital Music, Queen Mary, University of London.
00007     This file copyright 2006 Chris Cannam and QMUL.
00008     
00009     This program is free software; you can redistribute it and/or
00010     modify it under the terms of the GNU General Public License as
00011     published by the Free Software Foundation; either version 2 of the
00012     License, or (at your option) any later version.  See the file
00013     COPYING included with this distribution for more information.
00014 */
00015 
00016 #include "WavFileReader.h"
00017 
00018 #include <iostream>
00019 
00020 #include <QMutexLocker>
00021 #include <QFileInfo>
00022 
00023 WavFileReader::WavFileReader(FileSource source, bool fileUpdating) :
00024     m_file(0),
00025     m_source(source),
00026     m_path(source.getLocalFilename()),
00027     m_seekable(false),
00028     m_buffer(0),
00029     m_bufsiz(0),
00030     m_lastStart(0),
00031     m_lastCount(0),
00032     m_updating(fileUpdating)
00033 {
00034     m_frameCount = 0;
00035     m_channelCount = 0;
00036     m_sampleRate = 0;
00037 
00038     m_fileInfo.format = 0;
00039     m_fileInfo.frames = 0;
00040     m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
00041 
00042     if (!m_file || (!fileUpdating && m_fileInfo.channels <= 0)) {
00043         cerr << "WavFileReader::initialize: Failed to open file at \""
00044                   << m_path << "\" ("
00045                   << sf_strerror(m_file) << ")" << endl;
00046 
00047         if (m_file) {
00048             m_error = QString("Couldn't load audio file '%1':\n%2")
00049                 .arg(m_path).arg(sf_strerror(m_file));
00050         } else {
00051             m_error = QString("Failed to open audio file '%1'")
00052                 .arg(m_path);
00053         }
00054         return;
00055     }
00056 
00057     if (m_fileInfo.channels > 0) {
00058 
00059         m_frameCount = m_fileInfo.frames;
00060         m_channelCount = m_fileInfo.channels;
00061         m_sampleRate = m_fileInfo.samplerate;
00062 
00063         m_seekable = (m_fileInfo.seekable != 0);
00064 
00065         // Our m_seekable reports whether a file is rapidly seekable,
00066         // so things like Ogg don't qualify. We cautiously report
00067         // every file type of "at least" the historical period of Ogg
00068         // or FLAC as non-seekable.
00069         int type = m_fileInfo.format & SF_FORMAT_TYPEMASK;
00070 //        cerr << "WavFileReader: format type is " << type << " (flac, ogg are " << SF_FORMAT_FLAC << ", " << SF_FORMAT_OGG << ")" << endl;
00071         if (type >= SF_FORMAT_FLAC || type >= SF_FORMAT_OGG) {
00072 //            cerr << "WavFileReader: Recording as non-seekable" << endl;
00073             m_seekable = false;
00074         }
00075     }
00076 
00077 //    cerr << "WavFileReader: Frame count " << m_frameCount << ", channel count " << m_channelCount << ", sample rate " << m_sampleRate << ", seekable " << m_seekable << endl;
00078 
00079 }
00080 
00081 WavFileReader::~WavFileReader()
00082 {
00083     if (m_file) sf_close(m_file);
00084     delete[] m_buffer;
00085 }
00086 
00087 void
00088 WavFileReader::updateFrameCount()
00089 {
00090     QMutexLocker locker(&m_mutex);
00091 
00092     int prevCount = m_fileInfo.frames;
00093 
00094     if (m_file) {
00095         sf_close(m_file);
00096         m_file = sf_open(m_path.toLocal8Bit(), SFM_READ, &m_fileInfo);
00097         if (!m_file || m_fileInfo.channels <= 0) {
00098             cerr << "WavFileReader::updateFrameCount: Failed to open file at \"" << m_path << "\" ("
00099                       << sf_strerror(m_file) << ")" << endl;
00100         }
00101     }
00102 
00103 //    SVDEBUG << "WavFileReader::updateFrameCount: now " << m_fileInfo.frames << endl;
00104 
00105     m_frameCount = m_fileInfo.frames;
00106 
00107     if (m_channelCount == 0) {
00108         m_channelCount = m_fileInfo.channels;
00109         m_sampleRate = m_fileInfo.samplerate;
00110     }
00111 
00112     if (m_frameCount != prevCount) {
00113 //        cerr << "frameCountChanged" << endl;
00114         emit frameCountChanged();
00115     }
00116 }
00117 
00118 void
00119 WavFileReader::updateDone()
00120 {
00121     updateFrameCount();
00122     m_updating = false;
00123 }
00124 
00125 void
00126 WavFileReader::getInterleavedFrames(int start, int count,
00127                                     SampleBlock &results) const
00128 {
00129     if (count == 0) return;
00130     results.clear();
00131     results.reserve(count * m_fileInfo.channels);
00132 
00133     QMutexLocker locker(&m_mutex);
00134 
00135     if (!m_file || !m_channelCount) {
00136         return;
00137     }
00138 
00139     if ((long)start >= m_fileInfo.frames) {
00140 //        SVDEBUG << "WavFileReader::getInterleavedFrames: " << start
00141 //                  << " > " << m_fileInfo.frames << endl;
00142         return;
00143     }
00144 
00145     if (long(start + count) > m_fileInfo.frames) {
00146         count = m_fileInfo.frames - start;
00147     }
00148 
00149     sf_count_t readCount = 0;
00150 
00151     if (start != m_lastStart || count != m_lastCount) {
00152 
00153         if (sf_seek(m_file, start, SEEK_SET) < 0) {
00154 //            cerr << "sf_seek failed" << endl;
00155             return;
00156         }
00157         
00158         if (count * m_fileInfo.channels > m_bufsiz) {
00159 //          cerr << "WavFileReader: Reallocating buffer for " << count
00160 //                    << " frames, " << m_fileInfo.channels << " channels: "
00161 //                    << m_bufsiz << " floats" << endl;
00162             m_bufsiz = count * m_fileInfo.channels;
00163             delete[] m_buffer;
00164             m_buffer = new float[m_bufsiz];
00165         }
00166         
00167         if ((readCount = sf_readf_float(m_file, m_buffer, count)) < 0) {
00168 //            cerr << "sf_readf_float failed" << endl;
00169             return;
00170         }
00171 
00172         m_lastStart = start;
00173         m_lastCount = readCount;
00174     }
00175 
00176     for (int i = 0; i < count * m_fileInfo.channels; ++i) {
00177         if (i >= m_bufsiz) {
00178             cerr << "INTERNAL ERROR: WavFileReader::getInterleavedFrames: " << i << " >= " << m_bufsiz << endl;
00179         }
00180         results.push_back(m_buffer[i]);
00181     }
00182 
00183     return;
00184 }
00185 
00186 void
00187 WavFileReader::getSupportedExtensions(std::set<QString> &extensions)
00188 {
00189     int count;
00190 
00191     if (sf_command(0, SFC_GET_FORMAT_MAJOR_COUNT, &count, sizeof(count))) {
00192         extensions.insert("wav");
00193         extensions.insert("aiff");
00194         extensions.insert("aifc");
00195         extensions.insert("aif");
00196         return;
00197     }
00198 
00199     SF_FORMAT_INFO info;
00200     for (int i = 0; i < count; ++i) {
00201         info.format = i;
00202         if (!sf_command(0, SFC_GET_FORMAT_MAJOR, &info, sizeof(info))) {
00203             QString ext = QString(info.extension).toLower();
00204             extensions.insert(ext);
00205             if (ext == "oga") {
00206                 // libsndfile is awfully proper, it says it only
00207                 // supports .oga but lots of Ogg audio files in the
00208                 // wild are .ogg and it will accept that
00209                 extensions.insert("ogg");
00210             }
00211         }
00212     }
00213 }
00214 
00215 bool
00216 WavFileReader::supportsExtension(QString extension)
00217 {
00218     std::set<QString> extensions;
00219     getSupportedExtensions(extensions);
00220     return (extensions.find(extension.toLower()) != extensions.end());
00221 }
00222 
00223 bool
00224 WavFileReader::supportsContentType(QString type)
00225 {
00226     return (type == "audio/x-wav" ||
00227             type == "audio/x-aiff" ||
00228             type == "audio/basic");
00229 }
00230 
00231 bool
00232 WavFileReader::supports(FileSource &source)
00233 {
00234     return (supportsExtension(source.getExtension()) ||
00235             supportsContentType(source.getContentType()));
00236 }
00237 
00238