changeset 1318:b149b53df365 import-audio-data

Support audio-format CSV format selection in dialog
author Chris Cannam
date Thu, 06 Sep 2018 11:49:31 +0100
parents c2fa7bb1eca9
children fbda05431ce0
files widgets/CSVFormatDialog.cpp widgets/CSVFormatDialog.h
diffstat 2 files changed, 208 insertions(+), 112 deletions(-) [+]
line wrap: on
line diff
--- a/widgets/CSVFormatDialog.cpp	Tue Sep 04 13:19:32 2018 +0100
+++ b/widgets/CSVFormatDialog.cpp	Thu Sep 06 11:49:31 2018 +0100
@@ -37,6 +37,9 @@
 CSVFormatDialog::CSVFormatDialog(QWidget *parent, CSVFormat format,
                                  int maxDisplayCols) :
     QDialog(parent),
+    m_dialogType(format.getModelType() == CSVFormat::WaveFileModel ?
+                 AudioDataDialog :
+                 AnnotationDataDialog),
     m_format(format),
     m_maxDisplayCols(maxDisplayCols),
     m_fuzzyColumn(-1)
@@ -48,8 +51,9 @@
 
     int row = 0;
 
-    layout->addWidget(new QLabel(tr("Please select the correct data format for this file.")),
-                      row++, 0, 1, 4);
+    layout->addWidget
+        (new QLabel(tr("Please select the correct data format for this file.")),
+         row++, 0, 1, 4);
 
     QFrame *exampleFrame = new QFrame;
     exampleFrame->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
@@ -64,9 +68,6 @@
 
     QFont fp;
     fp.setPointSize(int(floor(fp.pointSize() * 0.9)));
-//    fp.setFixedPitch(true);
-//    fp.setStyleHint(QFont::TypeWriter);
-//    fp.setFamily("Monospaced");
     
     int columns = format.getColumnCount();
     QList<QStringList> example = m_format.getExample();
@@ -77,28 +78,49 @@
         m_columnPurposeCombos.push_back(cpc);
         exampleLayout->addWidget(cpc, 0, i);
         connect(cpc, SIGNAL(activated(int)), this, SLOT(columnPurposeChanged(int)));
-
+        
         if (i == m_maxDisplayCols && columns > i + 2) {
             m_fuzzyColumn = i;
-            cpc->addItem(tr("<ignore>"));
-            cpc->addItem(tr("Values"));
-            cpc->setCurrentIndex
-                (m_format.getColumnPurpose(i-1) == CSVFormat::ColumnUnknown ? 0 : 1);
-            exampleLayout->addWidget(new QLabel(tr("(%1 more)").arg(columns - i)),
-                                     1, i);
+
+            if (m_dialogType == AnnotationDataDialog) {
+                cpc->addItem(tr("<ignore>"));
+                cpc->addItem(tr("Values"));
+                cpc->setCurrentIndex
+                    (m_format.getColumnPurpose(i-1) ==
+                     CSVFormat::ColumnUnknown ? 0 : 1);
+            } else {
+                cpc->addItem(tr("<ignore>"));
+                cpc->addItem(tr("Audio channels"));
+                cpc->setCurrentIndex
+                    (m_format.isColumnNumeric(i-1) ? 1 : 0);
+            }
+            exampleLayout->addWidget
+                (new QLabel(tr("(%1 more)").arg(columns - i)), 1, i);
             break;
         }
 
