a) basic prototype of OSC control

b) various changes to ControlProtocol model/implementation
c) more attempts to get autoscroll to work nicely (unfinished)
d) move editor item types into their own header


git-svn-id: svn://localhost/trunk/ardour2@506 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis
2006-05-18 02:19:27 +00:00
parent b3b383faa5
commit 60fbeedb5f
16 changed files with 1041 additions and 199 deletions

View File

@@ -418,6 +418,19 @@ else:
libraries['usb'] = conf.Finish ()
#
# Check for liblo
libraries['lo'] = LibraryInfo ()
conf = Configure (libraries['lo'])
if conf.CheckLib ('lo', 'lo_server_new'):
have_liblo = True
else:
have_liblo = False
libraries['lo'] = conf.Finish ()
#
# Check for dmalloc
@@ -558,6 +571,8 @@ if env['SURFACES']:
surface_subdirs += [ 'libs/surfaces/generic_midi' ]
if have_libusb:
surface_subdirs += [ 'libs/surfaces/tranzport' ]
if have_liblo:
surface_subdirs += [ 'libs/surfaces/osc' ]
opts.Save('scache.conf', env)
Help(opts.GenerateHelpText(env))

View File

@@ -5,6 +5,8 @@
#include <stdint.h>
#include "canvas.h"
#include "editor_items.h"
#include <ardour/types.h>
namespace ARDOUR {
@@ -16,6 +18,7 @@ class TimeAxisView;
struct DragInfo {
ArdourCanvas::Item* item;
ItemType item_type;
void* data;
jack_nframes_t last_frame_position;
int32_t pointer_frame_offset;

View File

@@ -2844,6 +2844,10 @@ Editor::autoscroll_canvas ()
{
jack_nframes_t new_frame;
bool keep_calling = true;
jack_nframes_t limit = max_frames - current_page_frames();
GdkEventMotion ev;
autoscroll_distance = current_page_frames() * 3 / 4;
if (autoscroll_direction < 0) {
if (leftmost_frame < autoscroll_distance) {
@@ -2851,42 +2855,62 @@ Editor::autoscroll_canvas ()
} else {
new_frame = leftmost_frame - autoscroll_distance;
}
ev.x = drag_info.current_pointer_x - autoscroll_distance;
} else {
if (leftmost_frame > max_frames - autoscroll_distance) {
new_frame = max_frames;
if (leftmost_frame > limit - autoscroll_distance) {
new_frame = limit;
} else {
new_frame = leftmost_frame + autoscroll_distance;
}
ev.x = drag_info.current_pointer_x + autoscroll_distance;
}
if (new_frame != leftmost_frame) {
cerr << "move to " << new_frame << " which is " << autoscroll_distance << " away" << endl;
reposition_x_origin (new_frame);
}
if (new_frame == 0 || new_frame == max_frames) {
/* now fake a motion event to get the object that is being dragged to move too */
ev.type = GDK_MOTION_NOTIFY;
ev.x = frame_to_unit (ev.x);
ev.y = frame_to_unit (drag_info.current_pointer_y);
motion_handler (drag_info.item, (GdkEvent*) &ev, drag_info.item_type, true);
if (new_frame == 0 || new_frame == limit) {
/* we are done */
return FALSE;
return false;
}
return false;
autoscroll_cnt++;
if (autoscroll_cnt == 1) {
/* connect the timeout so that we get called repeatedly */
autoscroll_timeout_tag = gtk_timeout_add (40, _autoscroll_canvas, this);
} else if (autoscroll_cnt > 10 && autoscroll_cnt < 20) {
autoscroll_timeout_tag = gtk_timeout_add (20, _autoscroll_canvas, this);
keep_calling = false;
} else if (autoscroll_cnt == 50) { /* 0.5 seconds */
/* after about a while, speed up a bit by changing the timeout interval */
autoscroll_timeout_tag = gtk_timeout_add (20, _autoscroll_canvas, this);
autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/50.0f);
cerr << "change distance to " << autoscroll_distance << endl;
} else if (autoscroll_cnt >= 30) {
} else if (autoscroll_cnt == 75) { /* 1.0 seconds */
autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/20.0f);
cerr << "change distance to " << autoscroll_distance << endl;
} else if (autoscroll_cnt == 100) { /* 1.5 seconds */
/* after about another while, speed up by increasing the shift per callback */
autoscroll_distance = (jack_nframes_t) floor (0.5 * current_page_frames());
autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/10.0f);
cerr << "change distance to " << autoscroll_distance << endl;
}
@@ -2903,7 +2927,7 @@ Editor::start_canvas_autoscroll (int dir)
stop_canvas_autoscroll ();
autoscroll_direction = dir;
autoscroll_distance = (jack_nframes_t) floor ((canvas_width * frames_per_unit)/50.0);
autoscroll_distance = (jack_nframes_t) floor (current_page_frames()/100.0);
autoscroll_cnt = 0;
/* do it right now, which will start the repeated callbacks */

View File

@@ -53,6 +53,7 @@
#include "public_editor.h"
#include "editing.h"
#include "enums.h"
#include "editor_items.h"
#include "region_selection.h"
#include "canvas.h"
#include "draginfo.h"
@@ -347,56 +348,6 @@ class Editor : public PublicEditor
PlaylistSelector* _playlist_selector;
enum ItemType {
RegionItem,
StreamItem,
PlayheadCursorItem,
EditCursorItem,
MarkerItem,
MarkerBarItem,
RangeMarkerBarItem,
TransportMarkerBarItem,
SelectionItem,
GainControlPointItem,
GainLineItem,
GainAutomationControlPointItem,
GainAutomationLineItem,
PanAutomationControlPointItem,
PanAutomationLineItem,
RedirectAutomationControlPointItem,
RedirectAutomationLineItem,
MeterMarkerItem,
TempoMarkerItem,
MeterBarItem,
TempoBarItem,
AudioRegionViewNameHighlight,
AudioRegionViewName,
StartSelectionTrimItem,
EndSelectionTrimItem,
AutomationTrackItem,
FadeInItem,
FadeInHandleItem,
FadeOutItem,
FadeOutHandleItem,
/* <CMT Additions> */
MarkerViewItem,
MarkerTimeAxisItem,
MarkerViewHandleStartItem,
MarkerViewHandleEndItem,
ImageFrameItem,
ImageFrameTimeAxisItem,
ImageFrameHandleStartItem,
ImageFrameHandleEndItem,
/* </CMT Additions> */
CrossfadeViewItem,
/* don't remove this */
NoItem
};
void set_frames_per_unit (double);
void frames_per_unit_modified ();
@@ -861,7 +812,7 @@ class Editor : public PublicEditor
bool typed_event (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool button_press_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool button_release_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool motion_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool motion_handler (ArdourCanvas::Item*, GdkEvent*, ItemType, bool from_autoscroll = false);
bool enter_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);
bool leave_handler (ArdourCanvas::Item*, GdkEvent*, ItemType);

View File

@@ -1107,26 +1107,23 @@ Editor::button_release_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemT
void
Editor::maybe_autoscroll (GdkEvent* event)
{
jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
jack_nframes_t rightmost_frame = leftmost_frame + one_page;
jack_nframes_t rightmost_frame = leftmost_frame + current_page_frames();
jack_nframes_t frame = drag_info.current_pointer_frame;
if (autoscroll_timeout_tag < 0) {
if (frame > rightmost_frame) {
if (rightmost_frame < max_frames) {
start_canvas_autoscroll (1);
}
} else if (frame < leftmost_frame) {
if (leftmost_frame > 0) {
start_canvas_autoscroll (-1);
}
}
} else {
if (frame >= leftmost_frame && frame < rightmost_frame) {
stop_canvas_autoscroll ();
cerr << "maybe autoscroll @ " << frame << " left = " << leftmost_frame << " right = " << rightmost_frame << endl;
if (frame > rightmost_frame) {
if (rightmost_frame < max_frames) {
autoscroll_direction = 1;
autoscroll_canvas ();
}
}
} else if (frame < leftmost_frame) {
if (leftmost_frame > 0) {
autoscroll_direction = -1;
autoscroll_canvas ();
}
}
}
bool
@@ -1469,7 +1466,7 @@ Editor::left_automation_track ()
}
bool
Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type)
Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type, bool from_autoscroll)
{
gint x, y;
@@ -1495,10 +1492,11 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
return true;
}
drag_info.item_type = item_type;
drag_info.current_pointer_frame = event_frame (event, &drag_info.current_pointer_x,
&drag_info.current_pointer_y);
if (drag_info.item) {
if (!from_autoscroll && drag_info.item) {
/* item != 0 is the best test i can think of for
dragging.
*/
@@ -1544,12 +1542,14 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
/* </CMT Additions> */
if (drag_info.item && (event->motion.state & Gdk::BUTTON1_MASK ||
(event->motion.state & Gdk::BUTTON2_MASK))) {
maybe_autoscroll (event);
(this->*(drag_info.motion_callback)) (item, event);
goto handled;
}
goto not_handled;
if (!from_autoscroll) {
maybe_autoscroll (event);
}
(this->*(drag_info.motion_callback)) (item, event);
goto handled;
}
goto not_handled;
default:
break;
}
@@ -1561,7 +1561,9 @@ Editor::motion_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item
case MouseTimeFX:
if (drag_info.item && (event->motion.state & GDK_BUTTON1_MASK ||
(event->motion.state & GDK_BUTTON2_MASK))) {
maybe_autoscroll (event);
if (!from_autoscroll) {
maybe_autoscroll (event);
}
(this->*(drag_info.motion_callback)) (item, event);
goto handled;
}
@@ -2770,6 +2772,8 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
vector<int32_t> height_list(512) ;
vector<int32_t>::iterator j;
cerr << "region motion to " << drag_info.current_pointer_frame << endl;
/* Which trackview is this ? */
TimeAxisView* tvp = trackview_by_y_position (drag_info.current_pointer_y);

