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:
David Robillard 2007-07-07 03:19:04 +00:00
parent f87954eeb5
commit 68653307e6
34 changed files with 819 additions and 367 deletions

View File

@ -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

View File

@ -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"/>

View File

@ -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

View File

@ -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 ()

View File

@ -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);

View File

@ -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();
}
}

View File

@ -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&);

View File

@ -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();
@ -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
@ -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

View File

@ -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);

View 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
View 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
View 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
View 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__ */

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -29,6 +29,7 @@
#include "audio_region_view.h"
#include "audio_streamview.h"
#include "automation_line.h"
#include "control_point.h"
#include "i18n.h"

View File

@ -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);
}
}

View File

@ -93,6 +93,7 @@ class MidiRegionView : public RegionView
private:
void display_events();
void clear_events();
std::vector<ArdourCanvas::Item*> _events;
ArdourCanvas::SimpleRect** _active_notes;

View File

@ -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;

View File

@ -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

View File

@ -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__ */

View File

@ -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());

View File

@ -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>);

View File

@ -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>);

View File

@ -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;

View File

@ -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*/

View File

@ -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;

View File

@ -143,6 +143,11 @@ namespace ARDOUR {
Destructive
};
enum NoteMode {
Note,
Percussion
};
struct BBT_Time {
uint32_t bars;
uint32_t beats;

View File

@ -463,3 +463,4 @@ Automatable::control_factory(boost::shared_ptr<AutomationList> list)
return boost::shared_ptr<AutomationControl>(new AutomationControl(_session, list));
}
}

View File

@ -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;
}

View File

@ -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
*/
@ -953,6 +961,22 @@ AutomationList::multipoint_eval (double x) const
double upos, lpos;
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) */
@ -1279,6 +1303,8 @@ AutomationList::state (bool full)
root->add_property ("max_yval", buf);
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));
@ -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 {

View File

@ -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()
@ -132,6 +135,10 @@ setup_enum_writer ()
REGISTER_ENUM (Normal);
REGISTER_ENUM (Destructive);
REGISTER (_TrackMode);
REGISTER_ENUM (Note);
REGISTER_ENUM (Percussion);
REGISTER (_NoteMode);
REGISTER_ENUM (MeterFalloffOff);
REGISTER_ENUM (MeterFalloffSlowest);
@ -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);
}

View File

@ -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));
// 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 {
_mode = Normal;
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,7 +706,8 @@ MidiTrack::set_mode (TrackMode m)
return 0;
}
#endif
/** \return true on success, false on failure (no buffer space left)
*/
bool