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@843
|
171 cerr << "ERROR in Match file: this hop time == 0, using 0.01 instead" << endl;
|
Chris@297
|
172 alignment.thisHopTime = 0.01;
|
Chris@297
|
173 }
|
Chris@297
|
174
|
Chris@297
|
175 if (alignment.refHopTime == 0.0) {
|
Chris@843
|
176 cerr << "ERROR in Match file: ref hop time == 0, using 0.01 instead" << endl;
|
Chris@297
|
177 alignment.refHopTime = 0.01;
|
Chris@297
|
178 }
|
Chris@297
|
179
|
Chris@843
|
180 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
|
181
|
Chris@297
|
182 return alignment;
|
Chris@297
|
183 }
|