View File

@@ -10,25 +10,31 @@ class BasicUI {
BasicUI (ARDOUR::Session&);
virtual ~BasicUI ();
void add_marker ();
/* transport control */
void loop_toggle ();
void goto_start ();
void goto_end ();
void add_marker ();
void rewind ();
void ffwd ();
void transport_stop ();
void transport_play ();
void rec_enable_toggle ();
void set_transport_speed (float speed);
float get_transport_speed (float speed);
void save_state ();
void prev_marker ();
void next_marker ();
void move_at (float speed);
void undo ();
void redo ();
void toggle_all_rec_enables ();
void toggle_punch_in ();
void toggle_punch_out ();
void rec_enable_toggle ();
void toggle_all_rec_enables ();
protected:
ARDOUR::Session& session;
};

View File

@@ -2,6 +2,7 @@
#define ardour_control_protocols_h
#include <string>
#include <vector>
#include <list>
#include <sigc++/sigc++.h>
@@ -35,9 +36,49 @@ class ControlProtocol : public sigc::trackable, public BasicUI {
static sigc::signal<void> Enter;
static sigc::signal<void,float> ScrollTimeline;
/* the model here is as follows:
we imagine most control surfaces being able to control
from 1 to N tracks at a time, with a session that may
contain 1 to M tracks, where M may be smaller, larger or
equal to N.
the control surface has a fixed set of physical controllers
which can potentially be mapped onto different tracks/busses
via some mechanism.
therefore, the control protocol object maintains
a table that reflects the current mapping between
the controls and route object.
*/
void set_route_table_size (uint32_t size);
void set_route_table (uint32_t table_index, ARDOUR::Route*);
void route_set_rec_enable (uint32_t table_index, bool yn);
bool route_get_rec_enable (uint32_t table_index);
float route_get_gain (uint32_t table_index);
void route_set_gain (uint32_t table_index, float);
float route_get_effective_gain (uint32_t table_index);
float route_get_peak_input_power (uint32_t table_index, uint32_t which_input);
bool route_get_muted (uint32_t table_index);
void route_set_muted (uint32_t table_index, bool);
bool route_get_soloed (uint32_t table_index);
void route_set_soloed (uint32_t table_index, bool);
std::string route_get_name (uint32_t table_index);
protected:
std::vector<ARDOUR::Route*> route_table;
std::string _name;
bool _active;
void next_track (uint32_t initial_id);
void prev_track (uint32_t initial_id);
};
extern "C" {

View File

@@ -157,7 +157,7 @@ BasicUI::next_marker ()
}
void
BasicUI::move_at (float speed)
BasicUI::set_transport_speed (float speed)
{
session.request_transport_speed (speed);
}

