changeset 70:e269ae6ed008

* When adding a layer, make it the selected layer on that pane * More OSC support, including transforms
author Chris Cannam
date Fri, 10 Nov 2006 17:45:26 +0000
parents 76cc2c424268
children 51f34d378a3a
files main/MainWindow.cpp main/MainWindow.h main/main.cpp osc/sv-command
diffstat 4 files changed, 157 insertions(+), 18 deletions(-) [+]
line wrap: on
line diff
--- a/main/MainWindow.cpp	Fri Nov 10 13:27:57 2006 +0000
+++ b/main/MainWindow.cpp	Fri Nov 10 17:45:26 2006 +0000
@@ -96,7 +96,7 @@
 using std::set;
 
 
-MainWindow::MainWindow(bool withAudioOutput) :
+MainWindow::MainWindow(bool withAudioOutput, bool withOSCSupport) :
     m_document(0),
     m_paneStack(0),
     m_viewManager(0),
@@ -105,7 +105,7 @@
     m_audioOutput(withAudioOutput),
     m_playSource(0),
     m_playTarget(0),
-    m_oscQueue(new OSCQueue()),
+    m_oscQueue(withOSCSupport ? new OSCQueue() : 0),
     m_recentFiles("RecentFiles"),
     m_recentTransforms("RecentTransforms", 20),
     m_mainMenusCreated(false),
@@ -119,6 +119,8 @@
     m_rightButtonLayerMenu(0),
     m_rightButtonTransformsMenu(0),
     m_documentModified(false),
+    m_openingAudioFile(false),
+    m_abandoning(false),
     m_preferencesDialog(0)
 {
     setWindowTitle(tr("Sonic Visualiser"));
@@ -231,7 +233,7 @@
             this,
             SLOT(preferenceChanged(PropertyContainer::PropertyName)));
 
