traverso-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Traverso-devel] Sample OSC Implementation [patch included]


From: Fred Gleason
Subject: [Traverso-devel] Sample OSC Implementation [patch included]
Date: Tue, 4 Dec 2007 14:21:27 -0500
User-agent: KMail/1.8.2

Howdy Folks:

Appended is a patch against current CVS that implements OSC support for 
Traverso.  It uses Steve Harris's and Nicholas Humfrey's 'liblo' library, 
available at:

        http://liblo.sourceforge.net/

At present, the namespace is extremely simple, consisting of just a single 
leaf:  '/traverso/transport/insert_track', which expects a single string 
argument: a fully qualified name for an audio file.  When executed (by 
sending the appropriate OSC message to UDP port 7770), traverso will create a 
new track and then attempt to import the referenced file into it.  The 
implementation uses two new classes in 'common/': 'OscEvent' (a container 
class for OSC message bundles) and 'OscHandler' (a C++ encapsulation of liblo 
that allows OSC events to by processed by means of the standard Qt 
signal/slot mechanism).  To date, I have tested this only on Linux (i386 
architecture).

This patch is intended to demonstrate a basic 'proof of concept', not a 
finished implementation.  Specifically, I'd appreciate it if some of the 
senior folks here could take a glance at it and give a shout if they find any 
obvious showstoppers (organization, coding style, cross-platform pitfalls, 
etc).  If it passes muster, I'll go ahead and start putting together a draft 
namespace layout for a full implementation.

Patch follows:

*** snip snip ***
diff --unified --recursive --new-file traverso/src/commands/Import.cpp 
traverso-fredg01/src/commands/Import.cpp
--- traverso/src/commands/Import.cpp    2007-11-19 06:18:52.000000000 -0500
+++ traverso-fredg01/src/commands/Import.cpp    2007-12-03 08:45:35.000000000 
-0500
@@ -98,22 +98,22 @@
                                tr("Import audio source"),
                                pm().get_project()->get_import_dir(),
                                tr("All files (*);;Audio files (*.wav 
*.flac)"));
+       }
                
-               int splitpoint = m_fileName.lastIndexOf("/") + 1;
-               QString dir = m_fileName.left(splitpoint - 1);
+               int splitpoint = m_fileName.lastIndexOf("/") + 1;
+               QString dir = m_fileName.left(splitpoint - 1);
                
-               if (m_fileName.isEmpty()) {
-                       PWARN("Import:: FileName is empty!");
-                       return -1;
-               }
+               if (m_fileName.isEmpty()) {
+                       PWARN("Import:: FileName is empty!");
+                       return -1;
+               }
                
-               pm().get_project()->set_import_dir(dir);
+               pm().get_project()->set_import_dir(dir);
                
-               if (create_readsource() == -1) {
-                       return -1;
-               }
-               create_audioclip();
-       }
+               if (create_readsource() == -1) {
+                       return -1;
+               }
+               create_audioclip();
        
        return 1;
 }
@@ -131,7 +131,6 @@
                PERROR("Can't import audiofile %s", QS_C(m_fileName));
                return -1;
        }
-       
        return 1;
 }
 