-        // NB must be in the same order as the CSVFormat::ColumnPurpose enum
-        cpc->addItem(tr("<ignore>")); // ColumnUnknown
-        cpc->addItem(tr("Time"));     // ColumnStartTime
-        cpc->addItem(tr("End time")); // ColumnEndTime
-        cpc->addItem(tr("Duration")); // ColumnDuration
-        cpc->addItem(tr("Value"));    // ColumnValue
-        cpc->addItem(tr("Pitch"));    // ColumnPitch
-        cpc->addItem(tr("Label"));    // ColumnLabel
-        cpc->setCurrentIndex(int(m_format.getColumnPurpose(i)));
+        if (m_dialogType == AnnotationDataDialog) {
 
+            // NB must be in the same order as the CSVFormat::ColumnPurpose enum
+            cpc->addItem(tr("<ignore>")); // ColumnUnknown
+            cpc->addItem(tr("Time"));     // ColumnStartTime
+            cpc->addItem(tr("End time")); // ColumnEndTime
+            cpc->addItem(tr("Duration")); // ColumnDuration
+            cpc->addItem(tr("Value"));    // ColumnValue
+            cpc->addItem(tr("Pitch"));    // ColumnPitch
+            cpc->addItem(tr("Label"));    // ColumnLabel
+            cpc->setCurrentIndex(int(m_format.getColumnPurpose(i)));
+
+        } else {
+            cpc->addItem(tr("<ignore>"));
+            cpc->addItem(tr("Audio channel"));
+            if (m_format.isColumnNumeric(i)) {
+                cpc->setCurrentIndex(1);
+            } else {
+                cpc->setCurrentIndex(0);
+            }
+        }
+        
         for (int j = 0; j < example.size() && j < 6; ++j) {
             if (i >= example[j].size()) {
                 continue;
@@ -118,41 +140,48 @@
     layout->setColumnStretch(3, 10);
     layout->setRowStretch(row++, 10);
 
-    layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
+    if (m_dialogType == AnnotationDataDialog) {
     
-    m_timingTypeCombo = new QComboBox;
+        layout->addWidget(new QLabel(tr("Timing is specified:")), row, 0);
+    
+        m_timingTypeCombo = new QComboBox;
 
-    m_timingLabels = {
-        { TimingExplicitSeconds, tr("Explicitly, in seconds") },
-        { TimingExplicitMsec, tr("Explicitly, in milliseconds") },
-        { TimingExplicitSamples, tr("Explicitly, in audio sample frames") },
-        { TimingImplicit, tr("Implicitly: rows are equally spaced in time") }
-    };
+        m_timingLabels = {
+            { TimingExplicitSeconds, tr("Explicitly, in seconds") },
+            { TimingExplicitMsec, tr("Explicitly, in milliseconds") },
+            { TimingExplicitSamples, tr("Explicitly, in audio sample frames") },
+            { TimingImplicit, tr("Implicitly: rows are equally spaced in time") }
+        };
 
-    for (auto &l: m_timingLabels) {
-        m_timingTypeCombo->addItem(l.second);
+        for (auto &l: m_timingLabels) {
+            m_timingTypeCombo->addItem(l.second);
+        }
+
+        layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
+
+        connect(m_timingTypeCombo, SIGNAL(activated(int)),
+                this, SLOT(timingTypeChanged(int)));
+
+        m_initialTimingOption = TimingImplicit;
+        if (m_format.getTimingType() == CSVFormat::ExplicitTiming) {
+            switch (m_format.getTimeUnits()) {
+            case CSVFormat::TimeSeconds:
+                m_initialTimingOption = TimingExplicitSeconds; break;
+            case CSVFormat::TimeMilliseconds:
+                m_initialTimingOption = TimingExplicitMsec; break;
+            case CSVFormat::TimeAudioFrames:
+                m_initialTimingOption = TimingExplicitSamples; break;
+            case CSVFormat::TimeWindows:
+                m_initialTimingOption = TimingImplicit; break;
+            }
+        }
+        m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption));
+
+    } else {
+
+        m_timingTypeCombo = 0;
     }
-
-    layout->addWidget(m_timingTypeCombo, row++, 1, 1, 2);
-
-    connect(m_timingTypeCombo, SIGNAL(activated(int)),
-            this, SLOT(timingTypeChanged(int)));
-
-    m_initialTimingOption = TimingImplicit;
-    if (m_format.getTimingType() == CSVFormat::ExplicitTiming) {
-        switch (m_format.getTimeUnits()) {
-        case CSVFormat::TimeSeconds:
-            m_initialTimingOption = TimingExplicitSeconds; break;
-        case CSVFormat::TimeMilliseconds:
-            m_initialTimingOption = TimingExplicitMsec; break;
-        case CSVFormat::TimeAudioFrames:
-            m_initialTimingOption = TimingExplicitSamples; break;
-        case CSVFormat::TimeWindows:
-            m_initialTimingOption = TimingImplicit; break;
-        }
-    }
-    m_timingTypeCombo->setCurrentIndex(int(m_initialTimingOption));
-
+        
     m_sampleRateLabel = new QLabel(tr("Audio sample rate (Hz):"));
     layout->addWidget(m_sampleRateLabel, row, 0);
     
@@ -176,30 +205,38 @@
     connect(m_sampleRateCombo, SIGNAL(editTextChanged(QString)),
             this, SLOT(sampleRateChanged(QString)));
 
-    m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
-    layout->addWidget(m_windowSizeLabel, row, 0);
+    if (m_dialogType == AnnotationDataDialog) {
+    
+        m_windowSizeLabel = new QLabel(tr("Frame increment between rows:"));
+        layout->addWidget(m_windowSizeLabel, row, 0);
 
-    m_windowSizeCombo = new QComboBox;
-    for (int i = 0; i <= 16; ++i) {
-        int value = 1 << i;
-        m_windowSizeCombo->addItem(QString("%1").arg(value));
-        if (value == int(m_format.getWindowSize())) {
-            m_windowSizeCombo->setCurrentIndex(i);
+        m_windowSizeCombo = new QComboBox;
+        for (int i = 0; i <= 16; ++i) {
+            int value = 1 << i;
+            m_windowSizeCombo->addItem(QString("%1").arg(value));
+            if (value == int(m_format.getWindowSize())) {
+                m_windowSizeCombo->setCurrentIndex(i);
+            }
         }
+        m_windowSizeCombo->setEditable(true);
+
+        layout->addWidget(m_windowSizeCombo, row++, 1);
+        connect(m_windowSizeCombo, SIGNAL(activated(QString)),
+                this, SLOT(windowSizeChanged(QString)));
+        connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
+                this, SLOT(windowSizeChanged(QString)));
+
+        m_modelLabel = new QLabel;
+        QFont f(m_modelLabel->font());
+        f.setItalic(true);
+        m_modelLabel->setFont(f);
+        layout->addWidget(m_modelLabel, row++, 0, 1, 4);
+
+    } else {
+        m_windowSizeLabel = 0;
+        m_windowSizeCombo = 0;
+        m_modelLabel = 0;
     }
-    m_windowSizeCombo->setEditable(true);
-
-    layout->addWidget(m_windowSizeCombo, row++, 1);
-    connect(m_windowSizeCombo, SIGNAL(activated(QString)),
-            this, SLOT(windowSizeChanged(QString)));
-    connect(m_windowSizeCombo, SIGNAL(editTextChanged(QString)),
-            this, SLOT(windowSizeChanged(QString)));
-
-    m_modelLabel = new QLabel;
-    QFont f(m_modelLabel->font());
-    f.setItalic(true);
-    m_modelLabel->setFont(f);
-    layout->addWidget(m_modelLabel, row++, 0, 1, 4);
 
     QDialogButtonBox *bb = new QDialogButtonBox(QDialogButtonBox::Ok |
                                                 QDialogButtonBox::Cancel);
@@ -209,7 +246,12 @@
 
     setLayout(layout);
 
-    timingTypeChanged(m_timingTypeCombo->currentIndex());
+    if (m_timingTypeCombo) {
+        timingTypeChanged(m_timingTypeCombo->currentIndex());
+    } else {
+        updateFormatFromDialog();
+        updateComboVisibility();
+    }
 }
 
 CSVFormatDialog::~CSVFormatDialog()
@@ -225,6 +267,10 @@
 void
 CSVFormatDialog::updateModelLabel()
 {
+    if (!m_modelLabel) {
+        return;
+    }
+    
     LayerFactory *f = LayerFactory::getInstance();
 
     QString s;
@@ -249,12 +295,17 @@
         break;
     }   
 
-    m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.").arg(s));
+    m_modelLabel->setText("\n" + tr("Data will be displayed in a %1 layer.")
+                          .arg(s));
 }
 
 void
 CSVFormatDialog::applyStartTimePurpose()
 {
+    if (m_dialogType == AudioDataDialog) {
+        return;
+    }
+    
     // First check if we already have any. NB there may be fewer than
     // m_format.getColumnCount() elements in m_columnPurposeCombos
     // (because of the fuzzy column behaviour). Note also that the
@@ -282,6 +333,10 @@
 void
 CSVFormatDialog::removeStartTimePurpose()
 {
+    if (m_dialogType == AudioDataDialog) {
+        return;
+    }
+    
     // NB there may be fewer than m_format.getColumnCount() elements
     // in m_columnPurposeCombos (because of the fuzzy column
     // behaviour)
@@ -297,15 +352,18 @@
 void
 CSVFormatDialog::updateComboVisibility()
 {
-    bool wantRate = (m_format.getTimingType() == CSVFormat::ImplicitTiming ||
+    bool wantRate = (m_dialogType == AudioDataDialog ||
+                     m_format.getTimingType() == CSVFormat::ImplicitTiming ||
                      m_format.getTimeUnits() == CSVFormat::TimeAudioFrames);
     bool wantWindow = (m_format.getTimingType() == CSVFormat::ImplicitTiming);
     
     m_sampleRateCombo->setEnabled(wantRate);
     m_sampleRateLabel->setEnabled(wantRate);
 
-    m_windowSizeCombo->setEnabled(wantWindow);
-    m_windowSizeLabel->setEnabled(wantWindow);
+    if (m_windowSizeCombo) {
+        m_windowSizeCombo->setEnabled(wantWindow);
+        m_windowSizeLabel->setEnabled(wantWindow);
+    }
 }
 
 void
@@ -344,6 +402,23 @@
     QComboBox *cb = qobject_cast<QComboBox *>(o);
     if (!cb) return;
 
+    if (m_dialogType == AnnotationDataDialog) {
+        columnPurposeChangedForAnnotationType(cb, p);
+    }
+
+    updateFormatFromDialog();
+    updateComboVisibility();
+}
+    
+void
+CSVFormatDialog::columnPurposeChangedForAnnotationType(QComboBox *cb, int p)
+{
+    // Ensure a consistent set of column purposes, in a situation
+    // where some combinations are contradictory. This is only
+    // relevant to annotation type formats. Only updates the UI, does
+    // not update the stored format record from the UI - that's the
+    // job of updateFormatFromDialog
+    
     CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)p;
 
     bool haveStartTime = false; // so as to update timing type combo appropriately
@@ -402,46 +477,50 @@
         }
     }
 
