Deep "automation regions" support.
authorDavid Robillard <d@drobilla.net>
Thu, 6 Sep 2007 02:30:39 +0000 (02:30 +0000)
committerDavid Robillard <d@drobilla.net>
Thu, 6 Sep 2007 02:30:39 +0000 (02:30 +0000)
Fix zoom/height/etc changing for automation region views.
Broke smooth automation region dragging (make omelette, break eggs, etc).

git-svn-id: svn://localhost/ardour2/trunk@2424 d708f5d6-7413-0410-9779-e7cbd77b26cf

30 files changed:
gtk2_ardour/SConscript
gtk2_ardour/ardour_ui.cc
gtk2_ardour/ardour_ui_ed.cc
gtk2_ardour/audio_time_axis.cc
gtk2_ardour/automation_region_view.cc
gtk2_ardour/automation_region_view.h
gtk2_ardour/automation_streamview.cc [new file with mode: 0644]
gtk2_ardour/automation_streamview.h [new file with mode: 0644]
gtk2_ardour/automation_time_axis.cc
gtk2_ardour/automation_time_axis.h
gtk2_ardour/midi_region_view.cc
gtk2_ardour/midi_streamview.cc
gtk2_ardour/midi_time_axis.cc
gtk2_ardour/region_view.cc
gtk2_ardour/route_time_axis.cc
gtk2_ardour/streamview.cc
gtk2_ardour/streamview.h
gtk2_ardour/time_axis_view.h
libs/ardour/ardour/audioregion.h
libs/ardour/ardour/midi_region.h
libs/ardour/ardour/region.h
libs/ardour/ardour/smf_source.h
libs/ardour/audio_library.cc
libs/ardour/audioregion.cc
libs/ardour/crossfade.cc
libs/ardour/midi_model.cc
libs/ardour/plugin_manager.cc
libs/ardour/region.cc
libs/ardour/smf_source.cc
libs/gtkmm2ext/gtk_ui.cc

index ee80002f13bf35a1516e431a691b80725b613aaa..b96498602e1d5b69cc0d022002694effa55d2343 100644 (file)
@@ -99,6 +99,7 @@ audio_region_editor.cc
 control_point.cc
 automation_line.cc
 automation_time_axis.cc
+automation_streamview.cc
 automation_controller.cc
 automation_region_view.cc
 midi_port_dialog.cc
index d6fc5493715d643e710982af38bdfcc8cb981610..cac63dc7529006d33098aa9108bd789136e0d385 100644 (file)
@@ -1438,7 +1438,7 @@ ARDOUR_UI::engine_running ()
        ActionManager::set_sensitive (ActionManager::jack_opposite_sensitive_actions, false);
 
        Glib::RefPtr<Action> action;
-       char* action_name = 0;
+       const char* action_name = 0;
 
        switch (engine->frames_per_cycle()) {
        case 32:
@@ -2788,7 +2788,7 @@ ARDOUR_UI::TransportControllable::set_value (float val)
                return;
        }
 
-       char *action = 0;
+       const char *action = 0;
 
        switch (type) {
        case Roll:
index 2a798793ebf2627d8e2f143d95f44d42e109c323..a043128700414ab531b5393221cd0deedb24a07a 100644 (file)
@@ -576,7 +576,7 @@ void
 ARDOUR_UI::set_jack_buffer_size (nframes_t nframes)
 {
        Glib::RefPtr<Action> action;
-       char* action_name = 0;
+       const char* action_name = 0;
 
        switch (nframes) {
        case 32:
index 437e0378368a983be49e6385481f9b8529f7e6f5..f406da955a7d5ce0b061d4ffd5af25414fb8ca87 100644 (file)
@@ -310,6 +310,7 @@ AudioTimeAxisView::create_automation_child (Parameter param, bool show)
                                _route, _route, c,
                                editor,
                                *this,
+                               false,
                                parent_canvas,
                                _route->describe_parameter(param)));
 
@@ -343,6 +344,7 @@ AudioTimeAxisView::update_pans (bool show)
                                        _route, _route/*FIXME*/, pan_control, 
                                        editor,
                                        *this,
+                                       false,
                                        parent_canvas,
                                        _route->describe_parameter(pan_control->parameter())));
                add_automation_child(Parameter(PanAutomation, i), pan_track, show);
index 51650e94aee856a82e520984f3a04c2503aa9b69..539ff233efc2081ceabcf1fdd57a6399984e248c 100644 (file)
     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
 
+#include <pbd/memento_command.h>
 #include "automation_region_view.h"