View File

@@ -19,6 +19,9 @@
*/
#include <ardour/control_protocol.h>
#include <ardour/session.h>
#include <ardour/route.h>
#include <ardour/audio_track.h>
using namespace ARDOUR;
using namespace std;
@@ -40,3 +43,269 @@ ControlProtocol::~ControlProtocol ()
{
}
void
ControlProtocol::next_track (uint32_t initial_id)
{
uint32_t limit = session.nroutes();
Route* cr = route_table[0];
uint32_t id;
if (cr) {
id = cr->remote_control_id ();
} else {
id = 0;
}
if (id == limit) {
id = 0;
} else {
id++;
}
while (id < limit) {
if ((cr = session.route_by_remote_id (id)) != 0) {
break;
}
id++;
}
if (id == limit) {
id = 0;
while (id != initial_id) {
if ((cr = session.route_by_remote_id (id)) != 0) {
break;
}
id++;
}
}
route_table[0] = cr;
}
void
ControlProtocol::prev_track (uint32_t initial_id)
{
uint32_t limit = session.nroutes() - 1;
Route* cr = route_table[0];
uint32_t id;
if (cr) {
id = cr->remote_control_id ();
} else {
id = 0;
}
if (id == 0) {
id = session.nroutes() - 1;
} else {
id--;
}
while (id >= 0) {
if ((cr = session.route_by_remote_id (id)) != 0) {
break;
}
id--;
}
if (id < 0) {
id = limit;
while (id > initial_id) {
if ((cr = session.route_by_remote_id (id)) != 0) {
break;
}
id--;
}
}
route_table[0] = cr;
}
void
ControlProtocol::set_route_table_size (uint32_t size)
{
while (route_table.size() < size) {
route_table.push_back (0);
}
}
void
ControlProtocol::set_route_table (uint32_t table_index, ARDOUR::Route*)
{
}
void
ControlProtocol::route_set_rec_enable (uint32_t table_index, bool yn)
{
if (table_index > route_table.size()) {
return;
}
Route* r = route_table[table_index];
AudioTrack* at = dynamic_cast<AudioTrack*>(r);
if (at) {
at->set_record_enable (yn, this);
}
}
bool
ControlProtocol::route_get_rec_enable (uint32_t table_index)
{
if (table_index > route_table.size()) {
return false;
}
Route* r = route_table[table_index];
AudioTrack* at = dynamic_cast<AudioTrack*>(r);
if (at) {
at->record_enabled ();
}
}
float
ControlProtocol::route_get_gain (uint32_t table_index)
{
if (table_index > route_table.size()) {
return 0.0f;
}
Route* r = route_table[table_index];
if (r == 0) {
return 0.0f;
}
return r->gain ();
}
void
ControlProtocol::route_set_gain (uint32_t table_index, float gain)
{
if (table_index > route_table.size()) {
return;
}
Route* r = route_table[table_index];
if (r != 0) {
r->set_gain (gain, this);
}
}
float
ControlProtocol::route_get_effective_gain (uint32_t table_index)
{
if (table_index > route_table.size()) {
return 0.0f;
}
Route* r = route_table[table_index];
if (r == 0) {
return 0.0f;
}
return r->effective_gain ();
}
float
ControlProtocol::route_get_peak_input_power (uint32_t table_index, uint32_t which_input)
{
if (table_index > route_table.size()) {
return 0.0f;
}
Route* r = route_table[table_index];
if (r == 0) {
return 0.0f;
}
return r->peak_input_power (which_input);
}
bool
ControlProtocol::route_get_muted (uint32_t table_index)
{
if (table_index > route_table.size()) {
return false;
}
Route* r = route_table[table_index];
if (r == 0) {
return false;
}
return r->muted ();
}
void
ControlProtocol::route_set_muted (uint32_t table_index, bool yn)
{
if (table_index > route_table.size()) {
return;
}
Route* r = route_table[table_index];
if (r != 0) {
r->set_mute (yn, this);
}
}
bool
ControlProtocol::route_get_soloed (uint32_t table_index)
{
if (table_index > route_table.size()) {
return false;
}
Route* r = route_table[table_index];
if (r == 0) {
return false;
}
return r->soloed ();
}
void
ControlProtocol::route_set_soloed (uint32_t table_index, bool yn)
{
if (table_index > route_table.size()) {
return;
}
Route* r = route_table[table_index];
if (r != 0) {
r->set_solo (yn, this);
}
}
string
ControlProtocol:: route_get_name (uint32_t table_index)
{
if (table_index > route_table.size()) {
return "";
}
Route* r = route_table[table_index];
if (r == 0) {
return "";
}
return r->name();
}

