lbajardsilogic@0: /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */ lbajardsilogic@0: lbajardsilogic@0: /* lbajardsilogic@0: Sonic Visualiser lbajardsilogic@0: An audio file viewer and annotation editor. lbajardsilogic@0: Centre for Digital Music, Queen Mary, University of London. lbajardsilogic@0: This file copyright 2006 Chris Cannam. lbajardsilogic@0: lbajardsilogic@0: This program is free software; you can redistribute it and/or lbajardsilogic@0: modify it under the terms of the GNU General Public License as lbajardsilogic@0: published by the Free Software Foundation; either version 2 of the lbajardsilogic@0: License, or (at your option) any later version. See the file lbajardsilogic@0: COPYING included with this distribution for more information. lbajardsilogic@0: */ lbajardsilogic@189: #include "system/System.h" lbajardsilogic@0: lbajardsilogic@189: #include lbajardsilogic@0: lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: #include lbajardsilogic@0: lbajardsilogic@189: #include "model/Model.h" lbajardsilogic@189: #include "base/RealTime.h" lbajardsilogic@189: #include "model/SparseOneDimensionalModel.h" lbajardsilogic@189: #include "model/SparseTimeValueModel.h" lbajardsilogic@189: #include "model/EditableDenseThreeDimensionalModel.h" lbajardsilogic@189: lbajardsilogic@189: #include "CSVFileReader.h" lbajardsilogic@0: lbajardsilogic@0: CSVFileReader::CSVFileReader(QString path, size_t mainModelSampleRate) : lbajardsilogic@0: m_file(0), lbajardsilogic@0: m_mainModelSampleRate(mainModelSampleRate) lbajardsilogic@0: { lbajardsilogic@0: m_file = new QFile(path); lbajardsilogic@0: bool good = false; lbajardsilogic@0: lbajardsilogic@0: if (!m_file->exists()) { lbajardsilogic@0: m_error = QFile::tr("File \"%1\" does not exist").arg(path); lbajardsilogic@0: } else if (!m_file->open(QIODevice::ReadOnly | QIODevice::Text)) { lbajardsilogic@0: m_error = QFile::tr("Failed to open file \"%1\"").arg(path); lbajardsilogic@0: } else { lbajardsilogic@0: good = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (!good) { lbajardsilogic@0: delete m_file; lbajardsilogic@0: m_file = 0; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: CSVFileReader::~CSVFileReader() lbajardsilogic@0: { lbajardsilogic@0: std::cerr << "CSVFileReader::~CSVFileReader: file is " << m_file << std::endl; lbajardsilogic@0: lbajardsilogic@0: if (m_file) { lbajardsilogic@0: std::cerr << "CSVFileReader::CSVFileReader: Closing file" << std::endl; lbajardsilogic@0: m_file->close(); lbajardsilogic@0: } lbajardsilogic@0: delete m_file; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: CSVFileReader::isOK() const lbajardsilogic@0: { lbajardsilogic@0: return (m_file != 0); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QString lbajardsilogic@0: CSVFileReader::getError() const lbajardsilogic@0: { lbajardsilogic@0: return m_error; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: Model * lbajardsilogic@0: CSVFileReader::load() const lbajardsilogic@0: { lbajardsilogic@0: if (!m_file) return 0; lbajardsilogic@0: lbajardsilogic@0: CSVFormatDialog *dialog = new CSVFormatDialog lbajardsilogic@0: (0, m_file, m_mainModelSampleRate); lbajardsilogic@0: lbajardsilogic@0: if (dialog->exec() == QDialog::Rejected) { lbajardsilogic@0: delete dialog; lbajardsilogic@0: return 0; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: CSVFormatDialog::ModelType modelType = dialog->getModelType(); lbajardsilogic@0: CSVFormatDialog::TimingType timingType = dialog->getTimingType(); lbajardsilogic@0: CSVFormatDialog::TimeUnits timeUnits = dialog->getTimeUnits(); lbajardsilogic@0: QString separator = dialog->getSeparator(); lbajardsilogic@0: size_t sampleRate = dialog->getSampleRate(); lbajardsilogic@0: size_t windowSize = dialog->getWindowSize(); lbajardsilogic@0: lbajardsilogic@0: delete dialog; lbajardsilogic@0: lbajardsilogic@0: if (timingType == CSVFormatDialog::ExplicitTiming) { lbajardsilogic@0: windowSize = 1; lbajardsilogic@0: if (timeUnits == CSVFormatDialog::TimeSeconds) { lbajardsilogic@0: sampleRate = m_mainModelSampleRate; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: SparseOneDimensionalModel *model1 = 0; lbajardsilogic@0: SparseTimeValueModel *model2 = 0; lbajardsilogic@0: EditableDenseThreeDimensionalModel *model3 = 0; lbajardsilogic@0: Model *model = 0; lbajardsilogic@0: lbajardsilogic@0: QTextStream in(m_file); lbajardsilogic@0: in.seek(0); lbajardsilogic@0: lbajardsilogic@0: unsigned int warnings = 0, warnLimit = 10; lbajardsilogic@0: unsigned int lineno = 0; lbajardsilogic@0: lbajardsilogic@0: float min = 0.0, max = 0.0; lbajardsilogic@0: lbajardsilogic@0: size_t frameNo = 0; lbajardsilogic@0: lbajardsilogic@0: while (!in.atEnd()) { lbajardsilogic@0: lbajardsilogic@0: QString line = in.readLine().trimmed(); lbajardsilogic@0: if (line.startsWith("#") || line.trimmed() == "") continue; lbajardsilogic@0: lbajardsilogic@0: QStringList list = line.split(separator); lbajardsilogic@0: lbajardsilogic@0: if (!model) { lbajardsilogic@0: lbajardsilogic@0: switch (modelType) { lbajardsilogic@0: lbajardsilogic@0: case CSVFormatDialog::OneDimensionalModel: lbajardsilogic@0: model1 = new SparseOneDimensionalModel(sampleRate, windowSize); lbajardsilogic@0: model = model1; lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case CSVFormatDialog::TwoDimensionalModel: lbajardsilogic@0: model2 = new SparseTimeValueModel(sampleRate, windowSize, false); lbajardsilogic@0: model = model2; lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case CSVFormatDialog::ThreeDimensionalModel: lbajardsilogic@0: model3 = new EditableDenseThreeDimensionalModel(sampleRate, lbajardsilogic@0: windowSize, lbajardsilogic@0: list.size()); lbajardsilogic@0: model = model3; lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QStringList tidyList; lbajardsilogic@0: QRegExp nonNumericRx("[^0-9.,+-]"); lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i < list.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QString s(list[i].trimmed()); lbajardsilogic@0: lbajardsilogic@0: if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"")) { lbajardsilogic@0: s = s.mid(1, s.length() - 2); lbajardsilogic@0: } else if (s.length() >= 2 && s.startsWith("'") && s.endsWith("'")) { lbajardsilogic@0: s = s.mid(1, s.length() - 2); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (i == 0 && timingType == CSVFormatDialog::ExplicitTiming) { lbajardsilogic@0: lbajardsilogic@0: bool ok = false; lbajardsilogic@0: QString numeric = s; lbajardsilogic@0: numeric.remove(nonNumericRx); lbajardsilogic@0: lbajardsilogic@0: if (timeUnits == CSVFormatDialog::TimeSeconds) { lbajardsilogic@0: lbajardsilogic@0: double time = numeric.toDouble(&ok); lbajardsilogic@0: frameNo = int(time * sampleRate + 0.00001); lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: frameNo = numeric.toInt(&ok); lbajardsilogic@0: lbajardsilogic@0: if (timeUnits == CSVFormatDialog::TimeWindows) { lbajardsilogic@0: frameNo *= windowSize; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (!ok) { lbajardsilogic@0: if (warnings < warnLimit) { lbajardsilogic@0: std::cerr << "WARNING: CSVFileReader::load: " lbajardsilogic@0: << "Bad time format (\"" << s.toStdString() lbajardsilogic@0: << "\") in data line " lbajardsilogic@0: << lineno << ":" << std::endl; lbajardsilogic@0: std::cerr << line.toStdString() << std::endl; lbajardsilogic@0: } else if (warnings == warnLimit) { lbajardsilogic@0: std::cerr << "WARNING: Too many warnings" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: ++warnings; lbajardsilogic@0: } lbajardsilogic@0: } else { lbajardsilogic@0: tidyList.push_back(s); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (modelType == CSVFormatDialog::OneDimensionalModel) { lbajardsilogic@0: lbajardsilogic@0: SparseOneDimensionalModel::Point point lbajardsilogic@0: (frameNo, lbajardsilogic@0: tidyList.size() > 0 ? tidyList[tidyList.size()-1] : lbajardsilogic@0: QString("%1").arg(lineno)); lbajardsilogic@0: lbajardsilogic@0: model1->addPoint(point); lbajardsilogic@0: lbajardsilogic@0: } else if (modelType == CSVFormatDialog::TwoDimensionalModel) { lbajardsilogic@0: lbajardsilogic@0: SparseTimeValueModel::Point point lbajardsilogic@0: (frameNo, lbajardsilogic@0: tidyList.size() > 0 ? tidyList[0].toFloat() : 0.0, lbajardsilogic@0: tidyList.size() > 1 ? tidyList[1] : QString("%1").arg(lineno)); lbajardsilogic@0: lbajardsilogic@0: model2->addPoint(point); lbajardsilogic@0: lbajardsilogic@0: } else if (modelType == CSVFormatDialog::ThreeDimensionalModel) { lbajardsilogic@0: lbajardsilogic@0: DenseThreeDimensionalModel::Column values; lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i < tidyList.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: bool ok = false; lbajardsilogic@0: float value = list[i].toFloat(&ok); lbajardsilogic@0: values.push_back(value); lbajardsilogic@0: lbajardsilogic@0: if ((lineno == 0 && i == 0) || value < min) min = value; lbajardsilogic@0: if ((lineno == 0 && i == 0) || value > max) max = value; lbajardsilogic@0: lbajardsilogic@0: if (!ok) { lbajardsilogic@0: if (warnings < warnLimit) { lbajardsilogic@0: std::cerr << "WARNING: CSVFileReader::load: " lbajardsilogic@0: << "Non-numeric value in data line " << lineno lbajardsilogic@0: << ":" << std::endl; lbajardsilogic@0: std::cerr << line.toStdString() << std::endl; lbajardsilogic@0: ++warnings; lbajardsilogic@0: } else if (warnings == warnLimit) { lbajardsilogic@0: std::cerr << "WARNING: Too many warnings" << std::endl; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::cerr << "Setting bin values for count " << lineno << ", frame " lbajardsilogic@0: << frameNo << ", time " << RealTime::frame2RealTime(frameNo, sampleRate) << std::endl; lbajardsilogic@0: lbajardsilogic@0: model3->setColumn(frameNo / model3->getResolution(), values); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: ++lineno; lbajardsilogic@0: if (timingType == CSVFormatDialog::ImplicitTiming || lbajardsilogic@0: list.size() == 0) { lbajardsilogic@0: frameNo += windowSize; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (modelType == CSVFormatDialog::ThreeDimensionalModel) { lbajardsilogic@0: model3->setMinimumLevel(min); lbajardsilogic@0: model3->setMaximumLevel(max); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: return model; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: lbajardsilogic@0: CSVFormatDialog::CSVFormatDialog(QWidget *parent, QFile *file, lbajardsilogic@0: size_t defaultSampleRate) : lbajardsilogic@0: QDialog(parent), lbajardsilogic@0: m_modelType(OneDimensionalModel), lbajardsilogic@0: m_timingType(ExplicitTiming), lbajardsilogic@0: m_timeUnits(TimeAudioFrames), lbajardsilogic@0: m_separator("") lbajardsilogic@0: { lbajardsilogic@0: setModal(true); lbajardsilogic@0: setWindowTitle(tr("Select Data Format")); lbajardsilogic@0: lbajardsilogic@0: (void)guessFormat(file); lbajardsilogic@0: lbajardsilogic@0: QGridLayout *layout = new QGridLayout; lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(new QLabel(tr("\nPlease select the correct data format for this file.\n")), lbajardsilogic@0: 0, 0, 1, 4); lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(new QLabel(tr("Each row specifies:")), 1, 0); lbajardsilogic@0: lbajardsilogic@0: m_modelTypeCombo = new QComboBox; lbajardsilogic@0: m_modelTypeCombo->addItem(tr("A point in time")); lbajardsilogic@0: m_modelTypeCombo->addItem(tr("A value at a time")); lbajardsilogic@0: m_modelTypeCombo->addItem(tr("A set of values")); lbajardsilogic@0: layout->addWidget(m_modelTypeCombo, 1, 1, 1, 2); lbajardsilogic@0: connect(m_modelTypeCombo, SIGNAL(activated(int)), lbajardsilogic@0: this, SLOT(modelTypeChanged(int))); lbajardsilogic@0: m_modelTypeCombo->setCurrentIndex(int(m_modelType)); lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(new QLabel(tr("The first column contains:")), 2, 0); lbajardsilogic@0: lbajardsilogic@0: m_timingTypeCombo = new QComboBox; lbajardsilogic@0: m_timingTypeCombo->addItem(tr("Time, in seconds")); lbajardsilogic@0: m_timingTypeCombo->addItem(tr("Time, in audio sample frames")); lbajardsilogic@0: m_timingTypeCombo->addItem(tr("Data (rows are consecutive in time)")); lbajardsilogic@0: layout->addWidget(m_timingTypeCombo, 2, 1, 1, 2); lbajardsilogic@0: connect(m_timingTypeCombo, SIGNAL(activated(int)), lbajardsilogic@0: this, SLOT(timingTypeChanged(int))); lbajardsilogic@0: m_timingTypeCombo->setCurrentIndex(m_timingType == ExplicitTiming ? lbajardsilogic@0: m_timeUnits == TimeSeconds ? 0 : 1 : 2); lbajardsilogic@0: lbajardsilogic@0: m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):")); lbajardsilogic@0: layout->addWidget(m_sampleRateLabel, 3, 0); lbajardsilogic@0: lbajardsilogic@0: size_t sampleRates[] = { lbajardsilogic@0: 8000, 11025, 12000, 22050, 24000, 32000, lbajardsilogic@0: 44100, 48000, 88200, 96000, 176400, 192000 lbajardsilogic@0: }; lbajardsilogic@0: lbajardsilogic@0: m_sampleRateCombo = new QComboBox; lbajardsilogic@0: m_sampleRate = defaultSampleRate; lbajardsilogic@0: for (size_t i = 0; i < sizeof(sampleRates) / sizeof(sampleRates[0]); ++i) { lbajardsilogic@0: m_sampleRateCombo->addItem(QString("%1").arg(sampleRates[i])); lbajardsilogic@0: if (sampleRates[i] == m_sampleRate) m_sampleRateCombo->setCurrentIndex(i); lbajardsilogic@0: } lbajardsilogic@0: m_sampleRateCombo->setEditable(true); lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(m_sampleRateCombo, 3, 1); lbajardsilogic@0: connect(m_sampleRateCombo, SIGNAL(activated(QString)), lbajardsilogic@0: this, SLOT(sampleRateChanged(QString))); lbajardsilogic@0: connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)), lbajardsilogic@0: this, SLOT(sampleRateChanged(QString))); lbajardsilogic@0: lbajardsilogic@0: m_windowSizeLabel = new QLabel(tr("Frame increment between rows:")); lbajardsilogic@0: layout->addWidget(m_windowSizeLabel, 4, 0); lbajardsilogic@0: lbajardsilogic@0: m_windowSizeCombo = new QComboBox; lbajardsilogic@0: m_windowSize = 1024; lbajardsilogic@0: for (int i = 0; i <= 16; ++i) { lbajardsilogic@0: int value = 1 << i; lbajardsilogic@0: m_windowSizeCombo->addItem(QString("%1").arg(value)); lbajardsilogic@0: if (value == int(m_windowSize)) m_windowSizeCombo->setCurrentIndex(i); lbajardsilogic@0: } lbajardsilogic@0: m_windowSizeCombo->setEditable(true); lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(m_windowSizeCombo, 4, 1); lbajardsilogic@0: connect(m_windowSizeCombo, SIGNAL(activated(QString)), lbajardsilogic@0: this, SLOT(windowSizeChanged(QString))); lbajardsilogic@0: connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)), lbajardsilogic@0: this, SLOT(windowSizeChanged(QString))); lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(new QLabel(tr("\nExample data from file:")), 5, 0, 1, 4); lbajardsilogic@0: lbajardsilogic@189: m_exampleWidget = new QTableWidget(MIN(10, m_example.size()), m_maxExampleCols); lbajardsilogic@0: lbajardsilogic@0: layout->addWidget(m_exampleWidget, 6, 0, 1, 4); lbajardsilogic@0: layout->setColumnStretch(3, 10); lbajardsilogic@0: layout->setRowStretch(4, 10); lbajardsilogic@0: lbajardsilogic@0: QPushButton *ok = new QPushButton(tr("OK")); lbajardsilogic@0: connect(ok, SIGNAL(clicked()), this, SLOT(accept())); lbajardsilogic@0: ok->setDefault(true); lbajardsilogic@0: lbajardsilogic@0: QPushButton *cancel = new QPushButton(tr("Cancel")); lbajardsilogic@0: connect(cancel, SIGNAL(clicked()), this, SLOT(reject())); lbajardsilogic@0: lbajardsilogic@0: QHBoxLayout *buttonLayout = new QHBoxLayout; lbajardsilogic@0: buttonLayout->addStretch(1); lbajardsilogic@0: buttonLayout->addWidget(ok); lbajardsilogic@0: buttonLayout->addWidget(cancel); lbajardsilogic@0: lbajardsilogic@0: QVBoxLayout *mainLayout = new QVBoxLayout; lbajardsilogic@0: mainLayout->addLayout(layout); lbajardsilogic@0: mainLayout->addLayout(buttonLayout); lbajardsilogic@0: lbajardsilogic@0: setLayout(mainLayout); lbajardsilogic@0: lbajardsilogic@0: timingTypeChanged(m_timingTypeCombo->currentIndex()); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: CSVFormatDialog::~CSVFormatDialog() lbajardsilogic@0: { lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: CSVFormatDialog::populateExample() lbajardsilogic@0: { lbajardsilogic@0: m_exampleWidget->setColumnCount lbajardsilogic@0: (m_timingType == ExplicitTiming ? lbajardsilogic@0: m_maxExampleCols - 1 : m_maxExampleCols); lbajardsilogic@0: lbajardsilogic@0: m_exampleWidget->setHorizontalHeaderLabels(QStringList()); lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i < m_example.size(); ++i) { lbajardsilogic@0: for (int j = 0; j < m_example[i].size(); ++j) { lbajardsilogic@0: lbajardsilogic@0: QTableWidgetItem *item = new QTableWidgetItem(m_example[i][j]); lbajardsilogic@0: lbajardsilogic@0: if (j == 0) { lbajardsilogic@0: if (m_timingType == ExplicitTiming) { lbajardsilogic@0: m_exampleWidget->setVerticalHeaderItem(i, item); lbajardsilogic@0: continue; lbajardsilogic@0: } else { lbajardsilogic@0: QTableWidgetItem *header = lbajardsilogic@0: new QTableWidgetItem(QString("%1").arg(i)); lbajardsilogic@0: header->setFlags(Qt::ItemIsEnabled); lbajardsilogic@0: m_exampleWidget->setVerticalHeaderItem(i, header); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: int index = j; lbajardsilogic@0: if (m_timingType == ExplicitTiming) --index; lbajardsilogic@0: item->setFlags(Qt::ItemIsEnabled); lbajardsilogic@0: m_exampleWidget->setItem(i, index, item); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: CSVFormatDialog::modelTypeChanged(int type) lbajardsilogic@0: { lbajardsilogic@0: m_modelType = (ModelType)type; lbajardsilogic@0: lbajardsilogic@0: if (m_modelType == ThreeDimensionalModel) { lbajardsilogic@0: // We can't load 3d models with explicit timing, because the 3d lbajardsilogic@0: // model is dense so we need a fixed sample increment lbajardsilogic@0: m_timingTypeCombo->setCurrentIndex(2); lbajardsilogic@0: timingTypeChanged(2); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: CSVFormatDialog::timingTypeChanged(int type) lbajardsilogic@0: { lbajardsilogic@0: switch (type) { lbajardsilogic@0: lbajardsilogic@0: case 0: lbajardsilogic@0: m_timingType = ExplicitTiming; lbajardsilogic@0: m_timeUnits = TimeSeconds; lbajardsilogic@0: m_sampleRateCombo->setEnabled(false); lbajardsilogic@0: m_sampleRateLabel->setEnabled(false); lbajardsilogic@0: m_windowSizeCombo->setEnabled(false); lbajardsilogic@0: m_windowSizeLabel->setEnabled(false); lbajardsilogic@0: if (m_modelType == ThreeDimensionalModel) { lbajardsilogic@0: m_modelTypeCombo->setCurrentIndex(1); lbajardsilogic@0: modelTypeChanged(1); lbajardsilogic@0: } lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case 1: lbajardsilogic@0: m_timingType = ExplicitTiming; lbajardsilogic@0: m_timeUnits = TimeAudioFrames; lbajardsilogic@0: m_sampleRateCombo->setEnabled(true); lbajardsilogic@0: m_sampleRateLabel->setEnabled(true); lbajardsilogic@0: m_windowSizeCombo->setEnabled(false); lbajardsilogic@0: m_windowSizeLabel->setEnabled(false); lbajardsilogic@0: if (m_modelType == ThreeDimensionalModel) { lbajardsilogic@0: m_modelTypeCombo->setCurrentIndex(1); lbajardsilogic@0: modelTypeChanged(1); lbajardsilogic@0: } lbajardsilogic@0: break; lbajardsilogic@0: lbajardsilogic@0: case 2: lbajardsilogic@0: m_timingType = ImplicitTiming; lbajardsilogic@0: m_timeUnits = TimeWindows; lbajardsilogic@0: m_sampleRateCombo->setEnabled(true); lbajardsilogic@0: m_sampleRateLabel->setEnabled(true); lbajardsilogic@0: m_windowSizeCombo->setEnabled(true); lbajardsilogic@0: m_windowSizeLabel->setEnabled(true); lbajardsilogic@0: break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: populateExample(); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: CSVFormatDialog::sampleRateChanged(QString rateString) lbajardsilogic@0: { lbajardsilogic@0: bool ok = false; lbajardsilogic@0: int sampleRate = rateString.toInt(&ok); lbajardsilogic@0: if (ok) m_sampleRate = sampleRate; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: void lbajardsilogic@0: CSVFormatDialog::windowSizeChanged(QString sizeString) lbajardsilogic@0: { lbajardsilogic@0: bool ok = false; lbajardsilogic@0: int size = sizeString.toInt(&ok); lbajardsilogic@0: if (ok) m_windowSize = size; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: bool lbajardsilogic@0: CSVFormatDialog::guessFormat(QFile *file) lbajardsilogic@0: { lbajardsilogic@0: QTextStream in(file); lbajardsilogic@0: in.seek(0); lbajardsilogic@0: lbajardsilogic@0: unsigned int lineno = 0; lbajardsilogic@0: lbajardsilogic@0: bool nonIncreasingPrimaries = false; lbajardsilogic@0: bool nonNumericPrimaries = false; lbajardsilogic@0: bool floatPrimaries = false; lbajardsilogic@0: bool variableItemCount = false; lbajardsilogic@0: int itemCount = 1; lbajardsilogic@0: int earliestNonNumericItem = -1; lbajardsilogic@0: lbajardsilogic@0: float prevPrimary = 0.0; lbajardsilogic@0: lbajardsilogic@0: m_maxExampleCols = 0; lbajardsilogic@0: lbajardsilogic@0: while (!in.atEnd()) { lbajardsilogic@0: lbajardsilogic@0: QString line = in.readLine().trimmed(); lbajardsilogic@0: if (line.startsWith("#")) continue; lbajardsilogic@0: lbajardsilogic@0: if (m_separator == "") { lbajardsilogic@0: //!!! to do: ask the user lbajardsilogic@0: if (line.split(",").size() >= 2) m_separator = ","; lbajardsilogic@0: else if (line.split("\t").size() >= 2) m_separator = "\t"; lbajardsilogic@0: else if (line.split("|").size() >= 2) m_separator = "|"; lbajardsilogic@0: else if (line.split("/").size() >= 2) m_separator = "/"; lbajardsilogic@0: else if (line.split(":").size() >= 2) m_separator = ":"; lbajardsilogic@0: else m_separator = " "; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: QStringList list = line.split(m_separator); lbajardsilogic@0: QStringList tidyList; lbajardsilogic@0: lbajardsilogic@0: for (int i = 0; i < list.size(); ++i) { lbajardsilogic@0: lbajardsilogic@0: QString s(list[i]); lbajardsilogic@0: bool numeric = false; lbajardsilogic@0: lbajardsilogic@0: if (s.length() >= 2 && s.startsWith("\"") && s.endsWith("\"")) { lbajardsilogic@0: s = s.mid(1, s.length() - 2); lbajardsilogic@0: } else if (s.length() >= 2 && s.startsWith("'") && s.endsWith("'")) { lbajardsilogic@0: s = s.mid(1, s.length() - 2); lbajardsilogic@0: } else { lbajardsilogic@0: (void)s.toFloat(&numeric); lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: tidyList.push_back(s); lbajardsilogic@0: lbajardsilogic@0: if (lineno == 0 || (list.size() < itemCount)) { lbajardsilogic@0: itemCount = list.size(); lbajardsilogic@0: } else { lbajardsilogic@0: if (itemCount != list.size()) { lbajardsilogic@0: variableItemCount = true; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (i == 0) { // primary lbajardsilogic@0: lbajardsilogic@0: if (numeric) { lbajardsilogic@0: lbajardsilogic@0: float primary = s.toFloat(); lbajardsilogic@0: lbajardsilogic@0: if (lineno > 0 && primary <= prevPrimary) { lbajardsilogic@0: nonIncreasingPrimaries = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (s.contains(".") || s.contains(",")) { lbajardsilogic@0: floatPrimaries = true; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: prevPrimary = primary; lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: nonNumericPrimaries = true; lbajardsilogic@0: } lbajardsilogic@0: } else { // secondary lbajardsilogic@0: lbajardsilogic@0: if (!numeric) { lbajardsilogic@0: if (earliestNonNumericItem < 0 || lbajardsilogic@0: i < earliestNonNumericItem) { lbajardsilogic@0: earliestNonNumericItem = i; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (lineno < 10) { lbajardsilogic@0: m_example.push_back(tidyList); lbajardsilogic@0: if (lineno == 0 || tidyList.size() > m_maxExampleCols) { lbajardsilogic@0: m_maxExampleCols = tidyList.size(); lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: ++lineno; lbajardsilogic@0: lbajardsilogic@0: if (lineno == 50) break; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (nonNumericPrimaries || nonIncreasingPrimaries) { lbajardsilogic@0: lbajardsilogic@0: // Primaries are probably not a series of times lbajardsilogic@0: lbajardsilogic@0: m_timingType = ImplicitTiming; lbajardsilogic@0: m_timeUnits = TimeWindows; lbajardsilogic@0: lbajardsilogic@0: if (nonNumericPrimaries) { lbajardsilogic@0: m_modelType = OneDimensionalModel; lbajardsilogic@0: } else if (itemCount == 1 || variableItemCount || lbajardsilogic@0: (earliestNonNumericItem != -1)) { lbajardsilogic@0: m_modelType = TwoDimensionalModel; lbajardsilogic@0: } else { lbajardsilogic@0: m_modelType = ThreeDimensionalModel; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: } else { lbajardsilogic@0: lbajardsilogic@0: // Increasing numeric primaries -- likely to be time lbajardsilogic@0: lbajardsilogic@0: m_timingType = ExplicitTiming; lbajardsilogic@0: lbajardsilogic@0: if (floatPrimaries) { lbajardsilogic@0: m_timeUnits = TimeSeconds; lbajardsilogic@0: } else { lbajardsilogic@0: m_timeUnits = TimeAudioFrames; lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: if (itemCount == 1) { lbajardsilogic@0: m_modelType = OneDimensionalModel; lbajardsilogic@0: } else if (variableItemCount || (earliestNonNumericItem != -1)) { lbajardsilogic@0: if (earliestNonNumericItem != -1 && earliestNonNumericItem < 2) { lbajardsilogic@0: m_modelType = OneDimensionalModel; lbajardsilogic@0: } else { lbajardsilogic@0: m_modelType = TwoDimensionalModel; lbajardsilogic@0: } lbajardsilogic@0: } else { lbajardsilogic@0: m_modelType = ThreeDimensionalModel; lbajardsilogic@0: } lbajardsilogic@0: } lbajardsilogic@0: lbajardsilogic@0: std::cerr << "Estimated model type: " << m_modelType << std::endl; lbajardsilogic@0: std::cerr << "Estimated timing type: " << m_timingType << std::endl; lbajardsilogic@0: std::cerr << "Estimated units: " << m_timeUnits << std::endl; lbajardsilogic@0: lbajardsilogic@0: in.seek(0); lbajardsilogic@0: return true; lbajardsilogic@0: }