annotate data/fileio/MatchFileReader.cpp @ 301:73537d900d4b

* Add MIDI file export (closes FR#1643721)
author Chris Cannam
date Thu, 04 Oct 2007 11:52:38 +0000
parents c022976d18e8
children 06f13a3b9e9e
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@297 89 std::cerr << "MatchFileReader::MatchFileReader: Closing file" << std::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 }