[Top][All Lists]
[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 |
|-------------------------------------------------------------------------|
- [Traverso-devel] Sample OSC Implementation [patch included],
Fred Gleason <=