View File

@@ -0,0 +1,52 @@
# -*- python -*-
import os
import os.path
import glob
Import('env final_prefix install_prefix final_config_prefix libraries i18n')
osc = env.Copy()
#
# this defines the version number of libardour_osc
#
domain = 'ardour_osc'
osc.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
osc.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
osc.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
osc.Append(PACKAGE = domain)
osc.Append(POTFILE = domain + '.pot')
osc_files=Split("""
interface.cc
osc_server.cc
""")
osc.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
osc.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
osc.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
osc.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
osc.Merge ([
libraries['ardour'],
libraries['sigc2'],
libraries['pbd3'],
libraries['lo']
])
libardour_osc = osc.SharedLibrary('ardour_osc', osc_files)
Default(libardour_osc)
if env['NLS']:
i18n (osc, osc_files, env)
env.Alias('install', env.Install(os.path.join(install_prefix, 'lib/ardour2/surfaces'), libardour_osc))
env.Alias('tarball', env.Distribute (env['DISTTREE'],
[ 'SConscript', 'i18n.h', 'gettext.h' ] +
osc_files +
glob.glob('po/*.po') + glob.glob('*.h')))

16
libs/surfaces/osc/i18n.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef __i18n_h__
#define __i18n_h__
#include <pbd/compose.h>
#include "gettext.h"
#include <vector>
#include <string>
std::vector<std::string> internationalize (const char **);
#define _(Text) dgettext (PACKAGE,Text)
#define N_(Text) gettext_noop (Text)
#define X_(Text) Text
#endif // __i18n_h__

View File

@@ -0,0 +1,44 @@
#include <ardour/control_protocol.h>
#include "osc_server.h"
using namespace ARDOUR;
ControlProtocol*
new_osc_protocol (ControlProtocolDescriptor* descriptor, Session* s)
{
ControlOSC* osc = new ControlOSC (*s, 3891);
if (osc->set_active (true)) {
delete osc;
return 0;
}
return osc;
}
void
delete_osc_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
{
delete cp;
}
static ControlProtocolDescriptor osc_descriptor = {
name : "OSC",
id : "uri://ardour.org/surfaces/osc:0",
ptr : 0,
module : 0,
initialize : new_osc_protocol,
destroy : delete_osc_protocol
};
extern "C" {
ControlProtocolDescriptor*
protocol_descriptor () {
return &osc_descriptor;
}
}

