Note modes: note, percussion.
Percussion tracks display diamonds. Separated/fixed MIDI and audio mode menus. CC automation modes: discrete, line. Bar controllers follow setting (hard steps or line) on playback. Sent CC data is always discrete (line not implemented yet). Discrete tracks show no lines, and always show control points. Separated ControlPoint from AutomationLine. Added some basic information (range) to Parameter (to be fleshed out..). git-svn-id: svn://localhost/ardour2/trunk@2123 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
f87954eeb5
commit
68653307e6
@ -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
|
||||
|
@ -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"/>
|
||||
|
@ -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"
|
||||
@ -962,7 +963,7 @@ 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);
|
||||
audio_region()->envelope()->erase (cp->model());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -219,6 +219,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 ()
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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,6 +115,7 @@ AutomationLine::queue_reset ()
|
||||
void
|
||||
AutomationLine::show ()
|
||||
{
|
||||
if (_interpolation != AutomationList::Discrete)
|
||||
line->show();
|
||||
|
||||
if (points_visible) {
|
||||
@ -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) {
|
||||
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,15 +1119,33 @@ 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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:
|
||||
@ -132,6 +90,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
|
||||
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 &);
|
||||
|
||||
@ -216,6 +179,8 @@ class AutomationLine : public sigc::trackable, public PBD::StatefulThingWithGoin
|
||||
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&);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -320,6 +323,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 ()
|
||||
{
|
||||
@ -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();
|
||||
@ -515,9 +545,34 @@ AutomationTimeAxisView::build_display_menu ()
|
||||
|
||||
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
|
||||
@ -815,28 +870,16 @@ AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
|
||||
line->show();
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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);
|
||||
|
202
gtk2_ardour/control_point.cc
Normal file
202
gtk2_ardour/control_point.cc
Normal file
@ -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;
|
||||
}
|
||||
|
102
gtk2_ardour/control_point.h
Normal file
102
gtk2_ardour/control_point.h
Normal file
@ -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__ */
|
||||
|
35
gtk2_ardour/diamond.cc
Normal file
35
gtk2_ardour/diamond.cc
Normal file
@ -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;
|
||||
}
|
||||
|
38
gtk2_ardour/diamond.h
Normal file
38
gtk2_ardour/diamond.h
Normal file
@ -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__ */
|
@ -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;
|
||||
|
@ -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,12 +2335,12 @@ 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
|
||||
@ -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
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "audio_region_view.h"
|
||||
#include "audio_streamview.h"
|
||||
#include "automation_line.h"
|
||||
#include "control_point.h"
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
|
@ -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,18 +233,19 @@ 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 (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(
|
||||
*(ArdourCanvas::Group*)get_canvas_group());
|
||||
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;
|
||||
@ -262,6 +270,19 @@ MidiRegionView::add_event (const MidiEvent& ev)
|
||||
}
|
||||
}
|
||||
|
||||
} else if (mtv->note_mode() == Percussion) {
|
||||
const Byte& note = ev.buffer[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;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -93,6 +93,7 @@ class MidiRegionView : public RegionView
|
||||
private:
|
||||
|
||||
void display_events();
|
||||
void clear_events();
|
||||
|
||||
std::vector<ArdourCanvas::Item*> _events;
|
||||
ArdourCanvas::SimpleRect** _active_notes;
|
||||
|
@ -61,6 +61,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 ();
|
||||
void rec_data_range_ready (boost::shared_ptr<ARDOUR::MidiBuffer> data, jack_nframes_t start, jack_nframes_t dur, boost::weak_ptr<ARDOUR::Source> src);
|
||||
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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__ */
|
||||
|
@ -523,23 +523,9 @@ RouteTimeAxisView::build_display_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());
|
||||
|
||||
|
||||
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());
|
||||
|
@ -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>);
|
||||
|
||||
|
@ -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>);
|
||||
|
@ -229,6 +229,15 @@ class AutomationList : public PBD::StatefulDestructible
|
||||
Curve& curve() { return *_curve; }
|
||||
const Curve& curve() const { return *_curve; }
|
||||
|
||||
enum InterpolationStyle {
|
||||
Discrete,
|
||||
Linear,
|
||||
Curved
|
||||
};
|
||||
|
||||
InterpolationStyle interpolation() const { return _interpolation; }
|
||||
void set_interpolation(InterpolationStyle style) { _interpolation = style; }
|
||||
|
||||
protected:
|
||||
|
||||
/** Called by unlocked_eval() to handle cases of 3 or more control points.
|
||||
@ -247,6 +256,7 @@ class AutomationList : public PBD::StatefulDestructible
|
||||
mutable SearchCache _search_cache;
|
||||
|
||||
Parameter _parameter;
|
||||
InterpolationStyle _interpolation;
|
||||
EventList _events;
|
||||
mutable Glib::Mutex _lock;
|
||||
int8_t _frozen;
|
||||
|
@ -57,7 +57,7 @@ public:
|
||||
int use_diskstream (string name);
|
||||
int use_diskstream (const PBD::ID& id);
|
||||
|
||||
int set_mode (TrackMode m);
|
||||
//int set_mode (TrackMode m);
|
||||
|
||||
void set_latency_delay (nframes_t);
|
||||
|
||||
@ -85,6 +85,9 @@ public:
|
||||
MidiTrack* _route;
|
||||
};
|
||||
|
||||
NoteMode note_mode() const { return _note_mode; }
|
||||
void set_note_mode (NoteMode m) { _note_mode = m; }
|
||||
|
||||
protected:
|
||||
|
||||
XMLNode& state (bool full);
|
||||
@ -101,6 +104,7 @@ private:
|
||||
void set_state_part_three ();
|
||||
|
||||
MidiRingBuffer _immediate_events;
|
||||
NoteMode _note_mode;
|
||||
};
|
||||
|
||||
} /* namespace ARDOUR*/
|
||||
|
@ -127,6 +127,28 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/* The below properties are only used for CC right now, but unchanging properties
|
||||
* of parameters (rather than changing parameters of automation lists themselves)
|
||||
* should be moved here */
|
||||
|
||||
inline double min() const {
|
||||
if (_type == MidiCCAutomation)
|
||||
return 0.0;
|
||||
else
|
||||
return DBL_MIN;
|
||||
}
|
||||
|
||||
inline double max() const {
|
||||
if (_type == MidiCCAutomation)
|
||||
return 127.0;
|
||||
else
|
||||
return DBL_MAX;
|
||||
}
|
||||
|
||||
inline bool is_integer() const {
|
||||
return (_type == MidiCCAutomation);
|
||||
}
|
||||
|
||||
private:
|
||||
// default copy constructor is ok
|
||||
AutomationType _type;
|
||||
|
@ -143,6 +143,11 @@ namespace ARDOUR {
|
||||
Destructive
|
||||
};
|
||||
|
||||
enum NoteMode {
|
||||
Note,
|
||||
Percussion
|
||||
};
|
||||
|
||||
struct BBT_Time {
|
||||
uint32_t bars;
|
||||
uint32_t beats;
|
||||
|
@ -463,3 +463,4 @@ Automatable::control_factory(boost::shared_ptr<AutomationList> list)
|
||||
return boost::shared_ptr<AutomationControl>(new AutomationControl(_session, list));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,6 @@ AutomationControl::AutomationControl(Session& session, boost::shared_ptr<Automat
|
||||
, _list(list)
|
||||
, _user_value(list->default_value())
|
||||
{
|
||||
cerr << "Created AutomationControl " << name << "(" << list->parameter().to_string() << ")" << endl;
|
||||
}
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <ardour/automation_event.h>
|
||||
#include <ardour/curve.h>
|
||||
#include <pbd/stacktrace.h>
|
||||
#include <pbd/enumwriter.h>
|
||||
|
||||
#include "i18n.h"
|
||||
|
||||
@ -56,6 +57,7 @@ static void dumpit (const AutomationList& al, string prefix = "")
|
||||
|
||||
AutomationList::AutomationList (Parameter id, double min_val, double max_val, double default_val)
|
||||
: _parameter(id)
|
||||
, _interpolation(Linear)
|
||||
, _curve(new Curve(*this))
|
||||
{
|
||||
_parameter = id;
|
||||
@ -81,6 +83,7 @@ AutomationList::AutomationList (Parameter id, double min_val, double max_val, do
|
||||
|
||||
AutomationList::AutomationList (const AutomationList& other)
|
||||
: _parameter(other._parameter)
|
||||
, _interpolation(Linear)
|
||||
, _curve(new Curve(*this))
|
||||
{
|
||||
_frozen = 0;
|
||||
@ -108,6 +111,7 @@ AutomationList::AutomationList (const AutomationList& other)
|
||||
|
||||
AutomationList::AutomationList (const AutomationList& other, double start, double end)
|
||||
: _parameter(other._parameter)
|
||||
, _interpolation(Linear)
|
||||
, _curve(new Curve(*this))
|
||||
{
|
||||
_frozen = 0;
|
||||
@ -146,7 +150,8 @@ AutomationList::AutomationList (const AutomationList& other, double start, doubl
|
||||
* in or below the <AutomationList> node. It is used if \a id is non-null.
|
||||
*/
|
||||
AutomationList::AutomationList (const XMLNode& node, Parameter id)
|
||||
: _curve(new Curve(*this))
|
||||
: _interpolation(Linear)
|
||||
, _curve(new Curve(*this))
|
||||
{
|
||||
_frozen = 0;
|
||||
_changed_when_thawed = false;
|
||||
@ -925,6 +930,9 @@ AutomationList::unlocked_eval (double x) const
|
||||
upos = _events.back()->when;
|
||||
uval = _events.back()->value;
|
||||
|
||||
if (_interpolation == Discrete)
|
||||
return lval;
|
||||
|
||||
/* linear interpolation betweeen the two points
|
||||
*/
|
||||
|
||||
@ -954,6 +962,22 @@ AutomationList::multipoint_eval (double x) const
|
||||
double uval, lval;
|
||||
double fraction;
|
||||
|
||||
/* "Stepped" lookup (no interpolation) */
|
||||
/* FIXME: no cache. significant? */
|
||||
if (_interpolation == Discrete) {
|
||||
const ControlEvent cp (x, 0);
|
||||
TimeComparator cmp;
|
||||
EventList::const_iterator i = lower_bound (_events.begin(), _events.end(), &cp, cmp);
|
||||
|
||||
// shouldn't have made it to multipoint_eval
|
||||
assert(i != _events.end());
|
||||
|
||||
if (i == _events.begin() || (*i)->when == x)
|
||||
return (*i)->value;
|
||||
else
|
||||
return (*(--i))->value;
|
||||
}
|
||||
|
||||
/* Only do the range lookup if x is in a different range than last time
|
||||
* this was called (or if the lookup cache has been marked "dirty" (left<0) */
|
||||
if ((_lookup_cache.left < 0) ||
|
||||
@ -1280,6 +1304,8 @@ AutomationList::state (bool full)
|
||||
snprintf (buf, sizeof (buf), "%.12g", _max_xval);
|
||||
root->add_property ("max_xval", buf);
|
||||
|
||||
root->add_property ("interpolation-style", enum_2_string (_interpolation));
|
||||
|
||||
if (full) {
|
||||
root->add_property ("state", auto_state_to_string (_state));
|
||||
} else {
|
||||
@ -1438,6 +1464,12 @@ AutomationList::set_state (const XMLNode& node)
|
||||
warning << "Legacy session: automation list has no automation-id property.";
|
||||
}
|
||||
|
||||
if ((prop = node.property (X_("interpolation-style"))) != 0) {
|
||||
_interpolation = (InterpolationStyle)string_2_enum(prop->value(), _interpolation);
|
||||
} else {
|
||||
_interpolation = Linear;
|
||||
}
|
||||
|
||||
if ((prop = node.property (X_("default"))) != 0){
|
||||
_default_value = atof (prop->value().c_str());
|
||||
} else {
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include <ardour/route_group.h>
|
||||
#include <ardour/panner.h>
|
||||
#include <ardour/track.h>
|
||||
#include <ardour/midi_track.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace PBD;
|
||||
@ -44,6 +45,7 @@ setup_enum_writer ()
|
||||
AlignStyle _AlignStyle;
|
||||
MeterPoint _MeterPoint;
|
||||
TrackMode _TrackMode;
|
||||
NoteMode _NoteMode;
|
||||
MeterFalloff _MeterFalloff;
|
||||
MeterHold _MeterHold;
|
||||
EditMode _EditMode;
|
||||
@ -81,6 +83,7 @@ setup_enum_writer ()
|
||||
RouteGroup::Flag _RouteGroup_Flag;
|
||||
Region::Flag _Region_Flag;
|
||||
Track::FreezeState _Track_FreezeState;
|
||||
AutomationList::InterpolationStyle _AutomationList_InterpolationStyle;
|
||||
|
||||
#define REGISTER(e) enum_writer->register_distinct (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||
#define REGISTER_BITS(e) enum_writer->register_bits (typeid(e).name(), i, s); i.clear(); s.clear()
|
||||
@ -133,6 +136,10 @@ setup_enum_writer ()
|
||||
REGISTER_ENUM (Destructive);
|
||||
REGISTER (_TrackMode);
|
||||
|
||||
REGISTER_ENUM (Note);
|
||||
REGISTER_ENUM (Percussion);
|
||||
REGISTER (_NoteMode);
|
||||
|
||||
REGISTER_ENUM (MeterFalloffOff);
|
||||
REGISTER_ENUM (MeterFalloffSlowest);
|
||||
REGISTER_ENUM (MeterFalloffSlow);
|
||||
@ -361,4 +368,9 @@ setup_enum_writer ()
|
||||
REGISTER_CLASS_ENUM (Track, UnFrozen);
|
||||
REGISTER (_Track_FreezeState);
|
||||
|
||||
REGISTER_CLASS_ENUM (AutomationList, Discrete);
|
||||
REGISTER_CLASS_ENUM (AutomationList, Linear);
|
||||
REGISTER_CLASS_ENUM (AutomationList, Curved);
|
||||
REGISTER (_AutomationList_InterpolationStyle);
|
||||
|
||||
}
|
||||
|
@ -161,10 +161,15 @@ MidiTrack::_set_state (const XMLNode& node, bool call_base)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((prop = node.property (X_("mode"))) != 0) {
|
||||
_mode = TrackMode (string_2_enum (prop->value(), _mode));
|
||||
} else {
|
||||
// No destructive MIDI tracks (yet?)
|
||||
_mode = Normal;
|
||||
|
||||
if ((prop = node.property (X_("note-mode"))) != 0) {
|
||||
_note_mode = NoteMode (string_2_enum (prop->value(), _note_mode));
|
||||
cerr << "NOTE MODE: " << prop->value() << " -> " << _note_mode << endl;
|
||||
} else {
|
||||
cerr << "NO NOTE MODE" << endl;
|
||||
_note_mode = Note;
|
||||
}
|
||||
|
||||
if ((prop = node.property ("diskstream-id")) == 0) {
|
||||
@ -245,7 +250,7 @@ MidiTrack::state(bool full_state)
|
||||
align_node->add_property (X_("style"), enum_2_string (as));
|
||||
root.add_child_nocopy (*align_node);
|
||||
|
||||
root.add_property (X_("mode"), enum_2_string (_mode));
|
||||
root.add_property (X_("note-mode"), enum_2_string (_note_mode));
|
||||
|
||||
/* we don't return diskstream state because we don't
|
||||
own the diskstream exclusively. control of the diskstream
|
||||
@ -682,7 +687,7 @@ MidiTrack::unfreeze ()
|
||||
_freeze_record.state = UnFrozen;
|
||||
FreezeChange (); /* EMIT SIGNAL */
|
||||
}
|
||||
|
||||
#if 0
|
||||
int
|
||||
MidiTrack::set_mode (TrackMode m)
|
||||
{
|
||||
@ -701,6 +706,7 @@ MidiTrack::set_mode (TrackMode m)
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/** \return true on success, false on failure (no buffer space left)
|
||||
*/
|
||||
|
Loading…
Reference in New Issue
Block a user