+#include "public_editor.h"
+
+#include "i18n.h"
 
 AutomationRegionView::AutomationRegionView(ArdourCanvas::Group*                      parent,
                                            AutomationTimeAxisView&                   time_axis,
@@ -32,20 +36,73 @@ AutomationRegionView::AutomationRegionView(ArdourCanvas::Group*
        _line.show();
        _line.show_all_control_points();
        
-       group->raise_to_top ();
+       //group->raise_to_top ();
        
        group->signal_event().connect (mem_fun (this, &AutomationRegionView::canvas_event), false);
 }
 
+void
+AutomationRegionView::init (Gdk::Color& basic_color, bool wfd)
+{
+       _enable_display = false;
+       
+       RegionView::init(basic_color, false);
+
+       compute_colors (basic_color);
+
+       reset_width_dependent_items ((double) _region->length() / samples_per_unit);
+
+       set_y_position_and_height (0, trackview.height);
+
+       _region->StateChanged.connect (mem_fun(*this, &AutomationRegionView::region_changed));
+
+       set_colors ();
+
+       _enable_display = true;
+}
 
 bool
 AutomationRegionView::canvas_event(GdkEvent* ev)
 {
-       cerr << "AUTOMATION EVENT" << endl;
+       if (ev->type == GDK_BUTTON_RELEASE) {
+
+               const nframes_t when = trackview.editor.pixel_to_frame((nframes_t)ev->button.x)
+                       - _region->position();
+               add_automation_event(ev, when, ev->button.y);
+       }
 
        return false;
 }
 
+void
+AutomationRegionView::add_automation_event (GdkEvent* event, nframes_t when, double y)
+{
+       double x = 0;
+       AutomationTimeAxisView* const view = automation_view();
+
+       view->canvas_display->w2i (x, y);
+
+       /* compute vertical fractional position */
+
+       const double height = trackview.height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2;
+       y = 1.0 - (y / height);
+
+       /* map using line */
+
+       _line.view_to_model_y (y);
+
+       view->session().begin_reversible_command (_("add automation event"));
+       XMLNode& before = _line.the_list()->get_state();
+
+       _line.the_list()->add (when, y);
+
+       XMLNode& after = _line.the_list()->get_state();
+       view->session().commit_reversible_command (new MementoCommand<ARDOUR::AutomationList>(
+                       *_line.the_list(), &before, &after));
+
+       view->session().set_dirty ();
+}
+
 
 void
 AutomationRegionView::set_y_position_and_height (double y, double h)
@@ -55,10 +112,31 @@ AutomationRegionView::set_y_position_and_height (double y, double h)
        _line.set_y_position_and_height ((uint32_t)y, (uint32_t) rint (h - NAME_HIGHLIGHT_SIZE));
 }
 
+bool
+AutomationRegionView::set_position (nframes_t pos, void* src, double* ignored)
+{
+       // Do nothing, region parent will move us
+       //return false;
+       
+       return RegionView::set_position(pos, src, ignored); // FIXME: eventually...
+}
+
+
+void
+AutomationRegionView::reset_width_dependent_items (double pixel_width)
+{
+       RegionView::reset_width_dependent_items(pixel_width);
+       
+       _line.reset();
+}
+
+
 void
 AutomationRegionView::region_resized (ARDOUR::Change what_changed)
 {
-       // Do nothing, parent will move us
+       RegionView::region_resized(what_changed);
+
+       _line.reset();
 }
 
 
index ba75b2fecbf66dd2a54693f3e71fd8ed4088affa..79ba84b2efc56504b0c4d9f2d3a99c4282cc5337 100644 (file)
@@ -47,13 +47,24 @@ public:
 
        ~AutomationRegionView() {}
        
+       void init (Gdk::Color& basic_color, bool wfd);
+       
+       inline AutomationTimeAxisView* automation_view() const
+               { return dynamic_cast<AutomationTimeAxisView*>(&trackview); }
+       
+       AutomationLine& line() { return _line; }
+       
        // We are a ghost.  Meta ghosts?  Crazy talk.
        virtual GhostRegion* add_ghost(AutomationTimeAxisView&) { return NULL; }
+       
+       void reset_width_dependent_items(double pixel_width);
 
 protected:
+       bool set_position(nframes_t pos, void* src, double* ignored);
        void set_y_position_and_height(double y, double h);
        void region_resized(ARDOUR::Change what_changed);
        bool canvas_event(GdkEvent* ev);
+       void add_automation_event (GdkEvent* event, nframes_t when, double y);
        void entered();
        void exited();
 
diff --git a/gtk2_ardour/automation_streamview.cc b/gtk2_ardour/automation_streamview.cc
new file mode 100644 (file)
index 0000000..0433156
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+    Copyright (C) 2001-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 <cmath>
+#include <cassert>
+#include <utility>
+
+#include <gtkmm.h>
+
+#include <gtkmm2ext/gtk_ui.h>
+
+#include <ardour/midi_playlist.h>
+#include <ardour/midi_region.h>
+#include <ardour/midi_source.h>
+#include <ardour/midi_diskstream.h>
+#include <ardour/midi_track.h>
+#include <ardour/midi_events.h>
+#include <ardour/smf_source.h>
+#include <ardour/region_factory.h>
+
+#include "automation_streamview.h"
+#include "region_view.h"
+#include "automation_region_view.h"
+#include "automation_time_axis.h"
+#include "canvas-simplerect.h"
+#include "region_selection.h"
+#include "selection.h"
+#include "public_editor.h"
+#include "ardour_ui.h"
+#include "rgb_macros.h"
+#include "gui_thread.h"
+#include "utils.h"
+#include "simplerect.h"
+#include "simpleline.h"
+
+using namespace std;
+using namespace ARDOUR;
+using namespace PBD;
+using namespace Editing;
+
+AutomationStreamView::AutomationStreamView (AutomationTimeAxisView& tv)
+       : StreamView (*dynamic_cast<RouteTimeAxisView*>(tv.get_parent()),
+                       new ArdourCanvas::Group(*tv.canvas_display))
+       , _controller(tv.controller())
+       , _automation_view(tv)
+{
+       //canvas_rect->property_fill_color_rgba() = stream_base_color;
+       canvas_rect->property_outline_color_rgba() = RGBA_BLACK;
+       canvas_rect->lower(2);
+
+       use_rec_regions = tv.editor.show_waveforms_recording ();
+}
+
+AutomationStreamView::~AutomationStreamView ()
+{
+}
+
+
+RegionView*
+AutomationStreamView::add_region_view_internal (boost::shared_ptr<Region> region, bool wfd)
+{
+       if ( ! region) {
+               cerr << "No region" << endl;
+               return NULL;
+       }
+
+       if (wfd) {
+               boost::shared_ptr<MidiRegion> mr = boost::dynamic_pointer_cast<MidiRegion>(region);
+               if (mr)
+                       mr->midi_source()->load_model();
+       }
+
+       const boost::shared_ptr<AutomationControl> control = region->control(_controller->controllable()->parameter());
+
+       if ( ! control) {
+               cerr << "No " << _controller->controllable()->parameter().to_string()
+                       << " for " << region->name() << endl;
+               return NULL;
+       }
+
+       const boost::shared_ptr<AutomationList> list = control->list();
+
+       AutomationRegionView *region_view;
+       std::list<RegionView *>::iterator i;
+
+       for (i = region_views.begin(); i != region_views.end(); ++i) {
+               if ((*i)->region() == region) {
+                       
+                       /* great. we already have a MidiRegionView for this Region. use it again. */
+
+                       (*i)->set_valid (true);
+                       (*i)->enable_display(wfd);
+                       display_region(dynamic_cast<AutomationRegionView*>(*i));
+
+                       return NULL;
+               }
+       }
+       
+       region_view = new AutomationRegionView (canvas_group, _automation_view, region, list,
+                       _samples_per_unit, region_color);
+               
+       region_view->init (region_color, false);
+       region_views.push_front (region_view);
+       
+       /* follow global waveform setting */
+
+       if (wfd) {
+               region_view->enable_display(true);
+               //region_view->midi_region()->midi_source(0)->load_model();
+       }
+
+       /* display events */
+       display_region(region_view);
+
+       /* catch regionview going away */
+       region->GoingAway.connect (bind (mem_fun (*this, &AutomationStreamView::remove_region_view), region));
+       
+       RegionViewAdded (region_view);
+
+       return region_view;
+}
+
+void
+AutomationStreamView::display_region(AutomationRegionView* region_view)
+{
+       region_view->line().reset();
+       region_view->raise();
+}
+
+void
+AutomationStreamView::redisplay_diskstream ()
+{
+       list<RegionView *>::iterator i, tmp;
+
+       for (i = region_views.begin(); i != region_views.end(); ++i)
+               (*i)->set_valid (false);
+       
+       if (_trackview.is_track()) {
+               _trackview.get_diskstream()->playlist()->foreach_region (static_cast<StreamView*>(this), &StreamView::add_region_view);
+       }
+
+       for (i = region_views.begin(); i != region_views.end(); ) {
+               tmp = i;
+               tmp++;
+
+               if (!(*i)->is_valid()) {
+                       delete *i;
+                       region_views.erase (i);
+               } else {
+                       (*i)->enable_display(true);
+                       (*i)->set_y_position_and_height(0, height);
+               }
+
+               i = tmp;
+       }
+       
+       /* now fix layering */
+
+       for (RegionViewList::iterator i = region_views.begin(); i != region_views.end(); ++i) {
+               region_layered (*i);
+       }
+}
+
+
+void
+AutomationStreamView::setup_rec_box ()
+{
+}
+
+void
+AutomationStreamView::update_rec_regions (nframes_t start, nframes_t dur)
+{
+}
+
+void
+AutomationStreamView::rec_data_range_ready (jack_nframes_t start, jack_nframes_t dur)
+{
+       // this is called from the butler thread for now
+       
+       ENSURE_GUI_THREAD(bind (mem_fun (*this, &AutomationStreamView::rec_data_range_ready), start, dur));
+       
+       this->update_rec_regions (start, dur);
+}
+
+void
+AutomationStreamView::color_handler ()
+{
+       /*if (_trackview.is_midi_track()) {
+               canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiTrackBase.get();
+       } 
+
+       if (!_trackview.is_midi_track()) {
+               canvas_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MidiBusBase.get();;
+       }*/
+}
+
diff --git a/gtk2_ardour/automation_streamview.h b/gtk2_ardour/automation_streamview.h
new file mode 100644 (file)
index 0000000..c5eac37
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+    Copyright (C) 2001, 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_automation_streamview_h__
+#define __ardour_automation_streamview_h__
+
+#include <list>
+#include <cmath>
+
+#include <ardour/location.h>
+#include "enums.h"
+#include "simplerect.h"
+#include "streamview.h"
+#include "time_axis_view_item.h"
+#include "route_time_axis.h"
+#include "automation_controller.h"
+
+namespace Gdk {
+       class Color;
+}
+
+class PublicEditor;
+class Selectable;
+class Selection;
+class AutomationRegionView;
+
+class AutomationStreamView : public StreamView
+{
+  public:
+       AutomationStreamView (AutomationTimeAxisView& tv);
+       ~AutomationStreamView ();
+
+       void set_selected_regionviews (RegionSelection&);
+       void get_selectables (jack_nframes_t start, jack_nframes_t end, list<Selectable* >&);
+       void get_inverted_selectables (Selection&, list<Selectable* >& results);
+
+       void redisplay_diskstream ();
+       
+       inline double contents_height() const
+               { return (_trackview.height - TimeAxisViewItem::NAME_HIGHLIGHT_SIZE - 2); }
+       
+  private:
+       void setup_rec_box ();
+       void rec_data_range_ready (jack_nframes_t start, jack_nframes_t dur); 
+       void update_rec_regions (jack_nframes_t start, jack_nframes_t dur);
+       
+       RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_data);
+       void        display_region(AutomationRegionView* region_view);
+       
+       void color_handler ();
+       
+       boost::shared_ptr<AutomationController> _controller;
+       
+       AutomationTimeAxisView& _automation_view;
+};
+
+#endif /* __ardour_automation_streamview_h__ */
index f14e70b52e6e03ebc28df5d00836948a224435f1..f91afcc19e9410a2f10f6bd77de9afcb90cb856f 100644 (file)
@@ -25,6 +25,7 @@
 
 #include "ardour_ui.h"
 #include "automation_time_axis.h"
+#include "automation_streamview.h"
 #include "route_time_axis.h"
 #include "automation_line.h"
 #include "public_editor.h"
@@ -51,16 +52,17 @@ const string AutomationTimeAxisView::state_node_name = "AutomationChild";
 
 AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Route> r,
                boost::shared_ptr<Automatable> a, boost::shared_ptr<AutomationControl> c,
-               PublicEditor& e, TimeAxisView& rent, 
+               PublicEditor& e, TimeAxisView& parent, bool show_regions,
                ArdourCanvas::Canvas& canvas, const string & nom, const string & nomparent)
 
        : AxisView (s), 
-         TimeAxisView (s, e, &rent, canvas),
+         TimeAxisView (s, e, &parent, canvas),
          _route (r),
          _control (c),
          _automatable (a),
          _controller(AutomationController::create(a, c->list(), c)),
          _base_rect (0),
+         _view (show_regions ? new AutomationStreamView(*this) : NULL),
          _name (nom),
          height_button (_("h")),
          clear_button (_("clear")),
@@ -196,15 +198,25 @@ AutomationTimeAxisView::AutomationTimeAxisView (Session& s, boost::shared_ptr<Ro
                set_state (*xml_node);
        } 
                
-       boost::shared_ptr<AutomationLine> line(new AutomationLine (
-                               _control->parameter().to_string(),
-                               *this,
-                               *canvas_display,
-                               _control->list()));
-               
-       line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
-       line->queue_reset ();
-       add_line (line);
+       /* ask for notifications of any new RegionViews */
+       if (show_regions) {
+
+               assert(_view);
+               _view->attach ();
+       
+       /* no regions, just a single line for the entire track (e.g. bus gain) */
+       } else {
+       
+               boost::shared_ptr<AutomationLine> line(new AutomationLine (
+                                       _control->parameter().to_string(),
+                                       *this,
+                                       *canvas_display,
+                                       _control->list()));
+
+               line->set_line_color (ARDOUR_UI::config()->canvasvar_ProcessorAutomationLine.get());
+               line->queue_reset ();
+               add_line (line);
+       }
 
        /* make sure labels etc. are correct */
 
@@ -338,13 +350,15 @@ AutomationTimeAxisView::interpolation_changed ()
                }
        }
        
-       _line->set_interpolation(style);
+       if (_line)
+               _line->set_interpolation(style);
 }
 
 void
 AutomationTimeAxisView::set_interpolation (AutomationList::InterpolationStyle style)
 {
        _control->list()->set_interpolation(style);
+               if (_line)
        _line->set_interpolation(style);
 }
 
@@ -358,7 +372,8 @@ void
 AutomationTimeAxisView::clear_clicked ()
 {
        _session.begin_reversible_command (_("clear automation"));
-       _line->clear ();
+       if (_line)
+               _line->clear ();
        _session.commit_reversible_command ();
 }
 
@@ -373,9 +388,14 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
 
        TimeAxisView::set_height (ht);
        _base_rect->property_y2() = h;
-
+       
        if (_line)
                _line->set_y_position_and_height (0, h);
+       
+       if (_view) {
+               _view->set_height(h);
+               _view->update_contents_y_position_and_height();
+       }
 
        for (list<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
                (*i)->set_height ();
@@ -480,9 +500,13 @@ AutomationTimeAxisView::set_height (TrackHeight ht)
 void
 AutomationTimeAxisView::set_samples_per_unit (double spu)
 {
-       TimeAxisView::set_samples_per_unit (editor.get_current_zoom());
+       TimeAxisView::set_samples_per_unit (spu);
 
-       _line->reset ();
+       if (_line)
+               _line->reset ();
+       
+       if (_view)
+               _view->set_samples_per_unit (spu);
 }
  
 void
@@ -578,6 +602,9 @@ AutomationTimeAxisView::build_display_menu ()
 void
 AutomationTimeAxisView::add_automation_event (ArdourCanvas::Item* item, GdkEvent* event, nframes_t when, double y)
 {
+       if (!_line)
+               return;
+
        double x = 0;
 
        canvas_display->w2i (x, y);
@@ -826,20 +853,23 @@ AutomationTimeAxisView::get_selectables (nframes_t start, nframes_t end, double
                        botfrac = 1.0 - ((bot - y_position) / height);
                }
 
-               _line->get_selectables (start, end, botfrac, topfrac, results);
+               if (_line)
+                       _line->get_selectables (start, end, botfrac, topfrac, results);
        }
 }
 
 void
 AutomationTimeAxisView::get_inverted_selectables (Selection& sel, list<Selectable*>& result)
 {
-       _line->get_inverted_selectables (sel, result);
+       if (_line)
+               _line->get_inverted_selectables (sel, result);
 }
 
 void
 AutomationTimeAxisView::set_selected_points (PointSelection& points)
 {
-       _line->set_selected_points (points);
+       if (_line)
+               _line->set_selected_points (points);
 }
 
 void
@@ -873,13 +903,15 @@ AutomationTimeAxisView::add_line (boost::shared_ptr<AutomationLine> line)
 void
 AutomationTimeAxisView::entered()
 {
-       _line->track_entered();
+       if (_line)
+               _line->track_entered();
 }
 
 void
 AutomationTimeAxisView::exited ()
 {
-       _line->track_exited();
+       if (_line)
+               _line->track_exited();
 }
 
 void
@@ -889,7 +921,8 @@ AutomationTimeAxisView::set_colors ()
                (*i)->set_colors();
     }
     
-       _line->set_colors();
+       if (_line)
+               _line->set_colors();
 }
 
 void
index b708b6f58e755d38e7c269e3fa237230089c209f..4e21d281a3613e9f547a5d1e56652fad2feff75d 100644 (file)
@@ -42,6 +42,7 @@ using std::string;
 namespace ARDOUR {
        class Session;
        class Route;
+       class AutomationControl;
 }
 
 class PublicEditor;
@@ -52,6 +53,8 @@ class AutomationLine;
 class GhostRegion;
 class Selection;
 class Selectable;
