changeset 728:2dce002539a0

Merge from branch spectrogram-export
author Chris Cannam
date Fri, 10 Jan 2020 14:54:43 +0000
parents 55f317633b93 (current diff) e2ad6fe768b0 (diff)
children 15da3ab3d416 8cf265f9b1b3
files
diffstat 3 files changed, 97 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/framework/MainWindowBase.cpp	Fri Dec 06 13:09:29 2019 +0000
+++ b/framework/MainWindowBase.cpp	Fri Jan 10 14:54:43 2020 +0000
@@ -37,6 +37,7 @@
 #include "layer/NoteLayer.h"
 #include "layer/FlexiNoteLayer.h"
 #include "layer/RegionLayer.h"
+#include "layer/SpectrogramLayer.h"
 
 #include "widgets/ListInputDialog.h"
 #include "widgets/CommandHistory.h"
@@ -61,6 +62,8 @@
 #include "rdf/RDFImporter.h"
 #include "rdf/RDFExporter.h"
 
+#include "transform/ModelTransformerFactory.h"
+
 #include "base/RecentFiles.h"
 
 #include "base/XmlExportable.h"
@@ -159,7 +162,6 @@
     m_recentTransforms("RecentTransforms", 20),
     m_documentModified(false),
     m_openingAudioFile(false),
-    m_abandoning(false),
     m_labeller(nullptr),
     m_lastPlayStatusSec(0),
     m_initialDarkBackground(false),
@@ -527,7 +529,7 @@
         connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
         QTimer *oscTimer = new QTimer(this);
         connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
-        oscTimer->start(1000);
+        oscTimer->start(2000);
 
         if (m_oscQueue->hasPort()) {
             SVDEBUG << "Finished setting up OSC interface" << endl;
@@ -686,6 +688,9 @@
     bool haveCurrentColour3DPlot =
         (haveCurrentLayer &&
          dynamic_cast<Colour3DPlotLayer *>(currentLayer));
+    bool haveCurrentSpectrogram =
+        (haveCurrentLayer &&
+         dynamic_cast<SpectrogramLayer *>(currentLayer));
     bool haveClipboardContents =
         (m_viewManager &&
          !m_viewManager->getClipboard().empty());
@@ -704,7 +709,9 @@
     emit canExportAudio(haveMainModel);
     emit canChangeSessionTemplate(haveMainModel);
     emit canExportLayer(haveMainModel &&
-                        (haveCurrentEditableLayer || haveCurrentColour3DPlot));
+                        (haveCurrentEditableLayer ||
+                         haveCurrentColour3DPlot ||
+                         haveCurrentSpectrogram));
     emit canExportImage(haveMainModel && haveCurrentPane);
     emit canDeleteCurrentLayer(haveCurrentLayer);
     emit canRenameLayer(haveCurrentLayer);
@@ -2797,13 +2804,20 @@
 }
 
 bool