-    if (m_oscQueue->isOK()) {
+    if (m_oscQueue && m_oscQueue->isOK()) {
         connect(m_oscQueue, SIGNAL(messagesAvailable()), this, SLOT(pollOSC()));
         QTimer *oscTimer = new QTimer(this);
         connect(oscTimer, SIGNAL(timeout()), this, SLOT(pollOSC()));
@@ -248,7 +250,9 @@
 
 MainWindow::~MainWindow()
 {
-    closeSession();
+    if (!m_abandoning) {
+        closeSession();
+    }
     delete m_playTarget;
     delete m_playSource;
     delete m_viewManager;
@@ -2042,10 +2046,13 @@
 	return false;
     }
 
+    m_openingAudioFile = true;
+
     WaveFileModel *newModel = new WaveFileModel(path);
 
     if (!newModel->isOK()) {
 	delete newModel;
+        m_openingAudioFile = false;
 	return false;
     }
 
@@ -2068,6 +2075,7 @@
             
             if (!ok || item.isEmpty()) {
                 delete newModel;
+                m_openingAudioFile = false;
                 return false;
             }
             
@@ -2138,6 +2146,7 @@
 
     updateMenuStates();
     m_recentFiles.addFile(path);
+    m_openingAudioFile = false;
 
     return true;
 }
@@ -2453,7 +2462,7 @@
 void
 MainWindow::closeEvent(QCloseEvent *e)
 {
-    if (!checkSaveModified()) {
+    if (!m_abandoning && !checkSaveModified()) {
 	e->ignore();
 	return;
     }
@@ -2935,6 +2944,7 @@
     m_document->addLayerToView(pane, newLayer);
 
     m_paneStack->setCurrentPane(pane);
+    m_paneStack->setCurrentLayer(pane, newLayer);
 
     CommandHistory::getInstance()->endCompoundOperation();
 
@@ -3129,6 +3139,7 @@
         m_document->addLayerToView(pane, newLayer);
         m_document->setChannel(newLayer, context.channel);
         m_recentTransforms.add(transform);
+        m_paneStack->setCurrentLayer(pane, newLayer);
     }
 
     updateMenuStates();
@@ -3412,9 +3423,11 @@
 void
 MainWindow::pollOSC()
 {
-    if (m_oscQueue->isEmpty()) return;
+    if (!m_oscQueue || m_oscQueue->isEmpty()) return;
     std::cerr << "MainWindow::pollOSC: have " << m_oscQueue->getMessagesAvailable() << " messages" << std::endl;
 
+    if (m_openingAudioFile) return;
+
     OSCMessage message = m_oscQueue->readMessage();
 
     if (message.getTarget() != 0) {
@@ -3427,6 +3440,9 @@
 void
 MainWindow::handleOSCMessage(const OSCMessage &message)
 {
+    std::cerr << "MainWindow::handleOSCMessage: thread id = " 
+              << QThread::currentThreadId() << std::endl;
+
     // This large function should really be abstracted out.
 
     if (message.getMethod() == "open") {
@@ -3668,7 +3684,7 @@
 
     } else if (message.getMethod() == "set") {
 
-        if (message.getArgCount() >= 2 &&
+        if (message.getArgCount() == 2 &&
             message.getArg(0).canConvert(QVariant::String) &&
             message.getArg(1).canConvert(QVariant::Double)) {
 
@@ -3689,6 +3705,28 @@
                 } else {
                     m_viewManager->setOverlayMode(ViewManager::AllOverlays);
                 }                    
+            } else if (property == "zoomwheels") {
+                m_viewManager->setZoomWheelsEnabled(value > 0.5);
+            }
+                
+        } else {
+            PropertyContainer *container = 0;
+            Pane *pane = m_paneStack->getCurrentPane();
+            if (pane &&
+                message.getArgCount() == 3 &&
+                message.getArg(0).canConvert(QVariant::String) &&
+                message.getArg(1).canConvert(QVariant::String) &&
+                message.getArg(2).canConvert(QVariant::String)) {
+                if (message.getArg(0).toString() == "pane") {
+                    container = pane->getPropertyContainer(0);
+                } else if (message.getArg(0).toString() == "layer") {
+                    container = pane->getSelectedLayer();
+                }
+            }
+            if (container) {
+                QString nameString = message.getArg(1).toString();
+                QString valueString = message.getArg(2).toString();
+                container->setPropertyWithCommand(nameString, valueString);
             }
         }
 
@@ -3711,13 +3749,12 @@
 
         if (paneIndex >= 0 && paneIndex < m_paneStack->getPaneCount()) {
             Pane *pane = m_paneStack->getPane(paneIndex);
+            m_paneStack->setCurrentPane(pane);
             if (layerIndex >= 0 && layerIndex < pane->getLayerCount()) {
                 Layer *layer = pane->getLayer(layerIndex);
                 m_paneStack->setCurrentLayer(pane, layer);
             } else if (wantLayer && layerIndex == -1) {
                 m_paneStack->setCurrentLayer(pane, 0);
-            } else {
-                m_paneStack->setCurrentPane(pane);
             }
         }
 
@@ -3762,6 +3799,59 @@
             }
         }
 
+    } else if (message.getMethod() == "quit") {
+        
+        m_abandoning = true;
+        close();
+
+    } else if (message.getMethod() == "resize") {
+        
+        if (message.getArgCount() == 2) {
+
+            int width = 0, height = 0;
+
+            if (message.getArg(1).canConvert(QVariant::Int)) {
+
+                height = message.getArg(1).toInt();
+
+                if (message.getArg(0).canConvert(QVariant::String) &&
+                    message.getArg(0).toString() == "pane") {
+
+                    Pane *pane = m_paneStack->getCurrentPane();
+                    if (pane) pane->resize(pane->width(), height);
+
+                } else if (message.getArg(0).canConvert(QVariant::Int)) {
+
+                    width = message.getArg(0).toInt();
+                    resize(width, height);
+                }
+            }
+        }
+
+    } else if (message.getMethod() == "transform") {
+
+        Pane *pane = m_paneStack->getCurrentPane();
+
+        if (getMainModel() &&
+            pane &&
+            message.getArgCount() == 1 &&
+            message.getArg(0).canConvert(QVariant::String)) {
+
+            TransformName transform = message.getArg(0).toString();
+
+            Layer *newLayer = m_document->createDerivedLayer
+                (transform,
+                 getMainModel(),
+                 PluginTransform::ExecutionContext(),
+                 "");
+
+            if (newLayer) {
+                m_document->addLayerToView(pane, newLayer);
+                m_recentTransforms.add(transform);
+                m_paneStack->setCurrentLayer(pane, newLayer);
+            }
+        }
+
     } else {
         std::cerr << "WARNING: MainWindow::handleOSCMessage: Unknown or unsupported "
                   << "method \"" << message.getMethod().toStdString()
@@ -3919,7 +4009,7 @@
     aboutText += tr("<br>With DSSI plugin support (API v%1) &copy; Chris Cannam, Steve Harris, Sean Bolton").arg(DSSI_VERSION);
 #ifdef HAVE_LIBLO
     aboutText += tr("<br>With liblo Lite OSC library (v%1) &copy; Steve Harris").arg(LIBLO_VERSION);
-    if (m_oscQueue->isOK()) {
+    if (m_oscQueue && m_oscQueue->isOK()) {
         aboutText += tr("<p>The OSC URL for this instance is: \"%1\"").arg(m_oscQueue->getOSCURL());
     }
 #endif
--- a/main/MainWindow.h	Fri Nov 10 13:27:57 2006 +0000
+++ b/main/MainWindow.h	Fri Nov 10 17:45:26 2006 +0000
@@ -57,7 +57,8 @@
     Q_OBJECT
 
 public:
-    MainWindow(bool withAudioOutput = true);
+    MainWindow(bool withAudioOutput = true,
+               bool withOSCSupport = true);
     virtual ~MainWindow();
     
     enum AudioFileOpenMode {
@@ -241,6 +242,8 @@
     QMenu                   *m_rightButtonTransformsMenu;
 
     bool                     m_documentModified;
+    bool                     m_openingAudioFile;
+    bool                     m_abandoning;
 
     QPointer<PreferencesDialog> m_preferencesDialog;
 
--- a/main/main.cpp	Fri Nov 10 13:27:57 2006 +0000
+++ b/main/main.cpp	Fri Nov 10 17:45:26 2006 +0000
@@ -91,7 +91,16 @@
     svSystemSpecificInitialisation();
 
     bool audioOutput = true;
+    bool oscSupport = true;
+
+    if (args.contains("--help")) {
+        std::cerr << QApplication::tr(
+            "\nSonic Visualiser is a program for viewing and exploring audio data\nfor semantic music analysis and annotation.\n\nUsage:\n\n  %1 [--no-audio] [--no-osc] [<file> ...]\n\n  --no-audio: Do not attempt to open an audio output device\n  --no-osc: Do not provide an Open Sound Control port for remote control\n  <file>: One or more Sonic Visualiser (.sv) and audio files may be provided.\n").arg(argv[0]).toStdString() << std::endl;
+        exit(2);
+    }
+
     if (args.contains("--no-audio")) audioOutput = false;
+    if (args.contains("--no-osc")) oscSupport = false;
 
     QApplication::setOrganizationName("sonic-visualiser");
     QApplication::setOrganizationDomain("sonicvisualiser.org");
@@ -117,7 +126,7 @@
     qRegisterMetaType<size_t>("size_t");
     qRegisterMetaType<PropertyContainer::PropertyName>("PropertyContainer::PropertyName");
 
-    MainWindow gui(audioOutput);
+    MainWindow gui(audioOutput, oscSupport);
     application.setMainWindow(&gui);
 
     QDesktopWidget *desktop = QApplication::desktop();
--- a/osc/sv-command	Fri Nov 10 13:27:57 2006 +0000
+++ b/osc/sv-command	Fri Nov 10 17:45:26 2006 +0000
@@ -1,17 +1,54 @@
 #!/bin/sh
-port=`lsof -c sonic- | grep UDP | sed -e 's/^.*[^0-9]\([0-9][0-9]*\) *$/\1/' | grep -v ' ' | head -1`
+#
+# A very simple command shell for Sonic Visualiser.
+# 
+# This provides a wrapper for the sv-osc-send program, which is a
+# generic OSC sending program (not specific to SV, despite its name).
+# This script attempts to guess the OSC port number for an SV
+# process running on the local host, and then composes a method name
+# and arguments into a complete OSC call.
+# 
+# You can either run this with the method and its arguments on the
+# command line, e.g. "sv-command set layer Frequency-Scale Log", or
+# you can provide a series of method + argument commands on stdin.
+# 
+# Unless you use the -q option, this script will echo the OSC URL
+# and arguments that it is sending for each command.
+#
+# Note that the method and arguments may not contain spaces.
+# 
+# Chris Cannam, Nov 2006
+
+quiet=
+if [ "$1" = "-q" ]; then
+    quiet=true; shift;
+fi
+
+# The yucky bit
+
+port=`lsof -c sonic- | \
+          grep UDP | \
+          sed -e 's/^.*[^0-9]\([0-9][0-9]*\) *$/\1/' | \
+          grep -v ' ' | \
+          head -1 `
+
+host=127.0.0.1
+scheme=osc.udp
+
 if [ -z "$port" ]; then
     echo "Sonic Visualiser OSC port not found"
     exit 1
 fi
+
 if [ -n "$1" ]; then
     command=$1; shift
-    echo "osc.udp://127.0.0.1:$port/$command" "$@"
-    sv-osc-send "osc.udp://127.0.0.1:$port/$command" "$@"
+    [ -z "$quiet" ] && echo "$scheme://$host:$port/$command" "$@"
+    sv-osc-send "$scheme://$host:$port/$command" "$@"
 else
-    while read command arg1 arg2 arg3 arg4 arg5; do
-	echo "osc.udp://127.0.0.1:$port/$command" $arg1 $arg2 $arg3 $arg4 $arg5
-	sv-osc-send "osc.udp://127.0.0.1:$port/$command" $arg1 $arg2 $arg3 $arg4 $arg5
+    while read command a1 a2 a3 a4 a5; do
+        [ -z "$command" ] && continue
+	[ -z "$quiet" ] && echo "$scheme://$host:$port/$command" $a1 $a2 $a3 $a4 $a5
+	sv-osc-send "$scheme://$host:$port/$command" $a1 $a2 $a3 $a4 $a5
     done
 fi