mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-08 15:54:57 +01:00
modification to make generic MIDI actually work again
git-svn-id: svn://localhost/ardour2/trunk@673 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
05f8fcd189
commit
26843b34fd
14 changed files with 142 additions and 24 deletions
|
|
@ -23,6 +23,7 @@ struct ControlProtocolInfo {
|
|||
std::string path;
|
||||
bool requested;
|
||||
bool mandatory;
|
||||
XMLNode* state;
|
||||
};
|
||||
|
||||
class ControlProtocolManager : public sigc::trackable, public Stateful
|
||||
|
|
|
|||
|
|
@ -49,6 +49,10 @@ ControlProtocolManager::set_session (Session& s)
|
|||
if ((*i)->requested || (*i)->mandatory) {
|
||||
instantiate (**i);
|
||||
(*i)->requested = false;
|
||||
|
||||
if ((*i)->state) {
|
||||
(*i)->protocol->set_state (*(*i)->state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -181,6 +185,7 @@ ControlProtocolManager::control_protocol_discover (string path)
|
|||
cpi->protocol = 0;
|
||||
cpi->requested = false;
|
||||
cpi->mandatory = descriptor->mandatory;
|
||||
cpi->state = 0;
|
||||
|
||||
control_protocol_info.push_back (cpi);
|
||||
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
|
|||
if (Controllable::StartLearning (&controllable)) {
|
||||
string prompt = _("operate controller now");
|
||||
prompter.set_text (prompt);
|
||||
prompter.show_all ();
|
||||
prompter.touch (); // shows popup
|
||||
learning_connection = controllable.LearningFinished.connect (mem_fun (*this, &BindingProxy::learning_finished));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
@ -70,9 +71,18 @@ BindingProxy::button_press_handler (GdkEventButton *ev)
|
|||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
BindingProxy::learning_finished ()
|
||||
{
|
||||
learning_connection.disconnect ();
|
||||
prompter.touch (); // hides popup
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
BindingProxy::prompter_hiding (GdkEventAny *ev)
|
||||
{
|
||||
learning_connection.disconnect ();
|
||||
Controllable::StopLearning (&controllable);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ class BindingProxy : public sigc::trackable
|
|||
PBD::Controllable& controllable;
|
||||
guint bind_button;
|
||||
guint bind_statemask;
|
||||
|
||||
sigc::connection learning_connection;
|
||||
void learning_finished ();
|
||||
bool prompter_hiding (GdkEventAny *);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -73,11 +73,12 @@ PopUp::remove ()
|
|||
{
|
||||
hide ();
|
||||
|
||||
if (delete_on_hide) {
|
||||
std::cerr << "deleting prompter\n";
|
||||
if (popdown_time != 0 && timeout != -1) {
|
||||
gtk_timeout_remove (timeout);
|
||||
}
|
||||
|
||||
if (delete_on_hide) {
|
||||
std::cerr << "deleting prompter\n";
|
||||
gtk_idle_add (idle_delete, this);
|
||||
}
|
||||
}
|
||||
|
|
@ -125,11 +126,12 @@ PopUp::on_delete_event (GdkEventAny* ev)
|
|||
{
|
||||
hide();
|
||||
|
||||
if (delete_on_hide) {
|
||||
std::cerr << "deleting prompter\n" << endl;
|
||||
if (popdown_time != 0 && timeout != -1) {
|
||||
gtk_timeout_remove (timeout);
|
||||
}
|
||||
|
||||
if (delete_on_hide) {
|
||||
std::cerr << "deleting prompter\n" << endl;
|
||||
gtk_idle_add (idle_delete, this);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -21,6 +21,8 @@ class Controllable : public virtual sigc::trackable, public Stateful {
|
|||
|
||||
virtual bool can_send_feedback() const { return true; }
|
||||
|
||||
sigc::signal<void> LearningFinished;
|
||||
|
||||
static sigc::signal<void,Controllable*> Created;
|
||||
static sigc::signal<void,Controllable*> GoingAway;
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include <vector>
|
||||
#include <list>
|
||||
#include <sigc++/sigc++.h>
|
||||
|
||||
#include <pbd/stateful.h>
|
||||
#include <control_protocol/basic_ui.h>
|
||||
|
||||
namespace ARDOUR {
|
||||
|
|
@ -34,7 +34,7 @@ namespace ARDOUR {
|
|||
class Route;
|
||||
class Session;
|
||||
|
||||
class ControlProtocol : public sigc::trackable, public BasicUI {
|
||||
class ControlProtocol : public sigc::trackable, public Stateful, public BasicUI {
|
||||
public:
|
||||
ControlProtocol (Session&, std::string name);
|
||||
virtual ~ControlProtocol();
|
||||
|
|
|
|||
|
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include <algorithm>
|
||||
|
||||
#include <pbd/error.h>
|
||||
#include <pbd/failed_constructor.h>
|
||||
|
||||
#include <midi++/port.h>
|
||||
#include <midi++/manager.h>
|
||||
#include <midi++/port_request.h>
|
||||
|
|
@ -39,9 +42,17 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
|
|||
: ControlProtocol (s, _("GenericMIDI"))
|
||||
{
|
||||
MIDI::Manager* mm = MIDI::Manager::instance();
|
||||
MIDI::PortRequest pr ("ardour:MIDI control", "ardour:MIDI control", "duplex", "alsa/seq");
|
||||
|
||||
_port = mm->add_port (pr);
|
||||
/* XXX it might be nice to run "control" through i18n, but thats a bit tricky because
|
||||
the name is defined in ardour.rc which is likely not internationalized.
|
||||
*/
|
||||
|
||||
_port = mm->port (X_("control"));
|
||||
|
||||
if (_port == 0) {
|
||||
error << _("no MIDI port named \"control\" exists - generic MIDI control disabled") << endmsg;
|
||||
throw failed_constructor();
|
||||
}
|
||||
|
||||
_feedback_interval = 10000; // microseconds
|
||||
last_feedback_time = 0;
|
||||
|
|
@ -112,11 +123,13 @@ GenericMidiControlProtocol::start_learning (Controllable* c)
|
|||
|
||||
MIDIControllable* mc = new MIDIControllable (*_port, *c);
|
||||
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lm (pending_lock);
|
||||
pending_controllables.push_back (mc);
|
||||
mc->learning_stopped.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
|
||||
std::pair<MIDIControllables::iterator,bool> result;
|
||||
result = pending_controllables.insert (mc);
|
||||
if (result.second) {
|
||||
c->LearningFinished.connect (bind (mem_fun (*this, &GenericMidiControlProtocol::learning_stopped), mc));
|
||||
}
|
||||
}
|
||||
|
||||
mc->learn_about_external_control ();
|
||||
|
|
@ -135,7 +148,7 @@ GenericMidiControlProtocol::learning_stopped (MIDIControllable* mc)
|
|||
pending_controllables.erase (i);
|
||||
}
|
||||
|
||||
controllables.push_back (mc);
|
||||
controllables.insert (mc);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -156,3 +169,65 @@ GenericMidiControlProtocol::stop_learning (Controllable* c)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
GenericMidiControlProtocol::get_state ()
|
||||
{
|
||||
XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
|
||||
XMLNode* children = new XMLNode (X_("controls"));
|
||||
|
||||
node->add_child_nocopy (*children);
|
||||
|
||||
Glib::Mutex::Lock lm2 (controllables_lock);
|
||||
for (MIDIControllables::iterator i = controllables.begin(); i != controllables.end(); ++i) {
|
||||
children->add_child_nocopy ((*i)->get_state());
|
||||
}
|
||||
|
||||
return *node;
|
||||
}
|
||||
|
||||
int
|
||||
GenericMidiControlProtocol::set_state (const XMLNode& node)
|
||||
{
|
||||
XMLNodeList nlist;
|
||||
XMLNodeConstIterator niter;
|
||||
Controllable* c;
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lm (pending_lock);
|
||||
pending_controllables.clear ();
|
||||
}
|
||||
|
||||
Glib::Mutex::Lock lm2 (controllables_lock);
|
||||
|
||||
controllables.clear ();
|
||||
|
||||
nlist = node.children();
|
||||
|
||||
if (nlist.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlist = nlist.front()->children ();
|
||||
|
||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||
|
||||
XMLProperty* prop;
|
||||
|
||||
if ((prop = (*niter)->property ("id")) != 0) {
|
||||
|
||||
ID id = prop->value ();
|
||||
|
||||
c = session->controllable_by_id (id);
|
||||
|
||||
if (c) {
|
||||
MIDIControllable* mc = new MIDIControllable (*_port, *c);
|
||||
if (mc->set_state (**niter) == 0) {
|
||||
controllables.insert (mc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#ifndef ardour_generic_midi_control_protocol_h
|
||||
#define ardour_generic_midi_control_protocol_h
|
||||
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <glibmm/thread.h>
|
||||
#include <ardour/types.h>
|
||||
|
||||
|
|
@ -32,6 +32,9 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
|||
MIDI::Port* port () const { return _port; }
|
||||
void set_feedback_interval (ARDOUR::microseconds_t);
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&);
|
||||
|
||||
private:
|
||||
MIDI::Port* _port;
|
||||
ARDOUR::microseconds_t _feedback_interval;
|
||||
|
|
@ -40,7 +43,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
|||
void _send_feedback ();
|
||||
void send_feedback ();
|
||||
|
||||
typedef std::vector<MIDIControllable*> MIDIControllables;
|
||||
typedef std::set<MIDIControllable*> MIDIControllables;
|
||||
MIDIControllables controllables;
|
||||
MIDIControllables pending_controllables;
|
||||
Glib::Mutex controllables_lock;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <pbd/failed_constructor.h>
|
||||
|
||||
#include <control_protocol/control_protocol.h>
|
||||
#include "generic_midi_control_protocol.h"
|
||||
|
||||
|
|
@ -6,7 +8,13 @@ using namespace ARDOUR;
|
|||
ControlProtocol*
|
||||
new_generic_midi_protocol (ControlProtocolDescriptor* descriptor, Session* s)
|
||||
{
|
||||
GenericMidiControlProtocol* gmcp = new GenericMidiControlProtocol (*s);
|
||||
GenericMidiControlProtocol* gmcp;
|
||||
|
||||
try {
|
||||
gmcp = new GenericMidiControlProtocol (*s);
|
||||
} catch (failed_constructor& err) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gmcp->set_active (true)) {
|
||||
delete gmcp;
|
||||
|
|
|
|||
|
|
@ -90,7 +90,6 @@ MIDIControllable::learn_about_external_control ()
|
|||
{
|
||||
drop_external_control ();
|
||||
midi_learn_connection = _port.input()->any.connect (mem_fun (*this, &MIDIControllable::midi_receiver));
|
||||
learning_started ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -199,7 +198,7 @@ MIDIControllable::midi_receiver (Parser &p, byte *msg, size_t len)
|
|||
|
||||
bind_midi ((channel_t) (msg[0] & 0xf), eventType (msg[0] & 0xF0), msg[1]);
|
||||
|
||||
learning_stopped ();
|
||||
controllable.LearningFinished ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
|||
|
|
@ -53,9 +53,6 @@ class MIDIControllable : public Stateful
|
|||
void stop_learning ();
|
||||
void drop_external_control ();
|
||||
|
||||
sigc::signal<void> learning_started;
|
||||
sigc::signal<void> learning_stopped;
|
||||
|
||||
bool get_midi_feedback () { return feedback; }
|
||||
void set_midi_feedback (bool val) { feedback = val; }
|
||||
|
||||
|
|
|
|||
|
|
@ -1574,3 +1574,15 @@ TranzportControlProtocol::print (int row, int col, const char *text)
|
|||
}
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
TranzportControlProtocol::get_state ()
|
||||
{
|
||||
XMLNode* node = new XMLNode (_name); /* node name must match protocol name */
|
||||
return *node;
|
||||
}
|
||||
|
||||
int
|
||||
TranzportControlProtocol::set_state (const XMLNode& node)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ class TranzportControlProtocol : public ARDOUR::ControlProtocol
|
|||
|
||||
static bool probe ();
|
||||
|
||||
XMLNode& get_state ();
|
||||
int set_state (const XMLNode&);
|
||||
|
||||
private:
|
||||
static const int VENDORID = 0x165b;
|
||||
static const int PRODUCTID = 0x8101;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue