annotate data/fileio/AudioFileReaderFactory.cpp @ 1833:21c792334c2e sensible-delimited-data-strings

Rewrite all the DelimitedDataString stuff so as to return vectors of individual cell strings rather than having the classes add the delimiters themselves. Rename accordingly to names based on StringExport. Take advantage of this in the CSV writer code so as to properly quote cells that contain delimiter characters.
author Chris Cannam
date Fri, 03 Apr 2020 17:11:05 +0100
parents dbd13eb7dad1
children
rev   line source
Chris@386 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@386 2
Chris@386 3 /*
Chris@386 4 Sonic Visualiser
Chris@386 5 An audio file viewer and annotation editor.
Chris@386 6 Centre for Digital Music, Queen Mary, University of London.
Chris@386 7 This file copyright 2006 Chris Cannam and QMUL.
Chris@386 8
Chris@386 9 This program is free software; you can redistribute it and/or
Chris@386 10 modify it under the terms of the GNU General Public License as
Chris@386 11 published by the Free Software Foundation; either version 2 of the
Chris@386 12 License, or (at your option) any later version. See the file
Chris@386 13 COPYING included with this distribution for more information.
Chris@386 14 */
Chris@386 15
Chris@386 16 #include "AudioFileReaderFactory.h"
Chris@386 17
Chris@386 18 #include "WavFileReader.h"
Chris@823 19 #include "DecodingWavFileReader.h"
Chris@386 20 #include "MP3FileReader.h"
Chris@1583 21 #include "BQAFileReader.h"
Chris@1098 22 #include "AudioFileSizeEstimator.h"
Chris@1098 23
Chris@1098 24 #include "base/StorageAdviser.h"
Chris@386 25
Chris@386 26 #include <QString>
Chris@386 27 #include <QFileInfo>
Chris@386 28 #include <iostream>
Chris@386 29
Chris@1583 30 using namespace std;
Chris@1583 31
Chris@386 32 QString
Chris@386 33 AudioFileReaderFactory::getKnownExtensions()
Chris@386 34 {
Chris@1583 35 set<QString> extensions;
Chris@386 36
Chris@386 37 WavFileReader::getSupportedExtensions(extensions);
Chris@386 38 #ifdef HAVE_MAD
Chris@386 39 MP3FileReader::getSupportedExtensions(extensions);
Chris@386 40 #endif
Chris@1583 41 BQAFileReader::getSupportedExtensions(extensions);
Chris@386 42
Chris@386 43 QString rv;
Chris@1583 44 for (set<QString>::const_iterator i = extensions.begin();
Chris@386 45 i != extensions.end(); ++i) {
Chris@386 46 if (i != extensions.begin()) rv += " ";
Chris@386 47 rv += "*." + *i;
Chris@386 48 }
Chris@386 49
Chris@386 50 return rv;
Chris@386 51 }
Chris@386 52
Chris@1592 53 bool
Chris@1592 54 AudioFileReaderFactory::isSupported(FileSource source)
Chris@1592 55 {
Chris@1592 56 #ifdef HAVE_MAD
Chris@1592 57 if (MP3FileReader::supports(source)) {
Chris@1592 58 return true;
Chris@1592 59 }
Chris@1592 60 #endif
Chris@1592 61 if (WavFileReader::supports(source)) {
Chris@1592 62 return true;
Chris@1592 63 }
Chris@1592 64 if (BQAFileReader::supports(source)) {
Chris@1592 65 return true;
Chris@1592 66 }
Chris@1592 67 return false;
Chris@1592 68 }
Chris@1592 69
Chris@386 70 AudioFileReader *
Chris@1313 71 AudioFileReaderFactory::createReader(FileSource source,
Chris@1313 72 Parameters params,
Chris@392 73 ProgressReporter *reporter)
Chris@386 74 {
Chris@386 75 QString err;
Chris@386 76
Chris@1342 77 SVDEBUG << "AudioFileReaderFactory: url \"" << source.getLocation() << "\": requested rate: " << params.targetRate << (params.targetRate == 0 ? " (use source rate)" : "") << endl;
Chris@1342 78 SVDEBUG << "AudioFileReaderFactory: local filename \"" << source.getLocalFilename() << "\", content type \"" << source.getContentType() << "\"" << endl;
Chris@386 79
Chris@667 80 if (!source.isOK()) {
Chris@1698 81 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Failed to retrieve source (transmission error?): " << source.getErrorString() << endl;
Chris@1582 82 return nullptr;
Chris@667 83 }
Chris@667 84
Chris@667 85 if (!source.isAvailable()) {
Chris@1698 86 SVDEBUG << "AudioFileReaderFactory::createReader(\"" << source.getLocation() << "\": Source not found" << endl;
Chris@1582 87 return nullptr;
Chris@386 88 }
Chris@386 89
Chris@1582 90 AudioFileReader *reader = nullptr;
Chris@386 91
Chris@1313 92 sv_samplerate_t targetRate = params.targetRate;
Chris@1313 93 bool normalised = (params.normalisation == Normalisation::Peak);
Chris@1313 94
Chris@1098 95 sv_frame_t estimatedSamples =
Chris@1098 96 AudioFileSizeEstimator::estimate(source, targetRate);
Chris@1098 97
Chris@1097 98 CodedAudioFileReader::CacheMode cacheMode =
Chris@1097 99 CodedAudioFileReader::CacheInTemporaryFile;
Chris@1097 100
Chris@1098 101 if (estimatedSamples > 0) {
Chris@1098 102 size_t kb = (estimatedSamples * sizeof(float)) / 1024;
Chris@1342 103 SVDEBUG << "AudioFileReaderFactory: checking where to potentially cache "
Chris@1342 104 << kb << "K of sample data" << endl;
Chris@1098 105 StorageAdviser::Recommendation rec =
Chris@1098 106 StorageAdviser::recommend(StorageAdviser::SpeedCritical, kb, kb);
Chris@1277 107 if ((rec & StorageAdviser::UseMemory) ||
Chris@1277 108 (rec & StorageAdviser::PreferMemory)) {
Chris@1342 109 SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) in memory" << endl;
Chris@1098 110 cacheMode = CodedAudioFileReader::CacheInMemory;
Chris@1342 111 } else {
Chris@1342 112 SVDEBUG << "AudioFileReaderFactory: cacheing (if at all) on disc" << endl;
Chris@1098 113 }
Chris@1098 114 }
Chris@1098 115
Chris@1097 116 CodedAudioFileReader::DecodeMode decodeMode =
Chris@1313 117 (params.threadingMode == ThreadingMode::Threaded ?
Chris@1097 118 CodedAudioFileReader::DecodeThreaded :
Chris@1097 119 CodedAudioFileReader::DecodeAtOnce);
Chris@386 120
Chris@1313 121 // We go through the set of supported readers at most twice: once
Chris@1313 122 // picking out only the readers that claim to support the given
Chris@1313 123 // file's extension or MIME type, and (if that fails) again
Chris@1313 124 // providing the file to every reader in turn regardless of
Chris@1313 125 // extension or type. (If none of the readers claim to support a
Chris@1313 126 // file, that may just mean its extension is missing or
Chris@1313 127 // misleading. We have to be confident that the reader won't open
Chris@1313 128 // just any old text file or whatever and pretend it's succeeded.)
Chris@1097 129
Chris@1313 130 for (int any = 0; any <= 1; ++any) {
Chris@386 131
Chris@1313 132 bool anyReader = (any > 0);
Chris@386 133
Chris@1342 134 if (!anyReader) {
Chris@1342 135 SVDEBUG << "AudioFileReaderFactory: Checking whether any reader officially handles this source" << endl;
Chris@1342 136 } else {
Chris@1342 137 SVDEBUG << "AudioFileReaderFactory: Source not officially handled by any reader, trying again with each reader in turn"
Chris@1342 138 << endl;
Chris@1342 139 }
Chris@1359 140
Chris@1583 141 #ifdef HAVE_MAD
Chris@1592 142 // Having said we'll try any reader on the second pass, we
Chris@1592 143 // actually don't want to try the mp3 reader for anything not
Chris@1592 144 // identified as an mp3 - it can't identify files by header,
Chris@1592 145 // it'll try to read any data and then fail with
Chris@1592 146 // synchronisation errors - causing misleading and potentially
Chris@1592 147 // alarming warning messages at the least
Chris@1592 148 if (!anyReader) {
Chris@1592 149 if (MP3FileReader::supports(source)) {
Chris@1359 150
Chris@1592 151 MP3FileReader::GaplessMode gapless =
Chris@1592 152 params.gaplessMode == GaplessMode::Gapless ?
Chris@1592 153 MP3FileReader::GaplessMode::Gapless :
Chris@1592 154 MP3FileReader::GaplessMode::Gappy;
Chris@1583 155
Chris@1592 156 reader = new MP3FileReader
Chris@1592 157 (source, decodeMode, cacheMode, gapless,
Chris@1592 158 targetRate, normalised, reporter);
Chris@1359 159
Chris@1592 160 if (reader->isOK()) {
Chris@1592 161 SVDEBUG << "AudioFileReaderFactory: MP3 file reader is OK, returning it" << endl;
Chris@1592 162 return reader;
Chris@1592 163 } else {
Chris@1592 164 delete reader;
Chris@1592 165 }
Chris@1359 166 }
Chris@1359 167 }
Chris@1359 168 #endif
Chris@1342 169
Chris@1313 170 if (anyReader || WavFileReader::supports(source)) {
Chris@386 171
Chris@1313 172 reader = new WavFileReader(source);
Chris@823 173
Chris@1313 174 sv_samplerate_t fileRate = reader->getSampleRate();
Chris@1313 175
Chris@1313 176 if (reader->isOK() &&
Chris@1313 177 (!reader->isQuicklySeekable() ||
Chris@1313 178 normalised ||
Chris@1313 179 (cacheMode == CodedAudioFileReader::CacheInMemory) ||
Chris@1313 180 (targetRate != 0 && fileRate != targetRate))) {
Chris@1313 181
Chris@1342 182 SVDEBUG << "AudioFileReaderFactory: WAV file reader rate: " << reader->getSampleRate() << ", normalised " << normalised << ", seekable " << reader->isQuicklySeekable() << ", in memory " << (cacheMode == CodedAudioFileReader::CacheInMemory) << ", creating decoding reader" << endl;
Chris@1161 183
Chris@1313 184 delete reader;
Chris@1313 185 reader = new DecodingWavFileReader
Chris@1313 186 (source,
Chris@1313 187 decodeMode, cacheMode,
Chris@1313 188 targetRate ? targetRate : fileRate,
Chris@1313 189 normalised,
Chris@1313 190 reporter);
Chris@1313 191 }
Chris@1313 192
Chris@1313 193 if (reader->isOK()) {
Chris@1342 194 SVDEBUG << "AudioFileReaderFactory: WAV file reader is OK, returning it" << endl;
Chris@1313 195 return reader;
Chris@1313 196 } else {
Chris@1313 197 delete reader;
Chris@1313 198 }
Chris@386 199 }
Chris@1592 200
Chris@1592 201 if (anyReader || BQAFileReader::supports(source)) {
Chris@386 202
Chris@1592 203 reader = new BQAFileReader
Chris@1592 204 (source, decodeMode, cacheMode,
Chris@1313 205 targetRate, normalised, reporter);
Chris@1313 206
Chris@1313 207 if (reader->isOK()) {
Chris@1592 208 SVDEBUG << "AudioFileReaderFactory: BQA reader is OK, returning it" << endl;
Chris@1313 209 return reader;
Chris@1313 210 } else {
Chris@1313 211 delete reader;
Chris@1313 212 }
Chris@1313 213 }
Chris@1097 214 }
Chris@1097 215
Chris@1698 216 SVDEBUG << "AudioFileReaderFactory::Failed to create a reader for "
Chris@1698 217 << "url \"" << source.getLocation()
Chris@1698 218 << "\" (local filename \"" << source.getLocalFilename()
Chris@1698 219 << "\", content type \""
Chris@1698 220 << source.getContentType() << "\")" << endl;
Chris@1313 221 return nullptr;
Chris@386 222 }
Chris@386 223