View File

@@ -0,0 +1,392 @@
/*
** Copyright (C) 2004 Jesse Chappell <jesse@essej.net>
**
** This program 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
**
*/
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cerrno>
#include <algorithm>
#include <sys/poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <sigc++/sigc++.h>
#include <lo/lo.h>
#include "osc_server.h"
#include "i18n.h"
using namespace sigc;
using namespace std;
#include <pbd/abstract_ui.cc>
static void error_callback(int num, const char *m, const char *path)
{
#ifdef DEBUG
fprintf(stderr, "liblo server error %d in path %s: %s\n", num, path, m);
#endif
}
ControlOSC::ControlOSC (ARDOUR::Session& s, uint32_t port)
: ControlProtocol(s, X_("OSC")),
AbstractUI<OSCRequest> (X_("OSC"), false),
_port(port)
{
_shutdown = false;
_osc_server = 0;
_osc_unix_server = 0;
_osc_thread = 0;
}
int
ControlOSC::set_active (bool yn)
{
if (yn) {
char tmpstr[255];
for (int j=0; j < 20; ++j) {
snprintf(tmpstr, sizeof(tmpstr), "%d", _port);
if ((_osc_server = lo_server_new (tmpstr, error_callback))) {
break;
}
#ifdef DEBUG
cerr << "can't get osc at port: " << _port << endl;
#endif
_port++;
continue;
}
#ifdef ARDOUR_OSC_UNIX_SERVER
// APPEARS sluggish for now
// attempt to create unix socket server too
snprintf(tmpstr, sizeof(tmpstr), "/tmp/sooperlooper_XXXXXX");
int fd = mkstemp(tmpstr);
if (fd >= 0 ) {
unlink (tmpstr);
close (fd);
_osc_unix_server = lo_server_new (tmpstr, error_callback);
if (_osc_unix_server) {
_osc_unix_socket_path = tmpstr;
}
}
#endif
register_callbacks();
on_session_load ();
// lo_server_thread_add_method(_sthread, NULL, NULL, ControlOSC::_dummy_handler, this);
if (!init_osc_thread()) {
return -1;
}
} else {
/* need to stop the OSC UDP server */
if (!_osc_unix_socket_path.empty()) {
// unlink it
unlink(_osc_unix_socket_path.c_str());
}
// stop server thread
terminate_osc_thread();
}
return 0;
}
bool
ControlOSC::caller_is_ui_thread ()
{
return false;
}
ControlOSC::~ControlOSC()
{
set_active (false);
}
void
ControlOSC::register_callbacks()
{
lo_server srvs[2];
lo_server serv;
srvs[0] = _osc_server;
srvs[1] = _osc_unix_server;
for (size_t i = 0; i < 2; ++i) {
if (!srvs[i]) {
continue;
}
serv = srvs[i];
#define REGISTER_CALLBACK(serv,path,types, function) lo_server_add_method (serv, path, types, ControlOSC::_ ## function, this)
REGISTER_CALLBACK (serv, "/session/add_marker", "", add_marker);
REGISTER_CALLBACK (serv, "/session/loop_toggle", "", loop_toggle);
REGISTER_CALLBACK (serv, "/session/goto_start", "", goto_start);
REGISTER_CALLBACK (serv, "/session/goto_end", "", goto_end);
REGISTER_CALLBACK (serv, "/session/rewind", "", rewind);
REGISTER_CALLBACK (serv, "/session/ffwd", "", ffwd);
REGISTER_CALLBACK (serv, "/session/transport_stop", "", transport_stop);
REGISTER_CALLBACK (serv, "/session/transport_play", "", transport_play);
REGISTER_CALLBACK (serv, "/session/set_transport_speed", "f", set_transport_speed);
REGISTER_CALLBACK (serv, "/session/save_state", "", save_state);
REGISTER_CALLBACK (serv, "/session/prev_marker", "", prev_marker);
REGISTER_CALLBACK (serv, "/session/next_marker", "", next_marker);
REGISTER_CALLBACK (serv, "/session/undo", "", undo);
REGISTER_CALLBACK (serv, "/session/redo", "", redo);
REGISTER_CALLBACK (serv, "/session/toggle_punch_in", "", toggle_punch_in);
REGISTER_CALLBACK (serv, "/session/toggle_punch_out", "", toggle_punch_out);
REGISTER_CALLBACK (serv, "/session/rec_enable_toggle", "", rec_enable_toggle);
REGISTER_CALLBACK (serv, "/session/toggle_all_rec_enables", "", toggle_all_rec_enables);
#if 0
lo_server_add_method(serv, "/session/set", "ss", ControlOSC::global_set_handler, this);
lo_server_add_method(serv, "/session/get", "ss", ControlOSC::global_get_handler, this);
// un/register_update args= s:ctrl s:returl s:retpath
lo_server_add_method(serv, "/register_update", "sss", ControlOSC::global_register_update_handler, this);
lo_server_add_method(serv, "/unregister_update", "sss", ControlOSC::global_unregister_update_handler, this);
lo_server_add_method(serv, "/register_auto_update", "siss", ControlOSC::global_register_auto_update_handler, this);
lo_server_add_method(serv, "/unregister_auto_update", "sss", ControlOSC::_global_unregister_auto_update_handler, this);
#endif
}
}
bool
ControlOSC::init_osc_thread ()
{
// create new thread to run server
if (pipe (_request_pipe)) {
cerr << "Cannot create osc request signal pipe" << strerror (errno) << endl;
return false;
}
if (fcntl (_request_pipe[0], F_SETFL, O_NONBLOCK)) {
cerr << "osc: cannot set O_NONBLOCK on signal read pipe " << strerror (errno) << endl;
return false;
}
if (fcntl (_request_pipe[1], F_SETFL, O_NONBLOCK)) {
cerr << "osc: cannot set O_NONBLOCK on signal write pipe " << strerror (errno) << endl;
return false;
}
pthread_create (&_osc_thread, NULL, &ControlOSC::_osc_receiver, this);
if (!_osc_thread) {
return false;
}
//pthread_detach (_osc_thread);
return true;
}
void
ControlOSC::terminate_osc_thread ()
{
void* status;
_shutdown = true;
poke_osc_thread ();
pthread_join (_osc_thread, &status);
}
void
ControlOSC::poke_osc_thread ()
{
char c;
if (write (_request_pipe[1], &c, 1) != 1) {
cerr << "cannot send signal to osc thread! " << strerror (errno) << endl;
}
}
void
ControlOSC::on_session_load ()
{
}
void
ControlOSC::on_session_unload ()
{
// will be called from main event loop
}
std::string
ControlOSC::get_server_url()
{
string url;
char * urlstr;
if (_osc_server) {
urlstr = lo_server_get_url (_osc_server);
url = urlstr;
free (urlstr);
}
return url;
}
std::string
ControlOSC::get_unix_server_url()
{
string url;
char * urlstr;
if (_osc_unix_server) {
urlstr = lo_server_get_url (_osc_unix_server);
url = urlstr;
free (urlstr);
}
return url;
}
/* server thread */
void *
ControlOSC::_osc_receiver(void * arg)
{
static_cast<ControlOSC*> (arg)->osc_receiver();
return 0;
}
void
ControlOSC::osc_receiver()
{
struct pollfd pfd[3];
int fds[3];
lo_server srvs[3];
int nfds = 0;
int timeout = -1;
int ret;
fds[0] = _request_pipe[0];
nfds++;
if (_osc_server && lo_server_get_socket_fd(_osc_server) >= 0) {
fds[nfds] = lo_server_get_socket_fd(_osc_server);
srvs[nfds] = _osc_server;
nfds++;
}
if (_osc_unix_server && lo_server_get_socket_fd(_osc_unix_server) >= 0) {
fds[nfds] = lo_server_get_socket_fd(_osc_unix_server);
srvs[nfds] = _osc_unix_server;
nfds++;
}
while (!_shutdown) {
for (int i=0; i < nfds; ++i) {
pfd[i].fd = fds[i];
pfd[i].events = POLLIN|POLLPRI|POLLHUP|POLLERR;
pfd[i].revents = 0;
}
again:
//cerr << "poll on " << nfds << " for " << timeout << endl;
if ((ret = poll (pfd, nfds, timeout)) < 0) {
if (errno == EINTR) {
/* gdb at work, perhaps */
cerr << "EINTR hit " << endl;
goto again;
}
cerr << "OSC thread poll failed: " << strerror (errno) << endl;
break;
}
//cerr << "poll returned " << ret << " pfd[0].revents = " << pfd[0].revents << " pfd[1].revents = " << pfd[1].revents << endl;
if (_shutdown) {
break;
}
if ((pfd[0].revents & ~POLLIN)) {
cerr << "OSC: error polling extra port" << endl;
break;
}
for (int i=1; i < nfds; ++i) {
if (pfd[i].revents & POLLIN)
{
// this invokes callbacks
//cerr << "invoking recv on " << pfd[i].fd << endl;
lo_server_recv(srvs[i]);
}
}
}
//cerr << "SL engine shutdown" << endl;
if (_osc_server) {
int fd = lo_server_get_socket_fd(_osc_server);
if (fd >=0) {
// hack around
close(fd);
}
lo_server_free (_osc_server);
_osc_server = 0;
}
if (_osc_unix_server) {
cerr << "freeing unix server" << endl;
lo_server_free (_osc_unix_server);
_osc_unix_server = 0;
}
close(_request_pipe[0]);
close(_request_pipe[1]);
}
void
ControlOSC::do_request (OSCRequest* req)
{
}
/* path callbacks */