-MainWindowBase::exportLayerTo(Layer *layer, QString path, QString &error)
+MainWindowBase::exportLayerTo(Layer *layer, View *fromView,
+                              MultiSelection *selectionsToWrite,
+                              QString path, QString &error)
 {
+    //!!! should we pull out the whole export logic into another
+    // class?  then we can more reasonably query it for things like
+    // "can we export this layer type to this file format? can we
+    // export selections, or only the whole layer?"
+    
     if (QFileInfo(path).suffix() == "") path += ".svl";
 
     QString suffix = QFileInfo(path).suffix().toLower();
 
-    auto model = ModelById::get(layer->getModel());
+    auto model = ModelById::get(layer->getExportModel(fromView));
     if (!model) {
         error = tr("Internal error: unknown model");
         return false;
@@ -2839,8 +2853,27 @@
 
         if (!nm) {
             error = tr("Can't export non-note layers to MIDI");
+        } else if (!selectionsToWrite) {
+            MIDIFileWriter writer(path, nm.get(), nm->getSampleRate());
+            writer.write();
+            if (!writer.isOK()) {
+                error = writer.getError();
+            }
         } else {
-            MIDIFileWriter writer(path, nm.get(), nm->getSampleRate());
+            NoteModel temporary(nm->getSampleRate(),
+                                nm->getResolution(),
+                                nm->getValueMinimum(),
+                                nm->getValueMaximum(),
+                                false);
+            temporary.setScaleUnits(nm->getScaleUnits());
+            for (const auto &s: selectionsToWrite->getSelections()) {
+                EventVector ev(nm->getEventsStartingWithin
+                               (s.getStartFrame(), s.getDuration()));
+                for (const auto &e: ev) {
+                    temporary.add(e);
+                }
+            }
+            MIDIFileWriter writer(path, &temporary, temporary.getSampleRate());
             writer.write();
             if (!writer.isOK()) {
                 error = writer.getError();
@@ -2861,12 +2894,25 @@
 
     } else {
 
-        CSVFileWriter writer(path, model.get(),
+        ProgressDialog dialog {
+            QObject::tr("Exporting layer..."), true, 500, this,
+            Qt::ApplicationModal
+        };
+            
+        CSVFileWriter writer(path, model.get(), &dialog,
                              ((suffix == "csv") ? "," : "\t"));
-        writer.write();
+
+        if (selectionsToWrite) {
+            writer.writeSelection(*selectionsToWrite);
+        } else {
+            writer.write();
+        }
 
         if (!writer.isOK()) {
             error = writer.getError();
+            if (error == "") {
+                error = tr("Failed to export layer for an unknown reason");
+            }
         }
     }
 
@@ -4164,17 +4210,46 @@
 MainWindowBase::pollOSC()
 {
     if (!m_oscQueue || m_oscQueue->isEmpty()) return;
-    SVDEBUG << "MainWindowBase::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << endl;
-
-    if (m_openingAudioFile) return;
-
-    OSCMessage message = m_oscQueue->readMessage();
-
-    if (message.getTarget() != 0) {
-        return; //!!! for now -- this class is target 0, others not handled yet
+
+    while (!m_oscQueue->isEmpty()) {
+
+        if (m_openingAudioFile) {
+            SVDEBUG << "MainWindowBase::pollOSC: "
+                    << "waiting for audio to finish loading"
+                    << endl;
+            return;
+        }
+
+        if (ModelTransformerFactory::getInstance()->haveRunningTransformers()) {
+            SVDEBUG << "MainWindowBase::pollOSC: "
+                    << "waiting for running transforms to complete"
+                    << endl;
+            return;
+        }
+
+        SVDEBUG << "MainWindowBase::pollOSC: have "
+                << m_oscQueue->getMessagesAvailable()
+                << " messages" << endl;
+    
+        OSCMessage message = m_oscQueue->readMessage();
+
+        if (message.getTarget() != 0) {
+            SVCERR << "MainWindowBase::pollOSC: ignoring message with target "
+                   << message.getTarget() << " (we are target 0)" << endl;
+            continue;
+        }
+
+        handleOSCMessage(message);
+
+        disconnect(m_oscQueue, SIGNAL(messagesAvailable()),
+                   this, SLOT(pollOSC()));
+        
+        QApplication::processEvents(QEventLoop::ExcludeUserInputEvents |
+                                    QEventLoop::ExcludeSocketNotifiers);
+
+        connect(m_oscQueue, SIGNAL(messagesAvailable()),
+                this, SLOT(pollOSC()));
     }
-
-    handleOSCMessage(message);
 }
 
 void
--- a/framework/MainWindowBase.h	Fri Dec 06 13:09:29 2019 +0000
+++ b/framework/MainWindowBase.h	Fri Jan 10 14:54:43 2020 +0000
@@ -165,7 +165,9 @@
     virtual bool saveSessionFile(QString path);
     virtual bool saveSessionTemplate(QString path);
 
-    virtual bool exportLayerTo(Layer *layer, QString path, QString &error);
+    virtual bool exportLayerTo(Layer *layer, View *fromView,
+                               MultiSelection *selectionsToWrite, // or null
+                               QString toPath, QString &error);
 
     void cueOSCScript(QString filename);
     
@@ -428,7 +430,6 @@
 
     bool                     m_documentModified;
     bool                     m_openingAudioFile;
-    bool                     m_abandoning;
 
     Labeller                *m_labeller;
 
--- a/framework/OSCScript.h	Fri Dec 06 13:09:29 2019 +0000
+++ b/framework/OSCScript.h	Fri Jan 10 14:54:43 2020 +0000
@@ -105,7 +105,7 @@
                     message.addArg(parts[i]);
                 }
                 SVCERR << "OSCScript: " << reportedFilename << ":" << lineno
-                       << ": invoking: \"" << parts[0] << "\"" << endl;
+                       << ": posting " << message.toString() << endl;
                 m_queue->postMessage(message);
 
             } else {