Add support for Region Fx Automation
This commit is contained in:
parent
99c9135428
commit
1a3724db47
|
@ -36,6 +36,7 @@
|
|||
#include "ardour/audioregion.h"
|
||||
#include "ardour/audiosource.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/region_fx_plugin.h"
|
||||
#include "ardour/session.h"
|
||||
|
||||
#include "pbd/memento_command.h"
|
||||
|
@ -112,8 +113,7 @@ static Cairo::RefPtr<Cairo::Pattern> create_pending_peak_pattern() {
|
|||
return p;
|
||||
}
|
||||
|
||||
AudioRegionView::AudioRegionView (ArdourCanvas::Container *parent, RouteTimeAxisView &tv, std::shared_ptr<AudioRegion> r, double spu,
|
||||
uint32_t basic_color)
|
||||
AudioRegionView::AudioRegionView (ArdourCanvas::Container *parent, RouteTimeAxisView &tv, std::shared_ptr<AudioRegion> r, double spu, uint32_t basic_color)
|
||||
: RegionView (parent, tv, r, spu, basic_color)
|
||||
, fade_in_handle(0)
|
||||
, fade_out_handle(0)
|
||||
|
@ -129,6 +129,9 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Container *parent, RouteTimeAxis
|
|||
, _amplitude_above_axis(1.0)
|
||||
, trim_fade_in_drag_active(false)
|
||||
, trim_fade_out_drag_active(false)
|
||||
, _rfx_id (0)
|
||||
, _rdx_param (UINT32_MAX)
|
||||
, _ignore_line_change (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -149,6 +152,9 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Container *parent, RouteTimeAxis
|
|||
, _amplitude_above_axis(1.0)
|
||||
, trim_fade_in_drag_active(false)
|
||||
, trim_fade_out_drag_active(false)
|
||||
, _rfx_id (0)
|
||||
, _rdx_param (UINT32_MAX)
|
||||
, _ignore_line_change (false)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -168,6 +174,9 @@ AudioRegionView::AudioRegionView (const AudioRegionView& other, std::shared_ptr<
|
|||
, _amplitude_above_axis (other._amplitude_above_axis)
|
||||
, trim_fade_in_drag_active(false)
|
||||
, trim_fade_out_drag_active(false)
|
||||
, _rfx_id (0)
|
||||
, _rdx_param (UINT32_MAX)
|
||||
, _ignore_line_change (false)
|
||||
{
|
||||
init (true);
|
||||
}
|
||||
|
@ -232,12 +241,7 @@ AudioRegionView::init (bool wfd)
|
|||
set_fade_visibility (false);
|
||||
}
|
||||
|
||||
const string line_name = _region->name() + ":gain";
|
||||
|
||||
gain_line.reset (new AudioRegionGainLine (line_name, *this, *group, audio_region()->envelope()));
|
||||
|
||||
update_envelope_visibility ();
|
||||
gain_line->reset ();
|
||||
set_region_gain_line ();
|
||||
|
||||
/* streamview will call set_height() */
|
||||
//set_height (trackview.current_height()); // XXX not correct for Layered mode, but set_height() will fix later.
|
||||
|
@ -278,7 +282,7 @@ AudioRegionView::init (bool wfd)
|
|||
setup_waveform_visibility ();
|
||||
|
||||
get_canvas_frame()->set_data ("linemerger", (LineMerger*) this);
|
||||
gain_line->canvas_group().raise_to_top ();
|
||||
_fx_line->canvas_group().raise_to_top ();
|
||||
|
||||
/* XXX sync mark drag? */
|
||||
}
|
||||
|
@ -606,15 +610,15 @@ AudioRegionView::set_height (gdouble height)
|
|||
}
|
||||
}
|
||||
|
||||
if (gain_line) {
|
||||
if (_fx_line) {
|
||||
|
||||
if ((height / nchans) < NAME_HIGHLIGHT_THRESH) {
|
||||
gain_line->hide ();
|
||||
_fx_line->hide ();
|
||||
} else {
|
||||
update_envelope_visibility ();
|
||||
}
|
||||
|
||||
gain_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE) - 2);
|
||||
_fx_line->set_height ((uint32_t) rint (height - NAME_HIGHLIGHT_SIZE) - 2);
|
||||
}
|
||||
|
||||
reset_fade_shapes ();
|
||||
|
@ -1081,8 +1085,8 @@ AudioRegionView::set_samples_per_pixel (gdouble fpp)
|
|||
}
|
||||
}
|
||||
|
||||
if (gain_line) {
|
||||
gain_line->reset ();
|
||||
if (_fx_line) {
|
||||
_fx_line->reset ();
|
||||
}
|
||||
|
||||
reset_fade_shapes ();
|
||||
|
@ -1101,8 +1105,8 @@ AudioRegionView::set_colors ()
|
|||
{
|
||||
RegionView::set_colors();
|
||||
|
||||
if (gain_line) {
|
||||
gain_line->set_line_color (audio_region()->envelope_active() ?
|
||||
if (_fx_line) {
|
||||
_fx_line->set_line_color (audio_region()->envelope_active() ?
|
||||
UIConfiguration::instance().color ("gain line") :
|
||||
UIConfiguration::instance().color_mod ("gain line inactive", "gain line inactive"));
|
||||
}
|
||||
|
@ -1148,8 +1152,8 @@ AudioRegionView::setup_waveform_visibility ()
|
|||
void
|
||||
AudioRegionView::temporarily_hide_envelope ()
|
||||
{
|
||||
if (gain_line) {
|
||||
gain_line->hide ();
|
||||
if (_fx_line) {
|
||||
_fx_line->hide ();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1160,20 +1164,70 @@ AudioRegionView::unhide_envelope ()
|
|||
}
|
||||
|
||||
void
|
||||
AudioRegionView::update_envelope_visibility ()
|
||||
AudioRegionView::set_region_gain_line ()
|
||||
{
|
||||
if (!gain_line) {
|
||||
if (_ignore_line_change) {
|
||||
return;
|
||||
}
|
||||
const string line_name = _region->name() + ":gain";
|
||||
_fx_line.reset (new AudioRegionGainLine (line_name, *this, *group, audio_region()->envelope()));
|
||||
_fx_line->set_height ((uint32_t) rint (height() - NAME_HIGHLIGHT_SIZE) - 2);
|
||||
envelope_active_changed ();
|
||||
update_envelope_visibility ();
|
||||
_fx_line->reset ();
|
||||
_region_fx_connection.disconnect ();
|
||||
_rfx_id = PBD::ID (0);
|
||||
_rdx_param = UINT32_MAX;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioRegionView::set_region_fx_line (uint32_t plugin_id, uint32_t param_id)
|
||||
{
|
||||
if (_ignore_line_change) {
|
||||
return false;
|
||||
}
|
||||
std::shared_ptr<RegionFxPlugin> rfx = _region->nth_plugin (plugin_id);
|
||||
if (rfx) {
|
||||
std::shared_ptr<Evoral::Control> c = rfx->control (Evoral::Parameter (PluginAutomation, 0, param_id));
|
||||
std::shared_ptr<AutomationControl> ac = std::dynamic_pointer_cast<AutomationControl> (c);
|
||||
if (ac) {
|
||||
ac->set_automation_state (Play);
|
||||
_fx_line.reset (new RegionFxLine ("REGION FX", *this, *group, ac->alist()));
|
||||
_fx_line->set_height ((uint32_t) rint (height() - NAME_HIGHLIGHT_SIZE) - 2);
|
||||
envelope_active_changed ();
|
||||
update_envelope_visibility ();
|
||||
_fx_line->reset ();
|
||||
|
||||
rfx->DropReferences.connect (_region_fx_connection, invalidator (*this), boost::bind (&AudioRegionView::set_region_gain_line, this), gui_context ());
|
||||
_rfx_id = rfx->id ();
|
||||
_rdx_param = param_id;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
AudioRegionView::get_region_fx_line (PBD::ID& id, uint32_t& param_id)
|
||||
{
|
||||
id = _rfx_id;
|
||||
param_id = _rdx_param;
|
||||
return _rdx_param != UINT32_MAX && _rfx_id != 0;
|
||||
}
|
||||
|
||||
void
|
||||
AudioRegionView::update_envelope_visibility ()
|
||||
{
|
||||
assert (_fx_line);
|
||||
|
||||
if (trackview.editor().current_mouse_mode() == Editing::MouseDraw || trackview.editor().current_mouse_mode() == Editing::MouseContent ) {
|
||||
gain_line->set_visibility (AutomationLine::VisibleAspects(AutomationLine::ControlPoints|AutomationLine::Line));
|
||||
gain_line->canvas_group().raise_to_top ();
|
||||
_fx_line->set_visibility (AutomationLine::VisibleAspects(AutomationLine::ControlPoints|AutomationLine::Line));
|
||||
_fx_line->canvas_group().raise_to_top ();
|
||||
} else if (UIConfiguration::instance().get_show_region_gain() || trackview.editor().current_mouse_mode() == Editing::MouseRange ) {
|
||||
gain_line->set_visibility (AutomationLine::VisibleAspects(AutomationLine::Line));
|
||||
gain_line->canvas_group().raise_to_top ();
|
||||
_fx_line->set_visibility (AutomationLine::VisibleAspects(AutomationLine::Line));
|
||||
_fx_line->canvas_group().raise_to_top ();
|
||||
} else {
|
||||
gain_line->set_visibility (AutomationLine::VisibleAspects(0));
|
||||
_fx_line->set_visibility (AutomationLine::VisibleAspects(0));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1374,7 +1428,7 @@ AudioRegionView::peaks_ready_handler (uint32_t which)
|
|||
void
|
||||
AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, bool with_guard_points)
|
||||
{
|
||||
if (!gain_line) {
|
||||
if (!_fx_line) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1386,18 +1440,17 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b
|
|||
|
||||
samplecnt_t const sample_within_region = (samplecnt_t) floor (mx * samples_per_pixel);
|
||||
|
||||
if (!gain_line->control_points_adjacent (sample_within_region, before_p, after_p)) {
|
||||
/* no adjacent points */
|
||||
return;
|
||||
double y = my;
|
||||
|
||||
if (_fx_line->control_points_adjacent (sample_within_region, before_p, after_p)) {
|
||||
/* y is in item frame */
|
||||
double const bx = _fx_line->nth (before_p)->get_x();
|
||||
double const ax = _fx_line->nth (after_p)->get_x();
|
||||
double const click_ratio = (ax - mx) / (ax - bx);
|
||||
|
||||
y = ((_fx_line->nth (before_p)->get_y() * click_ratio) + (_fx_line->nth (after_p)->get_y() * (1 - click_ratio)));
|
||||
}
|
||||
|
||||
/* y is in item frame */
|
||||
double const bx = gain_line->nth (before_p)->get_x();
|
||||
double const ax = gain_line->nth (after_p)->get_x();
|
||||
double const click_ratio = (ax - mx) / (ax - bx);
|
||||
|
||||
double y = ((gain_line->nth (before_p)->get_y() * click_ratio) + (gain_line->nth (after_p)->get_y() * (1 - click_ratio)));
|
||||
|
||||
/* don't create points that can't be seen */
|
||||
|
||||
update_envelope_visibility ();
|
||||
|
@ -1412,28 +1465,28 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b
|
|||
|
||||
/* compute vertical fractional position */
|
||||
|
||||
y = 1.0 - (y / (gain_line->height()));
|
||||
y = 1.0 - (y / (_fx_line->height()));
|
||||
|
||||
/* map using gain line */
|
||||
|
||||
gain_line->view_to_model_coord_y (y);
|
||||
_fx_line->view_to_model_coord_y (y);
|
||||
|
||||
/* XXX STATEFUL: can't convert to stateful diff until we
|
||||
can represent automation data with it.
|
||||
*/
|
||||
|
||||
XMLNode &before = audio_region()->envelope()->get_state();
|
||||
XMLNode &before = _fx_line->the_list()->get_state();
|
||||
MementoCommand<AudioRegion>* region_memento = 0;
|
||||
|
||||
if (!audio_region()->envelope_active()) {
|
||||
if (!audio_region()->envelope_active() && _fx_line->the_list() == audio_region()->envelope()) {
|
||||
XMLNode ®ion_before = audio_region()->get_state();
|
||||
audio_region()->set_envelope_active(true);
|
||||
XMLNode ®ion_after = audio_region()->get_state();
|
||||
region_memento = new MementoCommand<AudioRegion>(*(audio_region().get()), ®ion_before, ®ion_after);
|
||||
}
|
||||
|
||||
if (audio_region()->envelope()->editor_add (timepos_t (fx), y, with_guard_points)) {
|
||||
XMLNode &after = audio_region()->envelope()->get_state();
|
||||
if (_fx_line->the_list()->editor_add (timepos_t (fx), y, with_guard_points)) {
|
||||
XMLNode &after = _fx_line->the_list()->get_state();
|
||||
std::list<Selectable*> results;
|
||||
|
||||
trackview.editor().begin_reversible_command (_("add gain control point"));
|
||||
|
@ -1442,9 +1495,9 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b
|
|||
trackview.session()->add_command (region_memento);
|
||||
}
|
||||
|
||||
trackview.session()->add_command (new MementoCommand<AutomationList>(*audio_region()->envelope().get(), &before, &after));
|
||||
trackview.session()->add_command (new MementoCommand<AutomationList>(*_fx_line->the_list(), &before, &after));
|
||||
|
||||
gain_line->get_selectables (region ()->position () + timecnt_t (fx), region ()->position () + timecnt_t (fx), 0.0, 1.0, results);
|
||||
_fx_line->get_selectables (region ()->position () + timecnt_t (fx), region ()->position () + timecnt_t (fx), 0.0, 1.0, results);
|
||||
trackview.editor ().get_selection ().set (results);
|
||||
|
||||
trackview.editor ().commit_reversible_command ();
|
||||
|
@ -1454,12 +1507,14 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev, b
|
|||
}
|
||||
}
|
||||
|
||||
#if 0 // unused
|
||||
void
|
||||
AudioRegionView::remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent* /*ev*/)
|
||||
{
|
||||
ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point"));
|
||||
audio_region()->envelope()->erase (cp->model());
|
||||
_fx_line->the_list()->erase (cp->model());
|
||||
}
|
||||
#endif
|
||||
|
||||
GhostRegion*
|
||||
AudioRegionView::add_ghost (TimeAxisView& tv)
|
||||
|
@ -1557,10 +1612,6 @@ AudioRegionView::exited ()
|
|||
trackview.editor().set_current_trimmable (std::shared_ptr<Trimmable>());
|
||||
trackview.editor().set_current_movable (std::shared_ptr<Movable>());
|
||||
|
||||
// if (gain_line) {
|
||||
// gain_line->remove_visibility (AutomationLine::ControlPoints);
|
||||
// }
|
||||
|
||||
if (fade_in_handle) { fade_in_handle->hide(); }
|
||||
if (fade_out_handle) { fade_out_handle->hide(); }
|
||||
if (fade_in_trim_handle) { fade_in_trim_handle->hide(); }
|
||||
|
@ -1572,12 +1623,15 @@ AudioRegionView::exited ()
|
|||
void
|
||||
AudioRegionView::envelope_active_changed ()
|
||||
{
|
||||
if (gain_line) {
|
||||
gain_line->set_line_color (audio_region()->envelope_active() ?
|
||||
UIConfiguration::instance().color ("gain line") :
|
||||
UIConfiguration::instance().color_mod ("gain line inactive", "gain line inactive"));
|
||||
update_envelope_visibility ();
|
||||
assert (_fx_line);
|
||||
if (_rdx_param != UINT32_MAX && _rfx_id != 0) {
|
||||
_fx_line->set_line_color (UIConfiguration::instance().color ("processor automation line")); // XXX
|
||||
} else {
|
||||
_fx_line->set_line_color (audio_region()->envelope_active()
|
||||
? UIConfiguration::instance().color ("gain line")
|
||||
: UIConfiguration::instance().color_mod ("gain line inactive", "gain line inactive"));
|
||||
}
|
||||
update_envelope_visibility ();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1858,7 +1912,7 @@ AudioRegionView::parameter_changed (string const & p)
|
|||
MergeableLine*
|
||||
AudioRegionView::make_merger ()
|
||||
{
|
||||
return new MergeableLine (gain_line, std::shared_ptr<AutomationControl>(),
|
||||
return new MergeableLine (_fx_line, std::shared_ptr<AutomationControl>(),
|
||||
[this](timepos_t const& t) { return timepos_t (_region->position().distance (t)); },
|
||||
nullptr, nullptr);
|
||||
}
|
||||
|
|
|
@ -50,9 +50,9 @@ namespace ARDOUR {
|
|||
};
|
||||
|
||||
class AudioTimeAxisView;
|
||||
class AudioRegionGainLine;
|
||||
class GhostRegion;
|
||||
class AutomationTimeAxisView;
|
||||
class RegionFxLine;
|
||||
class RouteTimeAxisView;
|
||||
|
||||
class AudioRegionView : public RegionView, public LineMerger
|
||||
|
@ -91,12 +91,16 @@ public:
|
|||
void temporarily_hide_envelope (); ///< Dangerous!
|
||||
void unhide_envelope (); ///< Dangerous!
|
||||
|
||||
void set_region_gain_line ();
|
||||
void set_ignore_line_change (bool v) { _ignore_line_change = v; };
|
||||
bool set_region_fx_line (uint32_t, uint32_t);
|
||||
bool get_region_fx_line (PBD::ID&, uint32_t&);
|
||||
void update_envelope_visibility ();
|
||||
|
||||
void add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event, bool with_guard_points);
|
||||
void remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event);
|
||||
|
||||
std::shared_ptr<AudioRegionGainLine> get_gain_line() const { return gain_line; }
|
||||
std::shared_ptr<RegionFxLine> fx_line() const { return _fx_line; }
|
||||
|
||||
void region_changed (const PBD::PropertyChange&);
|
||||
void envelope_active_changed ();
|
||||
|
@ -184,7 +188,7 @@ protected:
|
|||
ArdourCanvas::Rectangle* end_xfade_rect;
|
||||
bool _end_xfade_visible;
|
||||
|
||||
std::shared_ptr<AudioRegionGainLine> gain_line;
|
||||
std::shared_ptr<RegionFxLine> _fx_line;
|
||||
|
||||
double _amplitude_above_axis;
|
||||
|
||||
|
@ -234,6 +238,12 @@ private:
|
|||
|
||||
bool trim_fade_in_drag_active;
|
||||
bool trim_fade_out_drag_active;
|
||||
|
||||
PBD::ID _rfx_id;
|
||||
uint32_t _rdx_param;
|
||||
bool _ignore_line_change;
|
||||
|
||||
PBD::ScopedConnection _region_fx_connection;
|
||||
};
|
||||
|
||||
#endif /* __gtk_ardour_audio_region_view_h__ */
|
||||
|
|
|
@ -470,8 +470,8 @@ AudioStreamView::set_selected_points (PointSelection& points)
|
|||
{
|
||||
for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
|
||||
AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
|
||||
if (arv && arv->get_gain_line ()) {
|
||||
arv->get_gain_line ()->set_selected_points (points);
|
||||
if (arv && arv->fx_line ()) {
|
||||
arv->fx_line ()->set_selected_points (points);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@
|
|||
#include "ardour/lmath.h"
|
||||
#include "ardour/location.h"
|
||||
#include "ardour/profile.h"
|
||||
#include "ardour/region_fx_plugin.h"
|
||||
#include "ardour/route.h"
|
||||
#include "ardour/route_group.h"
|
||||
#include "ardour/session_playlists.h"
|
||||
|
@ -1954,6 +1955,76 @@ Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, std::share
|
|||
edit_items.push_back (*manage (_region_actions->get_action ("choose-top-region-context-menu")->create_menu_item ()));
|
||||
}
|
||||
edit_items.push_back (SeparatorElem());
|
||||
|
||||
for (auto const& r: rs) {
|
||||
Gtk::Menu* rm = manage (new Gtk::Menu);
|
||||
MenuList& rm_items (rm->items ());
|
||||
|
||||
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (r);
|
||||
if (!arv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int nth = 0;
|
||||
PBD::ID rfx_id (0);
|
||||
uint32_t param_id = 0;
|
||||
arv->get_region_fx_line (rfx_id, param_id);
|
||||
arv->set_ignore_line_change (true);
|
||||
|
||||
Gtk::RadioMenuItem::Group grp;
|
||||
|
||||
r->region ()->foreach_plugin ([&rm_items, arv, &nth, &grp, rfx_id, param_id](std::weak_ptr<RegionFxPlugin> wfx)
|
||||
{
|
||||
std::shared_ptr<RegionFxPlugin> fx (wfx.lock ());
|
||||
if (!fx) {
|
||||
return;
|
||||
}
|
||||
std::shared_ptr<Plugin> plugin = fx->plugin ();
|
||||
|
||||
Gtk::Menu* acm = manage (new Gtk::Menu);
|
||||
MenuList& acm_items (acm->items ());
|
||||
|
||||
for (size_t i = 0; i < plugin->parameter_count (); ++i) {
|
||||
if (!plugin->parameter_is_control (i) || !plugin->parameter_is_input (i)) {
|
||||
continue;
|
||||
}
|
||||
const Evoral::Parameter param (PluginAutomation, 0, i);
|
||||
std::string label = plugin->describe_parameter (param);
|
||||
if (label == X_("latency") || label == X_("hidden")) {
|
||||
continue;
|
||||
}
|
||||
std::shared_ptr<ARDOUR::AutomationControl> c (std::dynamic_pointer_cast<ARDOUR::AutomationControl> (fx->control (param)));
|
||||
if (c && c->flags () & (Controllable::HiddenControl | Controllable::NotAutomatable)) {
|
||||
continue;
|
||||
}
|
||||
acm_items.push_back (RadioMenuElem (grp, label));
|
||||
Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*> (&acm_items.back ());
|
||||
cmi->set_active (fx->id () == rfx_id && param_id == i);
|
||||
cmi->signal_activate ().connect ([arv, nth, i] () {arv->set_region_fx_line (nth, i);});
|
||||
}
|
||||
|
||||
if (!acm_items.empty ()) {
|
||||
rm_items.push_back (MenuElem (fx->name (), *acm));
|
||||
} else {
|
||||
delete acm;
|
||||
}
|
||||
++nth;
|
||||
});
|
||||
|
||||
if (!rm_items.empty ()) {
|
||||
rm_items.push_back (SeparatorElem ());
|
||||
rm_items.push_back (RadioMenuElem (grp, _("Gain Envelope")));
|
||||
Gtk::CheckMenuItem* cmi = static_cast<Gtk::CheckMenuItem*> (&rm_items.back ());
|
||||
cmi->set_active (rfx_id == 0 || param_id == UINT32_MAX);
|
||||
cmi->signal_activate ().connect ([arv] () {arv->set_region_gain_line ();});
|
||||
|
||||
edit_items.push_back (MenuElem (string_compose ("Region Fx %1", r->region ()->name ()), *rm));
|
||||
edit_items.push_back (SeparatorElem ());
|
||||
} else {
|
||||
delete rm;
|
||||
}
|
||||
arv->set_ignore_line_change (false);
|
||||
}
|
||||
}
|
||||
|
||||
/** Add context menu items relevant to selection ranges.
|
||||
|
|
|
@ -707,11 +707,11 @@ bool
|
|||
Editor::canvas_line_event (GdkEvent *event, ArdourCanvas::Item* item, AutomationLine* al)
|
||||
{
|
||||
ItemType type;
|
||||
AudioRegionGainLine* gl;
|
||||
if ((gl = dynamic_cast<AudioRegionGainLine*> (al)) != 0) {
|
||||
RegionFxLine* rfl;
|
||||
if ((rfl = dynamic_cast<RegionFxLine*> (al)) != 0) {
|
||||
type = GainLineItem;
|
||||
if (event->type == GDK_BUTTON_PRESS) {
|
||||
clicked_regionview = &gl->region_view ();
|
||||
clicked_regionview = &rfl->region_view ();
|
||||
}
|
||||
} else {
|
||||
type = AutomationLineItem;
|
||||
|
|
|
@ -5039,7 +5039,7 @@ LineDrag::finished (GdkEvent* event, bool movement_occurred)
|
|||
AudioRegionView* arv;
|
||||
|
||||
if ((arv = dynamic_cast<AudioRegionView*> (_editor->clicked_regionview)) != 0) {
|
||||
arv->add_gain_point_event (&arv->get_gain_line ()->grab_item (), event, false);
|
||||
arv->add_gain_point_event (&arv->fx_line ()->grab_item (), event, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6367,7 +6367,7 @@ AutomationRangeDrag::AutomationRangeDrag (Editor* editor, list<RegionView*> cons
|
|||
|
||||
for (list<RegionView*>::const_iterator i = v.begin (); i != v.end (); ++i) {
|
||||
if (AudioRegionView* audio_view = dynamic_cast<AudioRegionView*> (*i)) {
|
||||
lines.push_back (audio_view->get_gain_line ());
|
||||
lines.push_back (audio_view->fx_line ());
|
||||
} else if (AutomationRegionView* automation_view = dynamic_cast<AutomationRegionView*> (*i)) {
|
||||
lines.push_back (automation_view->line ());
|
||||
_integral = true;
|
||||
|
@ -6394,8 +6394,8 @@ AutomationRangeDrag::setup (list<std::shared_ptr<AutomationLine>> const& lines)
|
|||
|
||||
/* need a special detection for automation lanes (not region gain line) */
|
||||
// TODO: if we implement automation regions, this check can probably be removed
|
||||
AudioRegionGainLine* argl = dynamic_cast<AudioRegionGainLine*> ((*i).get ());
|
||||
if (!argl) {
|
||||
RegionFxLine* fxl = dynamic_cast<RegionFxLine*> ((*i).get ());
|
||||
if (!fxl) {
|
||||
/* in automation lanes, the EFFECTIVE range should be considered 0->max_position (even if there is no line) */
|
||||
r.first = Temporal::timepos_t ((*i)->the_list ()->time_domain ());
|
||||
r.second = Temporal::timepos_t::max ((*i)->the_list ()->time_domain ());
|
||||
|
|
|
@ -2340,7 +2340,7 @@ Editor::can_remove_control_point (ArdourCanvas::Item* item)
|
|||
}
|
||||
|
||||
AutomationLine& line = control_point->line ();
|
||||
if (dynamic_cast<AudioRegionGainLine*> (&line)) {
|
||||
if (dynamic_cast<RegionFxLine*> (&line)) {
|
||||
/* we shouldn't remove the first or last gain point in region gain lines */
|
||||
if (line.is_last_point(*control_point) || line.is_first_point(*control_point)) {
|
||||
return false;
|
||||
|
|
|
@ -4833,7 +4833,7 @@ Editor::cut_copy_points (Editing::CutCopyOp op, timepos_t const & earliest_time)
|
|||
|
||||
bool erase = true;
|
||||
|
||||
if (dynamic_cast<AudioRegionGainLine*> (&line)) {
|
||||
if (dynamic_cast<RegionFxLine*> (&line)) {
|
||||
/* removing of first and last gain point in region gain lines is prohibited*/
|
||||
if (line.is_last_point (*(*sel_point)) || line.is_first_point (*(*sel_point))) {
|
||||
erase = false;
|
||||
|
|
|
@ -42,6 +42,7 @@
|
|||
|
||||
#include "ardour_http.h"
|
||||
#include "ardour_ui.h"
|
||||
#include "audio_region_view.h"
|
||||
#include "public_editor.h"
|
||||
#include "region_selection.h"
|
||||
#include "luadialog.h"
|
||||
|
@ -826,10 +827,16 @@ LuaInstance::register_classes (lua_State* L, bool sandbox)
|
|||
.endClass ()
|
||||
|
||||
.deriveClass <RegionView, TimeAxisViewItem> ("RegionView")
|
||||
.addCast<AudioRegionView> ("to_audioregionview")
|
||||
.addFunction ("show_region_editor", &RegionView::show_region_editor)
|
||||
.addFunction ("hide_region_editor", &RegionView::hide_region_editor)
|
||||
.endClass ()
|
||||
|
||||
.deriveClass <AudioRegionView, RegionView> ("RegionView")
|
||||
.addFunction ("set_region_gain_line", &AudioRegionView::set_region_gain_line)
|
||||
.addFunction ("set_region_fx_line", &AudioRegionView::set_region_fx_line)
|
||||
.endClass ()
|
||||
|
||||
.deriveClass <RouteUI, Selectable> ("RouteUI")
|
||||
.endClass ()
|
||||
|
||||
|
|
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#include "audio_region_view.h"
|
||||
#include "region_fx_line.h"
|
||||
|
||||
#include "pbd/i18n.h"
|
||||
|
||||
RegionFxLine::RegionFxLine (std::string const& name, RegionView& r, ArdourCanvas::Container& parent, std::shared_ptr<ARDOUR::AutomationList> l)
|
||||
: AutomationLine (name, r.get_time_axis_view(), parent, l, l->parameter())
|
||||
, rv (r)
|
||||
{
|
||||
group->raise_to_top ();
|
||||
group->set_y_position (2);
|
||||
}
|
||||
|
||||
Temporal::timepos_t
|
||||
RegionFxLine::get_origin() const
|
||||
{
|
||||
return rv.region()->position();
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2024 Robin Gareus <robin@gareus.org>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*/
|
||||
|
||||
#ifndef __ardour_gtk_region_fx_line_h__
|
||||
#define __ardour_gtk_region_fx_line_h__
|
||||
|
||||
#include "automation_line.h"
|
||||
|
||||
class RegionView;
|
||||
|
||||
class RegionFxLine : public AutomationLine
|
||||
{
|
||||
public:
|
||||
RegionFxLine (std::string const&, RegionView&, ArdourCanvas::Container&, std::shared_ptr<ARDOUR::AutomationList>);
|
||||
|
||||
Temporal::timepos_t get_origin() const;
|
||||
|
||||
RegionView& region_view () { return rv; }
|
||||
|
||||
protected:
|
||||
RegionView& rv;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -44,26 +44,14 @@ using namespace ARDOUR;
|
|||
using namespace PBD;
|
||||
|
||||
AudioRegionGainLine::AudioRegionGainLine (const string & name, AudioRegionView& r, ArdourCanvas::Container& parent, std::shared_ptr<AutomationList> l)
|
||||
: AutomationLine (name, r.get_time_axis_view(), parent, l, l->parameter())
|
||||
, rv (r)
|
||||
: RegionFxLine (name, r, parent, l)
|
||||
, arv (r)
|
||||
{
|
||||
// If this isn't true something is horribly wrong, and we'll get catastrophic gain values
|
||||
assert(l->parameter().type() == EnvelopeAutomation);
|
||||
|
||||
r.region()->PropertyChanged.connect (_region_changed_connection, invalidator (*this), boost::bind (&AudioRegionGainLine::region_changed, this, _1), gui_context());
|
||||
|
||||
group->raise_to_top ();
|
||||
group->set_y_position (2);
|
||||
terminal_points_can_slide = false;
|
||||
}
|
||||
|
||||
timepos_t
|
||||
AudioRegionGainLine::get_origin() const
|
||||
{
|
||||
return rv.region()->position();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fraction)
|
||||
{
|
||||
|
@ -71,9 +59,9 @@ AudioRegionGainLine::start_drag_single (ControlPoint* cp, double x, float fracti
|
|||
|
||||
// XXX Stateful need to capture automation curve data
|
||||
|
||||
if (!rv.audio_region()->envelope_active()) {
|
||||
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), &rv.audio_region()->get_state(), 0));
|
||||
rv.audio_region()->set_envelope_active(false);
|
||||
if (!arv.audio_region()->envelope_active()) {
|
||||
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(arv.audio_region().get()), &arv.audio_region()->get_state(), 0));
|
||||
arv.audio_region()->set_envelope_active(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -84,10 +72,10 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
|
|||
trackview.editor().begin_reversible_command (_("remove control point"));
|
||||
XMLNode &before = alist->get_state();
|
||||
|
||||
if (!rv.audio_region()->envelope_active()) {
|
||||
rv.audio_region()->clear_changes ();
|
||||
rv.audio_region()->set_envelope_active(true);
|
||||
trackview.session()->add_command(new StatefulDiffCommand (rv.audio_region()));
|
||||
if (!arv.audio_region()->envelope_active()) {
|
||||
arv.audio_region()->clear_changes ();
|
||||
arv.audio_region()->set_envelope_active(true);
|
||||
trackview.session()->add_command(new StatefulDiffCommand (arv.audio_region()));
|
||||
}
|
||||
|
||||
trackview.editor ().get_selection ().clear_points ();
|
||||
|
@ -101,9 +89,9 @@ AudioRegionGainLine::remove_point (ControlPoint& cp)
|
|||
void
|
||||
AudioRegionGainLine::end_drag (bool with_push, uint32_t final_index)
|
||||
{
|
||||
if (!rv.audio_region()->envelope_active()) {
|
||||
rv.audio_region()->set_envelope_active(true);
|
||||
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(rv.audio_region().get()), 0, &rv.audio_region()->get_state()));
|
||||
if (!arv.audio_region()->envelope_active()) {
|
||||
arv.audio_region()->set_envelope_active(true);
|
||||
trackview.session()->add_command(new MementoCommand<AudioRegion>(*(arv.audio_region().get()), 0, &arv.audio_region()->get_state()));
|
||||
}
|
||||
|
||||
AutomationLine::end_drag (with_push, final_index);
|
||||
|
|
|
@ -27,8 +27,7 @@
|
|||
|
||||
#include "ardour/ardour.h"
|
||||
|
||||
|
||||
#include "automation_line.h"
|
||||
#include "region_fx_line.h"
|
||||
|
||||
namespace ARDOUR {
|
||||
class Session;
|
||||
|
@ -37,23 +36,21 @@ namespace ARDOUR {
|
|||
class TimeAxisView;
|
||||
class AudioRegionView;
|
||||
|
||||
class AudioRegionGainLine : public AutomationLine
|
||||
class AudioRegionGainLine : public RegionFxLine
|
||||
{
|
||||
public:
|
||||
AudioRegionGainLine (const std::string & name, AudioRegionView&, ArdourCanvas::Container& parent, std::shared_ptr<ARDOUR::AutomationList>);
|
||||
|
||||
Temporal::timepos_t get_origin() const;
|
||||
|
||||
void start_drag_single (ControlPoint*, double, float);
|
||||
void end_drag (bool with_push, uint32_t final_index);
|
||||
|
||||
void remove_point (ControlPoint&);
|
||||
AudioRegionView& region_view () { return rv; }
|
||||
|
||||
private:
|
||||
PBD::ScopedConnection _region_changed_connection;
|
||||
void region_changed (const PBD::PropertyChange& what_changed);
|
||||
AudioRegionView& rv;
|
||||
|
||||
AudioRegionView& arv;
|
||||
PBD::ScopedConnection _region_changed_connection;
|
||||
};
|
||||
|
||||
#endif /* __ardour_gtk_region_gain_line_h__ */
|
||||
|
|
|
@ -1176,11 +1176,11 @@ Selection::get_state () const
|
|||
continue;
|
||||
}
|
||||
|
||||
AudioRegionGainLine* argl = dynamic_cast<AudioRegionGainLine*> (&(*i)->line());
|
||||
if (argl) {
|
||||
RegionFxLine* fxl = dynamic_cast<RegionFxLine*> (&(*i)->line());
|
||||
if (fxl) {
|
||||
XMLNode* r = node->add_child (X_("ControlPoint"));
|
||||
r->set_property (X_("type"), "region");
|
||||
r->set_property (X_("region-id"), argl->region_view ().region ()->id ());
|
||||
r->set_property (X_("region-id"), fxl->region_view ().region ()->id ());
|
||||
r->set_property (X_("view-index"), (*i)->view_index());
|
||||
}
|
||||
|
||||
|
@ -1324,35 +1324,6 @@ Selection::set_state (XMLNode const & node, int)
|
|||
if (!cps.empty()) {
|
||||
add (cps);
|
||||
}
|
||||
} else if (prop_type->value () == "region") {
|
||||
|
||||
PBD::ID region_id;
|
||||
uint32_t view_index;
|
||||
if (!(*i)->get_property (X_("region-id"), region_id) ||
|
||||
!(*i)->get_property (X_("view-index"), view_index)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
RegionSelection rs;
|
||||
editor->get_regionviews_by_id (region_id, rs);
|
||||
|
||||
if (!rs.empty ()) {
|
||||
vector <ControlPoint *> cps;
|
||||
for (RegionSelection::iterator rsi = rs.begin(); rsi != rs.end(); ++rsi) {
|
||||
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*rsi);
|
||||
if (arv) {
|
||||
std::shared_ptr<AudioRegionGainLine> gl = arv->get_gain_line ();
|
||||
ControlPoint* cp = gl->nth(view_index);
|
||||
if (cp) {
|
||||
cps.push_back (cp);
|
||||
cp->show();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!cps.empty()) {
|
||||
add (cps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else if ((*i)->name() == X_("TimelineRange")) {
|
||||
|
|
|
@ -622,7 +622,7 @@ StreamView::get_selectables (timepos_t const & start, timepos_t const & end, dou
|
|||
|| (!within && (*i)->region()->coverage (start, end) != Temporal::OverlapNone)) {
|
||||
if (_trackview.editor().internal_editing()) {
|
||||
AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*i);
|
||||
if (arv && arv->get_gain_line ()) {
|
||||
if (arv && arv->fx_line ()) {
|
||||
/* Note: AutomationLine::get_selectables() uses trackview.current_height (),
|
||||
* disregarding Stacked layer display height
|
||||
*/
|
||||
|
@ -630,7 +630,7 @@ StreamView::get_selectables (timepos_t const & start, timepos_t const & end, dou
|
|||
double const y = (*i)->get_canvas_group ()->position().y;
|
||||
double t = 1.0 - std::min (1.0, std::max (0., (top - _trackview.y_position () - y) / c));
|
||||
double b = 1.0 - std::min (1.0, std::max (0., (bottom - _trackview.y_position () - y) / c));
|
||||
arv->get_gain_line()->get_selectables (start, end, b, t, results);
|
||||
arv->fx_line()->get_selectables (start, end, b, t, results);
|
||||
}
|
||||
} else {
|
||||
results.push_back (*i);
|
||||
|
|
|
@ -241,6 +241,7 @@ gtk2_ardour_sources = [
|
|||
'recorder_group_tabs.cc',
|
||||
'recorder_ui.cc',
|
||||
'region_editor.cc',
|
||||
'region_fx_line.cc',
|
||||
'region_gain_line.cc',
|
||||
'region_layering_order_editor.cc',
|
||||
'region_list_base.cc',
|
||||
|
|
Loading…
Reference in New Issue