more extensive automation display design for cue editor
This commit is contained in:
parent
f8f6e5d2ab
commit
bbdb6b0e63
@ -225,6 +225,19 @@ AutomationLine::hide ()
|
|||||||
set_visibility (AutomationLine::VisibleAspects (_visible & ~Line));
|
set_visibility (AutomationLine::VisibleAspects (_visible & ~Line));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AutomationLine::hide_all ()
|
||||||
|
{
|
||||||
|
set_visibility (AutomationLine::VisibleAspects (0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
AutomationLine::show ()
|
||||||
|
{
|
||||||
|
/* hide everything */
|
||||||
|
set_visibility (AutomationLine::VisibleAspects (~0));
|
||||||
|
}
|
||||||
|
|
||||||
double
|
double
|
||||||
AutomationLine::control_point_box_size ()
|
AutomationLine::control_point_box_size ()
|
||||||
{
|
{
|
||||||
|
@ -118,6 +118,8 @@ public:
|
|||||||
void remove_visibility (VisibleAspects);
|
void remove_visibility (VisibleAspects);
|
||||||
|
|
||||||
void hide ();
|
void hide ();
|
||||||
|
void hide_all ();
|
||||||
|
void show ();
|
||||||
void set_height (guint32);
|
void set_height (guint32);
|
||||||
|
|
||||||
bool get_uses_gain_mapping () const;
|
bool get_uses_gain_mapping () const;
|
||||||
|
@ -20,6 +20,7 @@
|
|||||||
#include "ardour/midi_source.h"
|
#include "ardour/midi_source.h"
|
||||||
#include "ardour/midi_track.h"
|
#include "ardour/midi_track.h"
|
||||||
#include "ardour/triggerbox.h"
|
#include "ardour/triggerbox.h"
|
||||||
|
#include "ardour/types.h"
|
||||||
|
|
||||||
#include "gtkmm2ext/utils.h"
|
#include "gtkmm2ext/utils.h"
|
||||||
|
|
||||||
@ -41,6 +42,7 @@
|
|||||||
|
|
||||||
#include "pbd/i18n.h"
|
#include "pbd/i18n.h"
|
||||||
|
|
||||||
|
using namespace ARDOUR;
|
||||||
using namespace Gtkmm2ext;
|
using namespace Gtkmm2ext;
|
||||||
|
|
||||||
MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
|
MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
|
||||||
@ -50,7 +52,6 @@ MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
|
|||||||
MidiViewBackground& bg,
|
MidiViewBackground& bg,
|
||||||
uint32_t basic_color)
|
uint32_t basic_color)
|
||||||
: MidiView (mt, parent, ec, bg, basic_color)
|
: MidiView (mt, parent, ec, bg, basic_color)
|
||||||
, velocity_base (nullptr)
|
|
||||||
, velocity_display (nullptr)
|
, velocity_display (nullptr)
|
||||||
, _slot_index (slot_index)
|
, _slot_index (slot_index)
|
||||||
{
|
{
|
||||||
@ -77,14 +78,13 @@ MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
|
|||||||
automation_group->set_fill_color (UIConfiguration::instance().color ("midi automation track fill"));
|
automation_group->set_fill_color (UIConfiguration::instance().color ("midi automation track fill"));
|
||||||
automation_group->set_data ("linemerger", this);
|
automation_group->set_data ("linemerger", this);
|
||||||
|
|
||||||
velocity_base = new ArdourCanvas::Rectangle (&parent);
|
velocity_display = new MidiCueVelocityDisplay (editing_context(), midi_context(), *this, *automation_group, 0x312244ff);
|
||||||
CANVAS_DEBUG_NAME (velocity_base, "cue velocity base");
|
|
||||||
velocity_display = new MidiCueVelocityDisplay (editing_context(), midi_context(), *this, *velocity_base, 0x312244ff);
|
|
||||||
|
|
||||||
for (auto & ev : _events) {
|
for (auto & ev : _events) {
|
||||||
velocity_display->add_note (ev.second);
|
velocity_display->add_note (ev.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
velocity_display->hide ();
|
||||||
|
|
||||||
button_bar = new ArdourCanvas::Box (&parent, ArdourCanvas::Box::Horizontal);
|
button_bar = new ArdourCanvas::Box (&parent, ArdourCanvas::Box::Horizontal);
|
||||||
CANVAS_DEBUG_NAME (button_bar, "button bar");
|
CANVAS_DEBUG_NAME (button_bar, "button bar");
|
||||||
@ -115,36 +115,37 @@ MidiCueView::MidiCueView (std::shared_ptr<ARDOUR::MidiTrack> mt,
|
|||||||
modulation_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground"));
|
modulation_button->text()->set_color (UIConfiguration::instance().color ("neutral:foreground"));
|
||||||
CANVAS_DEBUG_NAME (modulation_button, "modulation button");
|
CANVAS_DEBUG_NAME (modulation_button, "modulation button");
|
||||||
|
|
||||||
|
velocity_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiVelocityAutomation, 0));
|
||||||
|
pressure_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiChannelPressureAutomation, 0));
|
||||||
|
bender_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiPitchBenderAutomation, 0));
|
||||||
|
modulation_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_MODWHEEL));
|
||||||
|
expression_button->Event.connect (sigc::bind (sigc::mem_fun (*this, &MidiCueView::automation_button_event), ARDOUR::MidiCCAutomation, MIDI_CTL_MSB_EXPRESSION));
|
||||||
|
|
||||||
set_extensible (true);
|
set_extensible (true);
|
||||||
|
|
||||||
Evoral::Parameter fully_qualified_param (ARDOUR::MidiCCAutomation, 0, MIDI_CTL_MSB_MODWHEEL);
|
Evoral::Parameter fully_qualified_param (ARDOUR::MidiVelocityAutomation, 0, 0);
|
||||||
show_automation (fully_qualified_param);
|
update_automation_display (fully_qualified_param, SelectionSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiCueView::set_height (double h)
|
MidiCueView::set_height (double h)
|
||||||
{
|
{
|
||||||
double note_area_height = ceil (h / 2.);
|
|
||||||
double velocity_height = ceil ((h - note_area_height) / 2.);
|
|
||||||
|
|
||||||
double bbw, bbh;
|
double bbw, bbh;
|
||||||
button_bar->size_request (bbw, bbh);
|
button_bar->size_request (bbw, bbh);
|
||||||
|
|
||||||
double automation_height = h - note_area_height - velocity_height - bbh;
|
double note_area_height = ceil ((h - bbh) / 2.);
|
||||||
|
double automation_height = ceil (h - bbh - note_area_height);
|
||||||
|
|
||||||
event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, note_area_height));
|
event_rect->set (ArdourCanvas::Rect (0.0, 0.0, ArdourCanvas::COORD_MAX, note_area_height));
|
||||||
midi_context().set_size (midi_context().width(), note_area_height);
|
midi_context().set_size (midi_context().width(), note_area_height);
|
||||||
|
|
||||||
velocity_base->set_position (ArdourCanvas::Duple (0., note_area_height));
|
automation_group->set_position (ArdourCanvas::Duple (0., note_area_height));
|
||||||
velocity_base->set (ArdourCanvas::Rect (0., 0., ArdourCanvas::COORD_MAX, velocity_height));
|
|
||||||
|
|
||||||
automation_group->set_position (ArdourCanvas::Duple (0., note_area_height + velocity_height));
|
|
||||||
automation_group->set (ArdourCanvas::Rect (0., 0., ArdourCanvas::COORD_MAX, automation_height));
|
automation_group->set (ArdourCanvas::Rect (0., 0., ArdourCanvas::COORD_MAX, automation_height));
|
||||||
|
|
||||||
button_bar->size_allocate (ArdourCanvas::Rect (0., note_area_height + velocity_height + automation_height, ArdourCanvas::COORD_MAX, note_area_height + velocity_height + automation_height + bbh));
|
button_bar->size_allocate (ArdourCanvas::Rect (0., note_area_height + automation_height, ArdourCanvas::COORD_MAX, note_area_height + automation_height + bbh));
|
||||||
|
|
||||||
if (automation_line) {
|
for (auto & ads : automation_map) {
|
||||||
automation_line->set_height (automation_height);
|
ads.second.set_height (automation_height);
|
||||||
}
|
}
|
||||||
|
|
||||||
view_changed ();
|
view_changed ();
|
||||||
@ -275,8 +276,31 @@ MidiCueView::update_hit (Hit* h)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
MidiCueView::automation_button_event (GdkEvent* ev, Evoral::ParameterType type, int id)
|
||||||
|
{
|
||||||
|
SelectionOperation op = ArdourKeyboard::selection_type (ev->button.state);
|
||||||
|
|
||||||
|
switch (ev->type) {
|
||||||
|
case GDK_BUTTON_RELEASE:
|
||||||
|
automation_button_click (type, id, op);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MidiCueView::show_automation (Evoral::Parameter const & param)
|
MidiCueView::automation_button_click (Evoral::ParameterType type, int id, SelectionOperation op)
|
||||||
|
{
|
||||||
|
#warning paul allow channel selection (2nd param)
|
||||||
|
update_automation_display (Evoral::Parameter (type, 0, id), op);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiCueView::update_automation_display (Evoral::Parameter const & param, SelectionOperation op)
|
||||||
{
|
{
|
||||||
using namespace ARDOUR;
|
using namespace ARDOUR;
|
||||||
|
|
||||||
@ -284,52 +308,82 @@ MidiCueView::show_automation (Evoral::Parameter const & param)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (param.type() == NullAutomation) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// if (automation_line && automation_line->param() == param) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
automation_line.reset ();
|
|
||||||
automation_control.reset ();
|
|
||||||
|
|
||||||
std::shared_ptr<AutomationControl> control;
|
|
||||||
|
|
||||||
switch (param.type()) {
|
switch (param.type()) {
|
||||||
|
|
||||||
case MidiCCAutomation:
|
case MidiCCAutomation:
|
||||||
case MidiPgmChangeAutomation:
|
case MidiPgmChangeAutomation:
|
||||||
case MidiPitchBenderAutomation:
|
case MidiPitchBenderAutomation:
|
||||||
case MidiChannelPressureAutomation:
|
case MidiChannelPressureAutomation:
|
||||||
case MidiNotePressureAutomation:
|
case MidiNotePressureAutomation:
|
||||||
case MidiSystemExclusiveAutomation: {
|
case MidiSystemExclusiveAutomation:
|
||||||
/* These controllers are region "automation" - they are owned
|
case MidiVelocityAutomation:
|
||||||
* by regions (and their MidiModels), not by the track. As a
|
break;
|
||||||
* result there is no AutomationList/Line for the track, but we create
|
default:
|
||||||
* a controller for the user to write immediate events, so the editor
|
return;
|
||||||
* can act as a control surface for the present MIDI controllers.
|
}
|
||||||
*
|
|
||||||
* TODO: Record manipulation of the controller to regions?
|
|
||||||
*/
|
|
||||||
|
|
||||||
std::shared_ptr<Evoral::Control> control = _midi_region->model()->control (param, true);
|
CueAutomationMap::iterator i = automation_map.find (param);
|
||||||
automation_control = std::dynamic_pointer_cast<AutomationControl> (control);
|
AutomationDisplayState* ads = nullptr;
|
||||||
|
|
||||||
|
if (i != automation_map.end()) {
|
||||||
|
|
||||||
|
ads = &i->second;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (param.type() == MidiVelocityAutomation) {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
std::shared_ptr<Evoral::Control> control = _midi_region->model()->control (param, true);
|
||||||
|
automation_control = std::dynamic_pointer_cast<AutomationControl> (control);
|
||||||
|
|
||||||
|
if (!automation_control) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (automation_control) {
|
|
||||||
automation_line.reset (new MidiCueAutomationLine ("whatevs",
|
automation_line.reset (new MidiCueAutomationLine ("whatevs",
|
||||||
_editing_context,
|
_editing_context,
|
||||||
*automation_group,
|
*automation_group,
|
||||||
automation_group,
|
automation_group,
|
||||||
automation_control->alist(),
|
automation_control->alist(),
|
||||||
automation_control->desc()));
|
automation_control->desc()));
|
||||||
automation_line->set_height (automation_group->get().height());
|
AutomationDisplayState cad (automation_control, automation_line, true);
|
||||||
|
|
||||||
|
auto res = automation_map.insert (std::make_pair (param, cad));
|
||||||
|
|
||||||
|
ads = &((*res.first).second);
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
std::cerr << "sad " << op << " param " << enum_2_string (param.type()) << std::endl;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case SelectionSet:
|
||||||
|
/* hide the rest */
|
||||||
|
for (auto & as : automation_map) {
|
||||||
|
as.second.hide ();
|
||||||
|
}
|
||||||
|
/*FALLTHRU*/
|
||||||
|
case SelectionAdd:
|
||||||
|
ads->set_height (automation_group->get().height());
|
||||||
|
ads->show ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectionRemove:
|
||||||
|
ads->hide ();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SelectionToggle:
|
||||||
|
if (ads->visible) {
|
||||||
|
ads->hide ();
|
||||||
|
} else {
|
||||||
|
ads->set_height (automation_group->get().height());
|
||||||
|
ads->show ();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
|
||||||
|
case SelectionExtend:
|
||||||
|
/* undefined in this context */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -364,3 +418,38 @@ void
|
|||||||
MidiCueView::line_drag_click (GdkEvent* event, Temporal::timepos_t const & pos)
|
MidiCueView::line_drag_click (GdkEvent* event, Temporal::timepos_t const & pos)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MidiCueView::AutomationDisplayState::~AutomationDisplayState()
|
||||||
|
{
|
||||||
|
delete velocity_display;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiCueView::AutomationDisplayState::hide ()
|
||||||
|
{
|
||||||
|
if (velocity_display) {
|
||||||
|
velocity_display->hide ();
|
||||||
|
} else if (line) {
|
||||||
|
line->hide_all ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiCueView::AutomationDisplayState::show ()
|
||||||
|
{
|
||||||
|
if (velocity_display) {
|
||||||
|
velocity_display->show ();
|
||||||
|
} else if (line) {
|
||||||
|
line->show ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
MidiCueView::AutomationDisplayState::set_height (double h)
|
||||||
|
{
|
||||||
|
if (velocity_display) {
|
||||||
|
// velocity_display->set_height (h);
|
||||||
|
} else if (line) {
|
||||||
|
line->set_height (h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "ardour/types.h"
|
||||||
|
|
||||||
#include "midi_view.h"
|
#include "midi_view.h"
|
||||||
|
|
||||||
class VelocityDisplay;
|
class VelocityDisplay;
|
||||||
@ -56,7 +60,7 @@ class MidiCueView : public MidiView
|
|||||||
void ghost_add_note (NoteBase*);
|
void ghost_add_note (NoteBase*);
|
||||||
void ghost_sync_selection (NoteBase*);
|
void ghost_sync_selection (NoteBase*);
|
||||||
|
|
||||||
void show_automation (Evoral::Parameter const & param);
|
void update_automation_display (Evoral::Parameter const & param, ARDOUR::SelectionOperation);
|
||||||
|
|
||||||
ArdourCanvas::Item* drag_group() const;
|
ArdourCanvas::Item* drag_group() const;
|
||||||
|
|
||||||
@ -70,11 +74,37 @@ class MidiCueView : public MidiView
|
|||||||
bool scroll (GdkEventScroll* ev);
|
bool scroll (GdkEventScroll* ev);
|
||||||
|
|
||||||
ArdourCanvas::Rectangle* automation_group;
|
ArdourCanvas::Rectangle* automation_group;
|
||||||
std::shared_ptr<MidiCueAutomationLine> automation_line;
|
|
||||||
std::shared_ptr<ARDOUR::AutomationControl> automation_control;
|
|
||||||
|
|
||||||
ArdourCanvas::Rectangle* velocity_base;
|
typedef std::shared_ptr<MidiCueAutomationLine> CueAutomationLine;
|
||||||
|
typedef std::shared_ptr<ARDOUR::AutomationControl> CueAutomationControl;
|
||||||
|
|
||||||
|
struct AutomationDisplayState {
|
||||||
|
|
||||||
|
AutomationDisplayState (CueAutomationControl ctl, CueAutomationLine ln, bool vis)
|
||||||
|
: control (ctl), line (ln), velocity_display (nullptr), visible (vis) {}
|
||||||
|
AutomationDisplayState (VelocityDisplay& vdisp, bool vis)
|
||||||
|
: control (nullptr), velocity_display (&vdisp), visible (vis) {}
|
||||||
|
|
||||||
|
~AutomationDisplayState();
|
||||||
|
|
||||||
|
CueAutomationControl control;
|
||||||
|
CueAutomationLine line;
|
||||||
|
VelocityDisplay* velocity_display;
|
||||||
|
bool visible;
|
||||||
|
|
||||||
|
void hide ();
|
||||||
|
void show ();
|
||||||
|
void set_height (double);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::map<Evoral::Parameter, AutomationDisplayState> CueAutomationMap;
|
||||||
|
|
||||||
|
CueAutomationMap automation_map;
|
||||||
|
AutomationDisplayState* active_automation;
|
||||||
|
|
||||||
VelocityDisplay* velocity_display;
|
VelocityDisplay* velocity_display;
|
||||||
|
CueAutomationLine automation_line;
|
||||||
|
CueAutomationControl automation_control;
|
||||||
|
|
||||||
ArdourCanvas::Box* button_bar;
|
ArdourCanvas::Box* button_bar;
|
||||||
ArdourCanvas::Button* velocity_button;
|
ArdourCanvas::Button* velocity_button;
|
||||||
@ -90,6 +120,6 @@ class MidiCueView : public MidiView
|
|||||||
void update_sustained (Note *);
|
void update_sustained (Note *);
|
||||||
void update_hit (Hit *);
|
void update_hit (Hit *);
|
||||||
|
|
||||||
|
bool automation_button_event (GdkEvent*, Evoral::ParameterType type, int id);
|
||||||
|
void automation_button_click (Evoral::ParameterType type, int id, ARDOUR::SelectionOperation);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -430,3 +430,19 @@ VelocityDisplay::set_selected (bool yn)
|
|||||||
base.parent()->raise_to_top ();
|
base.parent()->raise_to_top ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VelocityDisplay::hide ()
|
||||||
|
{
|
||||||
|
if (lolli_container) {
|
||||||
|
lolli_container->hide ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
VelocityDisplay::show ()
|
||||||
|
{
|
||||||
|
if (lolli_container) {
|
||||||
|
lolli_container->hide ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -44,6 +44,9 @@ class VelocityDisplay
|
|||||||
VelocityDisplay (EditingContext&, MidiViewBackground&, MidiView&, ArdourCanvas::Rectangle& base_rect, ArdourCanvas::Container&, GhostEvent::EventList& el, Gtkmm2ext::Color oc);
|
VelocityDisplay (EditingContext&, MidiViewBackground&, MidiView&, ArdourCanvas::Rectangle& base_rect, ArdourCanvas::Container&, GhostEvent::EventList& el, Gtkmm2ext::Color oc);
|
||||||
virtual ~VelocityDisplay ();
|
virtual ~VelocityDisplay ();
|
||||||
|
|
||||||
|
void hide ();
|
||||||
|
void show ();
|
||||||
|
|
||||||
void redisplay();
|
void redisplay();
|
||||||
void add_note(NoteBase*);
|
void add_note(NoteBase*);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user