diff --unified --recursive --new-file traverso/src/common/OscEvent.cpp 
traverso-fredg01/src/common/OscEvent.cpp
--- traverso/src/common/OscEvent.cpp    1969-12-31 19:00:00.000000000 -0500
+++ traverso-fredg01/src/common/OscEvent.cpp    2007-12-03 13:47:01.000000000 
-0500
@@ -0,0 +1,59 @@
+// OscEvent.cpp
+//
+// Copyright (C) 2007 Fred Gleason <address@hidden>
+//  
+//  This file is part of Traverso
+//  
+//  Traverso is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//  
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  
USA.
+
+
+#include "OscEvent.h"
+
+
+OscEvent::OscEvent(const QString &path)
+{
+        m_path=path;
+}
+
+
+QString OscEvent::path() const
+{
+        return m_path;
+}
+
+
+unsigned OscEvent::args() const
+{
+        return m_args.size();
+}
+
+
+OscEvent::OscType OscEvent::type(unsigned n) const
+{
+        return m_types[n];
+}
+
+
+QVariant OscEvent::arg(unsigned n) const
+{
+        return m_args[n];
+}
+
+
+void OscEvent::addArg(OscType type,QVariant arg)
+{
+        m_types.push_back(type);
+        m_args.push_back(arg);
+}
diff --unified --recursive --new-file traverso/src/common/OscEvent.h 
traverso-fredg01/src/common/OscEvent.h
--- traverso/src/common/OscEvent.h      1969-12-31 19:00:00.000000000 -0500
+++ traverso-fredg01/src/common/OscEvent.h      2007-12-03 14:38:55.000000000 
-0500
@@ -0,0 +1,56 @@
+// OscEvent.h
+//
+// Copyright (C) 2007 Fred Gleason <address@hidden>
+//  
+//  This file is part of Traverso
+//  
+//  Traverso is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//  
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  
USA.
+//
+//
+//  This abstracts an OSC message, as defined in v1.0 of the Open Sound 
Control
+//  Protocol [http://opensoundcontrol.org/spec-1_0].
+//
+
+#ifndef OSCEVENT_H
+#define OSCEVENT_H
+
+#include <vector>
+
+#include <qstring.h>
+#include <qvariant.h>
+
+
+class OscEvent
+{
+ public :
+        enum OscType 
{TypeInt32='i',TypeFloat32='f',TypeString='s',TypeBlob='b'};
+       OscEvent(const QString &path);
+       QString path() const;
+       unsigned args() const;
+       OscEvent::OscType type(unsigned n) const;
+       QVariant arg(unsigned n) const;
+       void addArg(OscType type,QVariant arg);
+
+ private:
+       QString m_path;
+       OscEvent::OscType m_type;
+       QVariant m_arg;
+       std::vector<OscEvent::OscType> m_types;
+       std::vector<QVariant> m_args;
+};
+
+
+
+#endif
diff --unified --recursive --new-file traverso/src/common/OscHandler.cpp 
traverso-fredg01/src/common/OscHandler.cpp
--- traverso/src/common/OscHandler.cpp  1969-12-31 19:00:00.000000000 -0500
+++ traverso-fredg01/src/common/OscHandler.cpp  2007-12-03 14:35:27.000000000 
-0500
@@ -0,0 +1,87 @@
+// OscHandler.cpp
+//
+// Copyright (C) 2007 Fred Gleason <address@hidden>
+//  
+//  This file is part of Traverso
+//  
+//  Traverso is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//  
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  
USA.
+
+
+#include <qtimer.h>
+#include <qbytearray.h>
+
+#include "OscEvent.h"
+#include "OscHandler.h"
+
+int OscCallback(const char *path, const char *types, lo_arg **argv,
+               int argc, void *data, void *user_data)
+{
+        int size=0;
+        OscEvent *e=new OscEvent(path);
+       for (int i=0; i<argc; i++) {
+               switch((OscEvent::OscType)types[i]) {
+                       case OscEvent::TypeInt32:
+                               e->addArg(OscEvent::TypeInt32,argv[i]->i);
+                               break;
+
+                       case OscEvent::TypeFloat32:
+                               e->addArg(OscEvent::TypeFloat32,argv[i]->f);
+                               break;
+
+                       case OscEvent::TypeString:
+                               e->addArg(OscEvent::TypeString,QString((const 
char *)argv[i]));
+                               break;
+
+                       case OscEvent::TypeBlob:
+                               size=argv[i]->i;
+                               e->addArg(OscEvent::TypeBlob,QByteArray(((const 
char *)argv[i])+4,size));
+                               break;
+
+                       default:  // Ignore unknown types as per the OSC spec 
(http://opensoundcontrol.org/spec-1_0)
+                               return -1;
+               }
+       }
+       ((OscHandler *)user_data)->handlerData(e);
+       delete e;
+       return 1;
+}
+
+
+OscHandler::OscHandler(uint16_t port)
+{
+        m_server=lo_server_new_with_proto((const char 
*)QString().sprintf("%d",port).toAscii(),LO_UDP,NULL);
+       lo_server_add_method(m_server, NULL, NULL, OscCallback, this);
+       QTimer *timer=new QTimer(this);
+       connect(timer,SIGNAL(timeout()),this,SLOT(pollData()));
+       timer->start(OSC_POLL_INTERVAL);
+}
+
+
+OscHandler::~OscHandler()
+{
+        free(m_server);
+}
+
+
+void OscHandler::handlerData(OscEvent *e)
+{
+        emit messageReceived(e);
+}
+
+
+void OscHandler::pollData()
+{
+       while(lo_server_recv_noblock(m_server,0)>0);
+}
diff --unified --recursive --new-file traverso/src/common/OscHandler.h 
traverso-fredg01/src/common/OscHandler.h
--- traverso/src/common/OscHandler.h    1969-12-31 19:00:00.000000000 -0500
+++ traverso-fredg01/src/common/OscHandler.h    2007-12-03 14:41:37.000000000 
-0500
@@ -0,0 +1,58 @@
+// OscHandler.h
+//
+// Copyright (C) 2007 Fred Gleason <address@hidden>
+//  
+//  This file is part of Traverso
+//  
+//  Traverso is free software; you can redistribute it and/or modify
+//  it under the terms of the GNU General Public License as published by
+//  the Free Software Foundation; either version 2 of the License, or
+//  (at your option) any later version.
+//  
+//  This program is distributed in the hope that it will be useful,
+//  but WITHOUT ANY WARRANTY; without even the implied warranty of
+//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+//  GNU General Public License for more details.
+//  
+//  You should have received a copy of the GNU General Public License
+//  along with this program; if not, write to the Free Software
+//  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  
USA.
+//
+//
+//  This class is designed to make a thin wrapper around the 'liblo' library
+//  for formatting and handling OSC (Open Sound Control) messages, allowing
+//  such messages to be handled via Qt's standard signal/slot mechanism.
+//
+
+#ifndef OSCHANDLER_H
+#define OSCHANDLER_H
+
+#include <lo/lo.h>
+
+#include "OscEvent.h"
+#include "defines.h"
+
+#define DEFAULT_OSC_PORT 7770
+#define OSC_POLL_INTERVAL 100
+
+class OscHandler : public QObject
+{
+ Q_OBJECT;
+ public :
+       OscHandler(uint16_t port);
+       ~OscHandler();
+       void handlerData(OscEvent *e);
+
+ signals:
+       void messageReceived(OscEvent *e);
+
+ private slots:
+        void pollData();
+
+ private:
+       lo_server m_server;
+};
+
+
+
+#endif
diff --unified --recursive --new-file traverso/src/core/core.pro 
traverso-fredg01/src/core/core.pro
--- traverso/src/core/core.pro  2007-11-19 06:18:53.000000000 -0500
+++ traverso-fredg01/src/core/core.pro  2007-12-03 10:45:24.000000000 -0500
@@ -27,6 +27,8 @@
        ../common/Mixer.cpp \
        ../common/RingBuffer.cpp \
        ../common/Resampler.cpp \
+        ../common/OscEvent.cpp \
+        ../common/OscHandler.cpp \
        AudioClip.cpp \
        AudioClipManager.cpp \
        AudioSource.cpp \
@@ -66,6 +68,8 @@
        ../common/RingBuffer.h \
        ../common/RingBufferNPT.h \
        ../common/Resampler.h \
+        ../common/OscEvent.h \
+        ../common/OscHandler.h \
        AudioClip.h \
        AudioClipManager.h \
        AudioSource.h \
diff --unified --recursive --new-file traverso/src/traverso/Interface.cpp 
traverso-fredg01/src/traverso/Interface.cpp
--- traverso/src/traverso/Interface.cpp 2007-12-03 09:05:25.000000000 -0500
+++ traverso-fredg01/src/traverso/Interface.cpp 2007-12-03 15:10:28.000000000 
-0500
@@ -46,6 +46,7 @@
 #include "SpectralMeterWidget.h"
                
 #include "Import.h"
+#include "CommandGroup.h"
 
 #include "songcanvas/SongWidget.h"
 
@@ -200,6 +201,8 @@
        cpointer().add_contextitem(this);
 
        connect(&config(), SIGNAL(configChanged()), this, 
SLOT(config_changed()));
+
+       init_osc();
 }
 
 Interface::~Interface()
