annotate data/fileio/MatchFileReader.cpp @ 823:f0558e69a074

Rename Resampling- to DecodingWavFileReader, and use it whenever we have an audio file that is not quickly seekable using libsndfile. Avoids very slow performance when analysing ogg files.
author Chris Cannam
date Wed, 17 Jul 2013 15:40:01 +0100
parents 1424aa29ae95
children e802e550a1f2
rev   line source
Chris@297 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@297 2
Chris@297 3 /*
Chris@297 4 Sonic Visualiser
Chris@297 5 An audio file viewer and annotation editor.
Chris@297 6 Centre for Digital Music, Queen Mary, University of London.
Chris@297 7 This file copyright 2007 QMUL.
Chris@297 8
Chris@297 9 This program is free software; you can redistribute it and/or
Chris@297 10 modify it under the terms of the GNU General Public License as
Chris@297 11 published by the Free Software Foundation; either version 2 of the
Chris@297 12 License, or (at your option) any later version. See the file
Chris@297 13 COPYING included with this distribution for more information.
Chris@297 14 */
Chris@297 15
Chris@297 16 #include "MatchFileReader.h"
Chris@297 17
Chris@297 18 #include <QFile>
Chris@297 19 #include <QTextStream>
Chris@297 20
Chris@297 21 #include <cmath>
Chris@297 22 #include <iostream>
Chris@297 23
Chris@297 24 Alignment::Alignment() :
Chris@297 25 thisHopTime(0.0),
Chris@297 26 refHopTime(0.0)
Chris@297 27 {
Chris@297 28 }
Chris@297 29
Chris@297 30 double
Chris@297 31 Alignment::fromReference(double t) const
Chris@297 32 {
Chris@297 33 int ri = lrint(t / refHopTime);
Chris@297 34 int index = search(refIndex, ri);
Chris@297 35 return thisIndex[index] * thisHopTime;
Chris@297 36 }
Chris@297 37
Chris@297 38 double
Chris@297 39 Alignment::toReference(double t) const
Chris@297 40 {
Chris@297 41 int ti = lrint(t / thisHopTime);
Chris@297 42 int index = search(thisIndex, ti);
Chris@297 43 return refIndex[index] * refHopTime;
Chris@297 44 }
Chris@297 45
Chris@297 46 int
Chris@297 47 Alignment::search(const FrameArray &arr, int val) const
Chris@297 48 {
Chris@297 49 int len = arr.size();
Chris@297 50 int max = len - 1;
Chris@297 51 int min = 0;
Chris@297 52 while (max > min) {
Chris@297 53 int mid = (max + min) / 2;
Chris@297 54 if (val > arr[mid]) {
Chris@297 55 min = mid + 1;
Chris@297 56 } else {
Chris@297 57 max = mid;
Chris@297 58 }
Chris@297 59 } // max = MIN_j (arr[j] >= val) i.e. the first equal or next highest
Chris@297 60 while ((max + 1 < len) && (arr[max + 1] == val)) {
Chris@297 61 max++;
Chris@297 62 }
Chris@297 63 return (min + max) / 2;
Chris@297 64 }
Chris@297 65
Chris@297 66 MatchFileReader::MatchFileReader(QString path) :
Chris@297 67 m_file(0)
Chris@297 68 {
Chris@297 69 m_file = new QFile(path);
Chris@297 70 bool good = false;
Chris@297 71
Chris@297 72 if (!m_file->exists()) {
Chris@297 73 m_error = QFile::tr("File \"%1\" does not exist").arg(path);
Chris@297 74 } else if (!m_file->open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@297 75 m_error = QFile::tr("Failed to open file \"%1\"").arg(path);
Chris@297 76 } else {
Chris@297 77 good = true;
Chris@297 78 }
Chris@297 79
Chris@297 80 if (!good) {
Chris@297 81 delete m_file;
Chris@297 82 m_file = 0;
Chris@297 83 }
Chris@297 84 }
Chris@297 85
Chris@297 86 MatchFileReader::~MatchFileReader()
Chris@297 87 {
Chris@297 88 if (m_file) {
Chris@690 89 SVDEBUG << "MatchFileReader::MatchFileReader: Closing file" << endl;
Chris@297 90 m_file->close();
Chris@297 91 }
Chris@297 92 delete m_file;
Chris@297 93 }
Chris@297 94
Chris@297 95 bool
Chris@297 96 MatchFileReader::isOK() const
Chris@297 97 {
Chris@297 98 return (m_file != 0);
Chris@297 99 }
Chris@297 100
Chris@297 101 QString
Chris@297 102 MatchFileReader::getError() const
Chris@297 103 {
Chris@297 104 return m_error;
Chris@297 105 }
Chris@297 106
Chris@297 107 Alignment
Chris@297 108 MatchFileReader::load() const
Chris@297 109 {
Chris@297 110 Alignment alignment;
Chris@297 111
Chris@297 112 if (!m_file) return alignment;
Chris@297 113
Chris@297 114 QTextStream in(m_file);
Chris@297 115
Chris@297 116 /*
Chris@297 117 File: /home/studio/match-test/mahler-3-boulez-5.wav
Chris@297 118 Marks: -1
Chris@297 119 FixedPoints: true 0
Chris@297 120 0
Chris@297 121 0
Chris@297 122 0
Chris@297 123 0
Chris@297 124 File: /home/studio/match-test/mahler-3-haitink-5.wav
Chris@297 125 Marks: 0
Chris@297 126 FixedPoints: true 0
Chris@297 127 0.02
Chris@297 128 0.02
Chris@297 129 12836
Chris@297 130 */
Chris@297 131
Chris@297 132 int fileCount = 0;
Chris@297 133 int state = 0;
Chris@297 134 int count = 0;
Chris@297 135
Chris@297 136 while (!in.atEnd()) {
Chris@297 137
Chris@297 138 QString line = in.readLine().trimmed();
Chris@297 139 if (line.startsWith("File: ")) {
Chris@297 140 ++fileCount;
Chris@297 141 continue;
Chris@297 142 }
Chris@297 143 if (fileCount != 2) continue;
Chris@297 144 if (line.startsWith("Marks:") || line.startsWith("FixedPoints:")) {
Chris@297 145 continue;
Chris@297 146 }
Chris@297 147
Chris@297 148 switch (state) {
Chris@297 149 case 0:
Chris@297 150 alignment.thisHopTime = line.toDouble();
Chris@297 151 break;
Chris@297 152 case 1:
Chris@297 153 alignment.refHopTime = line.toDouble();
Chris@297 154 break;
Chris@297 155 case 2:
Chris@297 156 count = line.toInt();
Chris@297 157 break;
Chris@297 158 case 3:
Chris@297 159 alignment.thisIndex.push_back(line.toInt());
Chris@297 160 break;
Chris@297 161 case 4:
Chris@297 162 alignment.refIndex.push_back(line.toInt());
Chris@297 163 break;
Chris@297 164 }
Chris@297 165
Chris@297 166 if (state < 3) ++state;
Chris@297 167 else if (state == 3 && alignment.thisIndex.size() == count) ++state;
Chris@297 168 }
Chris@297 169
Chris@297 170 if (alignment.thisHopTime == 0.0) {
Chris@297 171 std::cerr << "ERROR in Match file: this hop time == 0, using 0.01 instead" << std::endl;
Chris@297 172 alignment.thisHopTime = 0.01;
Chris@297 173 }
Chris@297 174
Chris@297 175 if (alignment.refHopTime == 0.0) {
Chris@297 176 std::cerr << "ERROR in Match file: ref hop time == 0, using 0.01 instead" << std::endl;
Chris@297 177 alignment.refHopTime = 0.01;
Chris@297 178 }
Chris@297 179
Chris@297 180 std::cerr << "MatchFileReader: this hop = " << alignment.thisHopTime << ", ref hop = " << alignment.refHopTime << ", this index count = " << alignment.thisIndex.size() << ", ref index count = " << alignment.refIndex.size() << std::endl;
Chris@297 181
Chris@297 182 return alignment;
Chris@297 183 }