+class AutomationStreamView;
+class AutomationController;
 
 
 class AutomationTimeAxisView : public TimeAxisView {
@@ -62,6 +65,7 @@ class AutomationTimeAxisView : public TimeAxisView {
                                boost::shared_ptr<ARDOUR::AutomationControl>,
                                PublicEditor&,
                                TimeAxisView& parent,
+                               bool show_regions,
                                ArdourCanvas::Canvas& canvas,
                                const string & name, /* translatable */
                                const string & plug_name = "");
@@ -101,6 +105,9 @@ class AutomationTimeAxisView : public TimeAxisView {
        
        static const string state_node_name;
        XMLNode* get_state_node();
+       
+       boost::shared_ptr<ARDOUR::AutomationControl> control()    { return _control; }
+       boost::shared_ptr<AutomationController>      controller() { return _controller; }
 
   protected:
        boost::shared_ptr<ARDOUR::Route> _route; ///< Parent route
@@ -111,6 +118,7 @@ class AutomationTimeAxisView : public TimeAxisView {
        
        ArdourCanvas::SimpleRect* _base_rect;
        boost::shared_ptr<AutomationLine> _line;
+       AutomationStreamView*             _view;
        
        string _name;
        bool    in_destructor;
index 580282185fe9e12c583d958349eda5f1f93d730e..8dc4029d26bd5cc013d89b7754a8a35f87d8cb4c 100644 (file)
@@ -410,7 +410,7 @@ MidiRegionView::redisplay_model()
 
                end_write();
 
-               for (Automatable::Controls::const_iterator i = _model->controls().begin();
+               /*for (Automatable::Controls::const_iterator i = _model->controls().begin();
                                i != _model->controls().end(); ++i) {
 
                        assert(i->second);
@@ -431,14 +431,13 @@ MidiRegionView::redisplay_model()
                                                new AutomationRegionView(at->canvas_display,
                                                        *at.get(), _region, i->second->list(),
                                                        midi_stream_view()->get_samples_per_unit(), col));
-
-                               arv->set_duration(_region->length(), this);
-
-                               _automation_children.insert(std::make_pair(i->second->parameter(), arv));
                        }
 
+                       arv->set_duration(_region->length(), this);
                        arv->init(col, true);
-               }
+
+                       _automation_children.insert(std::make_pair(i->second->parameter(), arv));
+               }*/
                
                _model->read_unlock();
 
@@ -794,7 +793,6 @@ MidiRegionView::note_dropped(CanvasMidiEvent* ev, double dt, uint8_t dnote)
 void
 MidiRegionView::note_entered(ArdourCanvas::CanvasMidiEvent* ev)
 {
-       cerr << "NOTE ENTERED: " << _mouse_state << endl;
        if (ev->note() && _mouse_state == EraseTouchDragging) {
                start_delta_command();
                ev->selected(true);
index 3e33142b4dc0e09ecb3c1585684d13d1f3daf0ec..903197072d22798704a67729dd290ef99e2ae56a 100644 (file)
@@ -172,7 +172,7 @@ MidiStreamView::redisplay_diskstream ()
        list<RegionView *>::iterator i, tmp;
 
        for (i = region_views.begin(); i != region_views.end(); ++i) {
-               (*i)->enable_display(true); // FIXME: double display
+               (*i)->enable_display(true); // FIXME: double display, remove
                (*i)->set_valid (false);
                
                /* FIXME: slow.  MidiRegionView needs a find_note_range method
index e728a7c0f619589caf94dc7c031770168d414759..102b8ccba33ee795a041465bfd843f51f81227e0 100644 (file)
@@ -118,15 +118,9 @@ MidiTimeAxisView::MidiTimeAxisView (PublicEditor& ed, Session& sess, boost::shar
                controls_base_unselected_name = "MidiTrackControlsBaseUnselected";
 
                /* ask for notifications of any new RegionViews */
-               _view->RegionViewAdded.connect (mem_fun(*this, &MidiTimeAxisView::region_view_added));
                _view->attach ();
 
-       } /*else { // no MIDI busses yet
-
-               controls_ebox.set_name ("MidiBusControlsBaseUnselected");
-               controls_base_selected_name = "MidiBusControlsBaseSelected";
-               controls_base_unselected_name = "MidiBusControlsBaseUnselected";
-       }*/
+       }
 }
 
 MidiTimeAxisView::~MidiTimeAxisView ()
@@ -267,7 +261,7 @@ MidiTimeAxisView::create_automation_child (Parameter param, bool show)
 {
        if (param.type() == MidiCCAutomation) {
        
-               /* FIXME: this all probably leaks */
+               /* FIXME: don't create AutomationList for track itself */
 
                boost::shared_ptr<AutomationControl> c = _route->control(param);
 
@@ -281,6 +275,7 @@ MidiTimeAxisView::create_automation_child (Parameter param, bool show)
                                _route, _route, c,
                                editor,
                                *this,
+                               true,
                                parent_canvas,
                                _route->describe_parameter(param)));
                
index 0554cc41413d6f92322947ebf0875c4ebc00a4b4..699ecdbcfa1fcc0de13bde94a871fc95f2fec8ae 100644 (file)
@@ -258,10 +258,10 @@ RegionView::reset_width_dependent_items (double pixel_width)
        TimeAxisViewItem::reset_width_dependent_items (pixel_width);
        _pixel_width = pixel_width;
 
-       for (AutomationChildren::iterator i = _automation_children.begin();
+       /*for (AutomationChildren::iterator i = _automation_children.begin();
                        i != _automation_children.end(); ++i) {
                i->second->reset_width_dependent_items(pixel_width);
-       }
+       }*/
 }
 
 void
index 020b682f0a81502f26ff8e777d47b96971e1d7fd..9fe224b8141dabc5943e93a5e15eb3c1b0c70536 100644 (file)
@@ -1723,7 +1723,7 @@ RouteTimeAxisView::add_processor_automation_curve (boost::shared_ptr<Processor>
 
        pan->view = boost::shared_ptr<AutomationTimeAxisView>(
                        new AutomationTimeAxisView (_session, _route, processor, control,
-                               editor, *this, parent_canvas, name, state_name));
+                               editor, *this, false, parent_canvas, name, state_name));
 
        pan->view->Hiding.connect (bind (mem_fun(*this, &RouteTimeAxisView::processor_automation_track_hidden), pan, processor));
 
index 22ad90e7fe9cce9ccef491b1644a88c11f455dcf..0bcd591a4457f52e9bf24f701623b8e6b46148a1 100644 (file)
@@ -45,9 +45,9 @@ using namespace ARDOUR;
 using namespace PBD;
 using namespace Editing;
 
-StreamView::StreamView (RouteTimeAxisView& tv)
+StreamView::StreamView (RouteTimeAxisView& tv, ArdourCanvas::Group* group)
        : _trackview (tv)
-       , canvas_group(new ArdourCanvas::Group(*_trackview.canvas_display))
+       , canvas_group(group ? group : new ArdourCanvas::Group(*_trackview.canvas_display))
        , canvas_rect(new ArdourCanvas::SimpleRect (*canvas_group))
        , _samples_per_unit(_trackview.editor.get_current_zoom())
        , rec_updating(false)
index 5e716d7a36fd48d5d0a282f8ac541459faa0abbd..820b956cc3708f067ecdfc7f7136e8843d8a4637 100644 (file)
@@ -93,13 +93,14 @@ public:
 
        void add_region_view (boost::shared_ptr<ARDOUR::Region>);
        void region_layered (RegionView*);
+       void update_contents_y_position_and_height ();
        
        virtual void redisplay_diskstream () = 0;
        
        sigc::signal<void,RegionView*> RegionViewAdded;
 
 protected:
-       StreamView (RouteTimeAxisView&);
+       StreamView (RouteTimeAxisView&, ArdourCanvas::Group* group = NULL);
        
 //private: (FIXME?)
 
@@ -111,7 +112,7 @@ protected:
        void         update_rec_box ();
        //virtual void update_rec_regions () = 0;
        
-       virtual RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves) = 0;
+       virtual RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_data) = 0;
        virtual void remove_region_view (boost::weak_ptr<ARDOUR::Region> );
        //void         remove_rec_region (boost::shared_ptr<ARDOUR::Region>); (unused)
 
@@ -125,8 +126,6 @@ protected:
        
        virtual void color_handler () = 0;
 
-       virtual void update_contents_y_position_and_height ();
-
        RouteTimeAxisView&        _trackview;
        ArdourCanvas::Group*      canvas_group;
        ArdourCanvas::SimpleRect* canvas_rect; /* frame around the whole thing */
index 62590c1d2343c08830f75ab18f46e1a394c43f31..baf8327e672d03128edd86548667aa0b698297a9 100644 (file)
@@ -201,6 +201,7 @@ class TimeAxisView : public virtual AxisView
 
        /* state/serialization management */
 
+       TimeAxisView* get_parent () { return parent; }
        void set_parent (TimeAxisView& p);
        bool has_state () const;
 
index ddda1f4321ffdedaa90aa9d159454451bfc40d65..ba2bbaee223bf83b21553b720262bb63ce8f4a24 100644 (file)
@@ -170,7 +170,7 @@ class AudioRegion : public Region
   protected:
        /* default constructor for derived (compound) types */
 
-       AudioRegion (nframes_t, nframes_t, std::string name); 
+       AudioRegion (Session& s, nframes_t, nframes_t, std::string name); 
        AudioRegion (boost::shared_ptr<const AudioRegion>);
 
        int set_live_state (const XMLNode&, Change&, bool send);
index 294c2d3291e36605775df517ee5b5a64e666e646..869436e423b125c8d5f58b0986039542ced4ea97 100644 (file)
@@ -31,6 +31,7 @@
 #include <ardour/gain.h>
 #include <ardour/logcurve.h>
 #include <ardour/export.h>
+#include <ardour/midi_source.h>
 
 class XMLNode;
 
@@ -69,6 +70,17 @@ class MidiRegion : public Region
 
        UndoAction get_memento() const;
 
+       // Act as a proxy for MidiModel automation stuff (for CC)
+       // Yep, this is pretty ugly...
+       Controls&       controls()       { return midi_source()->model()->controls(); }
+       const Controls& controls() const { return midi_source()->model()->controls(); }
+       
+       boost::shared_ptr<AutomationControl> control(Parameter id, bool create_if_missing=false)
+                       { return midi_source()->model()->control(id, create_if_missing); }
+
+       boost::shared_ptr<const AutomationControl> control(Parameter id) const
+                       { return midi_source()->model()->control(id); }
+
   private:
        friend class RegionFactory;
 
index 496dc7874ebed8d416fbab9bb291753d460dcd80..e62b59ca61aba86c3edf3e474d67b573c03afbb2 100644 (file)
 #include <boost/enable_shared_from_this.hpp>
 
 #include <pbd/undo.h>
-#include <pbd/statefuldestructible.h> 
 
 #include <ardour/ardour.h>
 #include <ardour/data_type.h>
+#include <ardour/automatable.h>
 
 class XMLNode;
 
@@ -43,7 +43,7 @@ enum RegionEditState {
        EditChangesID      = 2
 };
 
-class Region : public PBD::StatefulDestructible, public boost::enable_shared_from_this<Region>
+class Region : public Automatable, public boost::enable_shared_from_this<Region>
 {
   public:
        typedef std::vector<boost::shared_ptr<Source> > SourceList;
@@ -86,10 +86,8 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
 
        virtual ~Region();
 
-       /* Note: changing the name of a Region does not constitute an edit */
-
-       string name() const { return _name; }
-       void set_name (string str);
+       /** Note: changing the name of a Region does not constitute an edit */
+       bool set_name (const std::string& str);
 
        const DataType& data_type() const { return _type; }
 
@@ -214,7 +212,7 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
 
        /* this one is for derived types of derived types */
 
-       Region (nframes_t start, nframes_t length, const string& name, DataType, layer_t = 0, Flag flags = DefaultFlags);
+       Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType, layer_t = 0, Flag flags = DefaultFlags);
 
   protected:
        XMLNode& get_short_state (); /* used only by Session */
@@ -234,7 +232,6 @@ class Region : public PBD::StatefulDestructible, public boost::enable_shared_fro
        virtual void recompute_at_start () = 0;
        virtual void recompute_at_end () = 0;
 
-       string                  _name;
        DataType                _type;
        Flag                    _flags;
        nframes_t               _start;
index bf5618d57a5f3518c43f371f7595e096f4795ae4..302fb15838a39c272a833efd7067dc35367b0d9a 100644 (file)
@@ -110,8 +110,8 @@ class SMFSource : public MidiSource {
        void seek_to_end();
        void write_footer();
 
-       void     write_chunk_header(char id[4], uint32_t length);
-       void     write_chunk(char id[4], uint32_t length, void* data);
+       void     write_chunk_header(const char id[4], uint32_t length);
+       void     write_chunk(const char id[4], uint32_t length, void* data);
        size_t   write_var_len(uint32_t val);
        uint32_t read_var_len() const;
        int      read_event(uint32_t* delta_t, uint32_t* size, Byte** buf) const;
index c5240988a8cd186d2c65c169a48cb029c9b3724c..a35846ab29e4bc28b21c6c62df2e95408c854be8 100644 (file)
@@ -40,7 +40,7 @@ namespace {
        const char* const sfdb_file_name = "sfdb";
 } // anonymous namespace
 
-static char* TAG = "http://ardour.org/ontology/Tag";
+static const char* TAG = "http://ardour.org/ontology/Tag";
 
 AudioLibrary::AudioLibrary ()
 {
@@ -91,7 +91,7 @@ AudioLibrary::get_tags (string member)
        
        lrdf_statement pattern;
        pattern.subject = strdup(Glib::filename_to_uri(member).c_str());
-       pattern.predicate = TAG;
+       pattern.predicate = (char*)TAG;
        pattern.object = 0;
        pattern.object_type = lrdf_literal;
        
@@ -123,8 +123,8 @@ AudioLibrary::search_members_and (vector<string>& members, const vector<string>
        vector<string>::const_iterator i;
        for (i = tags.begin(); i != tags.end(); ++i){
                pattern = new lrdf_statement;
-               pattern->subject = "?";
-               pattern->predicate = TAG;
+               pattern->subject = (char*)"?";
+               pattern->predicate = (char*)TAG;
                pattern->object = strdup((*i).c_str());
                pattern->next = old;
 
index 58ece331c3f426d1609fe833f4e5a638115c8fef..7ac14f1ddad5330357604a522348297b557d4866 100644 (file)
@@ -70,8 +70,8 @@ AudioRegion::init ()
 }
 
 /* constructor for use by derived types only */
-AudioRegion::AudioRegion (nframes_t start, nframes_t length, string name)
-       : Region (start, length, name, DataType::AUDIO)
+AudioRegion::AudioRegion (Session& s, nframes_t start, nframes_t length, string name)
+       : Region (s, start, length, name, DataType::AUDIO)
        , _fade_in (new AutomationList(Parameter(FadeInAutomation), 0.0, 2.0, 1.0))
        , _fade_out (new AutomationList(Parameter(FadeOutAutomation), 0.0, 2.0, 1.0))
        , _envelope (new AutomationList(Parameter(EnvelopeAutomation), 0.0, 2.0, 1.0))
index f69ec99f8da4b38bccaf9b74de5e88075d25f828..556f11125e6576d3347b1d6b455ba02523d2c498 100644 (file)
@@ -77,7 +77,7 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
                      nframes_t length,
                      nframes_t position,
                      AnchorPoint ap)
-       : AudioRegion (position, length, "foobar"),
+       : AudioRegion (in->session(), position, length, "foobar"),
          _fade_in (Parameter(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
          _fade_out (Parameter(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
 
@@ -95,7 +95,7 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
 }
 
 Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
-       : AudioRegion (0, 0, "foobar"),
+       : AudioRegion (a->session(), 0, 0, "foobar"),
          _fade_in (Parameter(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
          _fade_out (Parameter(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
 {
@@ -114,7 +114,7 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
 }
 
 Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
-       : AudioRegion (0, 0, "foobar"),
+       : AudioRegion (playlist.session(), 0, 0, "foobar"),
          _fade_in (Parameter(FadeInAutomation), 0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
          _fade_out (Parameter(FadeOutAutomation), 0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
 
index 765d5f7cadd0bb8d8b000731b804b420dd08dde5..27910b44f52d82aeba79872bfbf315d7d5753990 100644 (file)
@@ -223,7 +223,7 @@ MidiModel::read(MidiRingBuffer& dst, nframes_t start, nframes_t nframes, nframes
 
        if (start != _next_read) {
                _read_iter = const_iterator(*this, (double)start);
-               cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
+       //      cerr << "Repositioning iterator from " << _next_read << " to " << start << endl;
        //} else {
        //      cerr << "Using cached iterator at " << _next_read << endl;
        }
index 3e7da5d9a2c41113ae5cb65593dce6aabed714d2..dac8a9eead4060f752df94daa4c69e4587a38ee0 100644 (file)
@@ -287,7 +287,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
 
        snprintf(buf, sizeof(buf), "%s%" PRIu32, LADSPA_BASE, plugin_id);
        pattern.subject = buf;
-       pattern.predicate = RDF_TYPE;
+       pattern.predicate = (char*)RDF_TYPE;
        pattern.object = 0;
        pattern.object_type = lrdf_uri;
 
@@ -298,7 +298,7 @@ PluginManager::get_ladspa_category (uint32_t plugin_id)
        }
 
        pattern.subject = matches1->object;
-       pattern.predicate = LADSPA_BASE "hasLabel";
+       pattern.predicate = (char*)LADSPA_BASE "hasLabel";
        pattern.object = 0;
        pattern.object_type = lrdf_literal;
 
index a828460bce39f8250e3b79314698bdb14a412e51..1809af671cef6a6b2e1a83532f080df0bf519f30 100644 (file)
@@ -52,8 +52,8 @@ Change Region::HiddenChanged     = ARDOUR::new_change ();
 
 
 /* derived-from-derived constructor (no sources in constructor) */
-Region::Region (nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
-       : _name(name)
+Region::Region (Session& s, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
+       : Automatable(s, name)
        , _type(type)
        , _flags(flags)
        , _start(start) 
@@ -73,7 +73,7 @@ Region::Region (nframes_t start, nframes_t length, const string& name, DataType
 
 /** Basic Region constructor (single source) */
 Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
-       : _name(name)
+       : Automatable(src->session(), name)
        , _type(type)
        , _flags(flags)
        , _start(start) 
@@ -97,7 +97,7 @@ Region::Region (boost::shared_ptr<Source> src, nframes_t start, nframes_t length
 
 /** Basic Region constructor (many sources) */
 Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const string& name, DataType type, layer_t layer, Region::Flag flags)
-       : _name(name)
+       : Automatable(srcs.front()->session(), name)
        , _type(type)
        , _flags(flags)
        , _start(start) 
@@ -132,7 +132,7 @@ Region::Region (SourceList& srcs, nframes_t start, nframes_t length, const strin
 
 /** Create a new Region from part of an existing one */
 Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes_t length, const string& name, layer_t layer, Flag flags)
-       : _name(name)
+       : Automatable(other->session(), name)
        , _type(other->data_type())
        , _flags(Flag(flags & ~(Locked|PositionLocked|WholeFile|Hidden)))
        , _start(other->_start + offset) 
@@ -173,7 +173,7 @@ Region::Region (boost::shared_ptr<const Region> other, nframes_t offset, nframes
 
 /** Pure copy constructor */
 Region::Region (boost::shared_ptr<const Region> other)
-       : _name(other->_name)
+       : Automatable(other->session(), other->name())
        , _type(other->data_type())
        , _flags(Flag(other->_flags & ~(Locked|PositionLocked)))
        , _start(other->_start) 
@@ -214,7 +214,7 @@ Region::Region (boost::shared_ptr<const Region> other)
 }
 
 Region::Region (SourceList& srcs, const XMLNode& node)
-       : _name(X_("error: XML did not reset this"))
+       : Automatable(srcs.front()->session(), X_("error: XML did not reset this"))
        , _type(DataType::NIL) // to be loaded from XML
        , _flags(Flag(0))
        , _start(0) 
@@ -252,7 +252,7 @@ Region::Region (SourceList& srcs, const XMLNode& node)
 }
 
 Region::Region (boost::shared_ptr<Source> src, const XMLNode& node)
-       : _name(X_("error: XML did not reset this"))
+       : Automatable(src->session(), X_("error: XML did not reset this"))
        , _type(DataType::NIL)
        , _flags(Flag(0))
        , _start(0) 
@@ -323,13 +323,16 @@ Region::set_playlist (boost::weak_ptr<Playlist> wpl)
        }
 }
 
-void
-Region::set_name (string str)
+bool
+Region::set_name (const std::string& str)
 {
        if (_name != str) {
-               _name = str; 
-               send_change (NameChanged);
+               SessionObject::set_name(str); // EMIT SIGNAL NameChanged()
+               assert(_name == str); 
+               send_change (ARDOUR::NameChanged);
        }
+
+       return true;
 }
 
 void
@@ -383,7 +386,7 @@ Region::first_edit ()
                _name = pl->session().new_region_name (_name);
                _first_edit = EditChangesNothing;
 
-               send_change (NameChanged);
+               send_change (ARDOUR::NameChanged);
                RegionFactory::CheckNewRegion (shared_from_this());
        }
 }
@@ -907,7 +910,7 @@ Region::state (bool full_state)
 {
        XMLNode *node = new XMLNode ("Region");
        char buf[64];
-       char* fe = NULL;
+       const char* fe = NULL;
 
        _id.print (buf, sizeof (buf));
        node->add_property ("id", buf);
index 0cfdd51feb3da031982efd2b025432130e249601..4ad8f80b4bb2285f539ca3d8a38eb34c09d9b7d0 100644 (file)
@@ -783,7 +783,7 @@ SMFSource::is_empty () const
 
 
 void
-SMFSource::write_chunk_header(char id[4], uint32_t length)
+SMFSource::write_chunk_header(const char id[4], uint32_t length)
 {
        const uint32_t length_be = GUINT32_TO_BE(length);
 
@@ -792,7 +792,7 @@ SMFSource::write_chunk_header(char id[4], uint32_t length)
 }
 
 void
-SMFSource::write_chunk(char id[4], uint32_t length, void* data)
+SMFSource::write_chunk(const char id[4], uint32_t length, void* data)
 {
        write_chunk_header(id, length);
        
@@ -857,6 +857,8 @@ SMFSource::load_model(bool lock, bool force_reload)
                //cerr << _name << " NOT reloading model " << _model.get() << " (" << _model->n_notes()
                //      << " notes)" << endl;
                return;
+       } else {
+               cerr << _name << " loading model" << endl;
        }
 
        if (! _model) {
index cf755873fd07815c645007bbf47ea264c357a3fa..660ea32ad1aa2a4b0142a702350b92eb851cf7d3 100644 (file)
@@ -414,7 +414,7 @@ UI::process_error_message (Transmitter::Channel chn, const char *str)
        RefPtr<Style> style;
        RefPtr<TextBuffer::Tag> ptag;
        RefPtr<TextBuffer::Tag> mtag;
-       char *prefix;
+       const char *prefix;
        size_t prefix_len;
        bool fatal_received = false;
 #ifndef OLD_STYLE_ERRORS