'gtk2_ardour'
]
+surface_subdirs = [
+ 'libs/surfaces/tranzport',
+ 'libs/surfaces/generic_midi'
+ ]
+
opts.Save('scache.conf', env)
Help(opts.GenerateHelpText(env))
for subdir in coredirs:
SConscript (subdir + '/SConscript')
-for sublistdir in [subdirs, gtk_subdirs]:
+for sublistdir in [subdirs, gtk_subdirs, surface_subdirs]:
for subdir in sublistdir:
SConscript (subdir + '/SConscript')
#!/bin/sh
source ardev_common.sh
-exec valgrind --num-callers=12 --tool=memcheck ./ardour.bin --novst $*
+exec valgrind --db-attach=yes --num-callers=12 --tool=memcheck ./ardour.bin --novst $*
configuration.cc
connection.cc
control_protocol.cc
+control_protocol_manager.cc
crossfade.cc
curve.cc
cycle_timer.cc
filesource.cc
gain.cc
gdither.cc
-generic_midi_control_protocol.cc
globals.cc
import.cc
insert.cc
session.cc
session_butler.cc
session_click.cc
-session_control.cc
session_events.cc
session_export.cc
-session_feedback.cc
session_midi.cc
session_process.cc
session_state.cc
state_manager.cc
stateful.cc
tempo.cc
-tranzport_control_protocol.cc
utils.cc
version.cc
mix.cc
virtual ~ControlProtocol();
virtual int init () { return 0; }
- virtual bool active() const = 0;
+
+ sigc::signal<void> ActiveChanged;
enum SendWhat {
SendRoute,
std::string name() const { return _name; }
void set_send (SendWhat);
+ void set_active (bool yn);
+ bool get_active() const { return active_thread > 0; }
+
bool send() const { return _send != 0; }
bool send_route_feedback () const { return _send & SendRoute; }
virtual void send_global_feedback () {}
protected:
+
ARDOUR::Session& session;
SendWhat _send;
std::string _name;
+ int active_thread;
+ int thread_request_pipe[2];
+ pthread_t _thread;
+
+ static void* _thread_work (void *);
+ void* thread_work ();
+
+ struct ThreadRequest {
+ enum Type {
+ Start,
+ Stop,
+ Quit
+ };
+ };
+
+ int init_thread();
+ int start_thread ();
+ int stop_thread ();
+ void terminate_thread ();
+ int poke_thread (ThreadRequest::Type);
};
+extern "C" {
+ struct ControlProtocolDescriptor {
+ const char* name;
+ void* ptr;
+ void* module;
+ ControlProtocol* (*initialize)(ControlProtocolDescriptor*,Session*);
+ void (*destroy)(ControlProtocolDescriptor*,ControlProtocol*);
+
+ };
+}
+
}
#endif // ardour_control_protocols_h
+++ /dev/null
-#ifndef ardour_generic_midi_control_protocol_h
-#define ardour_generic_midi_control_protocol_h
-
-#include <ardour/control_protocol.h>
-
-namespace MIDI {
- class Port;
-}
-
-namespace ARDOUR {
-
-class GenericMidiControlProtocol : public ControlProtocol {
- public:
- GenericMidiControlProtocol (Session&);
- virtual ~GenericMidiControlProtocol();
-
- bool active() const;
-
- void set_port (MIDI::Port*);
- MIDI::Port* port () const { return _port; }
-
- void send_route_feedback (std::list<Route*>&);
-
- private:
- void route_feedback (ARDOUR::Route&, bool);
- MIDI::Port* _port;
-};
-
-}
-
-#endif // ardour_generic_midi_control_protocol_h
class Region;
class Playlist;
class VSTPlugin;
-class ControlProtocol;
-class GenericMidiControlProtocol;
+class ControlProtocolManager;
struct AudioExportSpecification;
struct RouteGroup;
std::string dead_sound_dir () const;
std::string automation_dir () const;
+ static string suffixed_search_path (std::string suffix);
+ static string control_protocol_path ();
static string template_path ();
static string template_dir ();
static void get_template_list (list<string>&);
void set_do_not_record_plugins (bool yn);
void set_crossfades_active (bool yn);
void set_seamless_loop (bool yn);
- void set_feedback (bool yn);
bool get_auto_play () const { return auto_play; }
bool get_auto_input () const { return auto_input; }
bool get_midi_control () const;
bool get_do_not_record_plugins () const { return do_not_record_plugins; }
bool get_crossfades_active () const { return crossfades_active; }
- bool get_feedback() const;
- bool get_tranzport_control() const;
bool get_input_auto_connect () const;
AutoConnectOption get_output_auto_connect () const { return output_auto_connect; }
bool send_mmc;
bool mmc_control;
bool midi_control;
- bool midi_feedback;
RingBuffer<Event*> pending_events;
void send_time_code_in_another_thread (bool full);
void send_mmc_in_another_thread (MIDI::MachineControl::Command, jack_nframes_t frame = 0);
- /* Feedback */
-
- typedef sigc::slot<int> FeedbackFunctionPtr;
- static void* _feedback_thread_work (void *);
- void* feedback_thread_work ();
- int feedback_generic_midi_function ();
- std::list<FeedbackFunctionPtr> feedback_functions;
- int active_feedback;
- int feedback_request_pipe[2];
- pthread_t feedback_thread;
-
- struct FeedbackRequest {
- enum Type {
- Start,
- Stop,
- Quit
- };
- };
-
- int init_feedback();
- int start_feedback ();
- int stop_feedback ();
- void terminate_feedback ();
- int poke_feedback (FeedbackRequest::Type);
-
jack_nframes_t adjust_apparent_position (jack_nframes_t frames);
void reset_record_status ();
LayerModel layer_model;
CrossfadeModel xfade_model;
-
- /* control protocols */
-
- vector<ControlProtocol*> control_protocols;
- GenericMidiControlProtocol* generic_midi_control_protocol;
- void initialize_control ();
};
}; /* namespace ARDOUR */
+++ /dev/null
-#ifndef ardour_tranzport_control_protocol_h
-#define ardour_tranzport_control_protocol_h
-
-#include <pthread.h>
-#include <usb.h>
-#include <ardour/control_protocol.h>
-#include <ardour/types.h>
-
-namespace ARDOUR {
-
-class TranzportControlProtocol : public ControlProtocol {
- public:
- TranzportControlProtocol (Session&);
- virtual ~TranzportControlProtocol();
-
- int init ();
- bool active() const;
-
- void send_route_feedback (std::list<Route*>&);
- void send_global_feedback ();
-
- private:
- static const int VENDORID = 0x165b;
- static const int PRODUCTID = 0x8101;
- static const int READ_ENDPOINT = 0x81;
- static const int WRITE_ENDPOINT = 0x02;
- const static int STATUS_OFFLINE = 0xff;
- const static int STATUS_ONLINE = 0x01;
-
- enum LightID {
- LightRecord = 0,
- LightTrackrec,
- LightTrackmute,
- LightTracksolo,
- LightAnysolo,
- LightLoop,
- LightPunch
- };
-
- enum ButtonID {
- ButtonBattery = 0x00004000,
- ButtonBacklight = 0x00008000,
- ButtonTrackLeft = 0x04000000,
- ButtonTrackRight = 0x40000000,
- ButtonTrackRec = 0x00040000,
- ButtonTrackMute = 0x00400000,
- ButtonTrackSolo = 0x00000400,
- ButtonUndo = 0x80000000,
- ButtonIn = 0x02000000,
- ButtonOut = 0x20000000,
- ButtonPunch = 0x00800000,
- ButtonLoop = 0x00080000,
- ButtonPrev = 0x00020000,
- ButtonAdd = 0x00200000,
- ButtonNext = 0x00000200,
- ButtonRewind = 0x01000000,
- ButtonFastForward = 0x10000000,
- ButtonStop = 0x00010000,
- ButtonPlay = 0x00100000,
- ButtonRecord = 0x00000100,
- ButtonShift = 0x08000000
- };
-
- pthread_t thread;
- uint32_t buttonmask;
- uint32_t timeout;
- uint8_t _datawheel;
- uint8_t _device_status;
- usb_dev_handle* udev;
- Route* current_route;
- uint32_t current_track_id;
-
- bool last_negative;
- uint32_t last_hrs;
- uint32_t last_mins;
- uint32_t last_secs;
- uint32_t last_frames;
- jack_nframes_t last_where;
-
- int open ();
- int read ();
- int write (uint8_t* cmd);
- int close ();
-
- int open_core (struct usb_device*);
-
- void lcd_clear ();
- int lcd_write (uint8_t cell, const char *text);
-
- int light_on (LightID);
- int light_off (LightID);
-
- void show_current_track ();
-
- static void* _thread_work (void* arg);
- void* thread_work ();
-
- void button_event_battery_press (bool shifted);
- void button_event_battery_release (bool shifted);
- void button_event_backlight_press (bool shifted);
- void button_event_backlight_release (bool shifted);
- void button_event_trackleft_press (bool shifted);
- void button_event_trackleft_release (bool shifted);
- void button_event_trackright_press (bool shifted);
- void button_event_trackright_release (bool shifted);
- void button_event_trackrec_press (bool shifted);
- void button_event_trackrec_release (bool shifted);
- void button_event_trackmute_press (bool shifted);
- void button_event_trackmute_release (bool shifted);
- void button_event_tracksolo_press (bool shifted);
- void button_event_tracksolo_release (bool shifted);
- void button_event_undo_press (bool shifted);
- void button_event_undo_release (bool shifted);
- void button_event_in_press (bool shifted);
- void button_event_in_release (bool shifted);
- void button_event_out_press (bool shifted);
- void button_event_out_release (bool shifted);
- void button_event_punch_press (bool shifted);
- void button_event_punch_release (bool shifted);
- void button_event_loop_press (bool shifted);
- void button_event_loop_release (bool shifted);
- void button_event_prev_press (bool shifted);
- void button_event_prev_release (bool shifted);
- void button_event_add_press (bool shifted);
- void button_event_add_release (bool shifted);
- void button_event_next_press (bool shifted);
- void button_event_next_release (bool shifted);
- void button_event_rewind_press (bool shifted);
- void button_event_rewind_release (bool shifted);
- void button_event_fastforward_press (bool shifted);
- void button_event_fastforward_release (bool shifted);
- void button_event_stop_press (bool shifted);
- void button_event_stop_release (bool shifted);
- void button_event_play_press (bool shifted);
- void button_event_play_release (bool shifted);
- void button_event_record_press (bool shifted);
- void button_event_record_release (bool shifted);
-};
-
-} // namespace
-
-#endif // ardour_tranzport_control_protocol_h
+++ /dev/null
-#include <ardour/generic_midi_control_protocol.h>
-#include <ardour/route.h>
-#include <ardour/session.h>
-
-using namespace ARDOUR;
-
-#include "i18n.h"
-
-GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
- : ControlProtocol (s, _("GenericMIDI"))
-{
- _port = 0;
-}
-
-GenericMidiControlProtocol::~GenericMidiControlProtocol ()
-{
-}
-
-void
-GenericMidiControlProtocol::set_port (MIDI::Port* p)
-{
- _port = p;
-}
-
-void
-GenericMidiControlProtocol::send_route_feedback (list<Route*>& routes)
-{
- if (_port != 0) {
-
- const int32_t bufsize = 16 * 1024;
- int32_t bsize = bufsize;
- MIDI::byte* buf = new MIDI::byte[bufsize];
- MIDI::byte* end = buf;
-
- for (list<Route*>::iterator r = routes.begin(); r != routes.end(); ++r) {
- end = (*r)->write_midi_feedback (end, bsize);
- }
-
- if (end == buf) {
- delete [] buf;
- return;
- }
-
- session.deliver_midi (_port, buf, (int32_t) (end - buf));
- //cerr << "MIDI feedback: wrote " << (int32_t) (end - buf) << " to midi port\n";
- }
-}
-
-bool
-GenericMidiControlProtocol::active() const
-{
- return _port && send();
-}
-
#include <ardour/source.h>
#include <ardour/utils.h>
#include <ardour/session.h>
+#include <ardour/control_protocol_manager.h>
#include <ardour/mix.h>
Change ARDOUR::NameChanged = ARDOUR::new_change ();
Change ARDOUR::BoundsChanged = Change (0); // see init(), below
-
static int
setup_midi ()
{
/* singleton - first object is "it" */
new PluginManager (engine);
+ /* singleton - first object is "it" */
+ new ControlProtocolManager ();
+ ControlProtocolManager::instance().discover_control_protocols (Session::control_protocol_path());
+
BoundsChanged = Change (StartChanged|PositionChanged|LengthChanged);
return 0;
terminate_butler_thread ();
terminate_midi_thread ();
- terminate_feedback ();
if (click_data && click_data != default_click) {
delete [] click_data;
using namespace ARDOUR;
//using namespace sigc;
-int
-Session::init_feedback ()
-{
- if (pipe (feedback_request_pipe) != 0) {
- error << string_compose (_("cannot create feedback request pipe (%1)"),
- strerror (errno))
- << endmsg;
- return -1;
- }
-
- if (fcntl (feedback_request_pipe[0], F_SETFL, O_NONBLOCK)) {
- error << string_compose(_("UI: cannot set O_NONBLOCK on " "signal read pipe (%1)"), strerror (errno)) << endmsg;
- return -1;
- }
-
- if (fcntl (feedback_request_pipe[1], F_SETFL, O_NONBLOCK)) {
- error << string_compose(_("UI: cannot set O_NONBLOCK on " "signal write pipe (%1)"), strerror (errno)) << endmsg;
- return -1;
- }
-
- active_feedback = 0;
-
- if (pthread_create_and_store ("feedback", &feedback_thread, 0, _feedback_thread_work, this)) {
- error << _("Session: could not create feedback thread") << endmsg;
- return -1;
- }
-
- return 0;
-}
-
-int
-Session::poke_feedback (FeedbackRequest::Type why)
-{
- char c = (char) why;
- return !(write (feedback_request_pipe[1], &c, 1) == 1);
-}
-
-int
-Session::start_feedback ()
-{
- return poke_feedback (FeedbackRequest::Start);
-}
-
-int
-Session::stop_feedback ()
-{
- return poke_feedback (FeedbackRequest::Stop);
-}
-
-void
-Session::set_feedback (bool yn)
-{
- set_dirty();
-
- if (yn) {
- /* make sure the feedback thread is alive */
- start_feedback ();
- } else {
- /* maybe put the feedback thread to sleep */
- stop_feedback ();
- }
-
- ControlChanged (Feedback); /* EMIT SIGNAL */
-}
-
-bool
-Session::get_feedback() const
-{
- return active_feedback > 0;
-}
-
-void
-Session::terminate_feedback ()
-{
- void* status;
- poke_feedback (FeedbackRequest::Quit);
- pthread_join (feedback_thread, &status);
-}
-
-void*
-Session::_feedback_thread_work (void* arg)
-{
- return static_cast<Session*> (arg)->feedback_thread_work ();
-}
-
-void*
-Session::feedback_thread_work ()
-{
- PBD::ThreadCreated (pthread_self(), X_("Feedback"));
- struct pollfd pfd[1];
- int timeout;
-
- pthread_setcancelstate (PTHREAD_CANCEL_ENABLE, 0);
- pthread_setcanceltype (PTHREAD_CANCEL_ASYNCHRONOUS, 0);
-
- if (active_feedback) {
- timeout = max (5, (int) Config->get_feedback_interval_ms());
- } else {
- timeout = -1;
- }
-
- while (1) {
-
- pfd[0].fd = feedback_request_pipe[0];
- pfd[0].events = POLLIN|POLLHUP|POLLERR;
-
- if (poll (pfd, 1, timeout) < 0) {
- if (errno == EINTR) {
- continue;
- }
- error << string_compose (_("Feedback thread poll failed (%1)"),
- strerror (errno))
- << endmsg;
- break;
- }
-
- if (pfd[0].revents & ~POLLIN) {
- error << _("Error on feedback thread request pipe") << endmsg;
- break;
- }
-
- if (pfd[0].revents & POLLIN) {
-
- char req;
-
- /* empty the pipe of all current requests */
-
- while (1) {
- size_t nread = read (feedback_request_pipe[0], &req, sizeof (req));
-
- if (nread == 1) {
- switch ((FeedbackRequest::Type) req) {
-
- case FeedbackRequest::Start:
- timeout = max (5, (int) Config->get_feedback_interval_ms());
- active_feedback++;
- break;
-
- case FeedbackRequest::Stop:
- timeout = -1;
- if (active_feedback) {
- active_feedback--;
- }
- break;
-
- case FeedbackRequest::Quit:
- pthread_exit_pbd (0);
- /*NOTREACHED*/
- break;
-
- default:
- break;
- }
-
- } else if (nread == 0) {
- break;
- } else if (errno == EAGAIN) {
- break;
- } else {
- fatal << _("Error reading from feedback request pipe") << endmsg;
- /*NOTREACHED*/
- }
- }
- }
-
- if (!active_feedback || transport_stopped()) {
- continue;
- }
-
- bool send = false;
-
- for (vector<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
- if ((*i)->send()) {
- send = true;
- break;
- }
- }
-
- if (send) {
-
- RouteList routes = get_routes(); /* copies the routes */
-
- for (vector<ControlProtocol*>::iterator i = control_protocols.begin(); i != control_protocols.end(); ++i) {
- if ((*i)->send_route_feedback ()) {
- (*i)->send_route_feedback (routes);
- }
- (*i)->send_global_feedback ();
- }
- }
- }
-
- return 0;
-}
#include <ardour/diskstream.h>
#include <ardour/slave.h>
#include <ardour/cycles.h>
-#include <ardour/generic_midi_control_protocol.h>
#include "i18n.h"
void
Session::set_midi_feedback (bool yn)
{
- if (generic_midi_control_protocol) {
- if (yn) {
- generic_midi_control_protocol->set_send (ControlProtocol::SendRoute);
- } else {
- generic_midi_control_protocol->set_send (ControlProtocol::SendWhat (0));
- }
- }
}
bool
Session::get_midi_feedback () const
{
- return generic_midi_control_protocol && generic_midi_control_protocol->active();
+ return false;
}
bool
_midi_port = port;
- if (generic_midi_control_protocol) {
- generic_midi_control_protocol->set_port (port);
- }
+ /* XXX need something to forward this to control protocols ? or just
+ use the signal below
+ */
Config->set_midi_port_name (port_tag);
#include <ardour/location.h>
#include <ardour/audioregion.h>
#include <ardour/crossfade.h>
+#include <ardour/control_protocol_manager.h>
#include "i18n.h"
#include <locale.h>
butler_mixdown_buffer = 0;
butler_gain_buffer = 0;
auditioner = 0;
- generic_midi_control_protocol = 0;
mmc_control = false;
- midi_feedback = false;
midi_control = true;
mmc = 0;
post_transport_work = PostTransportWork (0);
return -1;
}
- initialize_control();
-
- if (init_feedback ()) {
- return -1;
- }
-
if (state_tree) {
if (set_state (*state_tree->root())) {
return -1;
deliver_mmc (MIDI::MachineControl::cmdMmcReset, 0);
deliver_mmc (MIDI::MachineControl::cmdLocate, 0);
- // XXX need to poke the feedback thread to send full state
+ ControlProtocolManager::instance().startup (*this);
if (new_session) {
_end_location_is_free = true;
}
string
-Session::template_path ()
+Session::suffixed_search_path (string suffix)
{
string path;
for (vector<string>::iterator i = split_path.begin(); i != split_path.end(); ++i) {
path += *i;
- path += "templates/";
+ path += suffix;
+ path += '/';
if (distance (i, split_path.end()) != 1) {
path += ':';
return path;
}
+string
+Session::template_path ()
+{
+ return suffixed_search_path (X_("templates"));
+}
+
+string
+Session::control_protocol_path ()
+{
+ return suffixed_search_path (X_("surfaces"));
+}
+
int
Session::load_connections (const XMLNode& node)
{
+++ /dev/null
-#include <iostream>
-
-#include <pbd/pthread_utils.h>
-
-#include <ardour/tranzport_control_protocol.h>
-#include <ardour/route.h>
-#include <ardour/session.h>
-
-using namespace ARDOUR;
-using namespace std;
-
-#include "i18n.h"
-
-TranzportControlProtocol::TranzportControlProtocol (Session& s)
- : ControlProtocol (s, _("Tranzport"))
-{
- timeout = 60000;
- buttonmask = 0;
- _datawheel = 0;
- _device_status = STATUS_OFFLINE;
- udev = 0;
- current_route = 0;
- current_track_id = 0;
- last_where = max_frames;
-}
-
-TranzportControlProtocol::~TranzportControlProtocol ()
-{
- if (udev) {
- pthread_cancel_one (thread);
- close ();
- }
-}
-
-int
-TranzportControlProtocol::init ()
-{
- if (open ()) {
- return -1;
- }
-
- pthread_create_and_store (X_("Tranzport"), &thread, 0, _thread_work, this);
-
- return 0;
-}
-
-bool
-TranzportControlProtocol::active() const
-{
- return true;
-}
-
-void
-TranzportControlProtocol::send_route_feedback (list<Route*>& routes)
-{
-}
-
-void
-TranzportControlProtocol::send_global_feedback ()
-{
- jack_nframes_t where = session.transport_frame();
-
- if (where != last_where) {
-
- char clock_label[16];
- SMPTE_Time smpte;
- char* ptr = clock_label;
-
- session.smpte_time (where, smpte);
- memset (clock_label, ' ', sizeof (clock_label));
-
- if (smpte.negative) {
- sprintf (ptr, "-%02ld:", smpte.hours);
- } else {
- sprintf (ptr, " %02ld:", smpte.hours);
- }
- ptr += 4;
-
- sprintf (ptr, "%02ld:", smpte.minutes);
- ptr += 3;
-
- sprintf (ptr, "%02ld:", smpte.seconds);
- ptr += 3;
-
- sprintf (ptr, "%02ld", smpte.frames);
- ptr += 2;
-
- lcd_write (7, &clock_label[0]);
- lcd_write (8, &clock_label[4]);
- lcd_write (9, &clock_label[8]);
-
- last_where = where;
- }
-}
-
-void*
-TranzportControlProtocol::_thread_work (void* arg)
-{
- return static_cast<TranzportControlProtocol*>(arg)->thread_work ();
-}
-
-void*
-TranzportControlProtocol::thread_work ()
-{
- cerr << "tranzport thread here, sending message to LCD\n";
-
- while (true) {
- if (read()) {
- return 0;
- }
- switch (_device_status) {
- case STATUS_OFFLINE:
- cerr << "offline\n";
- break;
- case STATUS_ONLINE:
- cerr << "online\n";
- break;
- default:
- cerr << "unknown status\n";
- break;
- }
-
- if (_device_status == STATUS_ONLINE) {
- break;
- }
- }
-
- lcd_write (0, " ");
- lcd_write (1, "WELC");
- lcd_write (2, "OME ");
- lcd_write (3, "TO ");
- lcd_write (4, " ");
- lcd_write (5, " ");
- lcd_write (6, " ");
- lcd_write (7, "ARDO");
- lcd_write (8, "UR ");
- lcd_write (9, " ");
-
- while (true) {
- if (read ()) {
- cerr << "Tranzport command received\n";
- break;
- }
- }
-
- return 0;
-}
-
-int
-TranzportControlProtocol::open ()
-{
- struct usb_bus *bus;
- struct usb_device *dev;
-
- usb_init();
- usb_find_busses();
- usb_find_devices();
-
- cerr << "checking busses\n";
-
- for (bus = usb_busses; bus; bus = bus->next) {
-
- cerr << "checking devices\n";
-
- for(dev = bus->devices; dev; dev = dev->next) {
- cerr << "Checking " << dev->descriptor.idVendor << '/' << dev->descriptor.idProduct << endl;
- if (dev->descriptor.idVendor != VENDORID)
- continue;
- if (dev->descriptor.idProduct != PRODUCTID)
- continue;
- cerr << "Open this one" << endl;
- return open_core (dev);
- }
- }
-
- error << _("Tranzport: no device detected") << endmsg;
- return -1;
-}
-
-int
-TranzportControlProtocol::open_core (struct usb_device* dev)
-{
- if (!(udev = usb_open (dev))) {
- error << _("Tranzport: cannot open USB transport") << endmsg;
- return -1;
- }
-
- if (usb_claim_interface (udev, 0) < 0) {
- error << _("Tranzport: cannot claim USB interface") << endmsg;
- usb_close (udev);
- udev = 0;
- return -1;
- }
-
- return 0;
-}
-
-int
-TranzportControlProtocol::close ()
-{
- int ret = 0;
-
- if (udev == 0) {
- return 0;
- }
-
- if (usb_release_interface (udev, 0) < 0) {
- error << _("Tranzport: cannot release interface") << endmsg;
- ret = -1;
- }
-
- if (usb_close (udev)) {
- error << _("Tranzport: cannot close device") << endmsg;
- ret = 0;
- }
-
- return ret;
-}
-
-int
-TranzportControlProtocol::write (uint8_t* cmd)
-{
- int val;
- val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout);
- if (val < 0)
- return val;
- if (val != 8)
- return -1;
- return 0;
-
-}
-
-void
-TranzportControlProtocol::lcd_clear ()
-{
- lcd_write (0, " ");
- lcd_write (1, " ");
- lcd_write (2, " ");
- lcd_write (3, " ");
- lcd_write (4, " ");
- lcd_write (5, " ");
- lcd_write (6, " ");
- lcd_write (7, " ");
- lcd_write (8, " ");
- lcd_write (9, " ");
-}
-
-int
-TranzportControlProtocol::lcd_write (uint8_t cell, const char* text)
-{
- uint8_t cmd[8];
-
- if (cell > 9) {
- return -1;
- }
-
- cmd[0] = 0x00;
- cmd[1] = 0x01;
- cmd[2] = cell;
- cmd[3] = text[0];
- cmd[4] = text[1];
- cmd[5] = text[2];
- cmd[6] = text[3];
- cmd[7] = 0x00;
-
- return write (cmd);
-}
-
-int
-TranzportControlProtocol::light_on (LightID light)
-{
- uint8_t cmd[8];
-
- cmd[0] = 0x00;
- cmd[1] = 0x00;
- cmd[2] = light;
- cmd[3] = 0x01;
- cmd[4] = 0x00;
- cmd[5] = 0x00;
- cmd[6] = 0x00;
- cmd[7] = 0x00;
-
- return write (cmd);
-}
-
-int
-TranzportControlProtocol::light_off (LightID light)
-{
- uint8_t cmd[8];
-
- cmd[0] = 0x00;
- cmd[1] = 0x00;
- cmd[2] = light;
- cmd[3] = 0x00;
- cmd[4] = 0x00;
- cmd[5] = 0x00;
- cmd[6] = 0x00;
- cmd[7] = 0x00;
-
- return write (cmd);
-}
-
-int
-TranzportControlProtocol::read ()
-{
- uint8_t buf[8];
- int val;
-
- memset(buf, 0, 8);
- val = usb_interrupt_read(udev, READ_ENDPOINT, (char*) buf, 8, timeout);
- if (val < 0) {
- cerr << "Tranzport read error, val = " << val << endl;
- return val;
- }
- if (val != 8) {
- cerr << "Tranzport short read, val = " << val << endl;
- return -1;
- }
-
- /*printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
-
- uint32_t this_button_mask;
- uint32_t button_changes;
-
- _device_status = buf[1];
- this_button_mask = 0;
- this_button_mask |= buf[2] << 24;
- this_button_mask |= buf[3] << 16;
- this_button_mask |= buf[4] << 8;
- this_button_mask |= buf[5];
- _datawheel = buf[6];
-
- button_changes = (this_button_mask ^ buttonmask);
- buttonmask = this_button_mask;
-
- if (button_changes & ButtonBattery) {
- if (buttonmask & ButtonBattery) {
- button_event_battery_press (buttonmask&ButtonShift);
- } else {
- button_event_battery_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonBacklight) {
- if (buttonmask & ButtonBacklight) {
- button_event_backlight_press (buttonmask&ButtonShift);
- } else {
- button_event_backlight_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackLeft) {
- if (buttonmask & ButtonTrackLeft) {
- button_event_trackleft_press (buttonmask&ButtonShift);
- } else {
- button_event_trackleft_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackRight) {
- if (buttonmask & ButtonTrackRight) {
- button_event_trackright_press (buttonmask&ButtonShift);
- } else {
- button_event_trackright_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackRec) {
- if (buttonmask & ButtonTrackRec) {
- button_event_trackrec_press (buttonmask&ButtonShift);
- } else {
- button_event_trackrec_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackMute) {
- if (buttonmask & ButtonTrackMute) {
- button_event_trackmute_press (buttonmask&ButtonShift);
- } else {
- button_event_trackmute_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonTrackSolo) {
- if (buttonmask & ButtonTrackSolo) {
- button_event_tracksolo_press (buttonmask&ButtonShift);
- } else {
- button_event_tracksolo_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonUndo) {
- if (buttonmask & ButtonUndo) {
- button_event_undo_press (buttonmask&ButtonShift);
- } else {
- button_event_undo_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonIn) {
- if (buttonmask & ButtonIn) {
- button_event_in_press (buttonmask&ButtonShift);
- } else {
- button_event_in_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonOut) {
- if (buttonmask & ButtonOut) {
- button_event_out_press (buttonmask&ButtonShift);
- } else {
- button_event_out_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonPunch) {
- if (buttonmask & ButtonPunch) {
- button_event_punch_press (buttonmask&ButtonShift);
- } else {
- button_event_punch_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonLoop) {
- if (buttonmask & ButtonLoop) {
- button_event_loop_press (buttonmask&ButtonShift);
- } else {
- button_event_loop_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonPrev) {
- if (buttonmask & ButtonPrev) {
- button_event_prev_press (buttonmask&ButtonShift);
- } else {
- button_event_prev_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonAdd) {
- if (buttonmask & ButtonAdd) {
- button_event_add_press (buttonmask&ButtonShift);
- } else {
- button_event_add_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonNext) {
- if (buttonmask & ButtonNext) {
- button_event_next_press (buttonmask&ButtonShift);
- } else {
- button_event_next_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonRewind) {
- if (buttonmask & ButtonRewind) {
- button_event_rewind_press (buttonmask&ButtonShift);
- } else {
- button_event_rewind_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonFastForward) {
- if (buttonmask & ButtonFastForward) {
- button_event_fastforward_press (buttonmask&ButtonShift);
- } else {
- button_event_fastforward_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonStop) {
- if (buttonmask & ButtonStop) {
- button_event_stop_press (buttonmask&ButtonShift);
- } else {
- button_event_stop_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonPlay) {
- if (buttonmask & ButtonPlay) {
- button_event_play_press (buttonmask&ButtonShift);
- } else {
- button_event_play_release (buttonmask&ButtonShift);
- }
- }
- if (button_changes & ButtonRecord) {
- if (buttonmask & ButtonRecord) {
- button_event_record_press (buttonmask&ButtonShift);
- } else {
- button_event_record_release (buttonmask&ButtonShift);
- }
- }
-
- return 0;
-}
-
-void
-TranzportControlProtocol::show_current_track ()
-{
- current_route = session.route_by_remote_id (current_track_id);
-
- if (current_route == 0) {
- char buf[5];
- lcd_clear ();
- lcd_write (0, "NO T");
- lcd_write (1, "RACK");
- lcd_write (2, " ID ");
- snprintf (buf, sizeof (buf), "%4d", current_track_id);
- lcd_write (3, buf);
- return;
- }
-
- string name = current_route->name();
-
- lcd_write (0, name.substr (0, 4).c_str());
- lcd_write (1, name.substr (4, 4).c_str());
-}
-
-void
-TranzportControlProtocol::button_event_battery_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_battery_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_backlight_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_backlight_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_trackleft_press (bool shifted)
-{
- if (current_track_id == 0) {
- current_track_id = session.nroutes() - 1;
- } else {
- current_track_id--;
- }
-
- show_current_track ();
-}
-
-void
-TranzportControlProtocol::button_event_trackleft_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_trackright_press (bool shifted)
-{
- if (current_track_id == session.nroutes()) {
- current_track_id = 0;
- } else {
- current_track_id++;
- }
-
- show_current_track ();
-}
-
-void
-TranzportControlProtocol::button_event_trackright_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_trackrec_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_trackrec_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_trackmute_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_trackmute_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_undo_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_undo_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_in_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_in_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_out_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_out_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_punch_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_punch_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_loop_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_loop_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_prev_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_prev_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_add_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_add_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_next_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_next_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_rewind_press (bool shifted)
-{
- session.request_transport_speed (-2.0f);
-}
-
-void
-TranzportControlProtocol::button_event_rewind_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_fastforward_press (bool shifted)
-{
- session.request_transport_speed (2.0f);
-}
-
-void
-TranzportControlProtocol::button_event_fastforward_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_stop_press (bool shifted)
-{
- session.request_transport_speed (0.0);
-}
-
-void
-TranzportControlProtocol::button_event_stop_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_play_press (bool shifted)
-{
- session.request_transport_speed (1.0);
-}
-
-void
-TranzportControlProtocol::button_event_play_release (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_record_press (bool shifted)
-{
-}
-
-void
-TranzportControlProtocol::button_event_record_release (bool shifted)
-{
-}
#include <pbd/pthread_utils.h>
-using std::string;
+using namespace std;
typedef std::map<string,pthread_t> ThreadMap;
static ThreadMap all_threads;
{
int ret;
+ cerr << "Creating thread " << name << endl;
+
if ((ret = pthread_create (thread, attr, start_routine, arg)) == 0) {
std::pair<string,pthread_t> newpair;
newpair.first = name;
--- /dev/null
+# -*- python -*-
+
+import os
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+genericmidi = env.Copy()
+
+#
+# this defines the version number of libardour_genericmidi
+#
+
+domain = 'ardour_genericmidi'
+
+genericmidi.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+genericmidi.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+genericmidi.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+genericmidi.Append(PACKAGE = domain)
+genericmidi.Append(POTFILE = domain + '.pot')
+
+genericmidi_files=Split("""
+interface.cc
+generic_midi_control_protocol.cc
+""")
+
+genericmidi.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+genericmidi.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+genericmidi.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+genericmidi.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+genericmidi.Merge ([
+ libraries['usb'],
+ libraries['ardour'],
+ libraries['sigc2'],
+ libraries['pbd3'],
+ libraries['midi++2'],
+ libraries['xml']
+ ])
+
+libardour_genericmidi = genericmidi.SharedLibrary('ardour_genericmidi', genericmidi_files)
+
+Default(libardour_genericmidi)
+
+if env['NLS']:
+ i18n (genericmidi, genericmidi_files, env)
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript', 'i18n.h', 'gettext.h' ] +
+ genericmidi_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
--- /dev/null
+#include <ardour/route.h>
+#include <ardour/session.h>
+
+#include "generic_midi_control_protocol.h"
+
+using namespace ARDOUR;
+
+#include "i18n.h"
+
+GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
+ : ControlProtocol (s, _("GenericMIDI"))
+{
+ _port = 0;
+}
+
+GenericMidiControlProtocol::~GenericMidiControlProtocol ()
+{
+}
+
+void
+GenericMidiControlProtocol::set_port (MIDI::Port* p)
+{
+ _port = p;
+}
+
+void
+GenericMidiControlProtocol::send_route_feedback (list<Route*>& routes)
+{
+ if (_port != 0) {
+
+ const int32_t bufsize = 16 * 1024;
+ int32_t bsize = bufsize;
+ MIDI::byte* buf = new MIDI::byte[bufsize];
+ MIDI::byte* end = buf;
+
+ for (list<Route*>::iterator r = routes.begin(); r != routes.end(); ++r) {
+ end = (*r)->write_midi_feedback (end, bsize);
+ }
+
+ if (end == buf) {
+ delete [] buf;
+ return;
+ }
+
+ session.deliver_midi (_port, buf, (int32_t) (end - buf));
+ //cerr << "MIDI feedback: wrote " << (int32_t) (end - buf) << " to midi port\n";
+ }
+}
+
+bool
+GenericMidiControlProtocol::active() const
+{
+ return _port && send();
+}
+
--- /dev/null
+#ifndef ardour_generic_midi_control_protocol_h
+#define ardour_generic_midi_control_protocol_h
+
+#include <ardour/control_protocol.h>
+
+namespace MIDI {
+ class Port;
+}
+
+namespace ARDOUR {
+
+class GenericMidiControlProtocol : public ControlProtocol {
+ public:
+ GenericMidiControlProtocol (Session&);
+ virtual ~GenericMidiControlProtocol();
+
+ bool active() const;
+
+ void set_port (MIDI::Port*);
+ MIDI::Port* port () const { return _port; }
+
+ void send_route_feedback (std::list<Route*>&);
+
+ private:
+ void route_feedback (ARDOUR::Route&, bool);
+ MIDI::Port* _port;
+};
+
+}
+
+#endif // ardour_generic_midi_control_protocol_h
--- /dev/null
+#include <ardour/control_protocol.h>
+
+#include "generic_midi_control_protocol.h"
+
+using namespace ARDOUR;
+
+ControlProtocol*
+new_generic_midi_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ return new GenericMidiControlProtocol (*s);
+}
+
+void
+delete_generic_midi_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+static ControlProtocolDescriptor generic_midi_descriptor = {
+ name : "Generic MIDI",
+ ptr : 0,
+ module : 0,
+ initialize : new_generic_midi_protocol,
+ destroy : delete_generic_midi_protocol
+};
+
+
+extern "C" {
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &generic_midi_descriptor;
+}
+}
+
--- /dev/null
+# -*- python -*-
+
+import os
+import glob
+
+Import('env final_prefix install_prefix final_config_prefix libraries i18n')
+
+tranzport = env.Copy()
+
+#
+# this defines the version number of libardour_tranzport
+#
+
+domain = 'ardour_tranzport'
+
+tranzport.Append(DOMAIN = domain, MAJOR = 1, MINOR = 0, MICRO = 0)
+tranzport.Append(CXXFLAGS = "-DPACKAGE=\\\"" + domain + "\\\"")
+tranzport.Append(CXXFLAGS="-DLIBSIGC_DISABLE_DEPRECATED")
+tranzport.Append(PACKAGE = domain)
+tranzport.Append(POTFILE = domain + '.pot')
+
+tranzport_files=Split("""
+interface.cc
+tranzport_control_protocol.cc
+""")
+
+tranzport.Append(CCFLAGS="-D_REENTRANT -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE")
+tranzport.Append(CXXFLAGS="-DDATA_DIR=\\\""+final_prefix+"/share\\\"")
+tranzport.Append(CXXFLAGS="-DCONFIG_DIR=\\\""+final_config_prefix+"\\\"")
+tranzport.Append(CXXFLAGS="-DLOCALEDIR=\\\""+final_prefix+"/share/locale\\\"")
+
+tranzport.Append(CPPPATH=libraries['ardour'].get ('CPPPATH', []))
+tranzport.Append(CPPPATH=libraries['sigc2'].get ('CPPPATH', []))
+tranzport.Append(CPPPATH=libraries['pbd3'].get ('CPPPATH', []))
+tranzport.Append(CPPPATH=libraries['midi++2'].get ('CPPPATH', []))
+
+tranzport.Merge ([
+ libraries['xml'],
+ libraries['usb']
+ ])
+
+libardour_tranzport = tranzport.SharedLibrary('ardour_tranzport', tranzport_files)
+
+Default(libardour_tranzport)
+
+if env['NLS']:
+ i18n (tranzport, tranzport_files, env)
+
+env.Alias('tarball', env.Distribute (env['DISTTREE'],
+ [ 'SConscript', 'i18n.h', 'gettext.h' ] +
+ tranzport_files +
+ glob.glob('po/*.po') + glob.glob('*.h')))
--- /dev/null
+#include <ardour/control_protocol.h>
+
+#include "tranzport_control_protocol.h"
+
+using namespace ARDOUR;
+
+ControlProtocol*
+new_tranzport_protocol (ControlProtocolDescriptor* descriptor, Session* s)
+{
+ return new TranzportControlProtocol (*s);
+}
+
+void
+delete_tranzport_protocol (ControlProtocolDescriptor* descriptor, ControlProtocol* cp)
+{
+ delete cp;
+}
+
+static ControlProtocolDescriptor tranzport_descriptor = {
+ name : "Tranzport",
+ ptr : 0,
+ module : 0,
+ initialize : new_tranzport_protocol,
+ destroy : delete_tranzport_protocol
+};
+
+
+extern "C" {
+ControlProtocolDescriptor*
+protocol_descriptor () {
+ return &tranzport_descriptor;
+}
+}
+
--- /dev/null
+#include <iostream>
+#include <sys/time.h>
+
+#include <pbd/pthread_utils.h>
+
+#include <ardour/route.h>
+#include <ardour/session.h>
+
+#include "tranzport_control_protocol.h"
+
+using namespace ARDOUR;
+using namespace std;
+
+#include "i18n.h"
+
+TranzportControlProtocol::TranzportControlProtocol (Session& s)
+ : ControlProtocol (s, _("Tranzport"))
+{
+ timeout = 60000;
+ buttonmask = 0;
+ _datawheel = 0;
+ _device_status = STATUS_OFFLINE;
+ udev = 0;
+ current_route = 0;
+ current_track_id = 0;
+ last_where = max_frames;
+ memset (next_screen, ' ', sizeof (next_screen));
+ memset (current_screen, ' ', sizeof (current_screen));
+}
+
+TranzportControlProtocol::~TranzportControlProtocol ()
+{
+ if (udev) {
+ lcd_clear ();
+ pthread_cancel_one (thread);
+ close ();
+ }
+}
+
+int
+TranzportControlProtocol::init ()
+{
+ if (open ()) {
+ return -1;
+ }
+
+ /* outbound thread */
+
+ init_thread ();
+
+ /* inbound thread */
+
+ pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _thread_work, this);
+
+ return 0;
+}
+
+bool
+TranzportControlProtocol::active() const
+{
+ return true;
+}
+
+void
+TranzportControlProtocol::send_route_feedback (list<Route*>& routes)
+{
+}
+
+void
+TranzportControlProtocol::send_global_feedback ()
+{
+ show_transport_time ();
+
+ flush_lcd ();
+}
+
+void
+TranzportControlProtocol::show_transport_time ()
+{
+ jack_nframes_t where = session.transport_frame();
+
+ if (where != last_where) {
+
+ uint8_t label[12];
+ SMPTE_Time smpte;
+ char* ptr = (char *) label;
+
+ session.smpte_time (where, smpte);
+ memset (label, ' ', sizeof (label));
+
+ if (smpte.negative) {
+ sprintf (ptr, "-%02ld:", smpte.hours);
+ } else {
+ sprintf (ptr, " %02ld:", smpte.hours);
+ }
+ ptr += 4;
+
+ sprintf (ptr, "%02ld:", smpte.minutes);
+ ptr += 3;
+
+ sprintf (ptr, "%02ld:", smpte.seconds);
+ ptr += 3;
+
+ sprintf (ptr, "%02ld", smpte.frames);
+ ptr += 2;
+
+ write_clock (label);
+
+ last_where = where;
+ }
+}
+
+void
+TranzportControlProtocol::write_clock (const uint8_t* label)
+{
+ memcpy (&next_screen[1][8], &label[0]);
+ memcpy (&next_screen[1][12], &label[4]);
+ memcpy (&next_screen[1][16], &label[8]);
+}
+
+void
+TranzportControlProtocol::flush_lcd ()
+{
+ if (memcmp (&next_screen[0][0], ¤t_screen[0][0], 4)) {
+ lcd_write (0, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[0][4], ¤t_screen[0][4], 4)) {
+ lcd_write (1, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[0][8], ¤t_screen[0][8], 4)) {
+ lcd_write (2, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[0][12], ¤t_screen[0][12], 4)) {
+ lcd_write (3, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[0][16], ¤t_screen[0][16], 4)) {
+ lcd_write (4, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[1][0], ¤t_screen[1][0], 4)) {
+ lcd_write (5, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[1][4], ¤t_screen[1][4], 4)) {
+ lcd_write (6, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[1][8], ¤t_screen[1][8], 4)) {
+ lcd_write (7, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[1][12], ¤t_screen[1][12], 4)) {
+ lcd_write (8, &next_screen[0][0]);
+ }
+ if (memcmp (&next_screen[1][16], ¤t_screen[1][16], 4)) {
+ lcd_write (9, &next_screen[0][0]);
+ }
+
+ memcpy (current_screen, next_screen, sizeof (current_screen));
+}
+
+void*
+TranzportControlProtocol::_thread_work (void* arg)
+{
+ return static_cast<TranzportControlProtocol*>(arg)->thread_work ();
+}
+
+void*
+TranzportControlProtocol::thread_work ()
+{
+ PBD::ThreadCreated (pthread_self(), X_("tranzport monitor"));
+
+ while (true) {
+ if (read()) {
+ return 0;
+ }
+ switch (_device_status) {
+ case STATUS_OFFLINE:
+ cerr << "offline\n";
+ break;
+ case STATUS_ONLINE:
+ cerr << "online\n";
+ break;
+ default:
+ cerr << "unknown status\n";
+ break;
+ }
+
+ if (_device_status == STATUS_ONLINE) {
+ break;
+ }
+ }
+
+ lcd_write (0, " ");
+ lcd_write (1, "WELC");
+ lcd_write (2, "OME ");
+ lcd_write (3, "TO ");
+ lcd_write (4, " ");
+ lcd_write (5, " ");
+ lcd_write (6, " ");
+ lcd_write (7, "ARDO");
+ lcd_write (8, "UR ");
+ lcd_write (9, " ");
+
+ while (true) {
+ if (read ()) {
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+TranzportControlProtocol::open ()
+{
+ struct usb_bus *bus;
+ struct usb_device *dev;
+
+ usb_init();
+ usb_find_busses();
+ usb_find_devices();
+
+ for (bus = usb_busses; bus; bus = bus->next) {
+
+ for(dev = bus->devices; dev; dev = dev->next) {
+ if (dev->descriptor.idVendor != VENDORID)
+ continue;
+ if (dev->descriptor.idProduct != PRODUCTID)
+ continue;
+ return open_core (dev);
+ }
+ }
+
+ error << _("Tranzport: no device detected") << endmsg;
+ return -1;
+}
+
+int
+TranzportControlProtocol::open_core (struct usb_device* dev)
+{
+ if (!(udev = usb_open (dev))) {
+ error << _("Tranzport: cannot open USB transport") << endmsg;
+ return -1;
+ }
+
+ if (usb_claim_interface (udev, 0) < 0) {
+ error << _("Tranzport: cannot claim USB interface") << endmsg;
+ usb_close (udev);
+ udev = 0;
+ return -1;
+ }
+
+ return 0;
+}
+
+int
+TranzportControlProtocol::close ()
+{
+ int ret = 0;
+
+ if (udev == 0) {
+ return 0;
+ }
+
+ if (usb_release_interface (udev, 0) < 0) {
+ error << _("Tranzport: cannot release interface") << endmsg;
+ ret = -1;
+ }
+
+ if (usb_close (udev)) {
+ error << _("Tranzport: cannot close device") << endmsg;
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int
+TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override)
+{
+ int val;
+ struct timeval tv1, tv2, tv_diff;
+
+ gettimeofday (&tv1, 0);
+ val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout_override ? timeout_override : timeout);
+ gettimeofday (&tv2, 0);
+ if (val < 0)
+ return val;
+ if (val != 8)
+ return -1;
+ timersub (&tv2, &tv1, &tv_diff);
+ cerr << "time to write command = " << tv_diff.tv_sec << '.' << tv_diff.tv_usec << endl;
+ return 0;
+
+}
+
+void
+TranzportControlProtocol::lcd_clear ()
+{
+ lcd_write (0, " ");
+ lcd_write (1, " ");
+ lcd_write (2, " ");
+ lcd_write (3, " ");
+ lcd_write (4, " ");
+ lcd_write (5, " ");
+ lcd_write (6, " ");
+ lcd_write (7, " ");
+ lcd_write (8, " ");
+ lcd_write (9, " ");
+}
+
+int
+TranzportControlProtocol::lcd_write (uint8_t cell, const char* text)
+{
+ uint8_t cmd[8];
+
+ if (cell > 9) {
+ return -1;
+ }
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x01;
+ cmd[2] = cell;
+ cmd[3] = text[0];
+ cmd[4] = text[1];
+ cmd[5] = text[2];
+ cmd[6] = text[3];
+ cmd[7] = 0x00;
+
+ int index = cell%4;
+ cell /= 4;
+
+ current_screen[cell][index] = text[0];
+ current_screen[cell][index+1] = text[1];
+ current_screen[cell][index+2] = text[2];
+ current_screen[cell][index+3] = text[3];
+
+ return write (cmd, 500);
+}
+
+int
+TranzportControlProtocol::light_on (LightID light)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x01;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return write (cmd, 500);
+}
+
+int
+TranzportControlProtocol::light_off (LightID light)
+{
+ uint8_t cmd[8];
+
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ cmd[2] = light;
+ cmd[3] = 0x00;
+ cmd[4] = 0x00;
+ cmd[5] = 0x00;
+ cmd[6] = 0x00;
+ cmd[7] = 0x00;
+
+ return write (cmd, 500);
+}
+
+int
+TranzportControlProtocol::read (uint32_t timeout_override)
+{
+ uint8_t buf[8];
+ int val;
+
+ memset(buf, 0, 8);
+ again:
+ val = usb_interrupt_read(udev, READ_ENDPOINT, (char*) buf, 8, timeout_override ? timeout_override : timeout);
+ if (val < 0) {
+ return val;
+ }
+ if (val != 8) {
+ if (val == 0) {
+ goto again;
+ }
+ return -1;
+ }
+
+ /* printf("read: %02x %02x %02x %02x %02x %02x %02x %02x\n", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);*/
+
+ uint32_t this_button_mask;
+ uint32_t button_changes;
+
+ _device_status = buf[1];
+ this_button_mask = 0;
+ this_button_mask |= buf[2] << 24;
+ this_button_mask |= buf[3] << 16;
+ this_button_mask |= buf[4] << 8;
+ this_button_mask |= buf[5];
+ _datawheel = buf[6];
+
+ button_changes = (this_button_mask ^ buttonmask);
+ buttonmask = this_button_mask;
+
+ if (button_changes & ButtonBattery) {
+ if (buttonmask & ButtonBattery) {
+ button_event_battery_press (buttonmask&ButtonShift);
+ } else {
+ button_event_battery_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonBacklight) {
+ if (buttonmask & ButtonBacklight) {
+ button_event_backlight_press (buttonmask&ButtonShift);
+ } else {
+ button_event_backlight_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonTrackLeft) {
+ if (buttonmask & ButtonTrackLeft) {
+ button_event_trackleft_press (buttonmask&ButtonShift);
+ } else {
+ button_event_trackleft_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonTrackRight) {
+ if (buttonmask & ButtonTrackRight) {
+ button_event_trackright_press (buttonmask&ButtonShift);
+ } else {
+ button_event_trackright_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonTrackRec) {
+ if (buttonmask & ButtonTrackRec) {
+ button_event_trackrec_press (buttonmask&ButtonShift);
+ } else {
+ button_event_trackrec_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonTrackMute) {
+ if (buttonmask & ButtonTrackMute) {
+ button_event_trackmute_press (buttonmask&ButtonShift);
+ } else {
+ button_event_trackmute_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonTrackSolo) {
+ if (buttonmask & ButtonTrackSolo) {
+ button_event_tracksolo_press (buttonmask&ButtonShift);
+ } else {
+ button_event_tracksolo_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonUndo) {
+ if (buttonmask & ButtonUndo) {
+ button_event_undo_press (buttonmask&ButtonShift);
+ } else {
+ button_event_undo_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonIn) {
+ if (buttonmask & ButtonIn) {
+ button_event_in_press (buttonmask&ButtonShift);
+ } else {
+ button_event_in_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonOut) {
+ if (buttonmask & ButtonOut) {
+ button_event_out_press (buttonmask&ButtonShift);
+ } else {
+ button_event_out_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonPunch) {
+ if (buttonmask & ButtonPunch) {
+ button_event_punch_press (buttonmask&ButtonShift);
+ } else {
+ button_event_punch_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonLoop) {
+ if (buttonmask & ButtonLoop) {
+ button_event_loop_press (buttonmask&ButtonShift);
+ } else {
+ button_event_loop_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonPrev) {
+ if (buttonmask & ButtonPrev) {
+ button_event_prev_press (buttonmask&ButtonShift);
+ } else {
+ button_event_prev_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonAdd) {
+ if (buttonmask & ButtonAdd) {
+ button_event_add_press (buttonmask&ButtonShift);
+ } else {
+ button_event_add_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonNext) {
+ if (buttonmask & ButtonNext) {
+ button_event_next_press (buttonmask&ButtonShift);
+ } else {
+ button_event_next_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonRewind) {
+ if (buttonmask & ButtonRewind) {
+ button_event_rewind_press (buttonmask&ButtonShift);
+ } else {
+ button_event_rewind_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonFastForward) {
+ if (buttonmask & ButtonFastForward) {
+ button_event_fastforward_press (buttonmask&ButtonShift);
+ } else {
+ button_event_fastforward_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonStop) {
+ if (buttonmask & ButtonStop) {
+ button_event_stop_press (buttonmask&ButtonShift);
+ } else {
+ button_event_stop_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonPlay) {
+ if (buttonmask & ButtonPlay) {
+ button_event_play_press (buttonmask&ButtonShift);
+ } else {
+ button_event_play_release (buttonmask&ButtonShift);
+ }
+ }
+ if (button_changes & ButtonRecord) {
+ if (buttonmask & ButtonRecord) {
+ button_event_record_press (buttonmask&ButtonShift);
+ } else {
+ button_event_record_release (buttonmask&ButtonShift);
+ }
+ }
+
+ return 0;
+}
+
+void
+TranzportControlProtocol::show_current_track ()
+{
+ current_route = session.route_by_remote_id (current_track_id);
+
+ if (current_route == 0) {
+ char buf[5];
+ lcd_clear ();
+ lcd_write (0, "NO T");
+ lcd_write (1, "RACK");
+ lcd_write (2, " ID ");
+ snprintf (buf, sizeof (buf), "%4d", current_track_id);
+ lcd_write (3, buf);
+ return;
+ }
+
+ string name = current_route->name();
+
+ lcd_write (0, name.substr (0, 4).c_str());
+ lcd_write (1, name.substr (4, 4).c_str());
+}
+
+void
+TranzportControlProtocol::button_event_battery_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_battery_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_backlight_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_backlight_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackleft_press (bool shifted)
+{
+ if (current_track_id == 0) {
+ current_track_id = session.nroutes() - 1;
+ } else {
+ current_track_id--;
+ }
+
+ show_current_track ();
+}
+
+void
+TranzportControlProtocol::button_event_trackleft_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackright_press (bool shifted)
+{
+ if (current_track_id == session.nroutes()) {
+ current_track_id = 0;
+ } else {
+ current_track_id++;
+ }
+
+ show_current_track ();
+}
+
+void
+TranzportControlProtocol::button_event_trackright_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackrec_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackrec_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackmute_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_trackmute_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_tracksolo_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_tracksolo_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_undo_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_undo_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_in_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_in_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_out_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_out_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_punch_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_punch_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_loop_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_loop_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_prev_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_prev_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_add_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_add_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_next_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_next_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_rewind_press (bool shifted)
+{
+ session.request_transport_speed (-2.0f);
+}
+
+void
+TranzportControlProtocol::button_event_rewind_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_fastforward_press (bool shifted)
+{
+ session.request_transport_speed (2.0f);
+}
+
+void
+TranzportControlProtocol::button_event_fastforward_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_stop_press (bool shifted)
+{
+ session.request_transport_speed (0.0);
+}
+
+void
+TranzportControlProtocol::button_event_stop_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_play_press (bool shifted)
+{
+ session.request_transport_speed (1.0);
+}
+
+void
+TranzportControlProtocol::button_event_play_release (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_record_press (bool shifted)
+{
+}
+
+void
+TranzportControlProtocol::button_event_record_release (bool shifted)
+{
+}
--- /dev/null
+#ifndef ardour_tranzport_control_protocol_h
+#define ardour_tranzport_control_protocol_h
+
+#include <pthread.h>
+#include <usb.h>
+#include <ardour/control_protocol.h>
+#include <ardour/types.h>
+
+namespace ARDOUR {
+
+class TranzportControlProtocol : public ControlProtocol {
+ public:
+ TranzportControlProtocol (Session&);
+ virtual ~TranzportControlProtocol();
+
+ int init ();
+ bool active() const;
+
+ void send_route_feedback (std::list<Route*>&);
+ void send_global_feedback ();
+
+ private:
+ static const int VENDORID = 0x165b;
+ static const int PRODUCTID = 0x8101;
+ static const int READ_ENDPOINT = 0x81;
+ static const int WRITE_ENDPOINT = 0x02;
+ const static int STATUS_OFFLINE = 0xff;
+ const static int STATUS_ONLINE = 0x01;
+
+ enum LightID {
+ LightRecord = 0,
+ LightTrackrec,
+ LightTrackmute,
+ LightTracksolo,
+ LightAnysolo,
+ LightLoop,
+ LightPunch
+ };
+
+ enum ButtonID {
+ ButtonBattery = 0x00004000,
+ ButtonBacklight = 0x00008000,
+ ButtonTrackLeft = 0x04000000,
+ ButtonTrackRight = 0x40000000,
+ ButtonTrackRec = 0x00040000,
+ ButtonTrackMute = 0x00400000,
+ ButtonTrackSolo = 0x00000400,
+ ButtonUndo = 0x80000000,
+ ButtonIn = 0x02000000,
+ ButtonOut = 0x20000000,
+ ButtonPunch = 0x00800000,
+ ButtonLoop = 0x00080000,
+ ButtonPrev = 0x00020000,
+ ButtonAdd = 0x00200000,
+ ButtonNext = 0x00000200,
+ ButtonRewind = 0x01000000,
+ ButtonFastForward = 0x10000000,
+ ButtonStop = 0x00010000,
+ ButtonPlay = 0x00100000,
+ ButtonRecord = 0x00000100,
+ ButtonShift = 0x08000000
+ };
+
+ pthread_t thread;
+ uint32_t buttonmask;
+ uint32_t timeout;
+ uint8_t _datawheel;
+ uint8_t _device_status;
+ usb_dev_handle* udev;
+ Route* current_route;
+ uint32_t current_track_id;
+ uint8_t lcd_screen[2][20];
+
+ bool last_negative;
+ uint32_t last_hrs;
+ uint32_t last_mins;
+ uint32_t last_secs;
+ uint32_t last_frames;
+ jack_nframes_t last_where;
+
+ int open ();
+ int read (uint32_t timeout_override = 0);
+ int write (uint8_t* cmd, uint32_t timeout_override = 0);
+ int close ();
+
+ int open_core (struct usb_device*);
+
+ void lcd_clear ();
+ int lcd_write (uint8_t cell, const char *text);
+
+ int light_on (LightID);
+ int light_off (LightID);
+
+ void flush_lcd ();
+ void write_clock (const uint8_t* label);
+
+ void show_current_track ();
+ void show_transport_time ();
+
+ static void* _thread_work (void* arg);
+ void* thread_work ();
+
+ void button_event_battery_press (bool shifted);
+ void button_event_battery_release (bool shifted);
+ void button_event_backlight_press (bool shifted);
+ void button_event_backlight_release (bool shifted);
+ void button_event_trackleft_press (bool shifted);
+ void button_event_trackleft_release (bool shifted);
+ void button_event_trackright_press (bool shifted);
+ void button_event_trackright_release (bool shifted);
+ void button_event_trackrec_press (bool shifted);
+ void button_event_trackrec_release (bool shifted);
+ void button_event_trackmute_press (bool shifted);
+ void button_event_trackmute_release (bool shifted);
+ void button_event_tracksolo_press (bool shifted);
+ void button_event_tracksolo_release (bool shifted);
+ void button_event_undo_press (bool shifted);
+ void button_event_undo_release (bool shifted);
+ void button_event_in_press (bool shifted);
+ void button_event_in_release (bool shifted);
+ void button_event_out_press (bool shifted);
+ void button_event_out_release (bool shifted);
+ void button_event_punch_press (bool shifted);
+ void button_event_punch_release (bool shifted);
+ void button_event_loop_press (bool shifted);
+ void button_event_loop_release (bool shifted);
+ void button_event_prev_press (bool shifted);
+ void button_event_prev_release (bool shifted);
+ void button_event_add_press (bool shifted);
+ void button_event_add_release (bool shifted);
+ void button_event_next_press (bool shifted);
+ void button_event_next_release (bool shifted);
+ void button_event_rewind_press (bool shifted);
+ void button_event_rewind_release (bool shifted);
+ void button_event_fastforward_press (bool shifted);
+ void button_event_fastforward_release (bool shifted);
+ void button_event_stop_press (bool shifted);
+ void button_event_stop_release (bool shifted);
+ void button_event_play_press (bool shifted);
+ void button_event_play_release (bool shifted);
+ void button_event_record_press (bool shifted);
+ void button_event_record_release (bool shifted);
+};
+
+} // namespace
+
+#endif // ardour_tranzport_control_protocol_h