-    if (!haveStartTime) {
-        m_timingTypeCombo->setCurrentIndex(int(TimingImplicit));
-    } else if (m_timingTypeCombo->currentIndex() == int(TimingImplicit)) {
-        if (m_initialTimingOption == TimingImplicit) {
-            m_timingTypeCombo->setCurrentIndex(TimingExplicitSeconds);
-        } else {
-            m_timingTypeCombo->setCurrentIndex(m_initialTimingOption);
+    if (m_timingTypeCombo) {
+        if (!haveStartTime) {
+            m_timingTypeCombo->setCurrentIndex(int(TimingImplicit));
+        } else if (m_timingTypeCombo->currentIndex() == int(TimingImplicit)) {
+            if (m_initialTimingOption == TimingImplicit) {
+                m_timingTypeCombo->setCurrentIndex(TimingExplicitSeconds);
+            } else {
+                m_timingTypeCombo->setCurrentIndex(m_initialTimingOption);
+            }
         }
     }
-
-    updateFormatFromDialog();
-    updateComboVisibility();
 }
-
+    
 void
 CSVFormatDialog::updateFormatFromDialog()
 {
-    switch (TimingOption(m_timingTypeCombo->currentIndex())) {
+    if (m_timingTypeCombo) {
+        switch (TimingOption(m_timingTypeCombo->currentIndex())) {
 
-    case TimingExplicitSeconds:
-        m_format.setTimingType(CSVFormat::ExplicitTiming);
-        m_format.setTimeUnits(CSVFormat::TimeSeconds);
-        break;
+        case TimingExplicitSeconds:
+            m_format.setTimingType(CSVFormat::ExplicitTiming);
+            m_format.setTimeUnits(CSVFormat::TimeSeconds);
+            break;
 
-    case TimingExplicitMsec:
-        m_format.setTimingType(CSVFormat::ExplicitTiming);
-        m_format.setTimeUnits(CSVFormat::TimeMilliseconds);
-        break;
+        case TimingExplicitMsec:
+            m_format.setTimingType(CSVFormat::ExplicitTiming);
+            m_format.setTimeUnits(CSVFormat::TimeMilliseconds);
+            break;
 
-    case TimingExplicitSamples:
-        m_format.setTimingType(CSVFormat::ExplicitTiming);
+        case TimingExplicitSamples:
+            m_format.setTimingType(CSVFormat::ExplicitTiming);
+            m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
+            break;
+
+        case TimingImplicit:
+            m_format.setTimingType(CSVFormat::ImplicitTiming);
+            m_format.setTimeUnits(CSVFormat::TimeWindows);
+            break;
+        }
+    } else if (m_dialogType == AudioDataDialog) {
+        m_format.setTimingType(CSVFormat::ImplicitTiming);
         m_format.setTimeUnits(CSVFormat::TimeAudioFrames);
-        break;
-
-    case TimingImplicit:
-        m_format.setTimingType(CSVFormat::ImplicitTiming);
-        m_format.setTimeUnits(CSVFormat::TimeWindows);
-        break;
     }
-
+    
     bool haveStartTime = false;
     bool haveDuration = false;
     bool havePitch = false;
@@ -451,8 +530,15 @@
 
         QComboBox *thisCombo = m_columnPurposeCombos[i];
         
-        CSVFormat::ColumnPurpose purpose = (CSVFormat::ColumnPurpose)
-            (thisCombo->currentIndex());
+        CSVFormat::ColumnPurpose purpose;
+
+        if (m_dialogType == AnnotationDataDialog) {
+            purpose = (CSVFormat::ColumnPurpose) (thisCombo->currentIndex());
+        } else {
+            purpose = (thisCombo->currentIndex() == 1 ?
+                       CSVFormat::ColumnValue :
+                       CSVFormat::ColumnUnknown);
+        }
 
         if (i == m_fuzzyColumn) {
             for (int j = i; j < m_format.getColumnCount(); ++j) {
@@ -483,7 +569,9 @@
         }
     }
 
-    if (haveStartTime && haveDuration) {
+    if (m_dialogType == AudioDataDialog) {
+        m_format.setModelType(CSVFormat::WaveFileModel);
+    } else if (haveStartTime && haveDuration) {
         if (havePitch) {
             m_format.setModelType(CSVFormat::TwoDimensionalModelWithDurationAndPitch);
         } else {
--- a/widgets/CSVFormatDialog.h	Tue Sep 04 13:19:32 2018 +0100
+++ b/widgets/CSVFormatDialog.h	Thu Sep 06 11:49:31 2018 +0100
@@ -29,7 +29,8 @@
     Q_OBJECT
     
 public:
-    CSVFormatDialog(QWidget *parent, CSVFormat initialFormat,
+    CSVFormatDialog(QWidget *parent,
+                    CSVFormat initialFormat,
                     int maxDisplayCols = 5);
     ~CSVFormatDialog();
 
@@ -45,9 +46,15 @@
     void updateModelLabel();
 
 protected:
+    enum DialogType {
+        AnnotationDataDialog,
+        AudioDataDialog
+    };
+    DialogType m_dialogType;
+
     CSVFormat m_format;
     int m_maxDisplayCols;
-
+    
     enum TimingOption {
         TimingExplicitSeconds = 0,
         TimingExplicitMsec,
@@ -57,6 +64,7 @@
     std::map<TimingOption, QString> m_timingLabels;
     TimingOption m_initialTimingOption;
 
+    void columnPurposeChangedForAnnotationType(QComboBox *, int purpose);
     void updateComboVisibility();
     void applyStartTimePurpose();
     void removeStartTimePurpose();