View File

@@ -0,0 +1,102 @@
#ifndef ardour_osc_control_protocol_h
#define ardour_osc_control_protocol_h
#include <string>
#include <sys/time.h>
#include <pthread.h>
#include <lo/lo.h>
#include <pbd/lockmonitor.h>
#include <ardour/control_protocol.h>
#include <ardour/types.h>
#include <pbd/abstract_ui.h>
struct OSCRequest : public BaseUI::BaseRequestObject {
/* nothing yet */
};
class ControlOSC : public ARDOUR::ControlProtocol, public AbstractUI<OSCRequest>
{
public:
ControlOSC (ARDOUR::Session&, uint32_t port);
virtual ~ControlOSC();
int set_active (bool yn);
bool caller_is_ui_thread();
private:
uint32_t _port;
volatile bool _ok;
volatile bool _shutdown;
lo_server _osc_server;
lo_server _osc_unix_server;
std::string _osc_unix_socket_path;
pthread_t _osc_thread;
int _request_pipe[2];
static void * _osc_receiver(void * arg);
void osc_receiver();
bool init_osc_thread ();
void terminate_osc_thread ();
void poke_osc_thread ();
void register_callbacks ();
void on_session_load ();
void on_session_unload ();
std::string get_server_url ();
std::string get_unix_server_url ();
void do_request (OSCRequest* req);
#define PATH_CALLBACK(name) \
static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
return static_cast<ControlOSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
} \
int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
name (); \
return 0; \
}
PATH_CALLBACK(add_marker);
PATH_CALLBACK(loop_toggle);
PATH_CALLBACK(goto_start);
PATH_CALLBACK(goto_end);
PATH_CALLBACK(rewind);
PATH_CALLBACK(ffwd);
PATH_CALLBACK(transport_stop);
PATH_CALLBACK(transport_play);
PATH_CALLBACK(save_state);
PATH_CALLBACK(prev_marker);
PATH_CALLBACK(next_marker);
PATH_CALLBACK(undo);
PATH_CALLBACK(redo);
PATH_CALLBACK(toggle_punch_in);
PATH_CALLBACK(toggle_punch_out);
PATH_CALLBACK(rec_enable_toggle);
PATH_CALLBACK(toggle_all_rec_enables);
#define PATH_CALLBACK1(name,type) \
static int _ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data, void *user_data) { \
return static_cast<ControlOSC*>(user_data)->cb_ ## name (path, types, argv, argc, data); \
} \
int cb_ ## name (const char *path, const char *types, lo_arg **argv, int argc, void *data) { \
if (argc > 0) { \
name (argv[0]->type); \
}\
return 0; \
}
PATH_CALLBACK1(set_transport_speed,f);
};
#endif // ardour_osc_control_protocol_h

