mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-07 14:15:46 +01:00
fix dragging that involves locked regions; auto-rebinding patch for people to experiment with (probably needs a little work)
git-svn-id: svn://localhost/ardour2/branches/2.0-ongoing@3164 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
aa06f1f9f8
commit
fec2a96cec
26 changed files with 397 additions and 91 deletions
|
|
@ -42,6 +42,12 @@ class RegionFactory {
|
|||
|
||||
static sigc::signal<void,boost::shared_ptr<Region> > CheckNewRegion;
|
||||
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<const Region>);
|
||||
|
||||
/* note: both of the first two should use const shared_ptr as well, but
|
||||
gcc 4.1 doesn't seem to be able to disambiguate them if they do.
|
||||
*/
|
||||
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Region>, nframes_t start,
|
||||
nframes_t length, std::string name,
|
||||
layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
|
|
@ -50,7 +56,6 @@ class RegionFactory {
|
|||
layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Source>, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (const SourceList &, nframes_t start, nframes_t length, const string& name, layer_t = 0, Region::Flag flags = Region::DefaultFlags, bool announce = true);
|
||||
static boost::shared_ptr<Region> create (boost::shared_ptr<Region>);
|
||||
static boost::shared_ptr<Region> create (Session&, XMLNode&, bool);
|
||||
static boost::shared_ptr<Region> create (SourceList &, const XMLNode&);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -249,6 +249,9 @@ class Session : public PBD::StatefulDestructible
|
|||
bool deletion_in_progress() const { return _state_of_the_state & Deletion; }
|
||||
sigc::signal<void> DirtyChanged;
|
||||
|
||||
static sigc::signal<void> AutoBindingOn;
|
||||
static sigc::signal<void> AutoBindingOff;
|
||||
|
||||
std::string sound_dir (bool with_path = true) const;
|
||||
std::string peak_dir () const;
|
||||
std::string dead_sound_dir () const;
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ sigc::signal<void,boost::shared_ptr<Region> > RegionFactory::CheckNewRegion;
|
|||
|
||||
boost::shared_ptr<Region>
|
||||
RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
|
||||
nframes_t length, std::string name,
|
||||
layer_t layer, Region::Flag flags, bool announce)
|
||||
nframes_t length, std::string name,
|
||||
layer_t layer, Region::Flag flags, bool announce)
|
||||
{
|
||||
boost::shared_ptr<const AudioRegion> other;
|
||||
|
||||
|
|
@ -57,11 +57,11 @@ RegionFactory::create (boost::shared_ptr<Region> region, nframes_t start,
|
|||
}
|
||||
|
||||
boost::shared_ptr<Region>
|
||||
RegionFactory::create (boost::shared_ptr<Region> region)
|
||||
RegionFactory::create (boost::shared_ptr<const Region> region)
|
||||
{
|
||||
boost::shared_ptr<AudioRegion> other;
|
||||
boost::shared_ptr<const AudioRegion> other;
|
||||
|
||||
if ((other = boost::dynamic_pointer_cast<AudioRegion>(region)) != 0) {
|
||||
if ((other = boost::dynamic_pointer_cast<const AudioRegion>(region)) != 0) {
|
||||
boost::shared_ptr<Region> ret (new AudioRegion (other));
|
||||
/* pure copy constructor - no CheckNewRegion emitted */
|
||||
return ret;
|
||||
|
|
@ -75,8 +75,8 @@ RegionFactory::create (boost::shared_ptr<Region> region)
|
|||
|
||||
boost::shared_ptr<Region>
|
||||
RegionFactory::create (boost::shared_ptr<AudioRegion> region, nframes_t start,
|
||||
nframes_t length, std::string name,
|
||||
layer_t layer, Region::Flag flags, bool announce)
|
||||
nframes_t length, std::string name,
|
||||
layer_t layer, Region::Flag flags, bool announce)
|
||||
{
|
||||
return create (boost::static_pointer_cast<Region> (region), start, length, name, layer, flags, announce);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ sigc::signal<void> Session::SMPTEOffsetChanged;
|
|||
sigc::signal<void> Session::StartTimeChanged;
|
||||
sigc::signal<void> Session::EndTimeChanged;
|
||||
|
||||
sigc::signal<void> Session::AutoBindingOn;
|
||||
sigc::signal<void> Session::AutoBindingOff;
|
||||
|
||||
|
||||
int
|
||||
Session::find_session (string str, string& path, string& snapshot, bool& isnew)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,6 +59,7 @@ class BarController : public Gtk::Frame
|
|||
/* export this to allow direct connection to button events */
|
||||
|
||||
Gtk::Widget& event_widget() { return darea; }
|
||||
PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); }
|
||||
|
||||
protected:
|
||||
Gtk::Adjustment& adjustment;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ class BindableToggleButton : public Gtkmm2ext::StatefulToggleButton
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); }
|
||||
private:
|
||||
BindingProxy binding_proxy;
|
||||
};
|
||||
|
|
@ -71,6 +72,8 @@ class BindableButton : public Gtkmm2ext::StatefulButton
|
|||
}
|
||||
}
|
||||
|
||||
PBD::Controllable* get_controllable() { return binding_proxy.get_controllable(); }
|
||||
|
||||
private:
|
||||
BindingProxy binding_proxy;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ class BindingProxy : public sigc::trackable
|
|||
|
||||
bool button_press_handler (GdkEventButton *);
|
||||
|
||||
PBD::Controllable* get_controllable() { return &controllable; }
|
||||
protected:
|
||||
|
||||
Gtkmm2ext::PopUp* prompter;
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ using namespace PBD;
|
|||
sigc::signal<void,Controllable*> Controllable::Destroyed;
|
||||
sigc::signal<bool,Controllable*> Controllable::StartLearning;
|
||||
sigc::signal<void,Controllable*> Controllable::StopLearning;
|
||||
sigc::signal<void,Controllable*,int,int> Controllable::CreateBinding;
|
||||
sigc::signal<void,Controllable*> Controllable::DeleteBinding;
|
||||
|
||||
Glib::Mutex* Controllable::registry_lock = 0;
|
||||
Controllable::Controllables Controllable::registry;
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ class Controllable : public PBD::StatefulDestructible {
|
|||
virtual bool can_send_feedback() const { return true; }
|
||||
|
||||
sigc::signal<void> LearningFinished;
|
||||
static sigc::signal<void,PBD::Controllable*,int,int> CreateBinding;
|
||||
static sigc::signal<void,PBD::Controllable*> DeleteBinding;
|
||||
|
||||
static sigc::signal<bool,PBD::Controllable*> StartLearning;
|
||||
static sigc::signal<void,PBD::Controllable*> StopLearning;
|
||||
|
|
|
|||
|
|
@ -56,9 +56,17 @@ GenericMidiControlProtocol::GenericMidiControlProtocol (Session& s)
|
|||
_feedback_interval = 10000; // microseconds
|
||||
last_feedback_time = 0;
|
||||
|
||||
auto_binding = FALSE;
|
||||
|
||||
Controllable::StartLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::start_learning));
|
||||
Controllable::StopLearning.connect (mem_fun (*this, &GenericMidiControlProtocol::stop_learning));
|
||||
Session::SendFeedback.connect (mem_fun (*this, &GenericMidiControlProtocol::send_feedback));
|
||||
|
||||
Controllable::CreateBinding.connect (mem_fun (*this, &GenericMidiControlProtocol::create_binding));
|
||||
Controllable::DeleteBinding.connect (mem_fun (*this, &GenericMidiControlProtocol::delete_binding));
|
||||
|
||||
Session::AutoBindingOn.connect (mem_fun (*this, &GenericMidiControlProtocol::auto_binding_on));
|
||||
Session::AutoBindingOff.connect (mem_fun (*this, &GenericMidiControlProtocol::auto_binding_off));
|
||||
}
|
||||
|
||||
GenericMidiControlProtocol::~GenericMidiControlProtocol ()
|
||||
|
|
@ -225,6 +233,71 @@ GenericMidiControlProtocol::stop_learning (Controllable* c)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
GenericMidiControlProtocol::delete_binding ( PBD::Controllable* control )
|
||||
{
|
||||
if( control != 0 ) {
|
||||
Glib::Mutex::Lock lm2 (controllables_lock);
|
||||
|
||||
for( MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
|
||||
MIDIControllable* existingBinding = (*iter);
|
||||
|
||||
if( control == &(existingBinding->get_controllable()) ) {
|
||||
delete existingBinding;
|
||||
controllables.erase (iter);
|
||||
}
|
||||
|
||||
} // end for midi controllables
|
||||
} // end null check
|
||||
}
|
||||
void
|
||||
GenericMidiControlProtocol::create_binding (PBD::Controllable* control, int pos, int control_number)
|
||||
{
|
||||
if( control != NULL ) {
|
||||
Glib::Mutex::Lock lm2 (controllables_lock);
|
||||
|
||||
MIDI::channel_t channel = (pos & 0xf);
|
||||
MIDI::byte value = control_number;
|
||||
|
||||
// Create a MIDIControllable::
|
||||
MIDIControllable* mc = new MIDIControllable (*_port, *control);
|
||||
|
||||
// Remove any old binding for this midi channel/type/value pair
|
||||
// Note: can't use delete_binding() here because we don't know the specific controllable we want to remove, only the midi information
|
||||
for( MIDIControllables::iterator iter = controllables.begin(); iter != controllables.end(); ++iter) {
|
||||
MIDIControllable* existingBinding = (*iter);
|
||||
|
||||
if( (existingBinding->get_control_channel() & 0xf ) == channel &&
|
||||
existingBinding->get_control_additional() == value &&
|
||||
(existingBinding->get_control_type() & 0xf0 ) == MIDI::controller ) {
|
||||
|
||||
delete existingBinding;
|
||||
controllables.erase (iter);
|
||||
}
|
||||
|
||||
} // end for midi controllables
|
||||
|
||||
|
||||
// Update the MIDI Controllable based on the the pos param
|
||||
// Here is where a table lookup for user mappings could go; for now we'll just wing it...
|
||||
mc->bind_midi( channel, MIDI::controller, value );
|
||||
|
||||
controllables.insert (mc);
|
||||
} // end null test
|
||||
}
|
||||
|
||||
void
|
||||
GenericMidiControlProtocol::auto_binding_on()
|
||||
{
|
||||
auto_binding = TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
GenericMidiControlProtocol::auto_binding_off()
|
||||
{
|
||||
auto_binding = FALSE;
|
||||
}
|
||||
|
||||
XMLNode&
|
||||
GenericMidiControlProtocol::get_state ()
|
||||
{
|
||||
|
|
@ -269,46 +342,47 @@ GenericMidiControlProtocol::set_state (const XMLNode& node)
|
|||
_feedback_interval = 10000;
|
||||
}
|
||||
|
||||
Controllable* c;
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lm (pending_lock);
|
||||
pending_controllables.clear ();
|
||||
}
|
||||
|
||||
Glib::Mutex::Lock lm2 (controllables_lock);
|
||||
|
||||
controllables.clear ();
|
||||
|
||||
nlist = node.children(); // "controls"
|
||||
|
||||
if (nlist.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlist = nlist.front()->children ();
|
||||
|
||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||
|
||||
if ((prop = (*niter)->property ("id")) != 0) {
|
||||
// Are we using the autobinding feature? If so skip this part
|
||||
if ( !auto_binding ) {
|
||||
|
||||
Controllable* c;
|
||||
|
||||
{
|
||||
Glib::Mutex::Lock lm (pending_lock);
|
||||
pending_controllables.clear ();
|
||||
}
|
||||
|
||||
Glib::Mutex::Lock lm2 (controllables_lock);
|
||||
controllables.clear ();
|
||||
nlist = node.children(); // "controls"
|
||||
|
||||
if (nlist.empty()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
nlist = nlist.front()->children ();
|
||||
|
||||
for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
|
||||
|
||||
ID id = prop->value ();
|
||||
|
||||
c = Controllable::by_id (id);
|
||||
|
||||
if (c) {
|
||||
MIDIControllable* mc = new MIDIControllable (*_port, *c);
|
||||
if (mc->set_state (**niter) == 0) {
|
||||
controllables.insert (mc);
|
||||
}
|
||||
if ((prop = (*niter)->property ("id")) != 0) {
|
||||
|
||||
ID id = prop->value ();
|
||||
c = session->controllable_by_id (id);
|
||||
|
||||
} else {
|
||||
warning << string_compose (_("Generic MIDI control: controllable %1 not found (ignored)"), id)
|
||||
<< endmsg;
|
||||
if (c) {
|
||||
MIDIControllable* mc = new MIDIControllable (*_port, *c);
|
||||
if (mc->set_state (**niter) == 0) {
|
||||
controllables.insert (mc);
|
||||
}
|
||||
|
||||
} else {
|
||||
warning << string_compose (_("Generic MIDI control: controllable %1 not found in session (ignored)"),
|
||||
id)
|
||||
<< endmsg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // end autobinding check
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
|||
ARDOUR::microseconds_t last_feedback_time;
|
||||
|
||||
bool do_feedback;
|
||||
bool auto_binding;
|
||||
void _send_feedback ();
|
||||
void send_feedback ();
|
||||
|
||||
|
|
@ -59,6 +60,13 @@ class GenericMidiControlProtocol : public ARDOUR::ControlProtocol {
|
|||
void stop_learning (PBD::Controllable*);
|
||||
|
||||
void learning_stopped (MIDIControllable*);
|
||||
|
||||
void create_binding (PBD::Controllable*, int, int);
|
||||
void delete_binding (PBD::Controllable*);
|
||||
|
||||
void auto_binding_on();
|
||||
void auto_binding_off();
|
||||
|
||||
};
|
||||
|
||||
#endif /* ardour_generic_midi_control_protocol_h */
|
||||
|
|
|
|||
|
|
@ -63,6 +63,10 @@ class MIDIControllable : public Stateful
|
|||
XMLNode& get_state (void);
|
||||
int set_state (const XMLNode&);
|
||||
|
||||
void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte);
|
||||
MIDI::channel_t get_control_channel () { return control_channel; }
|
||||
MIDI::eventType get_control_type () { return control_type; }
|
||||
MIDI::byte get_control_additional () { return control_additional; }
|
||||
private:
|
||||
PBD::Controllable& controllable;
|
||||
MIDI::Port& _port;
|
||||
|
|
@ -86,8 +90,6 @@ class MIDIControllable : public Stateful
|
|||
void midi_sense_controller (MIDI::Parser &, MIDI::EventTwoBytes *);
|
||||
void midi_sense_program_change (MIDI::Parser &, MIDI::byte);
|
||||
void midi_sense_pitchbend (MIDI::Parser &, MIDI::pitchbend_t);
|
||||
|
||||
void bind_midi (MIDI::channel_t, MIDI::eventType, MIDI::byte);
|
||||
};
|
||||
|
||||
#endif // __gm_midicontrollable_h__
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue