2 Copyright (C) 2001-2007 Paul Davis
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <gtkmm2ext/gtk_ui.h>
27 #include "ardour/midi_playlist.h"
28 #include "ardour/midi_region.h"
29 #include "ardour/midi_source.h"
30 #include "ardour/midi_diskstream.h"
31 #include "ardour/midi_track.h"
32 #include "ardour/smf_source.h"
33 #include "ardour/region_factory.h"
35 #include "automation_streamview.h"
36 #include "region_view.h"
37 #include "automation_region_view.h"
38 #include "automation_time_axis.h"
39 #include "canvas-simplerect.h"
40 #include "region_selection.h"
41 #include "selection.h"
42 #include "public_editor.h"
43 #include "ardour_ui.h"
44 #include "rgb_macros.h"
45 #include "gui_thread.h"
47 #include "simplerect.h"
48 #include "simpleline.h"
51 using namespace ARDOUR;
53 using namespace Editing;
55 AutomationStreamView::AutomationStreamView (AutomationTimeAxisView& tv)
56 : StreamView (*dynamic_cast<RouteTimeAxisView*>(tv.get_parent()),
57 new ArdourCanvas::Group(*tv.canvas_background()),
58 new ArdourCanvas::Group(*tv.canvas_display()))
59 , _controller(tv.controller())
60 , _automation_view(tv)
61 , _pending_automation_state (Off)
63 //canvas_rect->property_fill_color_rgba() = stream_base_color;
64 canvas_rect->property_outline_color_rgba() = RGBA_BLACK;
67 AutomationStreamView::~AutomationStreamView ()
73 AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region, bool wfd, bool /*recording*/)
76 cerr << "No region" << endl;
81 boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
83 mr->midi_source()->load_model();
86 const boost::shared_ptr<AutomationControl> control = boost::dynamic_pointer_cast<AutomationControl> (
87 region->control (_controller->controllable()->parameter(), true)
90 boost::shared_ptr<AutomationList> list;
92 list = boost::dynamic_pointer_cast<AutomationList>(control->list());
93 assert(!control->list() || list);
96 AutomationRegionView *region_view;
97 std::list<RegionView *>::iterator i;
99 for (i = region_views.begin(); i != region_views.end(); ++i) {
100 if ((*i)->region() == region) {
102 /* great. we already have an AutomationRegionView for this Region. use it again. */
103 AutomationRegionView* arv = dynamic_cast<AutomationRegionView*>(*i);;
106 arv->line()->set_list (list);
107 (*i)->set_valid (true);
108 (*i)->enable_display(wfd);
115 region_view = new AutomationRegionView (_canvas_group, _automation_view, region,
116 _controller->controllable()->parameter(), list,
117 _samples_per_unit, region_color);
119 region_view->init (region_color, false);
120 region_views.push_front (region_view);
122 /* follow global waveform setting */
125 region_view->enable_display(true);
126 //region_view->midi_region()->midi_source(0)->load_model();
129 display_region(region_view);
131 /* catch regionview going away */
132 region->DropReferences.connect (*this, invalidator (*this), boost::bind (&AutomationStreamView::remove_region_view, this, boost::weak_ptr<Region>(region)), gui_context());
134 /* setup automation state for this region */
135 boost::shared_ptr<AutomationLine> line = region_view->line ();
136 if (line && line->the_list()) {
137 line->the_list()->set_automation_state (automation_state ());
140 RegionViewAdded (region_view);
146 AutomationStreamView::display_region(AutomationRegionView* region_view)
148 region_view->line().reset();
152 AutomationStreamView::set_automation_state (AutoState state)
154 /* XXX: not sure if this is right, but for now the automation state is basically held by
155 the regions' AutomationLists. Each region is always set to have the same AutoState.
158 if (region_views.empty()) {
159 _pending_automation_state = state;
161 list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
163 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
164 if ((*i)->the_list()) {
165 (*i)->the_list()->set_automation_state (state);
172 AutomationStreamView::redisplay_track ()
174 list<RegionView *>::iterator i, tmp;
176 // Flag region views as invalid and disable drawing
177 for (i = region_views.begin(); i != region_views.end(); ++i) {
178 (*i)->set_valid (false);
179 (*i)->enable_display(false);
182 // Add and display region views, and flag them as valid
183 if (_trackview.is_track()) {
184 _trackview.track()->playlist()->foreach_region (
185 sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
189 // Stack regions by layer, and remove invalid regions
195 AutomationStreamView::setup_rec_box ()
200 AutomationStreamView::color_handler ()
202 /*if (_trackview.is_midi_track()) {
203 canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
206 if (!_trackview.is_midi_track()) {
207 canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiBusBase.get();;
212 AutomationStreamView::automation_state () const
214 if (region_views.empty()) {
215 return _pending_automation_state;
218 boost::shared_ptr<AutomationLine> line = ((AutomationRegionView*) region_views.front())->line ();
219 if (!line || !line->the_list()) {
223 return line->the_list()->automation_state ();
227 AutomationStreamView::has_automation () const
229 list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
231 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
232 if ((*i)->npoints() > 0) {
240 /** Our parent AutomationTimeAxisView calls this when the user requests a particular
241 * InterpolationStyle; tell the AutomationLists in our regions.
244 AutomationStreamView::set_interpolation (AutomationList::InterpolationStyle s)
246 list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
248 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
249 (*i)->the_list()->set_interpolation (s);
253 AutomationList::InterpolationStyle
254 AutomationStreamView::interpolation () const
256 if (region_views.empty()) {
257 return AutomationList::Linear;
260 AutomationRegionView* v = dynamic_cast<AutomationRegionView*> (region_views.front());
263 return v->line()->the_list()->interpolation ();
266 /** Clear all automation displayed in this view */
268 AutomationStreamView::clear ()
270 list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
272 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
277 /** @param start Start position in session frames.
278 * @param end End position in session frames.
281 AutomationStreamView::get_selectables (framepos_t start, framepos_t end, double botfrac, double topfrac, list<Selectable*>& results)
283 for (list<RegionView*>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
284 AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
286 arv->line()->get_selectables (start, end, botfrac, topfrac, results);
291 AutomationStreamView::set_selected_points (PointSelection& ps)
293 list<boost::shared_ptr<AutomationLine> > lines = get_lines ();
295 for (list<boost::shared_ptr<AutomationLine> >::iterator i = lines.begin(); i != lines.end(); ++i) {
296 (*i)->set_selected_points (ps);
300 list<boost::shared_ptr<AutomationLine> >
301 AutomationStreamView::get_lines () const
303 list<boost::shared_ptr<AutomationLine> > lines;
305 for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
306 AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*i);
308 lines.push_back (arv->line());
314 struct RegionPositionSorter {
315 bool operator() (RegionView* a, RegionView* b) {
316 return a->region()->position() < b->region()->position();
321 /** @param pos Position, in session frames.
322 * @return AutomationLine to paste to for that position, or 0 if there is none appropriate.
324 boost::shared_ptr<AutomationLine>
325 AutomationStreamView::paste_line (framepos_t pos)
327 /* XXX: not sure how best to pick this; for now, just use the last region which starts before pos */
329 if (region_views.empty()) {
330 return boost::shared_ptr<AutomationLine> ();
333 region_views.sort (RegionPositionSorter ());
335 list<RegionView*>::const_iterator prev = region_views.begin ();
337 for (list<RegionView*>::const_iterator i = region_views.begin(); i != region_views.end(); ++i) {
338 if ((*i)->region()->position() > pos) {
344 boost::shared_ptr<Region> r = (*prev)->region ();
346 /* If *prev doesn't cover pos, it's no good */
347 if (r->position() > pos || ((r->position() + r->length()) < pos)) {
348 return boost::shared_ptr<AutomationLine> ();
351 AutomationRegionView* arv = dynamic_cast<AutomationRegionView*> (*prev);