View File

@@ -70,12 +70,15 @@ TranzportControlProtocol::TranzportControlProtocol (Session& s)
AbstractUI<TranzportRequest> (X_("Tranzport"), false)
{
/* tranzport controls one track at a time */
set_route_table_size (1);
timeout = 60000;
buttonmask = 0;
_datawheel = 0;
_device_status = STATUS_OFFLINE;
udev = 0;
current_route = 0;
current_track_id = 0;
last_where = max_frames;
wheel_mode = WheelTimeline;
@@ -139,11 +142,11 @@ TranzportControlProtocol::set_active (bool yn)
void
TranzportControlProtocol::show_track_gain ()
{
if (current_route) {
gain_t g = current_route->gain();
if (route_table[0]) {
gain_t g = route_get_gain (0);
if (g != last_track_gain) {
char buf[16];
snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (current_route->effective_gain()));
snprintf (buf, sizeof (buf), "%6.1fdB", coefficient_to_dB (route_get_effective_gain (0)));
print (0, 9, buf);
last_track_gain = g;
}
@@ -234,11 +237,11 @@ log_meter (float db)
void
TranzportControlProtocol::show_meter ()
{
if (current_route == 0) {
if (route_table[0] == 0) {
return;
}
float level = current_route->peak_input_power (0);
float level = route_get_peak_input_power (0, 0);
float fraction = log_meter (level);
/* we draw using a choice of a sort of double colon-like character ("::") or a single, left-aligned ":".
@@ -579,10 +582,6 @@ TranzportControlProtocol::monitor_work ()
val = usb_interrupt_read (udev, READ_ENDPOINT, (char*) buf, 8, 10);
pthread_testcancel();
/* any requests to handle? */
handle_ui_requests ();
if (val == 8) {
process (buf);
}
@@ -673,19 +672,19 @@ TranzportControlProtocol::update_state ()
/* per track */
if (current_route) {
AudioTrack* at = dynamic_cast<AudioTrack*> (current_route);
if (route_table[0]) {
AudioTrack* at = dynamic_cast<AudioTrack*> (route_table[0]);
if (at && at->record_enabled()) {
pending_lights[LightTrackrec] = true;
} else {
pending_lights[LightTrackrec] = false;
}
if (current_route->muted()) {
if (route_get_muted (0)) {
pending_lights[LightTrackmute] = true;
} else {
pending_lights[LightTrackmute] = false;
}
if (current_route->soloed()) {
if (route_get_soloed (0)) {
pending_lights[LightTracksolo] = true;
} else {
pending_lights[LightTracksolo] = false;
@@ -954,10 +953,10 @@ TranzportControlProtocol::process (uint8_t* buf)
void
TranzportControlProtocol::show_current_track ()
{
if (current_route == 0) {
if (route_table[0] == 0) {
print (0, 0, "--------");
} else {
print (0, 0, current_route->name().substr (0, 8).c_str());
print (0, 0, route_get_name (0).substr (0, 8).c_str());
}
}
@@ -1009,10 +1008,7 @@ TranzportControlProtocol::button_event_trackrec_press (bool shifted)
if (shifted) {
toggle_all_rec_enables ();
} else {
if (current_route) {
AudioTrack* at = dynamic_cast<AudioTrack*>(current_route);
at->set_record_enable (!at->record_enabled(), this);
}
route_set_rec_enable (0, !route_get_rec_enable (0));
}
}
@@ -1024,9 +1020,7 @@ TranzportControlProtocol::button_event_trackrec_release (bool shifted)
void
TranzportControlProtocol::button_event_trackmute_press (bool shifted)
{
if (current_route) {
current_route->set_mute (!current_route->muted(), this);
}
route_set_muted (0, !route_get_muted (0));
}
void
@@ -1045,9 +1039,7 @@ TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
if (shifted) {
session.set_all_solo (!session.soloing());
} else {
if (current_route) {
current_route->set_solo (!current_route->soloed(), this);
}
route_set_soloed (0, !route_get_soloed (0));
}
}
@@ -1267,7 +1259,7 @@ TranzportControlProtocol::datawheel ()
/* parameter control */
if (current_route) {
if (route_table[0]) {
switch (wheel_shift_mode) {
case WheelShiftGain:
if (_datawheel < WheelDirectionThreshold) {
@@ -1358,7 +1350,7 @@ TranzportControlProtocol::scrub ()
last_wheel_motion = now;
last_wheel_dir = dir;
move_at (speed * dir);
set_transport_speed (speed * dir);
}
void
@@ -1392,7 +1384,7 @@ TranzportControlProtocol::step_gain_up ()
gain_fraction = 2.0;
}
current_route->set_gain (slider_position_to_gain (gain_fraction), this);
route_set_gain (0, slider_position_to_gain (gain_fraction));
}
void
@@ -1408,7 +1400,7 @@ TranzportControlProtocol::step_gain_down ()
gain_fraction = 0.0;
}
current_route->set_gain (slider_position_to_gain (gain_fraction), this);
route_set_gain (0, slider_position_to_gain (gain_fraction));
}
void
@@ -1458,83 +1450,15 @@ TranzportControlProtocol::next_wheel_mode ()
void
TranzportControlProtocol::next_track ()
{
uint32_t limit = session.nroutes();
uint32_t start = current_track_id;
Route* cr = current_route;
if (current_track_id == limit) {
current_track_id = 0;
} else {
current_track_id++;
}
while (current_track_id < limit) {
if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
break;
}
current_track_id++;
}
if (current_track_id == limit) {
current_track_id = 0;
while (current_track_id != start) {
if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
break;
}
current_track_id++;
}
}
current_route = cr;
gain_fraction = gain_to_slider_position (current_route->effective_gain());
ControlProtocol::next_track (current_track_id);
gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
}
void
TranzportControlProtocol::prev_track ()
{
uint32_t limit = session.nroutes() - 1;
uint32_t start = current_track_id;
Route* cr = current_route;
if (current_track_id == 0) {
current_track_id = session.nroutes() - 1;
} else {
current_track_id--;
}
while (current_track_id >= 0) {
if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
break;
}
current_track_id--;
}
if (current_track_id < 0) {
current_track_id = limit;
while (current_track_id > start) {
if ((cr = session.route_by_remote_id (current_track_id)) != 0) {
break;
}
current_track_id--;
}
}
current_route = cr;
gain_fraction = gain_to_slider_position (current_route->effective_gain());
}
void
TranzportControlProtocol::set_current_track (Route* r)
{
TranzportRequest* req = get_request (SetCurrentTrack);
if (req == 0) {
return;
}
req->track = r;
send_request (req);
ControlProtocol::prev_track (current_track_id);
gain_fraction = gain_to_slider_position (route_get_effective_gain (0));
}
void
@@ -1640,8 +1564,8 @@ void
TranzportControlProtocol::do_request (TranzportRequest* req)
{
if (req->type == SetCurrentTrack) {
current_route = req->track;
}
return;
route_table[0] = req->track;
}
return;
}

View File

@@ -101,7 +101,6 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol, public Abstract
uint8_t _device_status;
usb_dev_handle* udev;
ARDOUR::Route* current_route;
uint32_t current_track_id;
WheelMode wheel_mode;
WheelShiftMode wheel_shift_mode;