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 }
|