Chris@297: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ Chris@297: Chris@297: /* Chris@297: Sonic Visualiser Chris@297: An audio file viewer and annotation editor. Chris@297: Centre for Digital Music, Queen Mary, University of London. Chris@297: This file copyright 2007 QMUL. Chris@297: Chris@297: This program is free software; you can redistribute it and/or Chris@297: modify it under the terms of the GNU General Public License as Chris@297: published by the Free Software Foundation; either version 2 of the Chris@297: License, or (at your option) any later version. See the file Chris@297: COPYING included with this distribution for more information. Chris@297: */ Chris@297: Chris@297: #include "MatchFileReader.h" Chris@297: Chris@297: #include Chris@297: #include Chris@297: Chris@297: #include Chris@297: #include Chris@297: Chris@297: Alignment::Alignment() : Chris@297: thisHopTime(0.0), Chris@297: refHopTime(0.0) Chris@297: { Chris@297: } Chris@297: Chris@297: double Chris@297: Alignment::fromReference(double t) const Chris@297: { Chris@297: int ri = lrint(t / refHopTime); Chris@297: int index = search(refIndex, ri); Chris@297: return thisIndex[index] * thisHopTime; Chris@297: } Chris@297: Chris@297: double Chris@297: Alignment::toReference(double t) const Chris@297: { Chris@297: int ti = lrint(t / thisHopTime); Chris@297: int index = search(thisIndex, ti); Chris@297: return refIndex[index] * refHopTime; Chris@297: } Chris@297: Chris@297: int Chris@297: Alignment::search(const FrameArray &arr, int val) const Chris@297: { Chris@297: int len = arr.size(); Chris@297: int max = len - 1; Chris@297: int min = 0; Chris@297: while (max > min) { Chris@297: int mid = (max + min) / 2; Chris@297: if (val > arr[mid]) { Chris@297: min = mid + 1; Chris@297: } else { Chris@297: max = mid; Chris@297: } Chris@297: } // max = MIN_j (arr[j] >= val) i.e. the first equal or next highest Chris@297: while ((max + 1 < len) && (arr[max + 1] == val)) { Chris@297: max++; Chris@297: } Chris@297: return (min + max) / 2; Chris@297: } Chris@297: Chris@297: MatchFileReader::MatchFileReader(QString path) : Chris@297: m_file(0) Chris@297: { Chris@297: m_file = new QFile(path); Chris@297: bool good = false; Chris@297: Chris@297: if (!m_file->exists()) { Chris@297: m_error = QFile::tr("File \"%1\" does not exist").arg(path); Chris@297: } else if (!m_file->open(QIODevice::ReadOnly | QIODevice::Text)) { Chris@297: m_error = QFile::tr("Failed to open file \"%1\"").arg(path); Chris@297: } else { Chris@297: good = true; Chris@297: } Chris@297: Chris@297: if (!good) { Chris@297: delete m_file; Chris@297: m_file = 0; Chris@297: } Chris@297: } Chris@297: Chris@297: MatchFileReader::~MatchFileReader() Chris@297: { Chris@297: if (m_file) { Chris@297: std::cerr << "MatchFileReader::MatchFileReader: Closing file" << std::endl; Chris@297: m_file->close(); Chris@297: } Chris@297: delete m_file; Chris@297: } Chris@297: Chris@297: bool Chris@297: MatchFileReader::isOK() const Chris@297: { Chris@297: return (m_file != 0); Chris@297: } Chris@297: Chris@297: QString Chris@297: MatchFileReader::getError() const Chris@297: { Chris@297: return m_error; Chris@297: } Chris@297: Chris@297: Alignment Chris@297: MatchFileReader::load() const Chris@297: { Chris@297: Alignment alignment; Chris@297: Chris@297: if (!m_file) return alignment; Chris@297: Chris@297: QTextStream in(m_file); Chris@297: Chris@297: /* Chris@297: File: /home/studio/match-test/mahler-3-boulez-5.wav Chris@297: Marks: -1 Chris@297: FixedPoints: true 0 Chris@297: 0 Chris@297: 0 Chris@297: 0 Chris@297: 0 Chris@297: File: /home/studio/match-test/mahler-3-haitink-5.wav Chris@297: Marks: 0 Chris@297: FixedPoints: true 0 Chris@297: 0.02 Chris@297: 0.02 Chris@297: 12836 Chris@297: */ Chris@297: Chris@297: int fileCount = 0; Chris@297: int state = 0; Chris@297: int count = 0; Chris@297: Chris@297: while (!in.atEnd()) { Chris@297: Chris@297: QString line = in.readLine().trimmed(); Chris@297: if (line.startsWith("File: ")) { Chris@297: ++fileCount; Chris@297: continue; Chris@297: } Chris@297: if (fileCount != 2) continue; Chris@297: if (line.startsWith("Marks:") || line.startsWith("FixedPoints:")) { Chris@297: continue; Chris@297: } Chris@297: Chris@297: switch (state) { Chris@297: case 0: Chris@297: alignment.thisHopTime = line.toDouble(); Chris@297: break; Chris@297: case 1: Chris@297: alignment.refHopTime = line.toDouble(); Chris@297: break; Chris@297: case 2: Chris@297: count = line.toInt(); Chris@297: break; Chris@297: case 3: Chris@297: alignment.thisIndex.push_back(line.toInt()); Chris@297: break; Chris@297: case 4: Chris@297: alignment.refIndex.push_back(line.toInt()); Chris@297: break; Chris@297: } Chris@297: Chris@297: if (state < 3) ++state; Chris@297: else if (state == 3 && alignment.thisIndex.size() == count) ++state; Chris@297: } Chris@297: Chris@297: if (alignment.thisHopTime == 0.0) { Chris@297: std::cerr << "ERROR in Match file: this hop time == 0, using 0.01 instead" << std::endl; Chris@297: alignment.thisHopTime = 0.01; Chris@297: } Chris@297: Chris@297: if (alignment.refHopTime == 0.0) { Chris@297: std::cerr << "ERROR in Match file: ref hop time == 0, using 0.01 instead" << std::endl; Chris@297: alignment.refHopTime = 0.01; Chris@297: } Chris@297: Chris@297: 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: Chris@297: return alignment; Chris@297: }