@@ -279,7 +282,7 @@
 {
        PENTER;
        
-       SongWidget* songWidget;
+       SongWidget* songWidget = 0;
        
        if (!song) {
                Project* project = pm().get_project();
@@ -1248,3 +1251,55 @@
        config().save();
 }
 
+
+void Interface::init_osc()
+{
+        m_oscHandler=new OscHandler(DEFAULT_OSC_PORT);
+       connect(m_oscHandler,SIGNAL(messageReceived(OscEvent 
*)),this,SLOT(handle_osc_messages(OscEvent *)));
+}
+
+
+void Interface::handle_osc_messages(OscEvent* e)
+{
+        if(e->path()!="/traverso/transport/insert_track") {
+               return;
+       }
+       if((e->args()==1)&&(e->type(0)==OscEvent::TypeString)) {
+               insert_audio(e->arg(0).toString());
+       }
+}
+
+
+void Interface::insert_audio(const QString &filename)
+{
+        //
+        // Create a new track
+        //
+        Project *project=pm().get_project();
+       if (! project) {
+               info().information(tr("I can't create a new Track if there is 
no Project 
loaded!!"));
+               return;
+       }
+       
+       Song* song = project->get_current_song();
+       if ( ! song ) {
+               return ;
+       }
+       
+       CommandGroup* group = new CommandGroup(song, "");
+       
+       Track* track = new Track(song, "Unnamed", Track::INITIAL_HEIGHT);
+       track->set_name("Unnamed");
+       group->add_command(song->add_track(track));
+               
+       group->setText(tr("Added 1 Track(s)", ""));
+       Command::process_command(group);
+
+       //
+       // Import Audio 
+       //
+               Import* cmd = new Import(track, filename, TimeRef());
+       Command::process_command(cmd);
+}
+
+
diff --unified --recursive --new-file traverso/src/traverso/Interface.h 
traverso-fredg01/src/traverso/Interface.h
--- traverso/src/traverso/Interface.h   2007-11-29 14:52:18.000000000 -0500
+++ traverso-fredg01/src/traverso/Interface.h   2007-12-03 15:09:36.000000000 
-0500
@@ -23,6 +23,7 @@
 #ifndef INTERFACE_H
 #define INTERFACE_H
 
+#include <OscHandler.h>
 #include <QMainWindow>
 #include <QHash>
 
@@ -87,6 +88,7 @@
        void select_fade_out_shape();
        void show_busselector(Track* track);
        void set_insertsilence_track(Track* track);
+       void init_osc();
        
 protected:
        void keyPressEvent ( QKeyEvent* e);
@@ -125,7 +127,7 @@
        NewProjectDialog*       m_newProjectDialog;
        QDialog*                m_quickStart;
        RestoreProjectBackupDialog* m_restoreProjectBackupDialog;
-
+       OscHandler*             m_oscHandler;
 
        BusMonitor*             busMonitor;
        QToolBar*               mainToolBar;
@@ -149,6 +151,7 @@
        QMenu* create_context_menu(QObject* item, QList<MenuData >* list = 0);
        QMenu* create_fade_selector_menu(const QString& fadeTypeName);
 
+
 public slots :
        void set_project(Project* project);
        void show_song(Song* song);
@@ -167,6 +170,8 @@
        void change_resample_quality_to_high();
        void change_resample_quality_to_medium();
        void change_resample_quality_to_fast();
+       void handle_osc_messages(OscEvent* e);
+       void insert_audio(const QString &filename);
 
        Command* full_screen();
        Command* about_traverso();
diff --unified --recursive --new-file traverso/src/traverso/Traverso.cpp 
traverso-fredg01/src/traverso/Traverso.cpp
--- traverso/src/traverso/Traverso.cpp  2007-12-03 11:27:31.000000000 -0500
+++ traverso-fredg01/src/traverso/Traverso.cpp  2007-12-03 14:50:13.000000000 
-0500
@@ -34,6 +34,7 @@
 #include <AudioDevice.h>
 #include <ContextPointer.h>
 #include <Information.h>
+#include <OscHandler.h>
 #include "defines.h"
 #include "fpu.h"
 #ifdef __SSE__
@@ -106,7 +107,7 @@
        srand ( time(NULL) );
        
        init_sse();
-       
+
        QMetaObject::invokeMethod(this, "create_interface", 
Qt::QueuedConnection);
 //     create_interface();
        
diff --unified --recursive --new-file traverso/src/traverso/traverso.pro 
traverso-fredg01/src/traverso/traverso.pro
--- traverso/src/traverso/traverso.pro  2007-11-07 17:02:48.000000000 -0500
+++ traverso-fredg01/src/traverso/traverso.pro  2007-12-03 10:25:42.000000000 
-0500
@@ -140,6 +140,10 @@
     LIBS += -lslv2 -lrdf -lrasqal -lraptor
     INCLUDEPATH +=     ../3rdparty/slv2 ../plugins/LV2
 }
+contains(DEFINES, OSC_SUPPORT) {
+    LIBS += -llo
+    INCLUDEPATH += lo/lo.h
+}
 
 contains(DEFINES, QT_OPENGL_SUPPORT){
     QT += opengl
*** snip snip ***

Cheers!


|-------------------------------------------------------------------------|
| Frederick F. Gleason, Jr. |               Chief Developer               |
|                           |               Paravel Systems               |
|-------------------------------------------------------------------------|
|               Machines should work.  People should think.               |
|                                           -- IBM Pollyanna Principle    |
|-------------------------------------------------------------------------|




reply via email to

[Prev in Thread] Current Thread [Next in Thread]