Chris@1098: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*-  vi:set ts=8 sts=4 sw=4: */
Chris@1098: 
Chris@1098: /*
Chris@1098:     Sonic Visualiser
Chris@1098:     An audio file viewer and annotation editor.
Chris@1098:     Centre for Digital Music, Queen Mary, University of London.
Chris@1098:     
Chris@1098:     This program is free software; you can redistribute it and/or
Chris@1098:     modify it under the terms of the GNU General Public License as
Chris@1098:     published by the Free Software Foundation; either version 2 of the
Chris@1098:     License, or (at your option) any later version.  See the file
Chris@1098:     COPYING included with this distribution for more information.
Chris@1098: */
Chris@1098: 
Chris@1098: #include "AudioFileSizeEstimator.h"
Chris@1098: 
Chris@1098: #include "WavFileReader.h"
Chris@1098: 
Chris@1098: #include <QFile>
Chris@1098: 
Chris@1342: #include "base/Debug.h"
Chris@1104: 
Chris@1098: sv_frame_t
Chris@1098: AudioFileSizeEstimator::estimate(FileSource source,
Chris@1341:                                  sv_samplerate_t targetRate)
Chris@1098: {
Chris@1098:     sv_frame_t estimate = 0;
Chris@1098:     
Chris@1342:     SVDEBUG << "AudioFileSizeEstimator: Sample count estimate requested for file \""
Chris@1342:             << source.getLocalFilename() << "\"" << endl;
Chris@1342: 
Chris@1098:     // Most of our file readers don't know the sample count until
Chris@1098:     // after they've finished decoding. This is an exception:
Chris@1098: 
Chris@1098:     WavFileReader *reader = new WavFileReader(source);
Chris@1098:     if (reader->isOK() &&
Chris@1341:         reader->getChannelCount() > 0 &&
Chris@1341:         reader->getFrameCount() > 0) {
Chris@1341:         sv_frame_t samples =
Chris@1341:             reader->getFrameCount() * reader->getChannelCount();
Chris@1341:         sv_samplerate_t rate = reader->getSampleRate();
Chris@1341:         if (targetRate != 0.0 && targetRate != rate) {
Chris@1341:             samples = sv_frame_t(double(samples) * targetRate / rate);
Chris@1341:         }
Chris@1342:         SVDEBUG << "AudioFileSizeEstimator: WAV file reader accepts this file, reports "
Chris@1342:                 << samples << " samples" << endl;
Chris@1341:         estimate = samples;
Chris@1342:     } else {
Chris@1342:         SVDEBUG << "AudioFileSizeEstimator: WAV file reader doesn't like this file, "
Chris@1342:                 << "estimating from file size and extension instead" << endl;
Chris@1098:     }
Chris@1098: 
Chris@1402:     delete reader;
Chris@1582:     reader = nullptr;
Chris@1402: 
Chris@1098:     if (estimate == 0) {
Chris@1098: 
Chris@1341:         // The remainder just makes an estimate based on the file size
Chris@1341:         // and extension. We don't even know its sample rate at this
Chris@1341:         // point, so the following is a wild guess.
Chris@1341:         
Chris@1341:         double rateRatio = 1.0;
Chris@1341:         if (targetRate != 0.0) {
Chris@1341:             rateRatio = targetRate / 44100.0;
Chris@1341:         }
Chris@1098:     
Chris@1341:         QString extension = source.getExtension();
Chris@1098: 
Chris@1341:         source.waitForData();
Chris@1341:         if (!source.isOK()) return 0;
Chris@1098: 
Chris@1341:         sv_frame_t sz = 0;
Chris@1342: 
Chris@1341:         {
Chris@1341:             QFile f(source.getLocalFilename());
Chris@1341:             if (f.open(QFile::ReadOnly)) {
Chris@1342:                 SVDEBUG << "AudioFileSizeEstimator: opened file, size is "
Chris@1342:                         << f.size() << endl;
Chris@1341:                 sz = f.size();
Chris@1341:                 f.close();
Chris@1341:             }
Chris@1341:         }
Chris@1098: 
Chris@1341:         if (extension == "ogg" || extension == "oga" ||
Chris@1341:             extension == "m4a" || extension == "mp3" ||
Chris@1592:             extension == "wma" || extension == "opus") {
Chris@1098: 
Chris@1341:             // Usually a lossy file. Compression ratios can vary
Chris@1341:             // dramatically, but don't usually exceed about 20x compared
Chris@1341:             // to 16-bit PCM (e.g. a 128kbps mp3 has 11x ratio over WAV at
Chris@1341:             // 44.1kHz). We can estimate the number of samples to be file
Chris@1341:             // size x 20, divided by 2 as we're comparing with 16-bit PCM.
Chris@1098: 
Chris@1341:             estimate = sv_frame_t(double(sz) * 10 * rateRatio);
Chris@1341:         }
Chris@1098: 
Chris@1341:         if (extension == "flac") {
Chris@1341:         
Chris@1341:             // FLAC usually takes up a bit more than half the space of
Chris@1341:             // 16-bit PCM. So the number of 16-bit samples is roughly the
Chris@1341:             // same as the file size in bytes. As above, let's be
Chris@1341:             // conservative.
Chris@1098: 
Chris@1341:             estimate = sv_frame_t(double(sz) * 1.2 * rateRatio);
Chris@1341:         }
Chris@1098: 
Chris@1342:         SVDEBUG << "AudioFileSizeEstimator: for extension \""
Chris@1342:                 << extension << "\", estimate = " << estimate << " samples" << endl;
Chris@1098:     }
Chris@1098:     
Chris@1098:     return estimate;
Chris@1098: }
Chris@1098: