diff options
Diffstat (limited to 'gtk2_ardour')
25 files changed, 719 insertions, 358 deletions
diff --git a/gtk2_ardour/SConscript b/gtk2_ardour/SConscript index cf8b8dbfaa..605e7d132b 100644 --- a/gtk2_ardour/SConscript +++ b/gtk2_ardour/SConscript @@ -96,6 +96,7 @@ ardour_ui_options.cc audio_clock.cc audio_time_axis.cc audio_region_editor.cc +control_point.cc automation_line.cc automation_time_axis.cc automation_controller.cc @@ -107,6 +108,7 @@ simpleline.cc canvas-simplerect.c simplerect.cc canvas-waveview.c +diamond.cc crossfade_edit.cc crossfade_view.cc curvetest.cc diff --git a/gtk2_ardour/ardour2_ui_default.conf b/gtk2_ardour/ardour2_ui_default.conf index d2272c7ac1..893c4ba6cd 100644 --- a/gtk2_ardour/ardour2_ui_default.conf +++ b/gtk2_ardour/ardour2_ui_default.conf @@ -13,11 +13,11 @@ <Option name="time-stretch-outline" value="63636396"/> <Option name="automation line" value="44bc59ff"/> <Option name="processor automation line" value="7aa3f9ff"/> - <Option name="control point fill" value="000000ff"/> - <Option name="control point outline" value="000000ff"/> + <Option name="control point fill" value="ffffff66"/> + <Option name="control point outline" value="ffffffaa"/> <Option name="entered control point outline" value="ff0000ee"/> <Option name="entered control point selected" value="ff3535ff"/> - <Option name="entered control point" value="000000cc"/> + <Option name="entered control point" value="ffffffaa"/> <Option name="control point selected" value="00ff00ff"/> <Option name="control point" value="ff0000ff"/> <Option name="automation track fill" value="a0a0ce68"/> diff --git a/gtk2_ardour/audio_region_view.cc b/gtk2_ardour/audio_region_view.cc index f3a8819cb8..dc6de8d0f6 100644 --- a/gtk2_ardour/audio_region_view.cc +++ b/gtk2_ardour/audio_region_view.cc @@ -40,6 +40,7 @@ #include "public_editor.h" #include "audio_region_editor.h" #include "region_gain_line.h" +#include "control_point.h" #include "ghostregion.h" #include "audio_time_axis.h" #include "utils.h" @@ -961,8 +962,8 @@ AudioRegionView::add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *ev) 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); + ControlPoint *cp = reinterpret_cast<ControlPoint *> (item->get_data ("control_point")); + audio_region()->envelope()->erase (cp->model()); } void diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc index 73500f3ea1..db88982089 100644 --- a/gtk2_ardour/audio_time_axis.cc +++ b/gtk2_ardour/audio_time_axis.cc @@ -218,6 +218,35 @@ AudioTimeAxisView::append_extra_display_menu_items () items.push_back (MenuElem (_("Layers"), *layers_menu)); } + +Gtk::Menu* +AudioTimeAxisView::build_mode_menu() +{ + using namespace Menu_Helpers; + + Menu* mode_menu = manage (new Menu); + MenuList& items = mode_menu->items(); + mode_menu->set_name ("ArdourContextMenu"); + + RadioMenuItem::Group mode_group; + items.push_back (RadioMenuElem (mode_group, _("Normal"), + bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::Normal))); + normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back()); + items.push_back (RadioMenuElem (mode_group, _("Tape"), + bind (mem_fun (*this, &AudioTimeAxisView::set_track_mode), ARDOUR::Destructive))); + destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back()); + + switch (track()->mode()) { + case ARDOUR::Destructive: + destructive_track_mode_item->set_active (); + break; + case ARDOUR::Normal: + normal_track_mode_item->set_active (); + break; + } + + return mode_menu; +} void AudioTimeAxisView::toggle_waveforms () diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h index b0183e5e19..822fbcadf0 100644 --- a/gtk2_ardour/audio_time_axis.h +++ b/gtk2_ardour/audio_time_axis.h @@ -91,6 +91,7 @@ class AudioTimeAxisView : public RouteTimeAxisView void route_active_changed (); void append_extra_display_menu_items (); + Gtk::Menu* build_mode_menu(); void toggle_show_waveforms (); void set_waveform_shape (WaveformShape); diff --git a/gtk2_ardour/automation_line.cc b/gtk2_ardour/automation_line.cc index f396a92d82..d9d1b827f9 100644 --- a/gtk2_ardour/automation_line.cc +++ b/gtk2_ardour/automation_line.cc @@ -32,6 +32,7 @@ #include "simplerect.h" #include "automation_line.h" +#include "control_point.h" #include "rgb_macros.h" #include "ardour_ui.h" #include "public_editor.h" @@ -54,178 +55,13 @@ using namespace PBD; using namespace Editing; using namespace Gnome; // for Canvas -ControlPoint::ControlPoint (AutomationLine& al) - : line (al) -{ - model = al.the_list()->end(); - view_index = 0; - can_slide = true; - _x = 0; - _y = 0; - _shape = Full; - _size = 4.0; - selected = false; - - item = new Canvas::SimpleRect (line.canvas_group()); - item->property_draw() = true; - item->property_fill() = false; - item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointFill.get(); - item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointOutline.get(); - item->property_outline_pixels() = 1; - item->set_data ("control_point", this); - item->signal_event().connect (mem_fun (this, &ControlPoint::event_handler)); - - hide (); - set_visible (false); -} - -ControlPoint::ControlPoint (const ControlPoint& other, bool dummy_arg_to_force_special_copy_constructor) - : line (other.line) -{ - if (&other == this) { - return; - } - - model = other.model; - view_index = other.view_index; - can_slide = other.can_slide; - _x = other._x; - _y = other._y; - _shape = other._shape; - _size = other._size; - selected = false; - - item = new Canvas::SimpleRect (line.canvas_group()); - item->property_fill() = false; - item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredControlPointOutline.get(); - item->property_outline_pixels() = 1; - - /* NOTE: no event handling in copied ControlPoints */ - - hide (); - set_visible (false); -} - -ControlPoint::~ControlPoint () -{ - delete item; -} - -bool -ControlPoint::event_handler (GdkEvent* event) -{ - return PublicEditor::instance().canvas_control_point_event (event, item, this); -} - -void -ControlPoint::hide () -{ - item->hide(); -} - -void -ControlPoint::show() -{ - item->show(); -} - -void -ControlPoint::set_visible (bool yn) -{ - item->property_draw() = (gboolean) yn; -} - -void -ControlPoint::reset (double x, double y, AutomationList::iterator mi, uint32_t vi, ShapeType shape) -{ - model = mi; - view_index = vi; - move_to (x, y, shape); -} - -void -ControlPoint::show_color (bool entered, bool hide_too) -{ - if (entered) { - if (selected) { - item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredControlPointSelected.get(); - set_visible(true); - } else { - item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_EnteredControlPoint.get(); - if (hide_too) { - set_visible(false); - } - } - - } else { - if (selected) { - item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointSelected.get(); - set_visible(true); - } else { - item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPoint.get(); - if (hide_too) { - set_visible(false); - } - } - } -} - -void -ControlPoint::set_size (double sz) -{ - _size = sz; - -#if 0 - if (_size > 6.0) { - item->property_fill() = (gboolean) TRUE; - } else { - item->property_fill() = (gboolean) FALSE; - } -#endif - - move_to (_x, _y, _shape); -} - -void -ControlPoint::move_to (double x, double y, ShapeType shape) -{ - double x1 = 0; - double x2 = 0; - double half_size = rint(_size/2.0); - - switch (shape) { - case Full: - x1 = x - half_size; - x2 = x + half_size; - break; - case Start: - x1 = x; - x2 = x + half_size; - break; - case End: - x1 = x - half_size; - x2 = x; - break; - } - - item->property_x1() = x1; - item->property_x2() = x2; - item->property_y1() = y - half_size; - item->property_y2() = y + half_size; - - _x = x; - _y = y; - _shape = shape; -} - -/*****/ - AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCanvas::Group& parent, boost::shared_ptr<AutomationList> al) : trackview (tv), _name (name), alist (al), _parent_group (parent) { + _interpolation = al->interpolation(); points_visible = false; update_pending = false; _vc_uses_gain_mapping = false; @@ -251,6 +87,8 @@ AutomationLine::AutomationLine (const string & name, TimeAxisView& tv, ArdourCan if (alist->parameter().type() == GainAutomation) set_verbose_cursor_uses_gain_mapping (true); + + set_interpolation(alist->interpolation()); } AutomationLine::~AutomationLine () @@ -277,7 +115,8 @@ AutomationLine::queue_reset () void AutomationLine::show () { - line->show(); + if (_interpolation != AutomationList::Discrete) + line->show(); if (points_visible) { for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { @@ -301,6 +140,11 @@ AutomationLine::hide () double AutomationLine::control_point_box_size () { + if (_interpolation == AutomationList::Discrete) { + return max((_height*4.0) / (double)(alist->parameter().max() - alist->parameter().min()), + 4.0); + } + if (_height > TimeAxisView::hLarger) { return 8.0; } else if (_height > (guint32) TimeAxisView::hNormal) { @@ -380,7 +224,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi y = min (1.0, y); y = _y_position + _height - (y * _height); - if (cp.can_slide) { + if (cp.can_slide()) { /* x-coord cannot move beyond adjacent points or the start/end, and is already in frames. it needs to be converted to canvas units. @@ -393,8 +237,8 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi ControlPoint *before; ControlPoint *after; - if (cp.view_index) { - before = nth (cp.view_index - 1); + if (cp.view_index()) { + before = nth (cp.view_index() - 1); x = max (x, before->get_x()+1.0); } else { before = &cp; @@ -402,9 +246,9 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi if (!with_push) { - if (cp.view_index < control_points.size() - 1) { + if (cp.view_index() < control_points.size() - 1) { - after = nth (cp.view_index + 1); + after = nth (cp.view_index() + 1); /*if it is a "spike" leave the x alone */ @@ -424,10 +268,10 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi /* find the first point that can't move */ - for (uint32_t n = cp.view_index + 1; (after = nth (n)) != 0; ++n) { - if (!after->can_slide) { + for (uint32_t n = cp.view_index() + 1; (after = nth (n)) != 0; ++n) { + if (!after->can_slide()) { x_limit = after->get_x() - 1.0; - last_movable = after->view_index; + last_movable = after->view_index(); break; } } @@ -439,7 +283,7 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi /* leave the x-coordinate alone */ - x = trackview.editor.frame_to_unit ((*cp.model)->when); + x = trackview.editor.frame_to_unit ((*cp.model())->when); } @@ -462,11 +306,11 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi /* now move all subsequent control points, to reflect the motion. */ - for (uint32_t i = cp.view_index + 1; i < limit; ++i) { + for (uint32_t i = cp.view_index() + 1; i < limit; ++i) { ControlPoint *p = nth (i); double new_x; - if (p->can_slide) { + if (p->can_slide()) { new_x = min (p->get_x() + delta, x_limit); p->move_to (new_x, p->get_y(), ControlPoint::Full); reset_line_coords (*p); @@ -478,9 +322,9 @@ AutomationLine::modify_view_point (ControlPoint& cp, double x, double y, bool wi void AutomationLine::reset_line_coords (ControlPoint& cp) { - if (cp.view_index < line_points.size()) { - line_points[cp.view_index].set_x (cp.get_x()); - line_points[cp.view_index].set_y (cp.get_y()); + if (cp.view_index() < line_points.size()) { + line_points[cp.view_index()].set_x (cp.get_x()); + line_points[cp.view_index()].set_y (cp.get_y()); } } @@ -511,8 +355,8 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) /* if xval has not changed, set it directly from the model to avoid rounding errors */ - if (mr.xval == trackview.editor.frame_to_unit((*cp.model)->when)) { - mr.xval = (nframes_t) (*cp.model)->when; + if (mr.xval == trackview.editor.frame_to_unit((*cp.model())->when)) { + mr.xval = (nframes_t) (*cp.model())->when; } else { mr.xval = trackview.editor.unit_to_frame (mr.xval); } @@ -526,8 +370,8 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) /* part 2: find out where the model point is now */ - mr.xpos = (nframes_t) (*cp.model)->when; - mr.ypos = (*cp.model)->value; + mr.xpos = (nframes_t) (*cp.model())->when; + mr.ypos = (*cp.model())->value; /* part 3: get the position of the visual control points before and after us. @@ -536,31 +380,31 @@ AutomationLine::model_representation (ControlPoint& cp, ModelRepresentation& mr) ControlPoint* before; ControlPoint* after; - if (cp.view_index) { - before = nth (cp.view_index - 1); + if (cp.view_index()) { + before = nth (cp.view_index() - 1); } else { before = 0; } - after = nth (cp.view_index + 1); + after = nth (cp.view_index() + 1); if (before) { - mr.xmin = (nframes_t) (*before->model)->when; - mr.ymin = (*before->model)->value; - mr.start = before->model; + mr.xmin = (nframes_t) (*before->model())->when; + mr.ymin = (*before->model())->value; + mr.start = before->model(); ++mr.start; } else { mr.xmin = mr.xpos; mr.ymin = mr.ypos; - mr.start = cp.model; + mr.start = cp.model(); } if (after) { - mr.end = after->model; + mr.end = after->model(); } else { mr.xmax = mr.xpos; mr.ymax = mr.ypos; - mr.end = cp.model; + mr.end = cp.model(); ++mr.end; } } @@ -678,21 +522,21 @@ AutomationLine::determine_visible_control_points (ALPoints& points) if (!terminal_points_can_slide) { if (pi == 0) { - control_points[view_index]->can_slide = false; + control_points[view_index]->set_can_slide(false); if (tx == 0) { shape = ControlPoint::Start; } else { shape = ControlPoint::Full; } } else if (pi == npoints - 1) { - control_points[view_index]->can_slide = false; + control_points[view_index]->set_can_slide(false); shape = ControlPoint::End; } else { - control_points[view_index]->can_slide = true; + control_points[view_index]->set_can_slide(true); shape = ControlPoint::Full; } } else { - control_points[view_index]->can_slide = true; + control_points[view_index]->set_can_slide(true); shape = ControlPoint::Full; } @@ -727,7 +571,7 @@ AutomationLine::determine_visible_control_points (ALPoints& points) } if (!terminal_points_can_slide) { - control_points.back()->can_slide = false; + control_points.back()->set_can_slide(false); } delete [] slope; @@ -753,9 +597,8 @@ AutomationLine::determine_visible_control_points (ALPoints& points) line->property_points() = line_points; - if (_visible) { - line->show (); - } + if (_visible && _interpolation != AutomationList::Discrete) + line->show(); } @@ -916,7 +759,7 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int /* change all points before the primary point */ - for (AutomationList::iterator i = mr.start; i != cp.model; ++i) { + for (AutomationList::iterator i = mr.start; i != cp.model(); ++i) { double fract = ((*i)->when - mr.xmin) / (mr.xpos - mr.xmin); double y_delta = ydelta * fract; @@ -932,12 +775,12 @@ AutomationLine::sync_model_with_view_point (ControlPoint& cp, bool did_push, int /* change the primary point */ update_pending = true; - alist->modify (cp.model, mr.xval, mr.yval); + alist->modify (cp.model(), mr.xval, mr.yval); /* change later points */ - AutomationList::iterator i = cp.model; + AutomationList::iterator i = cp.model(); ++i; @@ -982,12 +825,12 @@ AutomationLine::control_points_adjacent (double xval, uint32_t & before, uint32_ if (!bcp || (*i)->get_x() > bcp->get_x()) { bcp = *i; - before = bcp->view_index; + before = bcp->view_index(); } } else if ((*i)->get_x() > unit_xval) { acp = *i; - after = acp->view_index; + after = acp->view_index(); break; } } @@ -1067,7 +910,7 @@ AutomationLine::get_selectables (nframes_t& start, nframes_t& end, for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { - nframes_t when = (nframes_t) (*(*i)->model)->when; + nframes_t when = (nframes_t) (*(*i)->model())->when; if (when >= start && when <= end) { @@ -1111,7 +954,7 @@ AutomationLine::set_selected_points (PointSelection& points) double bot; for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->selected = false; + (*i)->set_selected(false); } if (points.empty()) { @@ -1140,7 +983,7 @@ AutomationLine::set_selected_points (PointSelection& points) if ((*i)->get_y() >= bot && (*i)->get_y() <= top) { - (*i)->selected = true; + (*i)->set_selected(true); } } @@ -1168,7 +1011,7 @@ AutomationLine::show_selection () for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { - (*i)->selected = false; + (*i)->set_selected(false); for (list<AudioRange>::iterator r = time.begin(); r != time.end(); ++r) { double rstart, rend; @@ -1177,7 +1020,7 @@ AutomationLine::show_selection () rend = trackview.editor.frame_to_unit ((*r).end); if ((*i)->get_x() >= rstart && (*i)->get_x() <= rend) { - (*i)->selected = true; + (*i)->set_selected(true); break; } } @@ -1267,6 +1110,7 @@ AutomationLine::show_all_control_points () points_visible = true; for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { + (*i)->show_color((_interpolation != AutomationList::Discrete), false); (*i)->show (); (*i)->set_visible (true); } @@ -1275,14 +1119,32 @@ AutomationLine::show_all_control_points () void AutomationLine::hide_all_but_selected_control_points () { + if (alist->interpolation() == AutomationList::Discrete) + return; + points_visible = false; for (vector<ControlPoint*>::iterator i = control_points.begin(); i != control_points.end(); ++i) { - if (!(*i)->selected) { + if (!(*i)->selected()) { (*i)->set_visible (false); } } } + +void +AutomationLine::track_entered() +{ + if (alist->interpolation() != AutomationList::Discrete) + show_all_control_points(); +} + +void +AutomationLine::track_exited() +{ + if (alist->interpolation() != AutomationList::Discrete) { + hide_all_but_selected_control_points(); + } +} XMLNode & AutomationLine::get_state (void) @@ -1330,3 +1192,18 @@ AutomationLine::model_to_view_y (double& y) } } + +void +AutomationLine::set_interpolation(AutomationList::InterpolationStyle style) +{ + _interpolation = style; + + if (style == AutomationList::Discrete) { + show_all_control_points(); + line->hide(); + } else { + hide_all_but_selected_control_points(); + line->show(); + } +} + diff --git a/gtk2_ardour/automation_line.h b/gtk2_ardour/automation_line.h index 3f01ae6cf9..6ce548e55d 100644 --- a/gtk2_ardour/automation_line.h +++ b/gtk2_ardour/automation_line.h @@ -53,48 +53,6 @@ namespace Gnome { } } -class ControlPoint -{ - public: - ControlPoint (AutomationLine& al); - ControlPoint (const ControlPoint&, bool dummy_arg_to_force_special_copy_constructor); - virtual ~ControlPoint (); - - enum ShapeType { - Full, - Start, - End - }; - - void move_to (double x, double y, ShapeType); - void reset (double x, double y, ARDOUR::AutomationList::iterator, uint32_t, ShapeType); - double get_x() const { return _x; } - double get_y() const { return _y; } - - void hide (); - void show (); - void show_color (bool entered, bool hide_too); - - void set_size (double); - void set_visible (bool); - - ArdourCanvas::SimpleRect* item; - AutomationLine& line; - uint32_t view_index; - ARDOUR::AutomationList::iterator model; - bool can_slide; - bool selected; - - protected: - virtual bool event_handler (GdkEvent*); - - private: - double _x; - double _y; - double _size; - ShapeType _shape; -}; - class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoingAway { public: @@ -129,9 +87,11 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin guint32 height() const { return _height; } guint32 y_position() const { return _y_position; } - void set_line_color (uint32_t); + void set_line_color (uint32_t); uint32_t get_line_color() const { return _line_color; } + void set_interpolation(ARDOUR::AutomationList::InterpolationStyle style); + void show (); void hide (); void set_y_position_and_height (uint32_t, uint32_t); @@ -155,6 +115,9 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin void show_all_control_points (); void hide_all_but_selected_control_points (); + void track_entered(); + void track_exited(); + bool is_last_point (ControlPoint &); bool is_first_point (ControlPoint &); @@ -215,6 +178,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin uint32_t line_drag_cp2; int64_t drag_x; int64_t drag_distance; + + ARDOUR::AutomationList::InterpolationStyle _interpolation; void modify_view_point(ControlPoint&, double, double, bool with_push); void reset_line_coords (ControlPoint&); diff --git a/gtk2_ardour/automation_time_axis.cc b/gtk2_ardour/automation_time_axis.cc index 5c5cd53dec..f14e70b52e 100644 --- a/gtk2_ardour/automation_time_axis.cc +++ b/gtk2_ardour/automation_time_axis.cc @@ -77,6 +77,9 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Ro auto_touch_item = 0; auto_write_item = 0; auto_play_item = 0; + mode_discrete_item = 0; + mode_line_item = 0; + ignore_state_request = false; first_call_to_set_height = true; @@ -321,6 +324,31 @@ AutomationTimeAxisView::automation_state_changed () } void +AutomationTimeAxisView::interpolation_changed () +{ + AutomationList::InterpolationStyle style = _control->list()->interpolation(); + + if (mode_line_item && mode_discrete_item) { + if (style == AutomationList::Discrete) { + mode_discrete_item->set_active(true); + mode_line_item->set_active(false); + } else { + mode_line_item->set_active(true); + mode_discrete_item->set_active(false); + } + } + + _line->set_interpolation(style); +} + +void +AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style) +{ + _control->list()->set_interpolation(style); + _line->set_interpolation(style); +} + +void AutomationTimeAxisView::height_clicked () { popup_size_menu (0); @@ -493,6 +521,8 @@ AutomationTimeAxisView::build_display_menu () items.push_back (MenuElem (_("Clear"), mem_fun(*this, &AutomationTimeAxisView::clear_clicked))); items.push_back (SeparatorElem()); + /* state menu */ + Menu* auto_state_menu = manage (new Menu); auto_state_menu->set_name ("ArdourContextMenu"); MenuList& as_items = auto_state_menu->items(); @@ -514,10 +544,35 @@ AutomationTimeAxisView::build_display_menu () auto_touch_item = dynamic_cast<CheckMenuItem*>(&as_items.back()); items.push_back (MenuElem (_("State"), *auto_state_menu)); + + /* mode menu */ + + if (_control->parameter().type() == MidiCCAutomation) { + Menu* auto_mode_menu = manage (new Menu); + auto_mode_menu->set_name ("ArdourContextMenu"); + MenuList& am_items = auto_mode_menu->items(); + + RadioMenuItem::Group group; + + am_items.push_back (RadioMenuElem (group, _("Discrete"), bind ( + mem_fun(*this, &AutomationTimeAxisView::set_interpolation), + AutomationList::Discrete))); + mode_discrete_item = dynamic_cast<CheckMenuItem*>(&am_items.back()); + //mode_discrete_item->set_active(_control->list()->interpolation() == AutomationList::Discrete); + + am_items.push_back (RadioMenuElem (group, _("Line"), bind ( + mem_fun(*this, &AutomationTimeAxisView::set_interpolation), + AutomationList::Linear))); + mode_line_item = dynamic_cast<CheckMenuItem*>(&am_items.back()); + //mode_line_item->set_active(_control->list()->interpolation() == AutomationList::Linear); + + items.push_back (MenuElem (_("Mode"), *auto_mode_menu)); + } /* make sure the automation menu state is correct */ automation_state_changed (); + interpolation_changed (); } void @@ -816,27 +871,15 @@ AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line) } void -AutomationTimeAxisView::show_all_control_points () -{ - _line->show_all_control_points (); -} - -void -AutomationTimeAxisView::hide_all_but_selected_control_points () -{ - _line->hide_all_but_selected_control_points (); -} - -void AutomationTimeAxisView::entered() { - show_all_control_points (); + _line->track_entered(); } void AutomationTimeAxisView::exited () { - hide_all_but_selected_control_points (); + _line->track_exited(); } void diff --git a/gtk2_ardour/automation_time_axis.h b/gtk2_ardour/automation_time_axis.h index c3be6ffd00..b708b6f58e 100644 --- a/gtk2_ardour/automation_time_axis.h +++ b/gtk2_ardour/automation_time_axis.h @@ -94,8 +94,6 @@ class AutomationTimeAxisView : public TimeAxisView { void add_ghost (GhostRegion*); void remove_ghost (GhostRegion*); - void show_all_control_points (); - void hide_all_but_selected_control_points (); void set_state (const XMLNode&); guint32 show_at (double y, int& nth, Gtk::VBox *parent); @@ -133,6 +131,9 @@ class AutomationTimeAxisView : public TimeAxisView { Gtk::CheckMenuItem* auto_touch_item; Gtk::CheckMenuItem* auto_write_item; + Gtk::CheckMenuItem* mode_discrete_item; + Gtk::CheckMenuItem* mode_line_item; + void add_line (boost::shared_ptr<AutomationLine>); void clear_clicked (); @@ -153,6 +154,10 @@ class AutomationTimeAxisView : public TimeAxisView { bool ignore_state_request; void automation_state_changed (); + + void set_interpolation (ARDOUR::AutomationList::InterpolationStyle); + void interpolation_changed (); + sigc::connection automation_connection; void update_extra_xml_shown (bool editor_shown); diff --git a/gtk2_ardour/control_point.cc b/gtk2_ardour/control_point.cc new file mode 100644 index 0000000000..b43826720c --- /dev/null +++ b/gtk2_ardour/control_point.cc @@ -0,0 +1,202 @@ +/* + Copyright (C) 2002-2007 Paul Davis + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include "control_point.h" +#include "diamond.h" +#include "automation_line.h" +#include "ardour_ui.h" +#include "public_editor.h" + +#include "i18n.h" + +using namespace std; +using namespace sigc; +using namespace ARDOUR; +using namespace PBD; +using namespace Gnome; // for Canvas + +ControlPoint::ControlPoint (AutomationLine& al) + : _line (al) +{ + _model = al.the_list()->end(); + _view_index = 0; + _can_slide = true; + _x = 0; + _y = 0; + _shape = Full; + _size = 4.0; + _selected = false; + + _item = new Canvas::SimpleRect (_line.canvas_group()); + _item->property_draw() = true; + _item->property_fill() = false; + _item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointFill.get(); + _item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointOutline.get(); + _item->property_outline_pixels() = 1; + _item->set_data ("control_point", this); + _item->signal_event().connect (mem_fun (this, &ControlPoint::event_handler)); + + hide (); + set_visible (false); +} + +ControlPoint::ControlPoint (const ControlPoint& other, bool dummy_arg_to_force_special_copy_constructor) + : _line (other._line) +{ + if (&other == this) { + return; + } + + _model = other._model; + _view_index = other._view_index; + _can_slide = other._can_slide; + _x = other._x; + _y = other._y; + _shape = other._shape; + _size = other._size; + _selected = false; + + _item = new Canvas::SimpleRect (_line.canvas_group()); + _item->property_fill() = false; + _item->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointOutline.get(); + _item->property_outline_pixels() = 1; + + /* NOTE: no event handling in copied ControlPoints */ + + hide (); + set_visible (false); +} + +ControlPoint::~ControlPoint () +{ + delete _item; +} + +bool +ControlPoint::event_handler (GdkEvent* event) +{ + return PublicEditor::instance().canvas_control_point_event (event, _item, this); +} + +void +ControlPoint::hide () +{ + _item->hide(); +} + +void +ControlPoint::show() +{ + _item->show(); +} + +void +ControlPoint::set_visible (bool yn) +{ + _item->property_draw() = (gboolean) yn; +} + +void +ControlPoint::reset (double x, double y, AutomationList::iterator mi, uint32_t vi, ShapeType shape) +{ + _model = mi; + _view_index = vi; + move_to (x, y, shape); +} + +void +ControlPoint::show_color (bool entered, bool hide_too) +{ + uint32_t color = 0; + + if (entered) { + if (_selected) { + color = ARDOUR_UI::config()->canvasvar_EnteredControlPointSelected.get(); + set_visible(true); + } else { + color = ARDOUR_UI::config()->canvasvar_EnteredControlPointOutline.get(); + if (hide_too) { + set_visible(false); + } + } + + } else { + if (_selected) { + color = ARDOUR_UI::config()->canvasvar_ControlPointSelected.get(); + set_visible(true); + } else { + color = ARDOUR_UI::config()->canvasvar_ControlPointOutline.get(); + if (hide_too) { + set_visible(false); + } + } + } + + _item->property_outline_color_rgba() = color; + _item->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ControlPointFill.get(); +} + +void +ControlPoint::set_size (double sz) +{ + _size = sz; + +#if 0 + if (_size > 6.0) { + item->property_fill() = (gboolean) TRUE; + } else { + item->property_fill() = (gboolean) FALSE; + } +#endif + + move_to (_x, _y, _shape); +} + +void +ControlPoint::move_to (double x, double y, ShapeType shape) +{ + double x1 = 0; + double x2 = 0; + double half_size = rint(_size/2.0); + + switch (shape) { + case Full: + x1 = x - half_size; + x2 = x + half_size; + break; + case Start: + x1 = x; + x2 = x + half_size; + break; + case End: + x1 = x - half_size; + x2 = x; + break; + } + + _item->property_x1() = x1; + _item->property_x2() = x2; + _item->property_y1() = y - half_size; + _item->property_y2() = y + half_size; + + _x = x; + _y = y; + _shape = shape; +} + diff --git a/gtk2_ardour/control_point.h b/gtk2_ardour/control_point.h new file mode 100644 index 0000000000..47b0d131b7 --- /dev/null +++ b/gtk2_ardour/control_point.h @@ -0,0 +1,102 @@ +/* + Copyright (C) 2002-2007 Paul Davis + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef __ardour_control_point_h__ +#define __ardour_control_point_h__ + +#include <sys/types.h> + +#include <ardour/automation_event.h> + +#include "canvas.h" +#include "simplerect.h" + +class AutomationLine; +class ControlPoint; +class PointSelection; +class TimeAxisView; +class AutomationTimeAxisView; +class Selectable; +class Selection; + +namespace Gnome { + namespace Canvas { + class SimpleRect; + class Diamond; + } +} + +class ControlPoint +{ + public: + ControlPoint (AutomationLine& al); + ControlPoint (const ControlPoint&, bool dummy_arg_to_force_special_copy_constructor); + virtual ~ControlPoint (); + + enum ShapeType { + Full, + Start, + End + }; + + void move_to (double x, double y, ShapeType); + void reset (double x, double y, ARDOUR::AutomationList::iterator, uint32_t, ShapeType); + double get_x() const { return _x; } + double get_y() const { return _y; } + + void hide (); + void show (); + void show_color (bool entered, bool hide_too); + + void set_size (double); + void set_visible (bool); + + bool can_slide() const { return _can_slide; } + void set_can_slide(bool yn) { _can_slide = yn; } + bool selected() const { return _selected; } + void set_selected(bool yn) { _selected = yn; } + uint32_t view_index() const { return _view_index; } + void set_view_index(uint32_t i) { _view_index = i; } + + ARDOUR::AutomationList::iterator model() const { return _model; } + AutomationLine& line() const { return _line; } + ArdourCanvas::Item* item() const { return _item; } + + protected: + ArdourCanvas::SimpleRect* _item; + + AutomationLine& _line; + + ARDOUR::AutomationList::iterator _model; + uint32_t _view_index; + bool _can_slide; + bool _selected; + + virtual bool event_handler (GdkEvent*); + + private: + double _x; + double _y; + double _size; + ShapeType _shape; +}; + + +#endif /* __ardour_control_point_h__ */ + diff --git a/gtk2_ardour/diamond.cc b/gtk2_ardour/diamond.cc new file mode 100644 index 0000000000..31761597cd --- /dev/null +++ b/gtk2_ardour/diamond.cc @@ -0,0 +1,35 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#include "diamond.h" + +using namespace Gnome::Canvas; +using namespace Gnome::Art; + +Diamond::Diamond(Group& group, double height) + : Polygon(group) +{ + Points points; + points.push_back(Point(0, height*2)); + points.push_back(Point(height, height)); + points.push_back(Point(0, 0)); + points.push_back(Point(-height, height)); + property_points() = points; +} + diff --git a/gtk2_ardour/diamond.h b/gtk2_ardour/diamond.h new file mode 100644 index 0000000000..a7f8c684ff --- /dev/null +++ b/gtk2_ardour/diamond.h @@ -0,0 +1,38 @@ +/* + Copyright (C) 2007 Paul Davis + Author: Dave Robillard + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. +*/ + +#ifndef __ardour_diamond_h__ +#define __ardour_diamond_h__ + +#include <libgnomecanvasmm/polygon.h> + +namespace Gnome { +namespace Canvas { + + +class Diamond : public Gnome::Canvas::Polygon { +public: + Diamond(Gnome::Canvas::Group& group, double height); +}; + + +} // namespace Canvas +} // namespace Gnome + +#endif /* __ardour_diamond_h__ */ diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc index 7ba3d9c537..a771fb51b4 100644 --- a/gtk2_ardour/editor.cc +++ b/gtk2_ardour/editor.cc @@ -2754,15 +2754,15 @@ Editor::duplicate_dialog (bool dup_region) void Editor::show_verbose_canvas_cursor () { - verbose_canvas_cursor->raise_to_top(); - verbose_canvas_cursor->show(); + verbose_canvas_cursor->raise_to_top(); + verbose_canvas_cursor->show(); verbose_cursor_visible = true; } void Editor::hide_verbose_canvas_cursor () { - verbose_canvas_cursor->hide(); + verbose_canvas_cursor->hide(); verbose_cursor_visible = false; } diff --git a/gtk2_ardour/editor_canvas_events.cc b/gtk2_ardour/editor_canvas_events.cc index e4908ccba9..394d35e245 100644 --- a/gtk2_ardour/editor_canvas_events.cc +++ b/gtk2_ardour/editor_canvas_events.cc @@ -36,6 +36,7 @@ #include "automation_line.h" #include "automation_time_axis.h" #include "automation_line.h" +#include "control_point.h" #include "canvas_impl.h" #include "simplerect.h" @@ -566,7 +567,7 @@ Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, C case GDK_2BUTTON_PRESS: case GDK_3BUTTON_PRESS: clicked_control_point = cp; - clicked_axisview = &cp->line.trackview; + clicked_axisview = &cp->line().trackview; clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview); clicked_regionview = 0; break; diff --git a/gtk2_ardour/editor_mouse.cc b/gtk2_ardour/editor_mouse.cc index fe17b31abf..406eda01db 100644 --- a/gtk2_ardour/editor_mouse.cc +++ b/gtk2_ardour/editor_mouse.cc @@ -39,6 +39,7 @@ #include "streamview.h" #include "region_gain_line.h" #include "automation_time_axis.h" +#include "control_point.h" #include "prompter.h" #include "utils.h" #include "selection.h" @@ -1019,13 +1020,13 @@ Editor::enter_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ double at_x, at_y; at_x = cp->get_x(); at_y = cp->get_y (); - cp->item->i2w (at_x, at_y); + cp->item()->i2w (at_x, at_y); at_x += 20.0; at_y += 20.0; - fraction = 1.0 - (cp->get_y() / cp->line.height()); + fraction = 1.0 - (cp->get_y() / cp->line().height()); - set_verbose_canvas_cursor (cp->line.get_verbose_cursor_string (fraction), at_x, at_y); + set_verbose_canvas_cursor (cp->line().get_verbose_cursor_string (fraction), at_x, at_y); show_verbose_canvas_cursor (); if (is_drawable()) { @@ -1196,8 +1197,8 @@ Editor::leave_handler (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_ switch (item_type) { case ControlPointItem: cp = reinterpret_cast<ControlPoint*>(item->get_data ("control_point")); - if (cp->line.npoints() > 1) { - if (!cp->selected) { + if (cp->line().the_list()->interpolation() != AutomationList::Discrete) { + if (cp->line().npoints() > 1 && !cp->selected()) { cp->set_visible (false); } } @@ -2334,16 +2335,16 @@ Editor::remove_gain_control_point (ArdourCanvas::Item*item, GdkEvent* event) } // We shouldn't remove the first or last gain point - if (control_point->line.is_last_point(*control_point) || - control_point->line.is_first_point(*control_point)) { + if (control_point->line().is_last_point(*control_point) || + control_point->line().is_first_point(*control_point)) { return; } - control_point->line.remove_point (*control_point); + control_point->line().remove_point (*control_point); } void -Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event) +Editor::remove_control_point (ArdourCanvas::Item* item, GdkEvent* event) { ControlPoint* control_point; @@ -2352,7 +2353,7 @@ Editor::remove_control_point (ArdourCanvas::Item*item, GdkEvent* event) /*NOTREACHED*/ } - control_point->line.remove_point (*control_point); + control_point->line().remove_point (*control_point); } void @@ -2372,10 +2373,10 @@ Editor::start_control_point_grab (ArdourCanvas::Item* item, GdkEvent* event) start_grab (event, fader_cursor); - control_point->line.start_drag (control_point, drag_info.grab_frame, 0); + control_point->line().start_drag (control_point, drag_info.grab_frame, 0); - double fraction = 1.0 - ((control_point->get_y() - control_point->line.y_position()) / (double)control_point->line.height()); - set_verbose_canvas_cursor (control_point->line.get_verbose_cursor_string (fraction), + double fraction = 1.0 - ((control_point->get_y() - control_point->line().y_position()) / (double)control_point->line().height()); + set_verbose_canvas_cursor (control_point->line().get_verbose_cursor_string (fraction), drag_info.current_pointer_x + 20, drag_info.current_pointer_y + 20); show_verbose_canvas_cursor (); @@ -2399,11 +2400,11 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* cy = drag_info.grab_y; } - cp->line.parent_group().w2i (cx, cy); + cp->line().parent_group().w2i (cx, cy); cx = max (0.0, cx); cy = max (0.0, cy); - cy = min ((double) (cp->line.y_position() + cp->line.height()), cy); + cy = min ((double) (cp->line().y_position() + cp->line().height()), cy); //translate cx to frames nframes_t cx_frames = unit_to_frame (cx); @@ -2412,7 +2413,7 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* snap_to (cx_frames); } - const double fraction = 1.0 - ((cy - cp->line.y_position()) / (double)cp->line.height()); + const double fraction = 1.0 - ((cy - cp->line().y_position()) / (double)cp->line().height()); bool push; @@ -2422,9 +2423,9 @@ Editor::control_point_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* push = false; } - cp->line.point_drag (*cp, cx_frames , fraction, push); + cp->line().point_drag (*cp, cx_frames , fraction, push); - set_verbose_canvas_cursor_text (cp->line.get_verbose_cursor_string (fraction)); + set_verbose_canvas_cursor_text (cp->line().get_verbose_cursor_string (fraction)); drag_info.first_move = false; } @@ -2445,7 +2446,7 @@ Editor::control_point_drag_finished_callback (ArdourCanvas::Item* item, GdkEvent } else { control_point_drag_motion_callback (item, event); } - cp->line.end_drag (cp); + cp->line().end_drag (cp); } void diff --git a/gtk2_ardour/editor_selection.cc b/gtk2_ardour/editor_selection.cc index 3f3edfe65b..41b6d32a0b 100644 --- a/gtk2_ardour/editor_selection.cc +++ b/gtk2_ardour/editor_selection.cc @@ -29,6 +29,7 @@ #include "audio_region_view.h" #include "audio_streamview.h" #include "automation_line.h" +#include "control_point.h" #include "i18n.h" diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc index 80e239e660..e4cb80bca0 100644 --- a/gtk2_ardour/midi_region_view.cc +++ b/gtk2_ardour/midi_region_view.cc @@ -36,6 +36,7 @@ #include "midi_time_axis.h" #include "simplerect.h" #include "simpleline.h" +#include "diamond.h" #include "public_editor.h" #include "ghostregion.h" #include "midi_time_axis.h" @@ -96,12 +97,20 @@ MidiRegionView::init (Gdk::Color& basic_color, bool wfd) void -MidiRegionView::display_events() +MidiRegionView::clear_events() { for (std::vector<ArdourCanvas::Item*>::iterator i = _events.begin(); i != _events.end(); ++i) delete *i; _events.clear(); +} + + +void +MidiRegionView::display_events() +{ + clear_events(); + begin_write(); for (size_t i=0; i < midi_region()->midi_source(0)->model()->n_events(); ++i) @@ -182,8 +191,6 @@ MidiRegionView::add_ghost (AutomationTimeAxisView& atv) double unit_position = _region->position () / samples_per_unit; GhostRegion* ghost = new GhostRegion (atv, unit_position); - cerr << "FIXME: add notes to MIDI region ghost." << endl; - ghost->set_height (); ghost->set_duration (_region->length() / samples_per_unit); ghosts.push_back (ghost); @@ -226,42 +233,56 @@ MidiRegionView::add_event (const MidiEvent& ev) MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview); MidiStreamView* const view = mtv->midi_view(); - + ArdourCanvas::Group* const group = (ArdourCanvas::Group*)get_canvas_group(); + const uint8_t note_range = view->highest_note() - view->lowest_note() + 1; const double footer_height = name_highlight->property_y2() - name_highlight->property_y1(); const double pixel_range = (trackview.height - footer_height - 5.0) / (double)note_range; - if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) { + if (mtv->note_mode() == Note) { + if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_ON) { + const Byte& note = ev.buffer[1]; + const double y1 = trackview.height - (pixel_range * (note - view->lowest_note() + 1)) + - footer_height - 3.0; + + ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect(*group); + ev_rect->property_x1() = trackview.editor.frame_to_pixel ( + (nframes_t)ev.time); + ev_rect->property_y1() = y1; + ev_rect->property_x2() = trackview.editor.frame_to_pixel ( + _region->length()); + ev_rect->property_y2() = y1 + ceil(pixel_range); + ev_rect->property_outline_color_rgba() = 0xFFFFFFAA; + /* outline all but right edge */ + ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8); + ev_rect->property_fill_color_rgba() = 0xFFFFFF66; + + _events.push_back(ev_rect); + if (_active_notes) + _active_notes[note] = ev_rect; + + } else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { + const Byte& note = ev.buffer[1]; + if (_active_notes && _active_notes[note]) { + _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)ev.time); + _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges + _active_notes[note] = NULL; + } + } + + } else if (mtv->note_mode() == Percussion) { const Byte& note = ev.buffer[1]; - const double y1 = trackview.height - (pixel_range * (note - view->lowest_note() + 1)) + const double x = trackview.editor.frame_to_pixel((nframes_t)ev.time); + const double y = trackview.height - (pixel_range * (note - view->lowest_note() + 1)) - footer_height - 3.0; - ArdourCanvas::SimpleRect * ev_rect = new Gnome::Canvas::SimpleRect( - *(ArdourCanvas::Group*)get_canvas_group()); - ev_rect->property_x1() = trackview.editor.frame_to_pixel ( - (nframes_t)ev.time); - ev_rect->property_y1() = y1; - ev_rect->property_x2() = trackview.editor.frame_to_pixel ( - _region->length()); - ev_rect->property_y2() = y1 + ceil(pixel_range); - ev_rect->property_outline_color_rgba() = 0xFFFFFFAA; - /* outline all but right edge */ - ev_rect->property_outline_what() = (guint32) (0x1 & 0x4 & 0x8); - ev_rect->property_fill_color_rgba() = 0xFFFFFF66; - - _events.push_back(ev_rect); - if (_active_notes) - _active_notes[note] = ev_rect; - - } else if ((ev.buffer[0] & 0xF0) == MIDI_CMD_NOTE_OFF) { - const Byte& note = ev.buffer[1]; - if (_active_notes && _active_notes[note]) { - _active_notes[note]->property_x2() = trackview.editor.frame_to_pixel((nframes_t)ev.time); - _active_notes[note]->property_outline_what() = (guint32) 0xF; // all edges - _active_notes[note] = NULL; - } + Diamond* ev_diamond = new Diamond(*group, std::min(pixel_range, 5.0)); + ev_diamond->move(x, y); + ev_diamond->show(); + ev_diamond->property_outline_color_rgba() = 0xFFFFFFDD; + ev_diamond->property_fill_color_rgba() = 0xFFFFFF66; + _events.push_back(ev_diamond); } - } diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h index e8175fe069..88ef43243b 100644 --- a/gtk2_ardour/midi_region_view.h +++ b/gtk2_ardour/midi_region_view.h @@ -93,6 +93,7 @@ class MidiRegionView : public RegionView private: void display_events(); + void clear_events(); std::vector<ArdourCanvas::Item*> _events; ArdourCanvas::SimpleRect** _active_notes; diff --git a/gtk2_ardour/midi_streamview.h b/gtk2_ardour/midi_streamview.h index 0122eb4e1b..ce459e2fad 100644 --- a/gtk2_ardour/midi_streamview.h +++ b/gtk2_ardour/midi_streamview.h @@ -60,6 +60,8 @@ class MidiStreamView : public StreamView uint8_t lowest_note() const { return _lowest_note; } uint8_t highest_note() const { return _highest_note; } + + void redisplay_diskstream (); private: void setup_rec_box (); @@ -69,8 +71,6 @@ class MidiStreamView : public StreamView RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves); void display_region(MidiRegionView* region_view, bool redisplay_events); - void redisplay_diskstream (); - void color_handler (); uint8_t _lowest_note; diff --git a/gtk2_ardour/midi_time_axis.cc b/gtk2_ardour/midi_time_axis.cc index a843659cbc..48aa78dc06 100644 --- a/gtk2_ardour/midi_time_axis.cc +++ b/gtk2_ardour/midi_time_axis.cc @@ -79,8 +79,10 @@ using namespace Editing; MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shared_ptr<Route> rt, Canvas& canvas) - : AxisView(sess), // FIXME: won't compile without this, why?? - RouteTimeAxisView(ed, sess, rt, canvas) + : AxisView(sess) // FIXME: won't compile without this, why?? + , RouteTimeAxisView(ed, sess, rt, canvas) + , _note_mode_item(NULL) + , _percussion_mode_item(NULL) { subplugin_menu.set_name ("ArdourContextMenu"); @@ -91,10 +93,12 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shar mute_button->set_active (false); solo_button->set_active (false); - if (is_midi_track()) + if (is_midi_track()) { controls_ebox.set_name ("MidiTimeAxisViewControlsBaseUnselected"); - else // bus + _note_mode = midi_track()->note_mode(); + } else { // MIDI bus (which doesn't exist yet..) controls_ebox.set_name ("MidiBusControlsBaseUnselected"); + } /* map current state of the route */ @@ -167,6 +171,39 @@ MidiTimeAxisView::build_automation_action_menu () mem_fun(*this, &MidiTimeAxisView::add_controller_track))); } +Gtk::Menu* +MidiTimeAxisView::build_mode_menu() +{ + using namespace Menu_Helpers; + + Menu* mode_menu = manage (new Menu); + MenuList& items = mode_menu->items(); + mode_menu->set_name ("ArdourContextMenu"); + + RadioMenuItem::Group mode_group; + items.push_back (RadioMenuElem (mode_group, _("Note"), + bind (mem_fun (*this, &MidiTimeAxisView::set_note_mode), Note))); + _note_mode_item = dynamic_cast<RadioMenuItem*>(&items.back()); + _note_mode_item->set_active(_note_mode == Note); + + items.push_back (RadioMenuElem (mode_group, _("Percussion"), + bind (mem_fun (*this, &MidiTimeAxisView::set_note_mode), Percussion))); + _percussion_mode_item = dynamic_cast<RadioMenuItem*>(&items.back()); + _percussion_mode_item->set_active(_note_mode == Percussion); + + return mode_menu; +} + +void +MidiTimeAxisView::set_note_mode(NoteMode mode) +{ + if (_note_mode != mode) { + _note_mode = mode; + midi_track()->set_note_mode(mode); + _view->redisplay_diskstream(); + } +} + /** Prompt for a controller with a dialog and add an automation track for it */ void diff --git a/gtk2_ardour/midi_time_axis.h b/gtk2_ardour/midi_time_axis.h index 6a5ba07a38..039affd979 100644 --- a/gtk2_ardour/midi_time_axis.h +++ b/gtk2_ardour/midi_time_axis.h @@ -66,15 +66,24 @@ class MidiTimeAxisView : public RouteTimeAxisView void add_controller_track (); void create_automation_child (ARDOUR::Parameter param, bool show); + ARDOUR::NoteMode note_mode() const { return _note_mode; } + private: void build_automation_action_menu (); - + Gtk::Menu* build_mode_menu(); + + void set_note_mode(ARDOUR::NoteMode mode); + void route_active_changed (); void add_insert_to_subplugin_menu (ARDOUR::Processor *); - Gtk::Menu subplugin_menu; + Gtk::Menu _subplugin_menu; + + ARDOUR::NoteMode _note_mode; + Gtk::RadioMenuItem* _note_mode_item; + Gtk::RadioMenuItem* _percussion_mode_item; }; #endif /* __ardour_midi_time_axis_h__ */ diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc index caead7fdd1..e0d93bd41a 100644 --- a/gtk2_ardour/route_time_axis.cc +++ b/gtk2_ardour/route_time_axis.cc @@ -521,25 +521,11 @@ RouteTimeAxisView::build_display_menu () items.push_back (MenuElem (_("Alignment"), *alignment_menu)); get_diskstream()->AlignmentStyleChanged.connect ( - mem_fun(*this, &RouteTimeAxisView::align_style_changed)); - - RadioMenuItem::Group mode_group; - items.push_back (RadioMenuElem (mode_group, _("Normal mode"), - bind (mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Normal))); - normal_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back()); - items.push_back (RadioMenuElem (mode_group, _("Tape mode"), - bind (mem_fun (*this, &RouteTimeAxisView::set_track_mode), ARDOUR::Destructive))); - destructive_track_mode_item = dynamic_cast<RadioMenuItem*>(&items.back()); - + mem_fun(*this, &RouteTimeAxisView::align_style_changed)); - switch (track()->mode()) { - case ARDOUR::Destructive: - destructive_track_mode_item->set_active (); - break; - case ARDOUR::Normal: - normal_track_mode_item->set_active (); - break; - } + mode_menu = build_mode_menu(); + if (mode_menu) + items.push_back (MenuElem (_("Mode"), *mode_menu)); } items.push_back (SeparatorElem()); diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h index 0a6c3f0173..0d42f331a9 100644 --- a/gtk2_ardour/route_time_axis.h +++ b/gtk2_ardour/route_time_axis.h @@ -247,6 +247,9 @@ protected: Gtk::Menu* playlist_menu; Gtk::Menu* playlist_action_menu; Gtk::MenuItem* playlist_item; + Gtk::Menu* mode_menu; + + virtual Gtk::Menu* build_mode_menu() { return NULL; } void use_playlist (boost::weak_ptr<ARDOUR::Playlist>); diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h index 389000c7ef..3c9bd43666 100644 --- a/gtk2_ardour/streamview.h +++ b/gtk2_ardour/streamview.h @@ -93,6 +93,8 @@ public: void add_region_view (boost::shared_ptr<ARDOUR::Region>); void region_layered (RegionView*); + virtual void redisplay_diskstream () = 0; + sigc::signal<void,RegionView*> RegionViewAdded; protected: @@ -114,7 +116,6 @@ protected: void display_diskstream (boost::shared_ptr<ARDOUR::Diskstream>); virtual void undisplay_diskstream (); - virtual void redisplay_diskstream () = 0; void diskstream_changed (); virtual void playlist_changed (boost::shared_ptr<ARDOUR::Diskstream>); |