lbajardsilogic@0
|
1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
|
lbajardsilogic@0
|
2
|
lbajardsilogic@0
|
3 /*
|
lbajardsilogic@0
|
4 Sonic Visualiser
|
lbajardsilogic@0
|
5 An audio file viewer and annotation editor.
|
lbajardsilogic@0
|
6 Centre for Digital Music, Queen Mary, University of London.
|
lbajardsilogic@0
|
7 This file copyright 2006 Chris Cannam.
|
lbajardsilogic@0
|
8
|
lbajardsilogic@0
|
9 This program is free software; you can redistribute it and/or
|
lbajardsilogic@0
|
10 modify it under the terms of the GNU General Public License as
|
lbajardsilogic@0
|
11 published by the Free Software Foundation; either version 2 of the
|
lbajardsilogic@0
|
12 License, or (at your option) any later version. See the file
|
lbajardsilogic@0
|
13 COPYING included with this distribution for more information.
|
lbajardsilogic@0
|
14 */
|
lbajardsilogic@189
|
15 #include "system/System.h"
|
lbajardsilogic@0
|
16
|
lbajardsilogic@189
|
17 #include <iostream>
|
lbajardsilogic@0
|
18
|
lbajardsilogic@0
|
19 #include <QFile>
|
lbajardsilogic@0
|
20 #include <QString>
|
lbajardsilogic@0
|
21 #include <QRegExp>
|
lbajardsilogic@0
|
22 #include <QStringList>
|
lbajardsilogic@0
|
23 #include <QTextStream>
|
lbajardsilogic@0
|
24 #include <QFrame>
|
lbajardsilogic@0
|
25 #include <QGridLayout>
|
lbajardsilogic@0
|
26 #include <QPushButton>
|
lbajardsilogic@0
|
27 #include <QHBoxLayout>
|
lbajardsilogic@0
|
28 #include <QVBoxLayout>
|
lbajardsilogic@0
|
29 #include <QTableWidget>
|
lbajardsilogic@0
|
30 #include <QComboBox>
|
lbajardsilogic@0
|
31 #include <QLabel>
|
lbajardsilogic@0
|
32
|
lbajardsilogic@189
|
33 #include "model/Model.h"
|
lbajardsilogic@189
|
34 #include "base/RealTime.h"
|
lbajardsilogic@189
|
35 #include "model/SparseOneDimensionalModel.h"
|
lbajardsilogic@189
|
36 #include "model/SparseTimeValueModel.h"
|
lbajardsilogic@189
|
37 #include "model/EditableDenseThreeDimensionalModel.h"
|
lbajardsilogic@189
|
38
|
lbajardsilogic@189
|
39 #include "CSVFileReader.h"
|
lbajardsilogic@0
|
40
|
lbajardsilogic@0
|
41 CSVFileReader::CSVFileReader(QString path, size_t mainModelSampleRate) :
|
lbajardsilogic@0
|
42 m_file(0),
|
lbajardsilogic@0
|
43 m_mainModelSampleRate(mainModelSampleRate)
|
lbajardsilogic@0
|
44 {
|
lbajardsilogic@0
|
45 m_file = new QFile(path);
|
lbajardsilogic@0
|
46 bool good = false;
|
lbajardsilogic@0
|
47
|
lbajardsilogic@0
|
48 if (!m_file->exists()) {
|
lbajardsilogic@0
|
49 m_error = QFile::tr("File \"%1\" does not exist").arg(path);
|
lbajardsilogic@0
|
50 } else if (!m_file->open(QIODevice::ReadOnly | QIODevice::Text)) {
|
lbajardsilogic@0
|
51 m_error = QFile::tr("Failed to open file \"%1\"").arg(path);
|
lbajardsilogic@0
|
52 } else {
|
lbajardsilogic@0
|
53 good = true;
|
lbajardsilogic@0
|
54 }
|
lbajardsilogic@0
|
55
|
lbajardsilogic@0
|
56 if (!good) {
|
lbajardsilogic@0
|
57 delete m_file;
|
lbajardsilogic@0
|
58 m_file = 0;
|
lbajardsilogic@0
|
59 }
|
lbajardsilogic@0
|
60 }
|
lbajardsilogic@0
|
61
|
lbajardsilogic@0
|
62 CSVFileReader::~CSVFileReader()
|
lbajardsilogic@0
|
63 {
|
lbajardsilogic@0
|
64 std::cerr << "CSVFileReader::~CSVFileReader: file is " << m_file << std::endl;
|
lbajardsilogic@0
|
65
|
lbajardsilogic@0
|
66 if (m_file) {
|
lbajardsilogic@0
|
67 std::cerr << "CSVFileReader::CSVFileReader: Closing file" << std::endl;
|
lbajardsilogic@0
|
68 m_file->close();
|
lbajardsilogic@0
|
69 }
|
lbajardsilogic@0
|
70 delete m_file;
|
lbajardsilogic@0
|
71 }
|
lbajardsilogic@0
|
72
|
lbajardsilogic@0
|
73 bool
|
lbajardsilogic@0
|
74 CSVFileReader::isOK() const
|
lbajardsilogic@0
|
75 {
|
lbajardsilogic@0
|
76 return (m_file != 0);
|
lbajardsilogic@0
|
77 }
|
lbajardsilogic@0
|
78
|
lbajardsilogic@0
|
79 QString
|
lbajardsilogic@0
|
80 CSVFileReader::getError() const
|
lbajardsilogic@0
|
81 {
|
lbajardsilogic@0
|
82 return m_error;
|
lbajardsilogic@0
|
83 }
|
lbajardsilogic@0
|
84
|
lbajardsilogic@0
|
85 Model *
|
lbajardsilogic@0
|
86 CSVFileReader::load() const
|
lbajardsilogic@0
|
87 {
|
lbajardsilogic@0
|
88 if (!m_file) return 0;
|
lbajardsilogic@0
|
89
|
lbajardsilogic@0
|
90 CSVFormatDialog *dialog = new CSVFormatDialog
|
lbajardsilogic@0
|
91 (0, m_file, m_mainModelSampleRate);
|
lbajardsilogic@0
|
92
|
lbajardsilogic@0
|
93 if (dialog->exec() == QDialog::Rejected) {
|
lbajardsilogic@0
|
94 delete dialog;
|
lbajardsilogic@0
|
95 return 0;
|
lbajardsilogic@0
|
96 }
|
lbajardsilogic@0
|
97
|
lbajardsilogic@0
|
98 CSVFormatDialog::ModelType modelType = dialog->getModelType();
|
lbajardsilogic@0
|
99 CSVFormatDialog::TimingType timingType = dialog->getTimingType();
|
lbajardsilogic@0
|
100 CSVFormatDialog::TimeUnits timeUnits = dialog->getTimeUnits();
|
lbajardsilogic@0
|
101 QString separator = dialog->getSeparator();
|
lbajardsilogic@0
|
102 size_t sampleRate = dialog->getSampleRate();
|
lbajardsilogic@0
|
103 size_t windowSize = dialog->getWindowSize();
|
lbajardsilogic@0
|
104
|
lbajardsilogic@0
|
105 delete dialog;
|
lbajardsilogic@0
|
106
|
lbajardsilogic@0
|
107 if (timingType == CSVFormatDialog::ExplicitTiming) {
|
lbajardsilogic@0
|
108 windowSize = 1;
|
lbajardsilogic@0
|
109 if (timeUnits == CSVFormatDialog::TimeSeconds) {
|
lbajardsilogic@0
|
110 sampleRate = m_mainModelSampleRate;
|
lbajardsilogic@0
|
111 }
|
lbajardsilogic@0
|
112 }
|
lbajardsilogic@0
|
113
|
lbajardsilogic@0
|
114 SparseOneDimensionalModel *model1 = 0;
|
lbajardsilogic@0
|
115 SparseTimeValueModel *model2 = 0;
|
lbajardsilogic@0
|
116 EditableDenseThreeDimensionalModel *model3 = 0;
|
lbajardsilogic@0
|
117 Model *model = 0;
|
lbajardsilogic@0
|
118
|
lbajardsilogic@0
|
119 QTextStream in(m_file);
|
lbajardsilogic@0
|
120 in.seek(0);
|
lbajardsilogic@0
|
121
|
lbajardsilogic@0
|
122 unsigned int warnings = 0, warnLimit = 10;
|
lbajardsilogic@0
|
123 unsigned int lineno = 0;
|
lbajardsilogic@0
|
124
|
lbajardsilogic@0
|
125 float min = 0.0, max = 0.0;
|
lbajardsilogic@0
|
126
|
lbajardsilogic@0
|
127 size_t frameNo = 0;
|
lbajardsilogic@0
|
128
|
lbajardsilogic@0
|
129 while (!in.atEnd()) {
|
lbajardsilogic@0
|
130
|
lbajardsilogic@0
|
131 QString line = in.readLine().trimmed();
|
lbajardsilogic@0
|
132 if (line.startsWith("#") || line.trimmed() == "") continue;
|
lbajardsilogic@0
|
133
|
lbajardsilogic@0
|
134 QStringList list = line.split(separator);
|
lbajardsilogic@0
|
135
|
lbajardsilogic@0
|
136 if (!model) {
|
lbajardsilogic@0
|
137
|
lbajardsilogic@0
|
138 switch (modelType) {
|
lbajardsilogic@0
|
139
|
lbajardsilogic@0
|
140 case CSVFormatDialog::OneDimensionalModel:
|
lbajardsilogic@0
|
141 model1 = new SparseOneDimensionalModel(sampleRate, windowSize);
|
lbajardsilogic@0
|
142 model = model1;
|
lbajardsilogic@0
|
143 break;
|
lbajardsilogic@0
|
144
|
lbajardsilogic@0
|
145 case CSVFormatDialog::TwoDimensionalModel:
|
lbajardsilogic@0
|
146 model2 = new SparseTimeValueModel(sampleRate, windowSize, false);
|
lbajardsilogic@0
|
147 model = model2;
|
lbajardsilogic@0
|
148 break;
|
lbajardsilogic@0
|
149
|
lbajardsilogic@0
|
150 case CSVFormatDialog::ThreeDimensionalModel:
|
lbajardsilogic@0
|
151 model3 = new EditableDenseThreeDimensionalModel(sampleRate,
|
lbajardsilogic@0
|
152 windowSize,
|
lbajardsilogic@0
|
153 list.size());
|
lbajardsilogic@0
|
154 model = model3;
|
lbajardsilogic@0
|
155 break;
|
lbajardsilogic@0
|
156 }
|
lbajardsilogic@0
|
157 }
|
lbajardsilogic@0
|
158
|
lbajardsilogic@0
|
159 QStringList tidyList;
|
lbajardsilogic@0
|
160 QRegExp nonNumericRx("[^0-9.,+-]");
|
lbajardsilogic@0
|
161
|
lbajardsilogic@0
|
162 for (int i = 0; i < list.size(); ++i) {
|
lbajardsilogic@0
|
163
|
lbajardsilogic@0
|
164 QString s(list[i].trimmed());
|
lbajardsilogic@0
|
165
|
lbajardsilogic@0
|
166 if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"")) {
|
lbajardsilogic@0
|
167 s = s.mid(1, s.length() - 2);
|
lbajardsilogic@0
|
168 } else if (s.length() >= 2 && s.startsWith("'") && s.endsWith("'")) {
|
lbajardsilogic@0
|
169 s = s.mid(1, s.length() - 2);
|
lbajardsilogic@0
|
170 }
|
lbajardsilogic@0
|
171
|
lbajardsilogic@0
|
172 if (i == 0 && timingType == CSVFormatDialog::ExplicitTiming) {
|
lbajardsilogic@0
|
173
|
lbajardsilogic@0
|
174 bool ok = false;
|
lbajardsilogic@0
|
175 QString numeric = s;
|
lbajardsilogic@0
|
176 numeric.remove(nonNumericRx);
|
lbajardsilogic@0
|
177
|
lbajardsilogic@0
|
178 if (timeUnits == CSVFormatDialog::TimeSeconds) {
|
lbajardsilogic@0
|
179
|
lbajardsilogic@0
|
180 double time = numeric.toDouble(&ok);
|
lbajardsilogic@0
|
181 frameNo = int(time * sampleRate + 0.00001);
|
lbajardsilogic@0
|
182
|
lbajardsilogic@0
|
183 } else {
|
lbajardsilogic@0
|
184
|
lbajardsilogic@0
|
185 frameNo = numeric.toInt(&ok);
|
lbajardsilogic@0
|
186
|
lbajardsilogic@0
|
187 if (timeUnits == CSVFormatDialog::TimeWindows) {
|
lbajardsilogic@0
|
188 frameNo *= windowSize;
|
lbajardsilogic@0
|
189 }
|
lbajardsilogic@0
|
190 }
|
lbajardsilogic@0
|
191
|
lbajardsilogic@0
|
192 if (!ok) {
|
lbajardsilogic@0
|
193 if (warnings < warnLimit) {
|
lbajardsilogic@0
|
194 std::cerr << "WARNING: CSVFileReader::load: "
|
lbajardsilogic@0
|
195 << "Bad time format (\"" << s.toStdString()
|
lbajardsilogic@0
|
196 << "\") in data line "
|
lbajardsilogic@0
|
197 << lineno << ":" << std::endl;
|
lbajardsilogic@0
|
198 std::cerr << line.toStdString() << std::endl;
|
lbajardsilogic@0
|
199 } else if (warnings == warnLimit) {
|
lbajardsilogic@0
|
200 std::cerr << "WARNING: Too many warnings" << std::endl;
|
lbajardsilogic@0
|
201 }
|
lbajardsilogic@0
|
202 ++warnings;
|
lbajardsilogic@0
|
203 }
|
lbajardsilogic@0
|
204 } else {
|
lbajardsilogic@0
|
205 tidyList.push_back(s);
|
lbajardsilogic@0
|
206 }
|
lbajardsilogic@0
|
207 }
|
lbajardsilogic@0
|
208
|
lbajardsilogic@0
|
209 if (modelType == CSVFormatDialog::OneDimensionalModel) {
|
lbajardsilogic@0
|
210
|
lbajardsilogic@0
|
211 SparseOneDimensionalModel::Point point
|
lbajardsilogic@0
|
212 (frameNo,
|
lbajardsilogic@0
|
213 tidyList.size() > 0 ? tidyList[tidyList.size()-1] :
|
lbajardsilogic@0
|
214 QString("%1").arg(lineno));
|
lbajardsilogic@0
|
215
|
lbajardsilogic@0
|
216 model1->addPoint(point);
|
lbajardsilogic@0
|
217
|
lbajardsilogic@0
|
218 } else if (modelType == CSVFormatDialog::TwoDimensionalModel) {
|
lbajardsilogic@0
|
219
|
lbajardsilogic@0
|
220 SparseTimeValueModel::Point point
|
lbajardsilogic@0
|
221 (frameNo,
|
lbajardsilogic@0
|
222 tidyList.size() > 0 ? tidyList[0].toFloat() : 0.0,
|
lbajardsilogic@0
|
223 tidyList.size() > 1 ? tidyList[1] : QString("%1").arg(lineno));
|
lbajardsilogic@0
|
224
|
lbajardsilogic@0
|
225 model2->addPoint(point);
|
lbajardsilogic@0
|
226
|
lbajardsilogic@0
|
227 } else if (modelType == CSVFormatDialog::ThreeDimensionalModel) {
|
lbajardsilogic@0
|
228
|
lbajardsilogic@0
|
229 DenseThreeDimensionalModel::Column values;
|
lbajardsilogic@0
|
230
|
lbajardsilogic@0
|
231 for (int i = 0; i < tidyList.size(); ++i) {
|
lbajardsilogic@0
|
232
|
lbajardsilogic@0
|
233 bool ok = false;
|
lbajardsilogic@0
|
234 float value = list[i].toFloat(&ok);
|
lbajardsilogic@0
|
235 values.push_back(value);
|
lbajardsilogic@0
|
236
|
lbajardsilogic@0
|
237 if ((lineno == 0 && i == 0) || value < min) min = value;
|
lbajardsilogic@0
|
238 if ((lineno == 0 && i == 0) || value > max) max = value;
|
lbajardsilogic@0
|
239
|
lbajardsilogic@0
|
240 if (!ok) {
|
lbajardsilogic@0
|
241 if (warnings < warnLimit) {
|
lbajardsilogic@0
|
242 std::cerr << "WARNING: CSVFileReader::load: "
|
lbajardsilogic@0
|
243 << "Non-numeric value in data line " << lineno
|
lbajardsilogic@0
|
244 << ":" << std::endl;
|
lbajardsilogic@0
|
245 std::cerr << line.toStdString() << std::endl;
|
lbajardsilogic@0
|
246 ++warnings;
|
lbajardsilogic@0
|
247 } else if (warnings == warnLimit) {
|
lbajardsilogic@0
|
248 std::cerr << "WARNING: Too many warnings" << std::endl;
|
lbajardsilogic@0
|
249 }
|
lbajardsilogic@0
|
250 }
|
lbajardsilogic@0
|
251 }
|
lbajardsilogic@0
|
252
|
lbajardsilogic@0
|
253 std::cerr << "Setting bin values for count " << lineno << ", frame "
|
lbajardsilogic@0
|
254 << frameNo << ", time " << RealTime::frame2RealTime(frameNo, sampleRate) << std::endl;
|
lbajardsilogic@0
|
255
|
lbajardsilogic@0
|
256 model3->setColumn(frameNo / model3->getResolution(), values);
|
lbajardsilogic@0
|
257 }
|
lbajardsilogic@0
|
258
|
lbajardsilogic@0
|
259 ++lineno;
|
lbajardsilogic@0
|
260 if (timingType == CSVFormatDialog::ImplicitTiming ||
|
lbajardsilogic@0
|
261 list.size() == 0) {
|
lbajardsilogic@0
|
262 frameNo += windowSize;
|
lbajardsilogic@0
|
263 }
|
lbajardsilogic@0
|
264 }
|
lbajardsilogic@0
|
265
|
lbajardsilogic@0
|
266 if (modelType == CSVFormatDialog::ThreeDimensionalModel) {
|
lbajardsilogic@0
|
267 model3->setMinimumLevel(min);
|
lbajardsilogic@0
|
268 model3->setMaximumLevel(max);
|
lbajardsilogic@0
|
269 }
|
lbajardsilogic@0
|
270
|
lbajardsilogic@0
|
271 return model;
|
lbajardsilogic@0
|
272 }
|
lbajardsilogic@0
|
273
|
lbajardsilogic@0
|
274
|
lbajardsilogic@0
|
275 CSVFormatDialog::CSVFormatDialog(QWidget *parent, QFile *file,
|
lbajardsilogic@0
|
276 size_t defaultSampleRate) :
|
lbajardsilogic@0
|
277 QDialog(parent),
|
lbajardsilogic@0
|
278 m_modelType(OneDimensionalModel),
|
lbajardsilogic@0
|
279 m_timingType(ExplicitTiming),
|
lbajardsilogic@0
|
280 m_timeUnits(TimeAudioFrames),
|
lbajardsilogic@0
|
281 m_separator("")
|
lbajardsilogic@0
|
282 {
|
lbajardsilogic@0
|
283 setModal(true);
|
lbajardsilogic@0
|
284 setWindowTitle(tr("Select Data Format"));
|
lbajardsilogic@0
|
285
|
lbajardsilogic@0
|
286 (void)guessFormat(file);
|
lbajardsilogic@0
|
287
|
lbajardsilogic@0
|
288 QGridLayout *layout = new QGridLayout;
|
lbajardsilogic@0
|
289
|
lbajardsilogic@0
|
290 layout->addWidget(new QLabel(tr("\nPlease select the correct data format for this file.\n")),
|
lbajardsilogic@0
|
291 0, 0, 1, 4);
|
lbajardsilogic@0
|
292
|
lbajardsilogic@0
|
293 layout->addWidget(new QLabel(tr("Each row specifies:")), 1, 0);
|
lbajardsilogic@0
|
294
|
lbajardsilogic@0
|
295 m_modelTypeCombo = new QComboBox;
|
lbajardsilogic@0
|
296 m_modelTypeCombo->addItem(tr("A point in time"));
|
lbajardsilogic@0
|
297 m_modelTypeCombo->addItem(tr("A value at a time"));
|
lbajardsilogic@0
|
298 m_modelTypeCombo->addItem(tr("A set of values"));
|
lbajardsilogic@0
|
299 layout->addWidget(m_modelTypeCombo, 1, 1, 1, 2);
|
lbajardsilogic@0
|
300 connect(m_modelTypeCombo, SIGNAL(activated(int)),
|
lbajardsilogic@0
|
301 this, SLOT(modelTypeChanged(int)));
|
lbajardsilogic@0
|
302 m_modelTypeCombo->setCurrentIndex(int(m_modelType));
|
lbajardsilogic@0
|
303
|
lbajardsilogic@0
|
304 layout->addWidget(new QLabel(tr("The first column contains:")), 2, 0);
|
lbajardsilogic@0
|
305
|
lbajardsilogic@0
|
306 m_timingTypeCombo = new QComboBox;
|
lbajardsilogic@0
|
307 m_timingTypeCombo->addItem(tr("Time, in seconds"));
|
lbajardsilogic@0
|
308 m_timingTypeCombo->addItem(tr("Time, in audio sample frames"));
|
lbajardsilogic@0
|
309 m_timingTypeCombo->addItem(tr("Data (rows are consecutive in time)"));
|
lbajardsilogic@0
|
310 layout->addWidget(m_timingTypeCombo, 2, 1, 1, 2);
|
lbajardsilogic@0
|
311 connect(m_timingTypeCombo, SIGNAL(activated(int)),
|
lbajardsilogic@0
|
312 this, SLOT(timingTypeChanged(int)));
|
lbajardsilogic@0
|
313 m_timingTypeCombo->setCurrentIndex(m_timingType == ExplicitTiming ?
|
lbajardsilogic@0
|
314 m_timeUnits == TimeSeconds ? 0 : 1 : 2);
|
lbajardsilogic@0
|
315
|
lbajardsilogic@0
|
316 m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
|
lbajardsilogic@0
|
317 layout->addWidget(m_sampleRateLabel, 3, 0);
|
lbajardsilogic@0
|
318
|
lbajardsilogic@0
|
319 size_t sampleRates[] = {
|
lbajardsilogic@0
|
320 8000, 11025, 12000, 22050, 24000, 32000,
|
lbajardsilogic@0
|
321 44100, 48000, 88200, 96000, 176400, 192000
|
lbajardsilogic@0
|
322 };
|
lbajardsilogic@0
|
323
|
lbajardsilogic@0
|
324 m_sampleRateCombo = new QComboBox;
|
lbajardsilogic@0
|
325 m_sampleRate = defaultSampleRate;
|
lbajardsilogic@0
|
326 for (size_t i = 0; i < sizeof(sampleRates) / sizeof(sampleRates[0]); ++i) {
|
lbajardsilogic@0
|
327 m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i]));
|
lbajardsilogic@0
|
328 if (sampleRates[i] == m_sampleRate) m_sampleRateCombo->setCurrentIndex(i);
|
lbajardsilogic@0
|
329 }
|
lbajardsilogic@0
|
330 m_sampleRateCombo->setEditable(true);
|
lbajardsilogic@0
|
331
|
lbajardsilogic@0
|
332 layout->addWidget(m_sampleRateCombo, 3, 1);
|
lbajardsilogic@0
|
333 connect(m_sampleRateCombo, SIGNAL(activated(QString)),
|
lbajardsilogic@0
|
334 this, SLOT(sampleRateChanged(QString)));
|
lbajardsilogic@0
|
335 connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
|
lbajardsilogic@0
|
336 this, SLOT(sampleRateChanged(QString)));
|
lbajardsilogic@0
|
337
|
lbajardsilogic@0
|
338 m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
|
lbajardsilogic@0
|
339 layout->addWidget(m_windowSizeLabel, 4, 0);
|
lbajardsilogic@0
|
340
|
lbajardsilogic@0
|
341 m_windowSizeCombo = new QComboBox;
|
lbajardsilogic@0
|
342 m_windowSize = 1024;
|
lbajardsilogic@0
|
343 for (int i = 0; i <= 16; ++i) {
|
lbajardsilogic@0
|
344 int value = 1 << i;
|
lbajardsilogic@0
|
345 m_windowSizeCombo->addItem(QString("%1").arg(value));
|
lbajardsilogic@0
|
346 if (value == int(m_windowSize)) m_windowSizeCombo->setCurrentIndex(i);
|
lbajardsilogic@0
|
347 }
|
lbajardsilogic@0
|
348 m_windowSizeCombo->setEditable(true);
|
lbajardsilogic@0
|
349
|
lbajardsilogic@0
|
350 layout->addWidget(m_windowSizeCombo, 4, 1);
|
lbajardsilogic@0
|
351 connect(m_windowSizeCombo, SIGNAL(activated(QString)),
|
lbajardsilogic@0
|
352 this, SLOT(windowSizeChanged(QString)));
|
lbajardsilogic@0
|
353 connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
|
lbajardsilogic@0
|
354 this, SLOT(windowSizeChanged(QString)));
|
lbajardsilogic@0
|
355
|
lbajardsilogic@0
|
356 layout->addWidget(new QLabel(tr("\nExample data from file:")), 5, 0, 1, 4);
|
lbajardsilogic@0
|
357
|
lbajardsilogic@189
|
358 m_exampleWidget = new QTableWidget(MIN(10, m_example.size()), m_maxExampleCols);
|
lbajardsilogic@0
|
359
|
lbajardsilogic@0
|
360 layout->addWidget(m_exampleWidget, 6, 0, 1, 4);
|
lbajardsilogic@0
|
361 layout->setColumnStretch(3, 10);
|
lbajardsilogic@0
|
362 layout->setRowStretch(4, 10);
|
lbajardsilogic@0
|
363
|
lbajardsilogic@0
|
364 QPushButton *ok = new QPushButton(tr("OK"));
|
lbajardsilogic@0
|
365 connect(ok, SIGNAL(clicked()), this, SLOT(accept()));
|
lbajardsilogic@0
|
366 ok->setDefault(true);
|
lbajardsilogic@0
|
367
|
lbajardsilogic@0
|
368 QPushButton *cancel = new QPushButton(tr("Cancel"));
|
lbajardsilogic@0
|
369 connect(cancel, SIGNAL(clicked()), this, SLOT(reject()));
|
lbajardsilogic@0
|
370
|
lbajardsilogic@0
|
371 QHBoxLayout *buttonLayout = new QHBoxLayout;
|
lbajardsilogic@0
|
372 buttonLayout->addStretch(1);
|
lbajardsilogic@0
|
373 buttonLayout->addWidget(ok);
|
lbajardsilogic@0
|
374 buttonLayout->addWidget(cancel);
|
lbajardsilogic@0
|
375
|
lbajardsilogic@0
|
376 QVBoxLayout *mainLayout = new QVBoxLayout;
|
lbajardsilogic@0
|
377 mainLayout->addLayout(layout);
|
lbajardsilogic@0
|
378 mainLayout->addLayout(buttonLayout);
|
lbajardsilogic@0
|
379
|
lbajardsilogic@0
|
380 setLayout(mainLayout);
|
lbajardsilogic@0
|
381
|
lbajardsilogic@0
|
382 timingTypeChanged(m_timingTypeCombo->currentIndex());
|
lbajardsilogic@0
|
383 }
|
lbajardsilogic@0
|
384
|
lbajardsilogic@0
|
385 CSVFormatDialog::~CSVFormatDialog()
|
lbajardsilogic@0
|
386 {
|
lbajardsilogic@0
|
387 }
|
lbajardsilogic@0
|
388
|
lbajardsilogic@0
|
389 void
|
lbajardsilogic@0
|
390 CSVFormatDialog::populateExample()
|
lbajardsilogic@0
|
391 {
|
lbajardsilogic@0
|
392 m_exampleWidget->setColumnCount
|
lbajardsilogic@0
|
393 (m_timingType == ExplicitTiming ?
|
lbajardsilogic@0
|
394 m_maxExampleCols - 1 : m_maxExampleCols);
|
lbajardsilogic@0
|
395
|
lbajardsilogic@0
|
396 m_exampleWidget->setHorizontalHeaderLabels(QStringList());
|
lbajardsilogic@0
|
397
|
lbajardsilogic@0
|
398 for (int i = 0; i < m_example.size(); ++i) {
|
lbajardsilogic@0
|
399 for (int j = 0; j < m_example[i].size(); ++j) {
|
lbajardsilogic@0
|
400
|
lbajardsilogic@0
|
401 QTableWidgetItem *item = new QTableWidgetItem(m_example[i][j]);
|
lbajardsilogic@0
|
402
|
lbajardsilogic@0
|
403 if (j == 0) {
|
lbajardsilogic@0
|
404 if (m_timingType == ExplicitTiming) {
|
lbajardsilogic@0
|
405 m_exampleWidget->setVerticalHeaderItem(i, item);
|
lbajardsilogic@0
|
406 continue;
|
lbajardsilogic@0
|
407 } else {
|
lbajardsilogic@0
|
408 QTableWidgetItem *header =
|
lbajardsilogic@0
|
409 new QTableWidgetItem(QString("%1").arg(i));
|
lbajardsilogic@0
|
410 header->setFlags(Qt::ItemIsEnabled);
|
lbajardsilogic@0
|
411 m_exampleWidget->setVerticalHeaderItem(i, header);
|
lbajardsilogic@0
|
412 }
|
lbajardsilogic@0
|
413 }
|
lbajardsilogic@0
|
414 int index = j;
|
lbajardsilogic@0
|
415 if (m_timingType == ExplicitTiming) --index;
|
lbajardsilogic@0
|
416 item->setFlags(Qt::ItemIsEnabled);
|
lbajardsilogic@0
|
417 m_exampleWidget->setItem(i, index, item);
|
lbajardsilogic@0
|
418 }
|
lbajardsilogic@0
|
419 }
|
lbajardsilogic@0
|
420 }
|
lbajardsilogic@0
|
421
|
lbajardsilogic@0
|
422 void
|
lbajardsilogic@0
|
423 CSVFormatDialog::modelTypeChanged(int type)
|
lbajardsilogic@0
|
424 {
|
lbajardsilogic@0
|
425 m_modelType = (ModelType)type;
|
lbajardsilogic@0
|
426
|
lbajardsilogic@0
|
427 if (m_modelType == ThreeDimensionalModel) {
|
lbajardsilogic@0
|
428 // We can't load 3d models with explicit timing, because the 3d
|
lbajardsilogic@0
|
429 // model is dense so we need a fixed sample increment
|
lbajardsilogic@0
|
430 m_timingTypeCombo->setCurrentIndex(2);
|
lbajardsilogic@0
|
431 timingTypeChanged(2);
|
lbajardsilogic@0
|
432 }
|
lbajardsilogic@0
|
433 }
|
lbajardsilogic@0
|
434
|
lbajardsilogic@0
|
435 void
|
lbajardsilogic@0
|
436 CSVFormatDialog::timingTypeChanged(int type)
|
lbajardsilogic@0
|
437 {
|
lbajardsilogic@0
|
438 switch (type) {
|
lbajardsilogic@0
|
439
|
lbajardsilogic@0
|
440 case 0:
|
lbajardsilogic@0
|
441 m_timingType = ExplicitTiming;
|
lbajardsilogic@0
|
442 m_timeUnits = TimeSeconds;
|
lbajardsilogic@0
|
443 m_sampleRateCombo->setEnabled(false);
|
lbajardsilogic@0
|
444 m_sampleRateLabel->setEnabled(false);
|
lbajardsilogic@0
|
445 m_windowSizeCombo->setEnabled(false);
|
lbajardsilogic@0
|
446 m_windowSizeLabel->setEnabled(false);
|
lbajardsilogic@0
|
447 if (m_modelType == ThreeDimensionalModel) {
|
lbajardsilogic@0
|
448 m_modelTypeCombo->setCurrentIndex(1);
|
lbajardsilogic@0
|
449 modelTypeChanged(1);
|
lbajardsilogic@0
|
450 }
|
lbajardsilogic@0
|
451 break;
|
lbajardsilogic@0
|
452
|
lbajardsilogic@0
|
453 case 1:
|
lbajardsilogic@0
|
454 m_timingType = ExplicitTiming;
|
lbajardsilogic@0
|
455 m_timeUnits = TimeAudioFrames;
|
lbajardsilogic@0
|
456 m_sampleRateCombo->setEnabled(true);
|
lbajardsilogic@0
|
457 m_sampleRateLabel->setEnabled(true);
|
lbajardsilogic@0
|
458 m_windowSizeCombo->setEnabled(false);
|
lbajardsilogic@0
|
459 m_windowSizeLabel->setEnabled(false);
|
lbajardsilogic@0
|
460 if (m_modelType == ThreeDimensionalModel) {
|
lbajardsilogic@0
|
461 m_modelTypeCombo->setCurrentIndex(1);
|
lbajardsilogic@0
|
462 modelTypeChanged(1);
|
lbajardsilogic@0
|
463 }
|
lbajardsilogic@0
|
464 break;
|
lbajardsilogic@0
|
465
|
lbajardsilogic@0
|
466 case 2:
|
lbajardsilogic@0
|
467 m_timingType = ImplicitTiming;
|
lbajardsilogic@0
|
468 m_timeUnits = TimeWindows;
|
lbajardsilogic@0
|
469 m_sampleRateCombo->setEnabled(true);
|
lbajardsilogic@0
|
470 m_sampleRateLabel->setEnabled(true);
|
lbajardsilogic@0
|
471 m_windowSizeCombo->setEnabled(true);
|
lbajardsilogic@0
|
472 m_windowSizeLabel->setEnabled(true);
|
lbajardsilogic@0
|
473 break;
|
lbajardsilogic@0
|
474 }
|
lbajardsilogic@0
|
475
|
lbajardsilogic@0
|
476 populateExample();
|
lbajardsilogic@0
|
477 }
|
lbajardsilogic@0
|
478
|
lbajardsilogic@0
|
479 void
|
lbajardsilogic@0
|
480 CSVFormatDialog::sampleRateChanged(QString rateString)
|
lbajardsilogic@0
|
481 {
|
lbajardsilogic@0
|
482 bool ok = false;
|
lbajardsilogic@0
|
483 int sampleRate = rateString.toInt(&ok);
|
lbajardsilogic@0
|
484 if (ok) m_sampleRate = sampleRate;
|
lbajardsilogic@0
|
485 }
|
lbajardsilogic@0
|
486
|
lbajardsilogic@0
|
487 void
|
lbajardsilogic@0
|
488 CSVFormatDialog::windowSizeChanged(QString sizeString)
|
lbajardsilogic@0
|
489 {
|
lbajardsilogic@0
|
490 bool ok = false;
|
lbajardsilogic@0
|
491 int size = sizeString.toInt(&ok);
|
lbajardsilogic@0
|
492 if (ok) m_windowSize = size;
|
lbajardsilogic@0
|
493 }
|
lbajardsilogic@0
|
494
|
lbajardsilogic@0
|
495 bool
|
lbajardsilogic@0
|
496 CSVFormatDialog::guessFormat(QFile *file)
|
lbajardsilogic@0
|
497 {
|
lbajardsilogic@0
|
498 QTextStream in(file);
|
lbajardsilogic@0
|
499 in.seek(0);
|
lbajardsilogic@0
|
500
|
lbajardsilogic@0
|
501 unsigned int lineno = 0;
|
lbajardsilogic@0
|
502
|
lbajardsilogic@0
|
503 bool nonIncreasingPrimaries = false;
|
lbajardsilogic@0
|
504 bool nonNumericPrimaries = false;
|
lbajardsilogic@0
|
505 bool floatPrimaries = false;
|
lbajardsilogic@0
|
506 bool variableItemCount = false;
|
lbajardsilogic@0
|
507 int itemCount = 1;
|
lbajardsilogic@0
|
508 int earliestNonNumericItem = -1;
|
lbajardsilogic@0
|
509
|
lbajardsilogic@0
|
510 float prevPrimary = 0.0;
|
lbajardsilogic@0
|
511
|
lbajardsilogic@0
|
512 m_maxExampleCols = 0;
|
lbajardsilogic@0
|
513
|
lbajardsilogic@0
|
514 while (!in.atEnd()) {
|
lbajardsilogic@0
|
515
|
lbajardsilogic@0
|
516 QString line = in.readLine().trimmed();
|
lbajardsilogic@0
|
517 if (line.startsWith("#")) continue;
|
lbajardsilogic@0
|
518
|
lbajardsilogic@0
|
519 if (m_separator == "") {
|
lbajardsilogic@0
|
520 //!!! to do: ask the user
|
lbajardsilogic@0
|
521 if (line.split(",").size() >= 2) m_separator = ",";
|
lbajardsilogic@0
|
522 else if (line.split("\t").size() >= 2) m_separator = "\t";
|
lbajardsilogic@0
|
523 else if (line.split("|").size() >= 2) m_separator = "|";
|
lbajardsilogic@0
|
524 else if (line.split("/").size() >= 2) m_separator = "/";
|
lbajardsilogic@0
|
525 else if (line.split(":").size() >= 2) m_separator = ":";
|
lbajardsilogic@0
|
526 else m_separator = " ";
|
lbajardsilogic@0
|
527 }
|
lbajardsilogic@0
|
528
|
lbajardsilogic@0
|
529 QStringList list = line.split(m_separator);
|
lbajardsilogic@0
|
530 QStringList tidyList;
|
lbajardsilogic@0
|
531
|
lbajardsilogic@0
|
532 for (int i = 0; i < list.size(); ++i) {
|
lbajardsilogic@0
|
533
|
lbajardsilogic@0
|
534 QString s(list[i]);
|
lbajardsilogic@0
|
535 bool numeric = false;
|
lbajardsilogic@0
|
536
|
lbajardsilogic@0
|
537 if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"")) {
|
lbajardsilogic@0
|
538 s = s.mid(1, s.length() - 2);
|
lbajardsilogic@0
|
539 } else if (s.length() >= 2 && s.startsWith("'") && s.endsWith("'")) {
|
lbajardsilogic@0
|
540 s = s.mid(1, s.length() - 2);
|
lbajardsilogic@0
|
541 } else {
|
lbajardsilogic@0
|
542 (void)s.toFloat(&numeric);
|
lbajardsilogic@0
|
543 }
|
lbajardsilogic@0
|
544
|
lbajardsilogic@0
|
545 tidyList.push_back(s);
|
lbajardsilogic@0
|
546
|
lbajardsilogic@0
|
547 if (lineno == 0 || (list.size() < itemCount)) {
|
lbajardsilogic@0
|
548 itemCount = list.size();
|
lbajardsilogic@0
|
549 } else {
|
lbajardsilogic@0
|
550 if (itemCount != list.size()) {
|
lbajardsilogic@0
|
551 variableItemCount = true;
|
lbajardsilogic@0
|
552 }
|
lbajardsilogic@0
|
553 }
|
lbajardsilogic@0
|
554
|
lbajardsilogic@0
|
555 if (i == 0) { // primary
|
lbajardsilogic@0
|
556
|
lbajardsilogic@0
|
557 if (numeric) {
|
lbajardsilogic@0
|
558
|
lbajardsilogic@0
|
559 float primary = s.toFloat();
|
lbajardsilogic@0
|
560
|
lbajardsilogic@0
|
561 if (lineno > 0 && primary <= prevPrimary) {
|
lbajardsilogic@0
|
562 nonIncreasingPrimaries = true;
|
lbajardsilogic@0
|
563 }
|
lbajardsilogic@0
|
564
|
lbajardsilogic@0
|
565 if (s.contains(".") || s.contains(",")) {
|
lbajardsilogic@0
|
566 floatPrimaries = true;
|
lbajardsilogic@0
|
567 }
|
lbajardsilogic@0
|
568
|
lbajardsilogic@0
|
569 prevPrimary = primary;
|
lbajardsilogic@0
|
570
|
lbajardsilogic@0
|
571 } else {
|
lbajardsilogic@0
|
572 nonNumericPrimaries = true;
|
lbajardsilogic@0
|
573 }
|
lbajardsilogic@0
|
574 } else { // secondary
|
lbajardsilogic@0
|
575
|
lbajardsilogic@0
|
576 if (!numeric) {
|
lbajardsilogic@0
|
577 if (earliestNonNumericItem < 0 ||
|
lbajardsilogic@0
|
578 i < earliestNonNumericItem) {
|
lbajardsilogic@0
|
579 earliestNonNumericItem = i;
|
lbajardsilogic@0
|
580 }
|
lbajardsilogic@0
|
581 }
|
lbajardsilogic@0
|
582 }
|
lbajardsilogic@0
|
583 }
|
lbajardsilogic@0
|
584
|
lbajardsilogic@0
|
585 if (lineno < 10) {
|
lbajardsilogic@0
|
586 m_example.push_back(tidyList);
|
lbajardsilogic@0
|
587 if (lineno == 0 || tidyList.size() > m_maxExampleCols) {
|
lbajardsilogic@0
|
588 m_maxExampleCols = tidyList.size();
|
lbajardsilogic@0
|
589 }
|
lbajardsilogic@0
|
590 }
|
lbajardsilogic@0
|
591
|
lbajardsilogic@0
|
592 ++lineno;
|
lbajardsilogic@0
|
593
|
lbajardsilogic@0
|
594 if (lineno == 50) break;
|
lbajardsilogic@0
|
595 }
|
lbajardsilogic@0
|
596
|
lbajardsilogic@0
|
597 if (nonNumericPrimaries || nonIncreasingPrimaries) {
|
lbajardsilogic@0
|
598
|
lbajardsilogic@0
|
599 // Primaries are probably not a series of times
|
lbajardsilogic@0
|
600
|
lbajardsilogic@0
|
601 m_timingType = ImplicitTiming;
|
lbajardsilogic@0
|
602 m_timeUnits = TimeWindows;
|
lbajardsilogic@0
|
603
|
lbajardsilogic@0
|
604 if (nonNumericPrimaries) {
|
lbajardsilogic@0
|
605 m_modelType = OneDimensionalModel;
|
lbajardsilogic@0
|
606 } else if (itemCount == 1 || variableItemCount ||
|
lbajardsilogic@0
|
607 (earliestNonNumericItem != -1)) {
|
lbajardsilogic@0
|
608 m_modelType = TwoDimensionalModel;
|
lbajardsilogic@0
|
609 } else {
|
lbajardsilogic@0
|
610 m_modelType = ThreeDimensionalModel;
|
lbajardsilogic@0
|
611 }
|
lbajardsilogic@0
|
612
|
lbajardsilogic@0
|
613 } else {
|
lbajardsilogic@0
|
614
|
lbajardsilogic@0
|
615 // Increasing numeric primaries -- likely to be time
|
lbajardsilogic@0
|
616
|
lbajardsilogic@0
|
617 m_timingType = ExplicitTiming;
|
lbajardsilogic@0
|
618
|
lbajardsilogic@0
|
619 if (floatPrimaries) {
|
lbajardsilogic@0
|
620 m_timeUnits = TimeSeconds;
|
lbajardsilogic@0
|
621 } else {
|
lbajardsilogic@0
|
622 m_timeUnits = TimeAudioFrames;
|
lbajardsilogic@0
|
623 }
|
lbajardsilogic@0
|
624
|
lbajardsilogic@0
|
625 if (itemCount == 1) {
|
lbajardsilogic@0
|
626 m_modelType = OneDimensionalModel;
|
lbajardsilogic@0
|
627 } else if (variableItemCount || (earliestNonNumericItem != -1)) {
|
lbajardsilogic@0
|
628 if (earliestNonNumericItem != -1 && earliestNonNumericItem < 2) {
|
lbajardsilogic@0
|
629 m_modelType = OneDimensionalModel;
|
lbajardsilogic@0
|
630 } else {
|
lbajardsilogic@0
|
631 m_modelType = TwoDimensionalModel;
|
lbajardsilogic@0
|
632 }
|
lbajardsilogic@0
|
633 } else {
|
lbajardsilogic@0
|
634 m_modelType = ThreeDimensionalModel;
|
lbajardsilogic@0
|
635 }
|
lbajardsilogic@0
|
636 }
|
lbajardsilogic@0
|
637
|
lbajardsilogic@0
|
638 std::cerr << "Estimated model type: " << m_modelType << std::endl;
|
lbajardsilogic@0
|
639 std::cerr << "Estimated timing type: " << m_timingType << std::endl;
|
lbajardsilogic@0
|
640 std::cerr << "Estimated units: " << m_timeUnits << std::endl;
|
lbajardsilogic@0
|
641
|
lbajardsilogic@0
|
642 in.seek(0);
|
lbajardsilogic@0
|
643 return true;
|
lbajardsilogic@0
|
644 }
|