diff options
20 files changed, 356 insertions, 293 deletions
diff --git a/SConstruct b/SConstruct index 0806ac4d26..04d1b3545f 100644 --- a/SConstruct +++ b/SConstruct @@ -518,6 +518,11 @@ else: 'gtk2_ardour' ] +surface_subdirs = [ + 'libs/surfaces/tranzport', + 'libs/surfaces/generic_midi' + ] + opts.Save('scache.conf', env) Help(opts.GenerateHelpText(env)) @@ -791,7 +796,7 @@ env.AddPostAction (srcdist, Action ('rm -rf ' + str (File (env['DISTTREE'])))) 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') diff --git a/gtk2_ardour/arval b/gtk2_ardour/arval index 5254ad4df0..a91943fb4d 100755 --- a/gtk2_ardour/arval +++ b/gtk2_ardour/arval @@ -1,3 +1,3 @@ #!/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 $* diff --git a/libs/ardour/SConscript b/libs/ardour/SConscript index 8bf62b9c01..572851d2f2 100644 --- a/libs/ardour/SConscript +++ b/libs/ardour/SConscript @@ -32,6 +32,7 @@ automation_event.cc configuration.cc connection.cc control_protocol.cc +control_protocol_manager.cc crossfade.cc curve.cc cycle_timer.cc @@ -42,7 +43,6 @@ externalsource.cc filesource.cc gain.cc gdither.cc -generic_midi_control_protocol.cc globals.cc import.cc insert.cc @@ -69,10 +69,8 @@ send.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 @@ -85,7 +83,6 @@ source.cc state_manager.cc stateful.cc tempo.cc -tranzport_control_protocol.cc utils.cc version.cc mix.cc diff --git a/libs/ardour/ardour/control_protocol.h b/libs/ardour/ardour/control_protocol.h index c0869fad9a..4088e2dd09 100644 --- a/libs/ardour/ardour/control_protocol.h +++ b/libs/ardour/ardour/control_protocol.h @@ -16,7 +16,8 @@ class ControlProtocol : sigc::trackable { virtual ~ControlProtocol(); virtual int init () { return 0; } - virtual bool active() const = 0; + + sigc::signal<void> ActiveChanged; enum SendWhat { SendRoute, @@ -26,6 +27,9 @@ class ControlProtocol : sigc::trackable { 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; } @@ -35,11 +39,43 @@ class ControlProtocol : sigc::trackable { 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 diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h index 1f6f464d24..201cc48ada 100644 --- a/libs/ardour/ardour/session.h +++ b/libs/ardour/ardour/session.h @@ -79,8 +79,7 @@ class AudioRegion; class Region; class Playlist; class VSTPlugin; -class ControlProtocol; -class GenericMidiControlProtocol; +class ControlProtocolManager; struct AudioExportSpecification; struct RouteGroup; @@ -246,6 +245,8 @@ class Session : public sigc::trackable, public Stateful 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>&); @@ -428,7 +429,6 @@ class Session : public sigc::trackable, public Stateful 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; } @@ -445,8 +445,6 @@ class Session : public sigc::trackable, public Stateful 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; } @@ -1136,7 +1134,6 @@ class Session : public sigc::trackable, public Stateful bool send_mmc; bool mmc_control; bool midi_control; - bool midi_feedback; RingBuffer<Event*> pending_events; @@ -1363,31 +1360,6 @@ class Session : public sigc::trackable, public Stateful 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 (); @@ -1770,12 +1742,6 @@ class Session : public sigc::trackable, public Stateful LayerModel layer_model; CrossfadeModel xfade_model; - - /* control protocols */ - - vector<ControlProtocol*> control_protocols; - GenericMidiControlProtocol* generic_midi_control_protocol; - void initialize_control (); }; }; /* namespace ARDOUR */ diff --git a/libs/ardour/globals.cc b/libs/ardour/globals.cc index 7210fcf9f5..18fad73f09 100644 --- a/libs/ardour/globals.cc +++ b/libs/ardour/globals.cc @@ -46,6 +46,7 @@ #include <ardour/source.h> #include <ardour/utils.h> #include <ardour/session.h> +#include <ardour/control_protocol_manager.h> #include <ardour/mix.h> @@ -71,7 +72,6 @@ Change ARDOUR::PositionChanged = ARDOUR::new_change (); Change ARDOUR::NameChanged = ARDOUR::new_change (); Change ARDOUR::BoundsChanged = Change (0); // see init(), below - static int setup_midi () { @@ -266,6 +266,10 @@ ARDOUR::init (AudioEngine& engine, bool use_vst, bool try_optimization, void (*s /* 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; diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc index 22686c6cbe..216517e668 100644 --- a/libs/ardour/session.cc +++ b/libs/ardour/session.cc @@ -361,7 +361,6 @@ Session::~Session () terminate_butler_thread (); terminate_midi_thread (); - terminate_feedback (); if (click_data && click_data != default_click) { delete [] click_data; diff --git a/libs/ardour/session_feedback.cc b/libs/ardour/session_feedback.cc index 09e9021461..600567892e 100644 --- a/libs/ardour/session_feedback.cc +++ b/libs/ardour/session_feedback.cc @@ -45,198 +45,5 @@ using namespace std; 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; -} diff --git a/libs/ardour/session_midi.cc b/libs/ardour/session_midi.cc index af08d3cc3e..aa079f8827 100644 --- a/libs/ardour/session_midi.cc +++ b/libs/ardour/session_midi.cc @@ -40,7 +40,6 @@ #include <ardour/diskstream.h> #include <ardour/slave.h> #include <ardour/cycles.h> -#include <ardour/generic_midi_control_protocol.h> #include "i18n.h" @@ -170,19 +169,12 @@ Session::set_send_mmc (bool yn) 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 @@ -328,9 +320,9 @@ Session::set_midi_port (string port_tag) _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); diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc index 5decba1d09..a78a2bdfa7 100644 --- a/libs/ardour/session_state.cc +++ b/libs/ardour/session_state.cc @@ -81,6 +81,7 @@ #include <ardour/location.h> #include <ardour/audioregion.h> #include <ardour/crossfade.h> +#include <ardour/control_protocol_manager.h> #include "i18n.h" #include <locale.h> @@ -165,9 +166,7 @@ Session::first_stage_init (string fullpath, string snapshot_name) 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); @@ -302,12 +301,6 @@ Session::second_stage_init (bool new_session) return -1; } - initialize_control(); - - if (init_feedback ()) { - return -1; - } - if (state_tree) { if (set_state (*state_tree->root())) { return -1; @@ -348,7 +341,7 @@ Session::second_stage_init (bool new_session) 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; @@ -2300,7 +2293,7 @@ Session::template_dir () } string -Session::template_path () +Session::suffixed_search_path (string suffix) { string path; @@ -2317,7 +2310,8 @@ Session::template_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 += ':'; @@ -2327,6 +2321,18 @@ Session::template_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) { diff --git a/libs/ardour/utils.cc b/libs/ardour/utils.cc index a5b0b4f2ce..8e9a36de59 100644 --- a/libs/ardour/utils.cc +++ b/libs/ardour/utils.cc @@ -257,3 +257,4 @@ path_expand (string path) return path; #endif } + diff --git a/libs/pbd3/pthread_utils.cc b/libs/pbd3/pthread_utils.cc index 88e9aef195..323542cdf7 100644 --- a/libs/pbd3/pthread_utils.cc +++ b/libs/pbd3/pthread_utils.cc @@ -25,7 +25,7 @@ #include <pbd/pthread_utils.h> -using std::string; +using namespace std; typedef std::map<string,pthread_t> ThreadMap; static ThreadMap all_threads; @@ -43,6 +43,8 @@ pthread_create_and_store (string name, pthread_t *thread, pthread_attr_t *attr, { 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; diff --git a/libs/surfaces/generic_midi/SConscript b/libs/surfaces/generic_midi/SConscript new file mode 100644 index 0000000000..abede3f4d7 --- /dev/null +++ b/libs/surfaces/generic_midi/SConscript @@ -0,0 +1,51 @@ +# -*- 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'))) diff --git a/libs/ardour/generic_midi_control_protocol.cc b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc index f9b9750982..4d64c6ce23 100644 --- a/libs/ardour/generic_midi_control_protocol.cc +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.cc @@ -1,7 +1,8 @@ -#include <ardour/generic_midi_control_protocol.h> #include <ardour/route.h> #include <ardour/session.h> +#include "generic_midi_control_protocol.h" + using namespace ARDOUR; #include "i18n.h" diff --git a/libs/ardour/ardour/generic_midi_control_protocol.h b/libs/surfaces/generic_midi/generic_midi_control_protocol.h index 75b514f016..75b514f016 100644 --- a/libs/ardour/ardour/generic_midi_control_protocol.h +++ b/libs/surfaces/generic_midi/generic_midi_control_protocol.h diff --git a/libs/surfaces/generic_midi/interface.cc b/libs/surfaces/generic_midi/interface.cc new file mode 100644 index 0000000000..8283b92e6f --- /dev/null +++ b/libs/surfaces/generic_midi/interface.cc @@ -0,0 +1,34 @@ +#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; +} +} + diff --git a/libs/surfaces/tranzport/SConscript b/libs/surfaces/tranzport/SConscript new file mode 100644 index 0000000000..e43f0bc77c --- /dev/null +++ b/libs/surfaces/tranzport/SConscript @@ -0,0 +1,52 @@ +# -*- 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'))) diff --git a/libs/surfaces/tranzport/interface.cc b/libs/surfaces/tranzport/interface.cc new file mode 100644 index 0000000000..a731be2ddf --- /dev/null +++ b/libs/surfaces/tranzport/interface.cc @@ -0,0 +1,34 @@ +#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; +} +} + diff --git a/libs/ardour/tranzport_control_protocol.cc b/libs/surfaces/tranzport/tranzport_control_protocol.cc index 9640ea4a75..518a4387d1 100644 --- a/libs/ardour/tranzport_control_protocol.cc +++ b/libs/surfaces/tranzport/tranzport_control_protocol.cc @@ -1,11 +1,13 @@ #include <iostream> +#include <sys/time.h> #include <pbd/pthread_utils.h> -#include <ardour/tranzport_control_protocol.h> #include <ardour/route.h> #include <ardour/session.h> +#include "tranzport_control_protocol.h" + using namespace ARDOUR; using namespace std; @@ -22,11 +24,14 @@ TranzportControlProtocol::TranzportControlProtocol (Session& s) 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 (); } @@ -39,7 +44,13 @@ TranzportControlProtocol::init () return -1; } - pthread_create_and_store (X_("Tranzport"), &thread, 0, _thread_work, this); + /* outbound thread */ + + init_thread (); + + /* inbound thread */ + + pthread_create_and_store (X_("tranzport monitor"), &thread, 0, _thread_work, this); return 0; } @@ -58,16 +69,24 @@ TranzportControlProtocol::send_route_feedback (list<Route*>& routes) void TranzportControlProtocol::send_global_feedback () { - jack_nframes_t where = session.transport_frame(); + show_transport_time (); + + flush_lcd (); +} +void +TranzportControlProtocol::show_transport_time () +{ + jack_nframes_t where = session.transport_frame(); + if (where != last_where) { - char clock_label[16]; + uint8_t label[12]; SMPTE_Time smpte; - char* ptr = clock_label; + char* ptr = (char *) label; session.smpte_time (where, smpte); - memset (clock_label, ' ', sizeof (clock_label)); + memset (label, ' ', sizeof (label)); if (smpte.negative) { sprintf (ptr, "-%02ld:", smpte.hours); @@ -85,14 +104,57 @@ TranzportControlProtocol::send_global_feedback () 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]); + 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) { @@ -102,7 +164,7 @@ TranzportControlProtocol::_thread_work (void* arg) void* TranzportControlProtocol::thread_work () { - cerr << "tranzport thread here, sending message to LCD\n"; + PBD::ThreadCreated (pthread_self(), X_("tranzport monitor")); while (true) { if (read()) { @@ -138,7 +200,6 @@ TranzportControlProtocol::thread_work () while (true) { if (read ()) { - cerr << "Tranzport command received\n"; break; } } @@ -156,19 +217,13 @@ TranzportControlProtocol::open () 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); } } @@ -218,14 +273,20 @@ TranzportControlProtocol::close () } int -TranzportControlProtocol::write (uint8_t* cmd) +TranzportControlProtocol::write (uint8_t* cmd, uint32_t timeout_override) { int val; - val = usb_interrupt_write (udev, WRITE_ENDPOINT, (char*) cmd, 8, timeout); + 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; } @@ -263,7 +324,15 @@ TranzportControlProtocol::lcd_write (uint8_t cell, const char* text) cmd[6] = text[3]; cmd[7] = 0x00; - return write (cmd); + 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 @@ -280,7 +349,7 @@ TranzportControlProtocol::light_on (LightID light) cmd[6] = 0x00; cmd[7] = 0x00; - return write (cmd); + return write (cmd, 500); } int @@ -297,27 +366,29 @@ TranzportControlProtocol::light_off (LightID light) cmd[6] = 0x00; cmd[7] = 0x00; - return write (cmd); + return write (cmd, 500); } int -TranzportControlProtocol::read () +TranzportControlProtocol::read (uint32_t timeout_override) { uint8_t buf[8]; int val; memset(buf, 0, 8); - val = usb_interrupt_read(udev, READ_ENDPOINT, (char*) buf, 8, timeout); + again: + val = usb_interrupt_read(udev, READ_ENDPOINT, (char*) buf, 8, timeout_override ? timeout_override : timeout); if (val < 0) { - cerr << "Tranzport read error, val = " << val << endl; return val; } if (val != 8) { - cerr << "Tranzport short read, val = " << val << endl; + 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]);*/ + /* 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; diff --git a/libs/ardour/ardour/tranzport_control_protocol.h b/libs/surfaces/tranzport/tranzport_control_protocol.h index 448d803c36..5880f3807a 100644 --- a/libs/ardour/ardour/tranzport_control_protocol.h +++ b/libs/surfaces/tranzport/tranzport_control_protocol.h @@ -69,6 +69,7 @@ class TranzportControlProtocol : public ControlProtocol { 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; @@ -78,8 +79,8 @@ class TranzportControlProtocol : public ControlProtocol { jack_nframes_t last_where; int open (); - int read (); - int write (uint8_t* cmd); + 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*); @@ -90,7 +91,11 @@ class TranzportControlProtocol : public ControlProtocol { 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 (); |