annotate data/fileio/MatchFileReader.cpp @ 1008:d9e0e59a1581

When using an aggregate model to pass data to a transform, zero-pad the shorter input to the duration of the longer rather than truncating the longer. (This is better behaviour for e.g. MATCH, and in any case the code was previously truncating incorrectly and ending up with garbage data at the end.)
author Chris Cannam
date Fri, 14 Nov 2014 13:51:33 +0000
parents 0a35adfb7b16
children
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@967 26 refHopTime(0.0),
Chris@967 27 m_mainModel(0)
Chris@297 28 {
Chris@297 29 }
Chris@297 30
Chris@297 31 double
Chris@297 32 Alignment::fromReference(double t) const
Chris@297 33 {
Chris@297 34 int ri = lrint(t / refHopTime);
Chris@297 35 int index = search(refIndex, ri);
Chris@297 36 return thisIndex[index] * thisHopTime;
Chris@297 37 }
Chris@297 38
Chris@297 39 double
Chris@297 40 Alignment::toReference(double t) const
Chris@297 41 {
Chris@297 42 int ti = lrint(t / thisHopTime);
Chris@297 43 int index = search(thisIndex, ti);
Chris@297 44 return refIndex[index] * refHopTime;
Chris@297 45 }
Chris@297 46
Chris@297 47 int
Chris@297 48 Alignment::search(const FrameArray &arr, int val) const
Chris@297 49 {
Chris@297 50 int len = arr.size();
Chris@297 51 int max = len - 1;
Chris@297 52 int min = 0;
Chris@297 53 while (max > min) {
Chris@297 54 int mid = (max + min) / 2;
Chris@297 55 if (val > arr[mid]) {
Chris@297 56 min = mid + 1;
Chris@297 57 } else {
Chris@297 58 max = mid;
Chris@297 59 }
Chris@297 60 } // max = MIN_j (arr[j] >= val) i.e. the first equal or next highest
Chris@297 61 while ((max + 1 < len) && (arr[max + 1] == val)) {
Chris@297 62 max++;
Chris@297 63 }
Chris@297 64 return (min + max) / 2;
Chris@297 65 }
Chris@297 66
Chris@297 67 MatchFileReader::MatchFileReader(QString path) :
Chris@297 68 m_file(0)
Chris@297 69 {
Chris@297 70 m_file = new QFile(path);
Chris@297 71 bool good = false;
Chris@297 72
Chris@297 73 if (!m_file->exists()) {
Chris@297 74 m_error = QFile::tr("File \"%1\" does not exist").arg(path);
Chris@297 75 } else if (!m_file->open(QIODevice::ReadOnly | QIODevice::Text)) {
Chris@297 76 m_error = QFile::tr("Failed to open file \"%1\"").arg(path);
Chris@297 77 } else {
Chris@297 78 good = true;
Chris@297 79 }
Chris@297 80
Chris@297 81 if (!good) {
Chris@297 82 delete m_file;
Chris@297 83 m_file = 0;
Chris@297 84 }
Chris@297 85 }
Chris@297 86
Chris@297 87 MatchFileReader::~MatchFileReader()
Chris@297 88 {
Chris@297 89 if (m_file) {
Chris@690 90 SVDEBUG << "MatchFileReader::MatchFileReader: Closing file" << endl;
Chris@297 91 m_file->close();
Chris@297 92 }
Chris@297 93 delete m_file;
Chris@297 94 }
Chris@297 95
Chris@297 96 bool
Chris@297 97 MatchFileReader::isOK() const
Chris@297 98 {
Chris@297 99 return (m_file != 0);
Chris@297 100 }
Chris@297 101
Chris@297 102 QString
Chris@297 103 MatchFileReader::getError() const
Chris@297 104 {
Chris@297 105 return m_error;
Chris@297 106 }
Chris@297 107
Chris@297 108 Alignment
Chris@297 109 MatchFileReader::load() const
Chris@297 110 {
Chris@297 111 Alignment alignment;
Chris@297 112
Chris@297 113 if (!m_file) return alignment;
Chris@297 114
Chris@297 115 QTextStream in(m_file);
Chris@297 116
Chris@297 117 /*
Chris@297 118 File: /home/studio/match-test/mahler-3-boulez-5.wav
Chris@297 119 Marks: -1
Chris@297 120 FixedPoints: true 0
Chris@297 121 0
Chris@297 122 0
Chris@297 123 0
Chris@297 124 0
Chris@297 125 File: /home/studio/match-test/mahler-3-haitink-5.wav
Chris@297 126 Marks: 0
Chris@297 127 FixedPoints: true 0
Chris@297 128 0.02
Chris@297 129 0.02
Chris@297 130 12836
Chris@297 131 */
Chris@297 132
Chris@297 133 int fileCount = 0;
Chris@297 134 int state = 0;
Chris@297 135 int count = 0;
Chris@297 136
Chris@297 137 while (!in.atEnd()) {
Chris@297 138
Chris@297 139 QString line = in.readLine().trimmed();
Chris@297 140 if (line.startsWith("File: ")) {
Chris@297 141 ++fileCount;
Chris@297 142 continue;
Chris@297 143 }
Chris@297 144 if (fileCount != 2) continue;
Chris@297 145 if (line.startsWith("Marks:") || line.startsWith("FixedPoints:")) {
Chris@297 146 continue;
Chris@297 147 }
Chris@297 148
Chris@297 149 switch (state) {
Chris@297 150 case 0:
Chris@297 151 alignment.thisHopTime = line.toDouble();
Chris@297 152 break;
Chris@297 153 case 1:
Chris@297 154 alignment.refHopTime = line.toDouble();
Chris@297 155 break;
Chris@297 156 case 2:
Chris@297 157 count = line.toInt();
Chris@297 158 break;
Chris@297 159 case 3:
Chris@297 160 alignment.thisIndex.push_back(line.toInt());
Chris@297 161 break;
Chris@297 162 case 4:
Chris@297 163 alignment.refIndex.push_back(line.toInt());
Chris@297 164 break;
Chris@297 165 }
Chris@297 166
Chris@929 167 if (state < 3) {
Chris@929 168 ++state;
Chris@929 169 } else if (state == 3 && int(alignment.thisIndex.size()) == count) {
Chris@929 170 ++state;
Chris@929 171 }
Chris@297 172 }
Chris@297 173
Chris@297 174 if (alignment.thisHopTime == 0.0) {
Chris@843 175 cerr << "ERROR in Match file: this hop time == 0, using 0.01 instead" << endl;
Chris@297 176 alignment.thisHopTime = 0.01;
Chris@297 177 }
Chris@297 178
Chris@297 179 if (alignment.refHopTime == 0.0) {
Chris@843 180 cerr << "ERROR in Match file: ref hop time == 0, using 0.01 instead" << endl;
Chris@297 181 alignment.refHopTime = 0.01;
Chris@297 182 }
Chris@297 183
Chris@843 184 cerr << "MatchFileReader: this hop = " << alignment.thisHopTime << ", ref hop = " << alignment.refHopTime << ", this index count = " << alignment.thisIndex.size() << ", ref index count = " << alignment.refIndex.size() << endl;
Chris@297 185
Chris@297 186 return alignment;
Chris@297 187 }