summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Robillard <d@drobilla.net>2006-07-30 03:25:38 +0000
committerDavid Robillard <d@drobilla.net>2006-07-30 03:25:38 +0000
commit9d5d82b4df5b3510177fd31557ac765f46778fe8 (patch)
treeb0b786f4f8fcee4e76c7c3ab1a66f603c08de070
parent8277d134b9733aee344782891c99f07114384d9e (diff)
Abstraction cleanups/polish, towards merging with trunk
git-svn-id: svn://localhost/ardour2/branches/midi@720 d708f5d6-7413-0410-9779-e7cbd77b26cf
-rw-r--r--gtk2_ardour/audio_regionview.cc298
-rw-r--r--gtk2_ardour/audio_regionview.h60
-rw-r--r--gtk2_ardour/audio_streamview.cc33
-rw-r--r--gtk2_ardour/audio_streamview.h9
-rw-r--r--gtk2_ardour/audio_time_axis.cc487
-rw-r--r--gtk2_ardour/audio_time_axis.h94
-rw-r--r--gtk2_ardour/editor.cc12
-rw-r--r--gtk2_ardour/plugin_selector.h1
-rw-r--r--gtk2_ardour/regionview.cc87
-rw-r--r--gtk2_ardour/regionview.h56
-rw-r--r--gtk2_ardour/route_time_axis.cc506
-rw-r--r--gtk2_ardour/route_time_axis.h164
-rw-r--r--gtk2_ardour/streamview.cc1
-rw-r--r--gtk2_ardour/streamview.h30
-rw-r--r--gtk2_ardour/taperegionview.cc46
-rw-r--r--libs/ardour/ardour/audio_diskstream.h93
-rw-r--r--libs/ardour/ardour/diskstream.h62
-rw-r--r--libs/ardour/ardour/midi_diskstream.h22
-rw-r--r--libs/ardour/ardour/playlist.h17
-rw-r--r--libs/ardour/ardour/region.h2
-rw-r--r--libs/ardour/ardour/session.h2
-rw-r--r--libs/ardour/audio_diskstream.cc197
-rw-r--r--libs/ardour/diskstream.cc112
-rw-r--r--libs/ardour/midi_diskstream.cc4
-rw-r--r--libs/ardour/session.cc4
-rw-r--r--libs/ardour/session_butler.cc18
-rw-r--r--libs/ardour/session_state.cc3
27 files changed, 973 insertions, 1447 deletions
diff --git a/gtk2_ardour/audio_regionview.cc b/gtk2_ardour/audio_regionview.cc
index 125654c35c..f22028f33e 100644
--- a/gtk2_ardour/audio_regionview.cc
+++ b/gtk2_ardour/audio_regionview.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2001 Paul Davis
+ Copyright (C) 2001-2006 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
@@ -19,6 +19,7 @@
*/
#include <cmath>
+#include <cassert>
#include <algorithm>
#include <gtkmm.h>
@@ -68,20 +69,18 @@ AudioRegionView::AudioRegionView (ArdourCanvas::Group *parent, RouteTimeAxisView
}
void
-AudioRegionView::init (Gdk::Color& basic_color, bool wfw)
+AudioRegionView::init (Gdk::Color& basic_color, bool wfd)
{
- ArdourCanvas::Points shape;
+ // FIXME: Some redundancy here with RegionView::init. Need to figure out
+ // where order is important and where it isn't...
+
+ RegionView::init(basic_color, wfd);
+
XMLNode *node;
- editor = 0;
- valid = true;
- in_destructor = false;
_amplitude_above_axis = 1.0;
- zero_line = 0;
- wait_for_waves = wfw;
- _height = 0;
-
- _flags = 0;
+ zero_line = 0;
+ _flags = 0;
if ((node = _region.extra_xml ("GUI")) != 0) {
set_flags (node);
@@ -98,23 +97,6 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfw)
create_waves ();
- name_highlight->set_data ("regionview", this);
- name_text->set_data ("regionview", this);
-
- // shape = new ArdourCanvas::Points ();
-
- /* an equilateral triangle */
-
- shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
- shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1));
- shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1));
- shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
-
- sync_mark = new ArdourCanvas::Polygon (*group);
- sync_mark->property_points() = shape;
- sync_mark->property_fill_color_rgba() = fill_color;
- sync_mark->hide();
-
fade_in_shape = new ArdourCanvas::Polygon (*group);
fade_in_shape->property_fill_color_rgba() = fade_color;
fade_in_shape->set_data ("regionview", this);
@@ -175,8 +157,6 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfw)
_region.StateChanged.connect (mem_fun(*this, &AudioRegionView::region_changed));
- group->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_event), group, this));
- name_highlight->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_region_view_name_highlight_event), name_highlight, this));
fade_in_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_event), fade_in_shape, this));
fade_in_handle->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_in_handle_event), fade_in_handle, this));
fade_out_shape->signal_event().connect (bind (mem_fun (PublicEditor::instance(), &PublicEditor::canvas_fade_out_event), fade_out_shape, this));
@@ -184,8 +164,6 @@ AudioRegionView::init (Gdk::Color& basic_color, bool wfw)
set_colors ();
- ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler));
-
/* XXX sync mark drag? */
}
@@ -201,14 +179,6 @@ AudioRegionView::~AudioRegionView ()
/* all waveviews etc will be destroyed when the group is destroyed */
- for (vector<GhostRegion*>::iterator g = ghosts.begin(); g != ghosts.end(); ++g) {
- delete *g;
- }
-
- if (editor) {
- delete editor;
- }
-
if (gain_line) {
delete gain_line;
}
@@ -217,58 +187,17 @@ AudioRegionView::~AudioRegionView ()
ARDOUR::AudioRegion&
AudioRegionView::audio_region() const
{
- // Guaranteed to succeed
+ // "Guaranteed" to succeed...
return dynamic_cast<AudioRegion&>(_region);
}
-
-gint
-AudioRegionView::_lock_toggle (ArdourCanvas::Item* item, GdkEvent* ev, void* arg)
-{
- switch (ev->type) {
- case GDK_BUTTON_RELEASE:
- static_cast<AudioRegionView*>(arg)->lock_toggle ();
- return TRUE;
- break;
- default:
- break;
- }
- return FALSE;
-}
-
-void
-AudioRegionView::lock_toggle ()
-{
- _region.set_locked (!_region.locked());
-}
-
void
AudioRegionView::region_changed (Change what_changed)
{
ENSURE_GUI_THREAD (bind (mem_fun(*this, &AudioRegionView::region_changed), what_changed));
- if (what_changed & BoundsChanged) {
- region_resized (what_changed);
- region_sync_changed ();
- }
- if (what_changed & Region::MuteChanged) {
- region_muted ();
- }
- if (what_changed & Region::OpacityChanged) {
- region_opacity ();
- }
- if (what_changed & ARDOUR::NameChanged) {
- region_renamed ();
- }
- if (what_changed & Region::SyncOffsetChanged) {
- region_sync_changed ();
- }
- if (what_changed & Region::LayerChanged) {
- region_layered ();
- }
- if (what_changed & Region::LockChanged) {
- region_locked ();
- }
+ RegionView::region_changed(what_changed);
+
if (what_changed & AudioRegion::ScaleAmplitudeChanged) {
region_scale_amplitude_changed ();
}
@@ -366,37 +295,18 @@ AudioRegionView::region_scale_amplitude_changed ()
}
void
-AudioRegionView::region_locked ()
-{
- /* name will show locked status */
- region_renamed ();
-}
-
-void
AudioRegionView::region_resized (Change what_changed)
{
- double unit_length;
-
- if (what_changed & ARDOUR::PositionChanged) {
- set_position (_region.position(), 0);
- }
+ RegionView::region_resized(what_changed);
if (what_changed & Change (StartChanged|LengthChanged)) {
- set_duration (_region.length(), 0);
-
- unit_length = _region.length() / samples_per_unit;
-
- reset_width_dependent_items (unit_length);
-
for (uint32_t n = 0; n < waves.size(); ++n) {
waves[n]->property_region_start() = _region.start();
- }
+ }
for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- (*i)->set_duration (unit_length);
-
for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) {
(*w)->property_region_start() = _region.start();
}
@@ -407,8 +317,8 @@ AudioRegionView::region_resized (Change what_changed)
void
AudioRegionView::reset_width_dependent_items (double pixel_width)
{
- TimeAxisViewItem::reset_width_dependent_items (pixel_width);
- _pixel_width = pixel_width;
+ RegionView::reset_width_dependent_items(pixel_width);
+ assert(_pixel_width == pixel_width);
if (zero_line) {
zero_line->property_x2() = pixel_width - 1.0;
@@ -433,17 +343,9 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
}
void
-AudioRegionView::region_layered ()
-{
- RouteTimeAxisView *atv = dynamic_cast<RouteTimeAxisView*> (&get_time_axis_view());
- atv->view()->region_layered (this);
-}
-
-void
AudioRegionView::region_muted ()
{
- set_frame_color ();
- region_renamed ();
+ RegionView::region_muted();
for (uint32_t n=0; n < waves.size(); ++n) {
if (_region.muted()) {
@@ -460,6 +362,7 @@ AudioRegionView::set_height (gdouble height)
{
uint32_t wcnt = waves.size();
+ // FIXME: ick
TimeAxisViewItem::set_height (height - 2);
_height = height;
@@ -695,36 +598,16 @@ AudioRegionView::reset_fade_out_shape_width (jack_nframes_t width)
void
AudioRegionView::set_samples_per_unit (gdouble spu)
{
- TimeAxisViewItem::set_samples_per_unit (spu);
+ RegionView::set_samples_per_unit (spu);
for (uint32_t n=0; n < waves.size(); ++n) {
waves[n]->property_samples_per_unit() = spu;
}
- for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- (*i)->set_samples_per_unit (spu);
- (*i)->set_duration (_region.length() / samples_per_unit);
- }
-
if (gain_line) {
gain_line->reset ();
}
reset_fade_shapes ();
- region_sync_changed ();
-}
-
-bool
-AudioRegionView::set_duration (jack_nframes_t frames, void *src)
-{
- if (!TimeAxisViewItem::set_duration (frames, src)) {
- return false;
- }
-
- for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- (*i)->set_duration (_region.length() / samples_per_unit);
- }
-
- return true;
}
void
@@ -738,7 +621,8 @@ AudioRegionView::set_amplitude_above_axis (gdouble spp)
void
AudioRegionView::compute_colors (Gdk::Color& basic_color)
{
- TimeAxisViewItem::compute_colors (basic_color);
+ RegionView::compute_colors(basic_color);
+
uint32_t r, g, b, a;
/* gain color computed in envelope_active_changed() */
@@ -750,16 +634,12 @@ AudioRegionView::compute_colors (Gdk::Color& basic_color)
void
AudioRegionView::set_colors ()
{
- TimeAxisViewItem::set_colors ();
+ RegionView::set_colors();
if (gain_line) {
gain_line->set_line_color (audio_region().envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]);
}
- if (sync_mark) {
- sync_mark->property_fill_color_rgba() = fill_color;
- }
-
for (uint32_t n=0; n < waves.size(); ++n) {
if (_region.muted()) {
waves[n]->property_wave_color() = color_map[cMutedWaveForm];
@@ -770,18 +650,6 @@ AudioRegionView::set_colors ()
}
void
-AudioRegionView::set_frame_color ()
-{
- if (_region.opaque()) {
- fill_opacity = 180;
- } else {
- fill_opacity = 100;
- }
-
- TimeAxisViewItem::set_frame_color ();
-}
-
-void
AudioRegionView::show_region_editor ()
{
if (editor == 0) {
@@ -796,89 +664,6 @@ AudioRegionView::show_region_editor ()
}
void
-AudioRegionView::hide_region_editor()
-{
- if (editor) {
- editor->hide_all ();
- }
-}
-
-void
-AudioRegionView::region_renamed ()
-{
- string str;
-
- if (_region.locked()) {
- str += '>';
- str += _region.name();
- str += '<';
- } else {
- str = _region.name();
- }
-
- if (audio_region().speed_mismatch (trackview.session().frame_rate())) {
- str = string ("*") + str;
- }
-
- if (_region.muted()) {
- str = string ("!") + str;
- }
-
- set_item_name (str, this);
- set_name_text (str);
-}
-
-void
-AudioRegionView::region_sync_changed ()
-{
- if (sync_mark == 0) {
- return;
- }
-
- int sync_dir;
- jack_nframes_t sync_offset;
-
- sync_offset = _region.sync_offset (sync_dir);
-
- /* this has to handle both a genuine change of position, a change of samples_per_unit,
- and a change in the bounds of the _region.
- */
-
- if (sync_offset == 0) {
-
- /* no sync mark - its the start of the region */
-
- sync_mark->hide();
-
- } else {
-
- if ((sync_dir < 0) || ((sync_dir > 0) && (sync_offset > _region.length()))) {
-
- /* no sync mark - its out of the bounds of the region */
-
- sync_mark->hide();
-
- } else {
-
- /* lets do it */
-
- Points points;
-
- //points = sync_mark->property_points().get_value();
-
- double offset = sync_offset / samples_per_unit;
- points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1));
- points.push_back (Gnome::Art::Point (offset + ((sync_mark_width-1)/2), 1));
- points.push_back (Gnome::Art::Point (offset, sync_mark_width - 1));
- points.push_back (Gnome::Art::Point (offset - ((sync_mark_width-1)/2), 1));
- sync_mark->property_points().set_value (points);
- sync_mark->show();
-
- }
- }
-}
-
-void
AudioRegionView::set_waveform_visible (bool yn)
{
if (((_flags & WaveformVisible) != yn)) {
@@ -954,8 +739,8 @@ AudioRegionView::create_waves ()
wave_caches.push_back (WaveView::create_cache ());
- if (wait_for_waves) {
- if (audio_region().source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), peaks_ready_connection)) {
+ if (wait_for_data) {
+ if (audio_region().source(n).peaks_ready (bind (mem_fun(*this, &AudioRegionView::peaks_ready_handler), n), data_ready_connection)) {
create_one_wave (n, true);
} else {
create_zero_line = false;
@@ -1056,7 +841,7 @@ AudioRegionView::peaks_ready_handler (uint32_t which)
if (!waves.empty()) {
/* all waves created, don't hook into peaks ready anymore */
- peaks_ready_connection.disconnect ();
+ data_ready_connection.disconnect ();
}
}
@@ -1184,22 +969,6 @@ AudioRegionView::set_waveform_shape (WaveformShape shape)
}
}
-void
-AudioRegionView::move (double x_delta, double y_delta)
-{
- if (_region.locked() || (x_delta == 0 && y_delta == 0)) {
- return;
- }
-
- get_canvas_group()->move (x_delta, y_delta);
-
- /* note: ghosts never leave their tracks so y_delta for them is always zero */
-
- for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- (*i)->group->move (x_delta, 0.0);
- }
-}
-
GhostRegion*
AudioRegionView::add_ghost (AutomationTimeAxisView& atv)
{
@@ -1244,21 +1013,6 @@ AudioRegionView::add_ghost (AutomationTimeAxisView& atv)
}
void
-AudioRegionView::remove_ghost (GhostRegion* ghost)
-{
- if (in_destructor) {
- return;
- }
-
- for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
- if (*i == ghost) {
- ghosts.erase (i);
- break;
- }
- }
-}
-
-void
AudioRegionView::entered ()
{
if (gain_line && _flags & EnvelopeVisible) {
diff --git a/gtk2_ardour/audio_regionview.h b/gtk2_ardour/audio_regionview.h
index 7889f0c8b5..b59f5f4791 100644
--- a/gtk2_ardour/audio_regionview.h
+++ b/gtk2_ardour/audio_regionview.h
@@ -57,21 +57,15 @@ class AudioRegionView : public RegionView
~AudioRegionView ();
- virtual void init (Gdk::Color& base_color, bool wait_for_waves);
+ virtual void init (Gdk::Color& base_color, bool wait_for_data = false);
ARDOUR::AudioRegion& audio_region() const;
- bool is_valid() const { return valid; }
- void set_valid (bool yn) { valid = yn; }
-
void set_height (double);
void set_samples_per_unit (double);
- bool set_duration (jack_nframes_t, void*);
void set_amplitude_above_axis (gdouble spp);
- void move (double xdelta, double ydelta);
-
void temporarily_hide_envelope (); ///< Dangerous!
void unhide_envelope (); ///< Dangerous!
@@ -80,11 +74,10 @@ class AudioRegionView : public RegionView
void set_waveform_shape (WaveformShape);
bool waveform_rectified() const { return _flags & WaveformRectified; }
- bool waveform_visible() const { return _flags & WaveformVisible; }
- bool envelope_visible() const { return _flags & EnvelopeVisible; }
+ bool waveform_visible() const { return _flags & WaveformVisible; }
+ bool envelope_visible() const { return _flags & EnvelopeVisible; }
void show_region_editor ();
- void hide_region_editor();
void add_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event);
void remove_gain_point_event (ArdourCanvas::Item *item, GdkEvent *event);
@@ -95,7 +88,6 @@ class AudioRegionView : public RegionView
void envelope_active_changed ();
GhostRegion* add_ghost (AutomationTimeAxisView&);
- void remove_ghost (GhostRegion*);
void reset_fade_in_shape_width (jack_nframes_t);
void reset_fade_out_shape_width (jack_nframes_t);
@@ -113,11 +105,11 @@ class AudioRegionView : public RegionView
*/
AudioRegionView (ArdourCanvas::Group *,
- RouteTimeAxisView&,
- ARDOUR::AudioRegion&,
- double initial_samples_per_unit,
- Gdk::Color& basic_color,
- TimeAxisViewItem::Visibility);
+ RouteTimeAxisView&,
+ ARDOUR::AudioRegion&,
+ double samples_per_unit,
+ Gdk::Color& basic_color,
+ TimeAxisViewItem::Visibility);
enum Flags {
EnvelopeVisible = 0x1,
@@ -125,32 +117,22 @@ class AudioRegionView : public RegionView
WaveformRectified = 0x8
};
- vector<ArdourCanvas::WaveView *> waves; ///< waveviews
+ vector<ArdourCanvas::WaveView *> waves;
vector<ArdourCanvas::WaveView *> tmp_waves; ///< see ::create_waves()
- ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position
- ArdourCanvas::Text* no_wave_msg; ///< text
- ArdourCanvas::SimpleLine* zero_line; ///< simpleline
- ArdourCanvas::Polygon* fade_in_shape; ///< polygon
- ArdourCanvas::Polygon* fade_out_shape; ///< polygon
- ArdourCanvas::SimpleRect* fade_in_handle; ///< simplerect
- ArdourCanvas::SimpleRect* fade_out_handle; ///< simplerect
+ ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position
+ ArdourCanvas::SimpleLine* zero_line;
+ ArdourCanvas::Polygon* fade_in_shape;
+ ArdourCanvas::Polygon* fade_out_shape;
+ ArdourCanvas::SimpleRect* fade_in_handle;
+ ArdourCanvas::SimpleRect* fade_out_handle;
AudioRegionGainLine * gain_line;
- AudioRegionEditor * editor;
- vector<ControlPoint *> control_points;
double _amplitude_above_axis;
- double current_visible_sync_position;
uint32_t _flags;
uint32_t fade_color;
- bool valid; /* see StreamView::redisplay_diskstream() */
- double _pixel_width;
- double _height;
- bool in_destructor;
- bool wait_for_waves;
- sigc::connection peaks_ready_connection;
-
+
void reset_fade_shapes ();
void reset_fade_in_shape ();
void reset_fade_out_shape ();
@@ -162,31 +144,21 @@ class AudioRegionView : public RegionView
void region_resized (ARDOUR::Change);
void region_moved (void *);
void region_muted ();
- void region_locked ();
- void region_layered ();
- void region_renamed ();
- void region_sync_changed ();
void region_scale_amplitude_changed ();
- static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*);
- void lock_toggle ();
-
void create_waves ();
void create_one_wave (uint32_t, bool);
void manage_zero_line ();
void peaks_ready_handler (uint32_t);
- void reset_name (gdouble width);
void set_flags (XMLNode *);
void store_flags ();
void set_colors ();
void compute_colors (Gdk::Color&);
- virtual void set_frame_color ();
void reset_width_dependent_items (double pixel_width);
void set_waveview_data_src();
vector<GnomeCanvasWaveViewCache*> wave_caches;
- vector<GhostRegion*> ghosts;
void color_handler (ColorID, uint32_t);
};
diff --git a/gtk2_ardour/audio_streamview.cc b/gtk2_ardour/audio_streamview.cc
index 1e43f1dac1..0d0cd7889c 100644
--- a/gtk2_ardour/audio_streamview.cc
+++ b/gtk2_ardour/audio_streamview.cc
@@ -54,7 +54,6 @@ using namespace Editing;
AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
: StreamView (tv)
{
- region_color = _trackview.color();
crossfades_visible = true;
if (tv.is_audio_track())
@@ -62,43 +61,16 @@ AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
else
stream_base_color = color_map[cAudioBusBase];
- /* set_position() will position the group */
-
- canvas_group = new ArdourCanvas::Group(*_trackview.canvas_display);
-
- canvas_rect = new ArdourCanvas::SimpleRect (*canvas_group);
- canvas_rect->property_x1() = 0.0;
- canvas_rect->property_y1() = 0.0;
- canvas_rect->property_x2() = 1000000.0;
- canvas_rect->property_y2() = (double) tv.height;
canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline];
- canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); // outline ends and bottom
- canvas_rect->property_fill_color_rgba() = stream_base_color;
-
- canvas_rect->signal_event().connect (bind (mem_fun (_trackview.editor, &PublicEditor::canvas_stream_view_event), canvas_rect, &_trackview));
- _samples_per_unit = _trackview.editor.get_current_zoom();
_amplitude_above_axis = 1.0;
- if (_trackview.is_audio_track()) {
- _trackview.audio_track()->DiskstreamChanged.connect (mem_fun (*this, &AudioStreamView::diskstream_changed));
- _trackview.session().TransportStateChange.connect (mem_fun (*this, &AudioStreamView::transport_changed));
- _trackview.get_diskstream()->RecordEnableChanged.connect (mem_fun (*this, &AudioStreamView::rec_enable_changed));
- _trackview.session().RecordStateChanged.connect (mem_fun (*this, &AudioStreamView::sess_rec_enable_changed));
- }
-
- rec_updating = false;
- rec_active = false;
use_rec_regions = tv.editor.show_waveforms_recording ();
last_rec_peak_frame = 0;
-
- ColorChanged.connect (mem_fun (*this, &AudioStreamView::color_handler));
}
AudioStreamView::~AudioStreamView ()
{
- undisplay_diskstream ();
- delete canvas_group;
}
int
@@ -132,7 +104,6 @@ AudioStreamView::set_samples_per_unit (gdouble spp)
int
AudioStreamView::set_amplitude_above_axis (gdouble app)
-
{
RegionViewList::iterator i;
@@ -206,8 +177,6 @@ AudioStreamView::remove_region_view (Region *r)
{
ENSURE_GUI_THREAD (bind (mem_fun (*this, &AudioStreamView::remove_region_view), r));
- StreamView::remove_region_view(r);
-
for (list<CrossfadeView *>::iterator i = crossfade_views.begin(); i != crossfade_views.end();) {
list<CrossfadeView*>::iterator tmp;
@@ -222,6 +191,8 @@ AudioStreamView::remove_region_view (Region *r)
i = tmp;
}
+
+ StreamView::remove_region_view(r);
}
void
diff --git a/gtk2_ardour/audio_streamview.h b/gtk2_ardour/audio_streamview.h
index d05ecd9307..05ce8125f6 100644
--- a/gtk2_ardour/audio_streamview.h
+++ b/gtk2_ardour/audio_streamview.h
@@ -59,10 +59,9 @@ class AudioStreamView : public StreamView
void set_waveform_shape (WaveformShape);
int set_height (gdouble h);
-
int set_samples_per_unit (gdouble spp);
- int set_amplitude_above_axis (gdouble app);
+ int set_amplitude_above_axis (gdouble app);
gdouble get_amplitude_above_axis () { return _amplitude_above_axis; }
void set_show_waveforms (bool yn);
@@ -90,17 +89,17 @@ class AudioStreamView : public StreamView
void playlist_modified ();
void playlist_changed (ARDOUR::Diskstream *ds);
- bool crossfades_visible;
void add_crossfade (ARDOUR::Crossfade*);
void remove_crossfade (ARDOUR::Crossfade*);
void color_handler (ColorID id, uint32_t val);
+ double _amplitude_above_axis;
+
typedef list<CrossfadeView*> CrossfadeViewList;
CrossfadeViewList crossfade_views;
-
- double _amplitude_above_axis;
+ bool crossfades_visible;
list<sigc::connection> peak_ready_connections;
jack_nframes_t last_rec_peak_frame;
diff --git a/gtk2_ardour/audio_time_axis.cc b/gtk2_ardour/audio_time_axis.cc
index ea822b97c5..13383fa6a4 100644
--- a/gtk2_ardour/audio_time_axis.cc
+++ b/gtk2_ardour/audio_time_axis.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -41,7 +41,6 @@
#include <ardour/audioplaylist.h>
#include <ardour/audio_diskstream.h>
#include <ardour/insert.h>
-#include <ardour/ladspa_plugin.h>
#include <ardour/location.h>
#include <ardour/panner.h>
#include <ardour/playlist.h>
@@ -53,25 +52,18 @@
#include "audio_time_axis.h"
#include "automation_gain_line.h"
#include "automation_pan_line.h"
-#include "automation_time_axis.h"
#include "canvas_impl.h"
#include "crossfade_view.h"
#include "enums.h"
#include "gain_automation_time_axis.h"
-#include "gui_thread.h"
#include "keyboard.h"
#include "pan_automation_time_axis.h"
#include "playlist_selector.h"
#include "plugin_selector.h"
#include "plugin_ui.h"
-#include "point_selection.h"
#include "prompter.h"
#include "public_editor.h"
-#include "redirect_automation_line.h"
-#include "redirect_automation_time_axis.h"
#include "audio_regionview.h"
-#include "rgb_macros.h"
-#include "selection.h"
#include "simplerect.h"
#include "audio_streamview.h"
#include "utils.h"
@@ -87,9 +79,12 @@ using namespace Editing;
AudioTimeAxisView::AudioTimeAxisView (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)
+ , RouteTimeAxisView(ed, sess, rt, canvas)
{
+ // Make sure things are sane...
+ assert(!is_track() || is_audio_track());
+
subplugin_menu.set_name ("ArdourContextMenu");
gain_track = 0;
pan_track = 0;
@@ -143,11 +138,6 @@ AudioTimeAxisView::AudioTimeAxisView (PublicEditor& ed, Session& sess, boost::sh
AudioTimeAxisView::~AudioTimeAxisView ()
{
- vector_delete (&redirect_automation_curves);
-
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
- delete *i;
- }
}
AudioStreamView*
@@ -227,56 +217,14 @@ AudioTimeAxisView::set_state (const XMLNode& node)
}
void
-AudioTimeAxisView::reset_redirect_automation_curves ()
-{
- for (vector<RedirectAutomationLine*>::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) {
- (*i)->reset();
- }
-}
-
-void
-AudioTimeAxisView::build_display_menu ()
+AudioTimeAxisView::build_automation_action_menu ()
{
using namespace Menu_Helpers;
- /* get the size menu ready */
-
- build_size_menu ();
-
- /* prepare it */
-
- TimeAxisView::build_display_menu ();
-
- /* now fill it with our stuff */
-
- MenuList& items = display_menu->items();
- display_menu->set_name ("ArdourContextMenu");
-
- items.push_back (MenuElem (_("Height"), *size_menu));
- items.push_back (MenuElem (_("Color"), mem_fun(*this, &AudioTimeAxisView::select_track_color)));
-
-
- items.push_back (SeparatorElem());
- items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
- items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
- items.push_back (SeparatorElem());
-
- build_remote_control_menu ();
- items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
+ RouteTimeAxisView::build_automation_action_menu ();
- automation_action_menu = manage (new Menu);
MenuList& automation_items = automation_action_menu->items();
- automation_action_menu->set_name ("ArdourContextMenu");
- automation_items.push_back (MenuElem (_("Show all automation"),
- mem_fun(*this, &AudioTimeAxisView::show_all_automation)));
-
- automation_items.push_back (MenuElem (_("Show existing automation"),
- mem_fun(*this, &AudioTimeAxisView::show_existing_automation)));
-
- automation_items.push_back (MenuElem (_("Hide all automation"),
- mem_fun(*this, &AudioTimeAxisView::hide_all_automation)));
-
automation_items.push_back (SeparatorElem());
automation_items.push_back (CheckMenuElem (_("Fader"),
@@ -288,11 +236,21 @@ AudioTimeAxisView::build_display_menu ()
mem_fun(*this, &AudioTimeAxisView::toggle_pan_track)));
pan_automation_item = static_cast<CheckMenuItem*> (&automation_items.back());
pan_automation_item->set_active(show_pan_automation);
+
+}
- automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
+void
+AudioTimeAxisView::append_extra_display_menu_items ()
+{
+ using namespace Menu_Helpers;
- items.push_back (MenuElem (_("Automation"), *automation_action_menu));
+ MenuList& items = display_menu->items();
+ // crossfade stuff
+ items.push_back (MenuElem (_("Hide all crossfades"), mem_fun(*this, &AudioTimeAxisView::hide_all_xfades)));
+ items.push_back (MenuElem (_("Show all crossfades"), mem_fun(*this, &AudioTimeAxisView::show_all_xfades)));
+
+ // waveform menu
Menu *waveform_menu = manage(new Menu);
MenuList& waveform_items = waveform_menu->items();
waveform_menu->set_name ("ArdourContextMenu");
@@ -312,39 +270,6 @@ AudioTimeAxisView::build_display_menu ()
rectified_item = static_cast<RadioMenuItem *> (&waveform_items.back());
items.push_back (MenuElem (_("Waveform"), *waveform_menu));
-
- if (is_audio_track()) {
-
- Menu* alignment_menu = manage (new Menu);
- MenuList& alignment_items = alignment_menu->items();
- alignment_menu->set_name ("ArdourContextMenu");
-
- RadioMenuItem::Group align_group;
-
- alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), ExistingMaterial)));
- align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
- if (get_diskstream()->alignment_style() == ExistingMaterial) {
- align_existing_item->set_active();
- }
- alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"), bind (mem_fun(*this, &AudioTimeAxisView::set_align_style), CaptureTime)));
- align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
- if (get_diskstream()->alignment_style() == CaptureTime) {
- align_capture_item->set_active();
- }
-
- items.push_back (MenuElem (_("Alignment"), *alignment_menu));
-
- get_diskstream()->AlignmentStyleChanged.connect (mem_fun(*this, &AudioTimeAxisView::align_style_changed));
- }
-
- items.push_back (SeparatorElem());
- items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active)));
- route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
- route_active_menu_item->set_active (_route->active());
-
- items.push_back (SeparatorElem());
- items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
-
}
void
@@ -394,16 +319,6 @@ AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
}
void
-AudioTimeAxisView::set_selected_regionviews (RegionSelection& regions)
-{
- AudioStreamView* asv = audio_view();
-
- if (asv) {
- asv->set_selected_regionviews (regions);
- }
-}
-
-void
AudioTimeAxisView::add_gain_automation_child ()
{
XMLProperty* prop;
@@ -587,322 +502,6 @@ AudioTimeAxisView::pan_hidden ()
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
}
-AudioTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo ()
-{
- for (vector<RedirectAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
- delete *i;
- }
-}
-
-
-AudioTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode ()
-{
- parent.remove_ran (this);
-
- if (view) {
- delete view;
- }
-}
-
-void
-AudioTimeAxisView::remove_ran (RedirectAutomationNode* ran)
-{
- if (ran->view) {
- remove_child (ran->view);
- }
-}
-
-AudioTimeAxisView::RedirectAutomationNode*
-AudioTimeAxisView::find_redirect_automation_node (boost::shared_ptr<Redirect> redirect, uint32_t what)
-{
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
-
- if ((*i)->redirect == redirect) {
-
- for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- if ((*ii)->what == what) {
- return *ii;
- }
- }
- }
- }
-
- return 0;
-}
-
-// FIXME: duplicated in midi_time_axis.cc
-static string
-legalize_for_xml_node (string str)
-{
- string::size_type pos;
- string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:";
- string legal;
-
- legal = str;
- pos = 0;
-
- while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
- legal.replace (pos, 1, "_");
- pos += 1;
- }
-
- return legal;
-}
-
-
-void
-AudioTimeAxisView::add_redirect_automation_curve (boost::shared_ptr<Redirect> redirect, uint32_t what)
-{
- RedirectAutomationLine* ral;
- string name;
- RedirectAutomationNode* ran;
-
- if ((ran = find_redirect_automation_node (redirect, what)) == 0) {
- fatal << _("programming error: ")
- << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"),
- redirect->name(), what)
- << endmsg;
- /*NOTREACHED*/
- return;
- }
-
- if (ran->view) {
- return;
- }
-
- name = redirect->describe_parameter (what);
-
- /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
-
- char state_name[256];
- snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what);
-
- ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name);
-
- ral = new RedirectAutomationLine (name,
- *redirect, what, _session, *ran->view,
- *ran->view->canvas_display, redirect->automation_list (what));
-
- ral->set_line_color (color_map[cRedirectAutomationLine]);
- ral->queue_reset ();
-
- ran->view->add_line (*ral);
-
- ran->view->Hiding.connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_automation_track_hidden), ran, redirect));
-
- if (!ran->view->marked_for_display()) {
- ran->view->hide ();
- } else {
- ran->menu_item->set_active (true);
- }
-
- add_child (ran->view);
-
- audio_view()->foreach_regionview (bind (mem_fun(*this, &AudioTimeAxisView::add_ghost_to_redirect), ran->view));
-
- redirect->mark_automation_visible (what, true);
-}
-
-void
-AudioTimeAxisView::redirect_automation_track_hidden (AudioTimeAxisView::RedirectAutomationNode* ran, boost::shared_ptr<Redirect> r)
-{
- if (!_hidden) {
- ran->menu_item->set_active (false);
- }
-
- r->mark_automation_visible (ran->what, false);
-
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
-}
-
-void
-AudioTimeAxisView::add_existing_redirect_automation_curves (boost::shared_ptr<Redirect> redirect)
-{
- set<uint32_t> s;
- RedirectAutomationLine *ral;
-
- redirect->what_has_visible_automation (s);
-
- for (set<uint32_t>::iterator i = s.begin(); i != s.end(); ++i) {
-
- if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) {
- ral->queue_reset ();
- } else {
- add_redirect_automation_curve (redirect, (*i));
- }
- }
-}
-
-void
-AudioTimeAxisView::add_redirect_to_subplugin_menu (boost::shared_ptr<Redirect> r)
-{
- using namespace Menu_Helpers;
- RedirectAutomationInfo *rai;
- list<RedirectAutomationInfo*>::iterator x;
-
- const std::set<uint32_t>& automatable = r->what_can_be_automated ();
- std::set<uint32_t> has_visible_automation;
-
- r->what_has_visible_automation(has_visible_automation);
-
- if (automatable.empty()) {
- return;
- }
-
- for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) {
- if ((*x)->redirect == r) {
- break;
- }
- }
-
- if (x == redirect_automation.end()) {
-
- rai = new RedirectAutomationInfo (r);
- redirect_automation.push_back (rai);
-
- } else {
-
- rai = *x;
-
- }
-
- /* any older menu was deleted at the top of redirects_changed()
- when we cleared the subplugin menu.
- */
-
- rai->menu = manage (new Menu);
- MenuList& items = rai->menu->items();
- rai->menu->set_name ("ArdourContextMenu");
-
- items.clear ();
-
- for (std::set<uint32_t>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
-
- RedirectAutomationNode* ran;
- CheckMenuItem* mitem;
-
- string name = r->describe_parameter (*i);
-
- items.push_back (CheckMenuElem (name));
- mitem = dynamic_cast<CheckMenuItem*> (&items.back());
-
- if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
- mitem->set_active(true);
- }
-
- if ((ran = find_redirect_automation_node (r, *i)) == 0) {
-
- /* new item */
-
- ran = new RedirectAutomationNode (*i, mitem, *this);
-
- rai->lines.push_back (ran);
-
- } else {
-
- ran->menu_item = mitem;
-
- }
-
- mitem->signal_toggled().connect (bind (mem_fun(*this, &AudioTimeAxisView::redirect_menu_item_toggled), rai, ran));
- }
-
- /* add the menu for this redirect, because the subplugin
- menu is always cleared at the top of redirects_changed().
- this is the result of some poor design in gtkmm and/or
- GTK+.
- */
-
- subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu));
- rai->valid = true;
-}
-
-void
-AudioTimeAxisView::redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo* rai,
- AudioTimeAxisView::RedirectAutomationNode* ran)
-{
- bool showit = ran->menu_item->get_active();
- bool redraw = false;
-
- if (ran->view == 0 && showit) {
- add_redirect_automation_curve (rai->redirect, ran->what);
- redraw = true;
- }
-
- if (showit != ran->view->marked_for_display()) {
-
- if (showit) {
- ran->view->set_marked_for_display (true);
- ran->view->canvas_display->show();
- } else {
- rai->redirect->mark_automation_visible (ran->what, true);
- ran->view->set_marked_for_display (false);
- ran->view->hide ();
- }
-
- redraw = true;
-
- }
-
- if (redraw && !no_redraw) {
-
- /* now trigger a redisplay */
-
- _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
-
- }
-}
-
-void
-AudioTimeAxisView::redirects_changed (void *src)
-{
- using namespace Menu_Helpers;
-
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
- (*i)->valid = false;
- }
-
- subplugin_menu.items().clear ();
-
- _route->foreach_redirect (this, &AudioTimeAxisView::add_redirect_to_subplugin_menu);
- _route->foreach_redirect (this, &AudioTimeAxisView::add_existing_redirect_automation_curves);
-
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) {
-
- list<RedirectAutomationInfo*>::iterator tmp;
-
- tmp = i;
- ++tmp;
-
- if (!(*i)->valid) {
-
- delete *i;
- redirect_automation.erase (i);
-
- }
-
- i = tmp;
- }
-
- /* change in visibility was possible */
-
- _route->gui_changed ("track_height", this);
-}
-
-RedirectAutomationLine *
-AudioTimeAxisView::find_redirect_automation_curve (boost::shared_ptr<Redirect> redirect, uint32_t what)
-{
- RedirectAutomationNode* ran;
-
- if ((ran = find_redirect_automation_node (redirect, what)) != 0) {
- if (ran->view) {
- return dynamic_cast<RedirectAutomationLine*> (ran->view->lines.front());
- }
- }
-
- return 0;
-}
-
void
AudioTimeAxisView::show_all_automation ()
{
@@ -911,15 +510,7 @@ AudioTimeAxisView::show_all_automation ()
pan_automation_item->set_active (true);
gain_automation_item->set_active (true);
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
- for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- if ((*ii)->view == 0) {
- add_redirect_automation_curve ((*i)->redirect, (*ii)->what);
- }
-
- (*ii)->menu_item->set_active (true);
- }
- }
+ RouteTimeAxisView::show_all_automation ();
no_redraw = false;
@@ -934,13 +525,7 @@ AudioTimeAxisView::show_existing_automation ()
pan_automation_item->set_active (true);
gain_automation_item->set_active (true);
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
- for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- if ((*ii)->view != 0) {
- (*ii)->menu_item->set_active (true);
- }
- }
- }
+ RouteTimeAxisView::show_existing_automation ();
no_redraw = false;
@@ -955,37 +540,13 @@ AudioTimeAxisView::hide_all_automation ()
pan_automation_item->set_active (false);
gain_automation_item->set_active (false);
- for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
- for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
- (*ii)->menu_item->set_active (false);
- }
- }
+ RouteTimeAxisView::hide_all_automation();
no_redraw = false;
_route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
}
void
-AudioTimeAxisView::region_view_added (RegionView* rv)
-{
- assert(dynamic_cast<AudioRegionView*>(rv));
-
- for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
- AutomationTimeAxisView* atv;
-
- if ((atv = dynamic_cast<AutomationTimeAxisView*> (*i)) != 0) {
- rv->add_ghost (*atv);
- }
- }
-}
-
-void
-AudioTimeAxisView::add_ghost_to_redirect (RegionView* rv, AutomationTimeAxisView* atv)
-{
- rv->add_ghost (*atv);
-}
-
-void
AudioTimeAxisView::show_all_xfades ()
{
AudioStreamView* asv = audio_view();
@@ -1030,7 +591,7 @@ AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi)
void
AudioTimeAxisView::route_active_changed ()
{
- RouteUI::route_active_changed ();
+ RouteTimeAxisView::route_active_changed ();
if (is_audio_track()) {
if (_route->active()) {
diff --git a/gtk2_ardour/audio_time_axis.h b/gtk2_ardour/audio_time_axis.h
index 2a6aa1c4d6..2162771285 100644
--- a/gtk2_ardour/audio_time_axis.h
+++ b/gtk2_ardour/audio_time_axis.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -33,7 +33,6 @@
#include <list>
#include <ardour/types.h>
-#include <ardour/region.h>
#include "ardour_dialog.h"
#include "route_ui.h"
@@ -62,7 +61,6 @@ class AudioRegionView;
class AutomationLine;
class AutomationGainLine;
class AutomationPanLine;
-class RedirectAutomationLine;
class TimeSelection;
class AutomationTimeAxisView;
@@ -78,11 +76,10 @@ class AudioTimeAxisView : public RouteTimeAxisView
void set_show_waveforms_recording (bool yn);
void show_all_xfades ();
void hide_all_xfades ();
- void set_selected_regionviews (RegionSelection&);
void hide_dependent_views (TimeAxisViewItem&);
void reveal_dependent_views (TimeAxisViewItem&);
- /* overridden from parent to store display state */
+ /* Overridden from parent to store display state */
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
void hide ();
@@ -95,83 +92,16 @@ class AudioTimeAxisView : public RouteTimeAxisView
void route_active_changed ();
- AutomationTimeAxisView *gain_track;
- AutomationTimeAxisView *pan_track;
-
- void update_automation_view (ARDOUR::AutomationType);
- void reset_redirect_automation_curves ();
-
- // variables to get the context menu
- // automation buttons correctly initialized
- bool show_gain_automation;
- bool show_pan_automation;
-
- // FIXME?
- void redirects_changed (void *);
-
- void build_display_menu ();
-
- Gtk::CheckMenuItem* waveform_item;
- Gtk::RadioMenuItem* traditional_item;
- Gtk::RadioMenuItem* rectified_item;
+ void build_automation_action_menu ();
+ void append_extra_display_menu_items ();
void toggle_show_waveforms ();
-
void set_waveform_shape (WaveformShape);
void toggle_waveforms ();
- /* automation stuff */
-
- Gtk::Menu* automation_action_menu;
- Gtk::CheckMenuItem* gain_automation_item;
- Gtk::CheckMenuItem* pan_automation_item;
-
- void automation_click ();
- void clear_automation ();
- void hide_all_automation ();
void show_all_automation ();
void show_existing_automation ();
-
- struct RedirectAutomationNode {
- uint32_t what;
- Gtk::CheckMenuItem* menu_item;
- AutomationTimeAxisView* view;
- AudioTimeAxisView& parent;
-
- RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, AudioTimeAxisView& p)
- : what (w), menu_item (mitem), view (0), parent (p) {}
-
- ~RedirectAutomationNode ();
- };
-
- struct RedirectAutomationInfo {
- boost::shared_ptr<ARDOUR::Redirect> redirect;
- bool valid;
- Gtk::Menu* menu;
- vector<RedirectAutomationNode*> lines;
-
- RedirectAutomationInfo (boost::shared_ptr<ARDOUR::Redirect> r)
- : redirect (r), valid (true) {}
-
- ~RedirectAutomationInfo ();
- };
-
- list<RedirectAutomationInfo*> redirect_automation;
- RedirectAutomationNode* find_redirect_automation_node (boost::shared_ptr<ARDOUR::Redirect> redirect, uint32_t what);
-
- Gtk::Menu subplugin_menu;
- void add_redirect_to_subplugin_menu (boost::shared_ptr<ARDOUR::Redirect>);
-
- void remove_ran (RedirectAutomationNode* ran);
-
- void redirect_menu_item_toggled (AudioTimeAxisView::RedirectAutomationInfo*,
- AudioTimeAxisView::RedirectAutomationNode*);
- void redirect_automation_track_hidden (RedirectAutomationNode*, boost::shared_ptr<ARDOUR::Redirect>);
-
- vector<RedirectAutomationLine*> redirect_automation_curves;
- RedirectAutomationLine *find_redirect_automation_curve (boost::shared_ptr<ARDOUR::Redirect>,uint32_t);
- void add_redirect_automation_curve (boost::shared_ptr<ARDOUR::Redirect>, uint32_t);
- void add_existing_redirect_automation_curves (boost::shared_ptr<ARDOUR::Redirect>);
+ void hide_all_automation ();
void add_gain_automation_child ();
void add_pan_automation_child ();
@@ -185,8 +115,18 @@ class AudioTimeAxisView : public RouteTimeAxisView
void update_pans ();
- void region_view_added (RegionView*);
- void add_ghost_to_redirect (RegionView*, AutomationTimeAxisView*);
+ AutomationTimeAxisView* gain_track;
+ AutomationTimeAxisView* pan_track;
+
+ // Set from XML so context menu automation buttons can be correctly initialized
+ bool show_gain_automation;
+ bool show_pan_automation;
+
+ Gtk::CheckMenuItem* waveform_item;
+ Gtk::RadioMenuItem* traditional_item;
+ Gtk::RadioMenuItem* rectified_item;
+ Gtk::CheckMenuItem* gain_automation_item;
+ Gtk::CheckMenuItem* pan_automation_item;
};
#endif /* __ardour_audio_time_axis_h__ */
diff --git a/gtk2_ardour/editor.cc b/gtk2_ardour/editor.cc
index 6edc738c41..fcd17cdb4c 100644
--- a/gtk2_ardour/editor.cc
+++ b/gtk2_ardour/editor.cc
@@ -209,15 +209,6 @@ Editor::Editor (AudioEngine& eng)
toolbar_selection_clock_table (2,3),
- //mouse_mode_button_table (2, 3),
-
- /*mouse_select_button (_("range")),
- mouse_move_button (_("object")),
- mouse_gain_button (_("gain")),
- mouse_zoom_button (_("zoom")),
- mouse_timefx_button (_("timefx")),
- mouse_audition_button (_("listen")),*/
-
automation_mode_button (_("mode")),
global_automation_button (_("automation")),
@@ -2588,9 +2579,8 @@ Editor::setup_toolbar ()
mouse_mode_button_box.pack_start(mouse_audition_button, true, true);
mouse_mode_button_box.set_homogeneous(true);
- // This one needs a little more "FUDGE" on my machine at least..
edit_mode_selector.set_name ("EditModeSelector");
- Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "Splice Edit", 3+FUDGE, 10);
+ Gtkmm2ext::set_size_request_to_display_given_text (edit_mode_selector, "Splice Edit", 2+FUDGE, 10);
set_popdown_strings (edit_mode_selector, internationalize (edit_mode_strings));
edit_mode_selector.signal_changed().connect (mem_fun(*this, &Editor::edit_mode_selection_done));
diff --git a/gtk2_ardour/plugin_selector.h b/gtk2_ardour/plugin_selector.h
index 220de74871..bbaf359aa4 100644
--- a/gtk2_ardour/plugin_selector.h
+++ b/gtk2_ardour/plugin_selector.h
@@ -29,6 +29,7 @@ namespace ARDOUR {
class Session;
class PluginManager;
class Plugin;
+ class PluginInfo;
}
class PluginSelector : public ArdourDialog
diff --git a/gtk2_ardour/regionview.cc b/gtk2_ardour/regionview.cc
index d47b09853c..411117b1af 100644
--- a/gtk2_ardour/regionview.cc
+++ b/gtk2_ardour/regionview.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2001 Paul Davis
+ Copyright (C) 2001-2006 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
@@ -82,35 +82,21 @@ RegionView::RegionView (ArdourCanvas::Group* parent,
}
void
-RegionView::init (Gdk::Color& basic_color, bool wfw)
+RegionView::init (Gdk::Color& basic_color, bool wfd)
{
- ArdourCanvas::Points shape;
- //XMLNode *node;
-
- editor = 0;
- valid = true;
+ editor = 0;
+ valid = true;
in_destructor = false;
- _height = 0;
-
- _flags = 0;
-
- /*
- if ((node = _region.extra_xml ("GUI")) != 0) {
- set_flags (node);
- } else {
- //_flags = WaveformVisible;
- store_flags ();
- }*/
+ _height = 0;
+ wait_for_data = wfd;
compute_colors (basic_color);
name_highlight->set_data ("regionview", this);
name_text->set_data ("regionview", this);
- // shape = new ArdourCanvas::Points ();
-
/* an equilateral triangle */
-
+ ArdourCanvas::Points shape;
shape.push_back (Gnome::Art::Point (-((sync_mark_width-1)/2), 1));
shape.push_back (Gnome::Art::Point ((sync_mark_width - 1)/2, 1));
shape.push_back (Gnome::Art::Point (0, sync_mark_width - 1));
@@ -234,9 +220,6 @@ RegionView::region_resized (Change what_changed)
(*i)->set_duration (unit_length);
- /*for (vector<WaveView*>::iterator w = (*i)->waves.begin(); w != (*i)->waves.end(); ++w) {
- (*w)->property_region_start() = _region.start();
- }*/
}
}
}
@@ -246,27 +229,6 @@ RegionView::reset_width_dependent_items (double pixel_width)
{
TimeAxisViewItem::reset_width_dependent_items (pixel_width);
_pixel_width = pixel_width;
-/*
- if (zero_line) {
- zero_line->property_x2() = pixel_width - 1.0;
- }
-
- if (fade_in_handle) {
- if (pixel_width <= 6.0) {
- fade_in_handle->hide();
- fade_out_handle->hide();
- } else {
- if (_height < 5.0) {
- fade_in_handle->hide();
- fade_out_handle->hide();
- } else {
- fade_in_handle->show();
- fade_out_handle->show();
- }
- }
- }
-
- reset_fade_shapes ();*/
}
void
@@ -282,14 +244,6 @@ RegionView::region_muted ()
{
set_frame_color ();
region_renamed ();
-
- /*for (uint32_t n=0; n < waves.size(); ++n) {
- if (_region.muted()) {
- waves[n]->property_wave_color() = color_map[cMutedWaveForm];
- } else {
- waves[n]->property_wave_color() = color_map[cWaveForm];
- }
- }*/
}
void
@@ -350,19 +304,11 @@ RegionView::set_samples_per_unit (gdouble spu)
{
TimeAxisViewItem::set_samples_per_unit (spu);
- /*for (uint32_t n=0; n < waves.size(); ++n) {
- waves[n]->property_samples_per_unit() = spu;
- }*/
-
for (vector<GhostRegion*>::iterator i = ghosts.begin(); i != ghosts.end(); ++i) {
(*i)->set_samples_per_unit (spu);
(*i)->set_duration (_region.length() / samples_per_unit);
}
- /*if (gain_line) {
- gain_line->reset ();
- }*/
- //reset_fade_shapes ();
region_sync_changed ();
}
@@ -384,10 +330,6 @@ void
RegionView::compute_colors (Gdk::Color& basic_color)
{
TimeAxisViewItem::compute_colors (basic_color);
- uint32_t r, g, b, a;
-
- UINT_TO_RGBA (fill_color, &r, &g, &b, &a);
- fade_color = RGBA_TO_UINT(r,g,b,120);
}
void
@@ -395,21 +337,9 @@ RegionView::set_colors ()
{
TimeAxisViewItem::set_colors ();
- /*if (gain_line) {
- gain_line->set_line_color (_region.envelope_active() ? color_map[cGainLine] : color_map[cGainLineInactive]);
- }*/
-
if (sync_mark) {
sync_mark->property_fill_color_rgba() = fill_color;
}
-
- /*for (uint32_t n=0; n < waves.size(); ++n) {
- if (_region.muted()) {
- waves[n]->property_wave_color() = color_map[cMutedWaveForm];
- } else {
- waves[n]->property_wave_color() = color_map[cWaveForm];
- }
- }*/
}
void
@@ -445,10 +375,9 @@ RegionView::region_renamed ()
str = _region.name();
}
- /* FIXME
if (_region.speed_mismatch (trackview.session().frame_rate())) {
str = string ("*") + str;
- }*/
+ }
if (_region.muted()) {
str = string ("!") + str;
diff --git a/gtk2_ardour/regionview.h b/gtk2_ardour/regionview.h
index 29c5817a25..d2d2c22760 100644
--- a/gtk2_ardour/regionview.h
+++ b/gtk2_ardour/regionview.h
@@ -49,7 +49,7 @@ class RegionView : public TimeAxisViewItem
~RegionView ();
- virtual void init (Gdk::Color& base_color, bool wait_for_waves);
+ virtual void init (Gdk::Color& base_color, bool wait_for_data);
ARDOUR::Region& region() const { return _region; }
@@ -57,8 +57,8 @@ class RegionView : public TimeAxisViewItem
void set_valid (bool yn) { valid = yn; }
virtual void set_height (double) = 0;
- void set_samples_per_unit (double);
- bool set_duration (jack_nframes_t, void*);
+ virtual void set_samples_per_unit (double);
+ virtual bool set_duration (jack_nframes_t, void*);
void move (double xdelta, double ydelta);
@@ -70,9 +70,9 @@ class RegionView : public TimeAxisViewItem
bool set_position(jack_nframes_t pos, void* src, double* delta = 0);
virtual void show_region_editor () = 0;
- void hide_region_editor();
+ virtual void hide_region_editor();
- void region_changed (ARDOUR::Change);
+ virtual void region_changed (ARDOUR::Change);
virtual GhostRegion* add_ghost (AutomationTimeAxisView&) = 0;
void remove_ghost (GhostRegion*);
@@ -93,56 +93,44 @@ class RegionView : public TimeAxisViewItem
RegionView (ArdourCanvas::Group *,
TimeAxisView&,
ARDOUR::Region&,
- double initial_samples_per_unit,
+ double samples_per_unit,
Gdk::Color& basic_color,
TimeAxisViewItem::Visibility);
ARDOUR::Region& _region;
- enum Flags {
- EnvelopeVisible = 0x1,
- WaveformVisible = 0x4,
- WaveformRectified = 0x8
- };
-
ArdourCanvas::Polygon* sync_mark; ///< polgyon for sync position
- ArdourCanvas::Text* no_wave_msg; ///< text
+ ArdourCanvas::Text* no_wave_msg;
RegionEditor *editor;
vector<ControlPoint *> control_points;
double current_visible_sync_position;
- uint32_t _flags;
- uint32_t fade_color;
bool valid; ///< see StreamView::redisplay_diskstream()
double _pixel_width;
double _height;
bool in_destructor;
- bool wait_for_waves;
-
- sigc::connection peaks_ready_connection;
-
- void region_resized (ARDOUR::Change);
- void region_moved (void *);
- void region_muted ();
- void region_locked ();
- void region_opacity ();
- void region_layered ();
- void region_renamed ();
- void region_sync_changed ();
- void region_scale_amplitude_changed ();
+
+ bool wait_for_data;
+ sigc::connection data_ready_connection;
+
+ virtual void region_resized (ARDOUR::Change);
+ void region_moved (void *);
+ virtual void region_muted ();
+ void region_locked ();
+ void region_opacity ();
+ void region_layered ();
+ void region_renamed ();
+ void region_sync_changed ();
static gint _lock_toggle (ArdourCanvas::Item*, GdkEvent*, void*);
void lock_toggle ();
- void peaks_ready_handler (uint32_t);
- void reset_name (gdouble width);
-
- void set_colors ();
- void compute_colors (Gdk::Color&);
+ virtual void set_colors ();
+ virtual void compute_colors (Gdk::Color&);
virtual void set_frame_color ();
- void reset_width_dependent_items (double pixel_width);
+ virtual void reset_width_dependent_items (double pixel_width);
vector<GhostRegion*> ghosts;
diff --git a/gtk2_ardour/route_time_axis.cc b/gtk2_ardour/route_time_axis.cc
index b4f250b5ef..1eba885b44 100644
--- a/gtk2_ardour/route_time_axis.cc
+++ b/gtk2_ardour/route_time_axis.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2006 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
@@ -30,6 +30,8 @@
#include <pbd/stl_delete.h>
#include <pbd/whitespace.h>
+#include <gtkmm/menu.h>
+#include <gtkmm/menuitem.h>
#include <gtkmm2ext/gtk_ui.h>
#include <gtkmm2ext/selector.h>
#include <gtkmm2ext/stop_signal.h>
@@ -49,6 +51,9 @@
#include "ardour_ui.h"
#include "route_time_axis.h"
+#include "automation_time_axis.h"
+#include "redirect_automation_time_axis.h"
+#include "redirect_automation_line.h"
#include "canvas_impl.h"
#include "crossfade_view.h"
#include "enums.h"
@@ -217,6 +222,12 @@ RouteTimeAxisView::~RouteTimeAxisView ()
{
GoingAway (); /* EMIT_SIGNAL */
+ vector_delete (&redirect_automation_curves);
+
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
+ delete *i;
+ }
+
if (playlist_menu) {
delete playlist_menu;
playlist_menu = 0;
@@ -374,6 +385,97 @@ RouteTimeAxisView::automation_click ()
}
void
+RouteTimeAxisView::build_automation_action_menu ()
+{
+ using namespace Menu_Helpers;
+
+ automation_action_menu = manage (new Menu);
+ MenuList& automation_items = automation_action_menu->items();
+ automation_action_menu->set_name ("ArdourContextMenu");
+
+ automation_items.push_back (MenuElem (_("Show all automation"),
+ mem_fun(*this, &RouteTimeAxisView::show_all_automation)));
+
+ automation_items.push_back (MenuElem (_("Show existing automation"),
+ mem_fun(*this, &RouteTimeAxisView::show_existing_automation)));
+
+ automation_items.push_back (MenuElem (_("Hide all automation"),
+ mem_fun(*this, &RouteTimeAxisView::hide_all_automation)));
+
+ automation_items.push_back (MenuElem (_("Plugins"), subplugin_menu));
+}
+
+void
+RouteTimeAxisView::build_display_menu ()
+{
+ using namespace Menu_Helpers;
+
+ /* get the size menu ready */
+
+ build_size_menu ();
+
+ /* prepare it */
+
+ TimeAxisView::build_display_menu ();
+
+ /* now fill it with our stuff */
+
+ MenuList& items = display_menu->items();
+ display_menu->set_name ("ArdourContextMenu");
+
+ items.push_back (MenuElem (_("Height"), *size_menu));
+ items.push_back (MenuElem (_("Color"), mem_fun(*this, &RouteTimeAxisView::select_track_color)));
+
+ items.push_back (SeparatorElem());
+
+ build_remote_control_menu ();
+ items.push_back (MenuElem (_("Remote Control ID"), *remote_control_menu));
+
+ build_automation_action_menu ();
+ items.push_back (MenuElem (_("Automation"), *automation_action_menu));
+
+ // Hook for derived classes to add type specific stuff
+ items.push_back (SeparatorElem());
+ append_extra_display_menu_items ();
+ items.push_back (SeparatorElem());
+
+ if (is_track()) {
+
+ Menu* alignment_menu = manage (new Menu);
+ MenuList& alignment_items = alignment_menu->items();
+ alignment_menu->set_name ("ArdourContextMenu");
+
+ RadioMenuItem::Group align_group;
+
+ alignment_items.push_back (RadioMenuElem (align_group, _("Align with existing material"),
+ bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), ExistingMaterial)));
+ align_existing_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
+ if (get_diskstream()->alignment_style() == ExistingMaterial)
+ align_existing_item->set_active();
+
+ alignment_items.push_back (RadioMenuElem (align_group, _("Align with capture time"),
+ bind (mem_fun(*this, &RouteTimeAxisView::set_align_style), CaptureTime)));
+ align_capture_item = dynamic_cast<RadioMenuItem*>(&alignment_items.back());
+ if (get_diskstream()->alignment_style() == CaptureTime)
+ align_capture_item->set_active();
+
+ items.push_back (MenuElem (_("Alignment"), *alignment_menu));
+
+ get_diskstream()->AlignmentStyleChanged.connect (
+ mem_fun(*this, &RouteTimeAxisView::align_style_changed));
+ }
+
+ items.push_back (SeparatorElem());
+ items.push_back (CheckMenuElem (_("Active"), mem_fun(*this, &RouteUI::toggle_route_active)));
+ route_active_menu_item = dynamic_cast<CheckMenuItem *> (&items.back());
+ route_active_menu_item->set_active (_route->active());
+
+ items.push_back (SeparatorElem());
+ items.push_back (MenuElem (_("Remove"), mem_fun(*this, &RouteUI::remove_this_route)));
+}
+
+
+void
RouteTimeAxisView::show_timestretch (jack_nframes_t start, jack_nframes_t end)
{
double x1;
@@ -760,6 +862,12 @@ RouteTimeAxisView::set_selected_points (PointSelection& points)
}
void
+RouteTimeAxisView::set_selected_regionviews (RegionSelection& regions)
+{
+ _view->set_selected_regionviews (regions);
+}
+
+void
RouteTimeAxisView::get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable*>& results)
{
double speed = 1.0;
@@ -1053,3 +1161,399 @@ RouteTimeAxisView::select_me (GdkEventButton* ev)
return false;
}
+void
+RouteTimeAxisView::show_all_automation ()
+{
+ no_redraw = true;
+
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
+ for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ if ((*ii)->view == 0) {
+ add_redirect_automation_curve ((*i)->redirect, (*ii)->what);
+ }
+
+ (*ii)->menu_item->set_active (true);
+ }
+ }
+
+ no_redraw = false;
+
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+}
+
+void
+RouteTimeAxisView::show_existing_automation ()
+{
+ no_redraw = true;
+
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
+ for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ if ((*ii)->view != 0) {
+ (*ii)->menu_item->set_active (true);
+ }
+ }
+ }
+
+ no_redraw = false;
+
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+}
+
+void
+RouteTimeAxisView::hide_all_automation ()
+{
+ no_redraw = true;
+
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
+ for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ (*ii)->menu_item->set_active (false);
+ }
+ }
+
+ no_redraw = false;
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+}
+
+
+void
+RouteTimeAxisView::region_view_added (RegionView* rv)
+{
+ for (vector<TimeAxisView*>::iterator i = children.begin(); i != children.end(); ++i) {
+ AutomationTimeAxisView* atv;
+
+ if ((atv = dynamic_cast<AutomationTimeAxisView*> (*i)) != 0) {
+ rv->add_ghost (*atv);
+ }
+ }
+}
+
+void
+RouteTimeAxisView::add_ghost_to_redirect (RegionView* rv, AutomationTimeAxisView* atv)
+{
+ rv->add_ghost (*atv);
+}
+
+RouteTimeAxisView::RedirectAutomationInfo::~RedirectAutomationInfo ()
+{
+ for (vector<RedirectAutomationNode*>::iterator i = lines.begin(); i != lines.end(); ++i) {
+ delete *i;
+ }
+}
+
+
+RouteTimeAxisView::RedirectAutomationNode::~RedirectAutomationNode ()
+{
+ parent.remove_ran (this);
+
+ if (view) {
+ delete view;
+ }
+}
+
+void
+RouteTimeAxisView::remove_ran (RedirectAutomationNode* ran)
+{
+ if (ran->view) {
+ remove_child (ran->view);
+ }
+}
+
+RouteTimeAxisView::RedirectAutomationNode*
+RouteTimeAxisView::find_redirect_automation_node (boost::shared_ptr<Redirect> redirect, uint32_t what)
+{
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
+
+ if ((*i)->redirect == redirect) {
+
+ for (vector<RedirectAutomationNode*>::iterator ii = (*i)->lines.begin(); ii != (*i)->lines.end(); ++ii) {
+ if ((*ii)->what == what) {
+ return *ii;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+// FIXME: duplicated in midi_time_axis.cc
+static string
+legalize_for_xml_node (string str)
+{
+ string::size_type pos;
+ string legal_chars = "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_+=:";
+ string legal;
+
+ legal = str;
+ pos = 0;
+
+ while ((pos = legal.find_first_not_of (legal_chars, pos)) != string::npos) {
+ legal.replace (pos, 1, "_");
+ pos += 1;
+ }
+
+ return legal;
+}
+
+
+void
+RouteTimeAxisView::add_redirect_automation_curve (boost::shared_ptr<Redirect> redirect, uint32_t what)
+{
+ RedirectAutomationLine* ral;
+ string name;
+ RedirectAutomationNode* ran;
+
+ if ((ran = find_redirect_automation_node (redirect, what)) == 0) {
+ fatal << _("programming error: ")
+ << string_compose (X_("redirect automation curve for %1:%2 not registered with audio track!"),
+ redirect->name(), what)
+ << endmsg;
+ /*NOTREACHED*/
+ return;
+ }
+
+ if (ran->view) {
+ return;
+ }
+
+ name = redirect->describe_parameter (what);
+
+ /* create a string that is a legal XML node name that can be used to refer to this redirect+port combination */
+
+ char state_name[256];
+ snprintf (state_name, sizeof (state_name), "Redirect-%s-%" PRIu32, legalize_for_xml_node (redirect->name()).c_str(), what);
+
+ ran->view = new RedirectAutomationTimeAxisView (_session, _route, editor, *this, parent_canvas, name, what, *redirect, state_name);
+
+ ral = new RedirectAutomationLine (name,
+ *redirect, what, _session, *ran->view,
+ *ran->view->canvas_display, redirect->automation_list (what));
+
+ ral->set_line_color (color_map[cRedirectAutomationLine]);
+ ral->queue_reset ();
+
+ ran->view->add_line (*ral);
+
+ ran->view->Hiding.connect (bind (mem_fun(*this, &RouteTimeAxisView::redirect_automation_track_hidden), ran, redirect));
+
+ if (!ran->view->marked_for_display()) {
+ ran->view->hide ();
+ } else {
+ ran->menu_item->set_active (true);
+ }
+
+ add_child (ran->view);
+
+ _view->foreach_regionview (bind (mem_fun(*this, &RouteTimeAxisView::add_ghost_to_redirect), ran->view));
+
+ redirect->mark_automation_visible (what, true);
+}
+
+void
+RouteTimeAxisView::redirect_automation_track_hidden (RouteTimeAxisView::RedirectAutomationNode* ran, boost::shared_ptr<Redirect> r)
+{
+ if (!_hidden) {
+ ran->menu_item->set_active (false);
+ }
+
+ r->mark_automation_visible (ran->what, false);
+
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+}
+
+void
+RouteTimeAxisView::add_existing_redirect_automation_curves (boost::shared_ptr<Redirect> redirect)
+{
+ set<uint32_t> s;
+ RedirectAutomationLine *ral;
+
+ redirect->what_has_visible_automation (s);
+
+ for (set<uint32_t>::iterator i = s.begin(); i != s.end(); ++i) {
+
+ if ((ral = find_redirect_automation_curve (redirect, *i)) != 0) {
+ ral->queue_reset ();
+ } else {
+ add_redirect_automation_curve (redirect, (*i));
+ }
+ }
+}
+
+void
+RouteTimeAxisView::add_redirect_to_subplugin_menu (boost::shared_ptr<Redirect> r)
+{
+ using namespace Menu_Helpers;
+ RedirectAutomationInfo *rai;
+ list<RedirectAutomationInfo*>::iterator x;
+
+ const std::set<uint32_t>& automatable = r->what_can_be_automated ();
+ std::set<uint32_t> has_visible_automation;
+
+ r->what_has_visible_automation(has_visible_automation);
+
+ if (automatable.empty()) {
+ return;
+ }
+
+ for (x = redirect_automation.begin(); x != redirect_automation.end(); ++x) {
+ if ((*x)->redirect == r) {
+ break;
+ }
+ }
+
+ if (x == redirect_automation.end()) {
+
+ rai = new RedirectAutomationInfo (r);
+ redirect_automation.push_back (rai);
+
+ } else {
+
+ rai = *x;
+
+ }
+
+ /* any older menu was deleted at the top of redirects_changed()
+ when we cleared the subplugin menu.
+ */
+
+ rai->menu = manage (new Menu);
+ MenuList& items = rai->menu->items();
+ rai->menu->set_name ("ArdourContextMenu");
+
+ items.clear ();
+
+ for (std::set<uint32_t>::const_iterator i = automatable.begin(); i != automatable.end(); ++i) {
+
+ RedirectAutomationNode* ran;
+ CheckMenuItem* mitem;
+
+ string name = r->describe_parameter (*i);
+
+ items.push_back (CheckMenuElem (name));
+ mitem = dynamic_cast<CheckMenuItem*> (&items.back());
+
+ if (has_visible_automation.find((*i)) != has_visible_automation.end()) {
+ mitem->set_active(true);
+ }
+
+ if ((ran = find_redirect_automation_node (r, *i)) == 0) {
+
+ /* new item */
+
+ ran = new RedirectAutomationNode (*i, mitem, *this);
+
+ rai->lines.push_back (ran);
+
+ } else {
+
+ ran->menu_item = mitem;
+
+ }
+
+ mitem->signal_toggled().connect (bind (mem_fun(*this, &RouteTimeAxisView::redirect_menu_item_toggled), rai, ran));
+ }
+
+ /* add the menu for this redirect, because the subplugin
+ menu is always cleared at the top of redirects_changed().
+ this is the result of some poor design in gtkmm and/or
+ GTK+.
+ */
+
+ subplugin_menu.items().push_back (MenuElem (r->name(), *rai->menu));
+ rai->valid = true;
+}
+
+void
+RouteTimeAxisView::redirect_menu_item_toggled (RouteTimeAxisView::RedirectAutomationInfo* rai,
+ RouteTimeAxisView::RedirectAutomationNode* ran)
+{
+ bool showit = ran->menu_item->get_active();
+ bool redraw = false;
+
+ if (ran->view == 0 && showit) {
+ add_redirect_automation_curve (rai->redirect, ran->what);
+ redraw = true;
+ }
+
+ if (showit != ran->view->marked_for_display()) {
+
+ if (showit) {
+ ran->view->set_marked_for_display (true);
+ ran->view->canvas_display->show();
+ } else {
+ rai->redirect->mark_automation_visible (ran->what, true);
+ ran->view->set_marked_for_display (false);
+ ran->view->hide ();
+ }
+
+ redraw = true;
+
+ }
+
+ if (redraw && !no_redraw) {
+
+ /* now trigger a redisplay */
+
+ _route->gui_changed ("track_height", (void *) 0); /* EMIT_SIGNAL */
+
+ }
+}
+
+void
+RouteTimeAxisView::redirects_changed (void *src)
+{
+ using namespace Menu_Helpers;
+
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ++i) {
+ (*i)->valid = false;
+ }
+
+ subplugin_menu.items().clear ();
+
+ _route->foreach_redirect (this, &RouteTimeAxisView::add_redirect_to_subplugin_menu);
+ _route->foreach_redirect (this, &RouteTimeAxisView::add_existing_redirect_automation_curves);
+
+ for (list<RedirectAutomationInfo*>::iterator i = redirect_automation.begin(); i != redirect_automation.end(); ) {
+
+ list<RedirectAutomationInfo*>::iterator tmp;
+
+ tmp = i;
+ ++tmp;
+
+ if (!(*i)->valid) {
+
+ delete *i;
+ redirect_automation.erase (i);
+
+ }
+
+ i = tmp;
+ }
+
+ /* change in visibility was possible */
+
+ _route->gui_changed ("track_height", this);
+}
+
+RedirectAutomationLine *
+RouteTimeAxisView::find_redirect_automation_curve (boost::shared_ptr<Redirect> redirect, uint32_t what)
+{
+ RedirectAutomationNode* ran;
+
+ if ((ran = find_redirect_automation_node (redirect, what)) != 0) {
+ if (ran->view) {
+ return dynamic_cast<RedirectAutomationLine*> (ran->view->lines.front());
+ }
+ }
+
+ return 0;
+}
+
+void
+RouteTimeAxisView::reset_redirect_automation_curves ()
+{
+ for (vector<RedirectAutomationLine*>::iterator i = redirect_automation_curves.begin(); i != redirect_automation_curves.end(); ++i) {
+ (*i)->reset();
+ }
+}
+
diff --git a/gtk2_ardour/route_time_axis.h b/gtk2_ardour/route_time_axis.h
index a75851b8a8..476a135c39 100644
--- a/gtk2_ardour/route_time_axis.h
+++ b/gtk2_ardour/route_time_axis.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2006 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
@@ -33,7 +33,6 @@
#include <list>
#include <ardour/types.h>
-#include <ardour/region.h>
#include "ardour_dialog.h"
#include "route_ui.h"
@@ -44,6 +43,7 @@
namespace ARDOUR {
class Session;
+ class Region;
class Diskstream;
class RouteGroup;
class Redirect;
@@ -57,12 +57,14 @@ class RegionView;
class StreamView;
class Selection;
class Selectable;
+class AutomationTimeAxisView;
class AutomationLine;
+class RedirectAutomationLine;
class TimeSelection;
class RouteTimeAxisView : public RouteUI, public TimeAxisView
{
- public:
+public:
RouteTimeAxisView (PublicEditor&, ARDOUR::Session&, boost::shared_ptr<ARDOUR::Route>, ArdourCanvas::Canvas& canvas);
virtual ~RouteTimeAxisView ();
@@ -74,51 +76,57 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView
void hide_timestretch ();
void selection_click (GdkEventButton*);
void set_selected_points (PointSelection&);
+ void set_selected_regionviews (RegionSelection&);
void get_selectables (jack_nframes_t start, jack_nframes_t end, double top, double bot, list<Selectable *>&);
void get_inverted_selectables (Selection&, list<Selectable*>&);
ARDOUR::Region* find_next_region (jack_nframes_t pos, ARDOUR::RegionPoint, int32_t dir);
- string name() const;
-
- ARDOUR::RouteGroup* edit_group() const;
-
- void build_playlist_menu (Gtk::Menu *);
- ARDOUR::Playlist* playlist() const;
-
- StreamView* view() { return _view; }
-
- /* editing operations */
-
+ /* Editing operations */
bool cut_copy_clear (Selection&, Editing::CutCopyOp);
bool paste (jack_nframes_t, float times, Selection&, size_t nth);
list<TimeAxisView*> get_child_list();
- /* the editor calls these when mapping an operation across multiple tracks */
-
+ /* The editor calls these when mapping an operation across multiple tracks */
void use_new_playlist (bool prompt);
void use_copy_playlist (bool prompt);
void clear_playlist ();
+
+ void build_playlist_menu (Gtk::Menu *);
+
+ string name() const;
+ StreamView* view() const { return _view; }
+ ARDOUR::RouteGroup* edit_group() const;
+ ARDOUR::Playlist* playlist() const;
- //private: (FIXME)
+protected:
friend class StreamView;
- StreamView *_view;
+ struct RedirectAutomationNode {
+ uint32_t what;
+ Gtk::CheckMenuItem* menu_item;
+ AutomationTimeAxisView* view;
+ RouteTimeAxisView& parent;
- ArdourCanvas::Canvas& parent_canvas;
+ RedirectAutomationNode (uint32_t w, Gtk::CheckMenuItem* mitem, RouteTimeAxisView& p)
+ : what (w), menu_item (mitem), view (0), parent (p) {}
- bool no_redraw;
-
- Gtk::HBox other_button_hbox;
- Gtk::Table button_table;
- Gtk::Button redirect_button;
- Gtk::Button edit_group_button;
- Gtk::Button playlist_button;
- Gtk::Button size_button;
- Gtk::Button automation_button;
- Gtk::Button hide_button;
- Gtk::Button visual_button;
+ ~RedirectAutomationNode ();
+ };
+
+ struct RedirectAutomationInfo {
+ boost::shared_ptr<ARDOUR::Redirect> redirect;
+ bool valid;
+ Gtk::Menu* menu;
+ vector<RedirectAutomationNode*> lines;
+
+ RedirectAutomationInfo (boost::shared_ptr<ARDOUR::Redirect> r)
+ : redirect (r), valid (true), menu (0) {}
+
+ ~RedirectAutomationInfo ();
+ };
+
void diskstream_changed (void *src);
void update_diskstream_display ();
@@ -133,11 +141,30 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView
void redirect_relist ();
void redirect_row_selected (gint row, gint col, GdkEvent *ev);
void add_to_redirect_display (ARDOUR::Redirect *);
- //void redirects_changed (void *);
+ void redirects_changed (void *);
+
+ void add_redirect_to_subplugin_menu (boost::shared_ptr<ARDOUR::Redirect>);
+ void remove_ran (RedirectAutomationNode* ran);
- sigc::connection modified_connection;
- sigc::connection state_changed_connection;
+ void redirect_menu_item_toggled (RouteTimeAxisView::RedirectAutomationInfo*,
+ RouteTimeAxisView::RedirectAutomationNode*);
+
+ void redirect_automation_track_hidden (RedirectAutomationNode*,
+ boost::shared_ptr<ARDOUR::Redirect>);
+
+ RedirectAutomationNode*
+ find_redirect_automation_node (boost::shared_ptr<ARDOUR::Redirect> r, uint32_t);
+
+ RedirectAutomationLine*
+ find_redirect_automation_curve (boost::shared_ptr<ARDOUR::Redirect> r, uint32_t);
+ void add_redirect_automation_curve (boost::shared_ptr<ARDOUR::Redirect> r, uint32_t);
+ void add_existing_redirect_automation_curves (boost::shared_ptr<ARDOUR::Redirect>);
+
+ void reset_redirect_automation_curves ();
+
+ void update_automation_view (ARDOUR::AutomationType);
+
void take_name_changed (void *);
void route_name_changed (void *);
void name_entry_changed ();
@@ -145,9 +172,7 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView
void on_area_realize ();
virtual void label_view ();
-
- Gtk::Menu edit_group_menu;
-
+
void add_edit_group_menu_item (ARDOUR::RouteGroup *, Gtk::RadioMenuItem::Group*);
void set_edit_group_from_menu (ARDOUR::RouteGroup *);
@@ -155,35 +180,27 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView
void select_track_color();
- virtual void build_display_menu () = 0;
-
- Gtk::RadioMenuItem* align_existing_item;
- Gtk::RadioMenuItem* align_capture_item;
+ virtual void build_automation_action_menu ();
+ virtual void append_extra_display_menu_items () {}
+ void build_display_menu ();
void align_style_changed ();
void set_align_style (ARDOUR::AlignStyle);
-
- Gtk::Menu *playlist_menu;
- Gtk::Menu *playlist_action_menu;
- Gtk::MenuItem *playlist_item;
- /* playlist */
-
virtual void set_playlist (ARDOUR::Playlist *);
- void playlist_click ();
- void show_playlist_selector ();
-
- void playlist_changed ();
- void playlist_state_changed (ARDOUR::Change);
- void playlist_modified ();
+ void playlist_click ();
+ void show_playlist_selector ();
+ void playlist_changed ();
+ void playlist_state_changed (ARDOUR::Change);
+ void playlist_modified ();
void add_playlist_to_playlist_menu (ARDOUR::Playlist*);
void rename_current_playlist ();
- Gtk::Menu* automation_action_menu;
- void automation_click ();
-
- ArdourCanvas::SimpleRect *timestretch_rect;
+ void automation_click ();
+ virtual void show_all_automation ();
+ virtual void show_existing_automation ();
+ virtual void hide_all_automation ();
void timestretch (jack_nframes_t start, jack_nframes_t end);
@@ -198,7 +215,40 @@ class RouteTimeAxisView : public RouteUI, public TimeAxisView
void color_handler (ColorID, uint32_t);
bool select_me (GdkEventButton*);
- virtual void region_view_added (RegionView*) = 0;
+ void region_view_added (RegionView*);
+ void add_ghost_to_redirect (RegionView*, AutomationTimeAxisView*);
+
+
+ StreamView* _view;
+ ArdourCanvas::Canvas& parent_canvas;
+ bool no_redraw;
+
+ Gtk::HBox other_button_hbox;
+ Gtk::Table button_table;
+ Gtk::Button redirect_button;
+ Gtk::Button edit_group_button;
+ Gtk::Button playlist_button;
+ Gtk::Button size_button;
+ Gtk::Button automation_button;
+ Gtk::Button hide_button;
+ Gtk::Button visual_button;
+
+ Gtk::Menu subplugin_menu;
+ Gtk::Menu* automation_action_menu;
+ Gtk::Menu edit_group_menu;
+ Gtk::RadioMenuItem* align_existing_item;
+ Gtk::RadioMenuItem* align_capture_item;
+ Gtk::Menu* playlist_menu;
+ Gtk::Menu* playlist_action_menu;
+ Gtk::MenuItem* playlist_item;
+
+ ArdourCanvas::SimpleRect* timestretch_rect;
+
+ list<RedirectAutomationInfo*> redirect_automation;
+ vector<RedirectAutomationLine*> redirect_automation_curves;
+
+ sigc::connection modified_connection;
+ sigc::connection state_changed_connection;
};
#endif /* __ardour_route_time_axis_h__ */
diff --git a/gtk2_ardour/streamview.cc b/gtk2_ardour/streamview.cc
index 93d25b6a97..c94184272e 100644
--- a/gtk2_ardour/streamview.cc
+++ b/gtk2_ardour/streamview.cc
@@ -60,7 +60,6 @@ StreamView::StreamView (RouteTimeAxisView& tv)
canvas_rect->property_y1() = 0.0;
canvas_rect->property_x2() = 1000000.0;
canvas_rect->property_y2() = (double) tv.height;
- canvas_rect->property_outline_color_rgba() = color_map[cAudioTrackOutline]; // FIXME
canvas_rect->property_outline_what() = (guint32) (0x1|0x2|0x8); // outline ends and bottom
canvas_rect->property_fill_color_rgba() = stream_base_color;
diff --git a/gtk2_ardour/streamview.h b/gtk2_ardour/streamview.h
index f2906d40c4..baa779ba67 100644
--- a/gtk2_ardour/streamview.h
+++ b/gtk2_ardour/streamview.h
@@ -98,35 +98,37 @@ public:
protected:
StreamView (RouteTimeAxisView&);
-//private:
- void update_rec_box ();
- void transport_changed();
- void rec_enable_changed(void* src = 0);
- void sess_rec_enable_changed();
+//private: (FIXME?)
+
+ void transport_changed();
+ void rec_enable_changed(void* src = 0);
+ void sess_rec_enable_changed();
virtual void setup_rec_box () = 0;
- void rec_peak_range_ready (jack_nframes_t start, jack_nframes_t cnt, ARDOUR::Source* src);
+ void update_rec_box ();
virtual void update_rec_regions () = 0;
virtual void add_region_view_internal (ARDOUR::Region*, bool wait_for_waves) = 0;
virtual void remove_region_view (ARDOUR::Region* );
- void remove_rec_region (ARDOUR::Region*);
+ void remove_rec_region (ARDOUR::Region*);
- void display_diskstream (ARDOUR::Diskstream* );
+ void display_diskstream (ARDOUR::Diskstream* );
virtual void undisplay_diskstream ();
virtual void redisplay_diskstream () = 0;
- void diskstream_changed (void* );
- void playlist_state_changed (ARDOUR::Change);
+ void diskstream_changed (void* );
+
+ void playlist_state_changed (ARDOUR::Change);
virtual void playlist_changed (ARDOUR::Diskstream* );
virtual void playlist_modified ();
+
+ virtual void color_handler (ColorID, uint32_t) = 0;
- RouteTimeAxisView& _trackview;
-
+ RouteTimeAxisView& _trackview;
ArdourCanvas::Group* canvas_group;
ArdourCanvas::SimpleRect* canvas_rect; /* frame around the whole thing */
typedef list<RegionView* > RegionViewList;
- RegionViewList region_views;
+ RegionViewList region_views;
double _samples_per_unit;
@@ -141,8 +143,6 @@ protected:
Gdk::Color region_color;
uint32_t stream_base_color;
- virtual void color_handler (ColorID, uint32_t) = 0;
-
vector<sigc::connection> playlist_connections;
sigc::connection playlist_change_connection;
};
diff --git a/gtk2_ardour/taperegionview.cc b/gtk2_ardour/taperegionview.cc
index 76fd91337e..19e6ba3ad3 100644
--- a/gtk2_ardour/taperegionview.cc
+++ b/gtk2_ardour/taperegionview.cc
@@ -63,53 +63,9 @@ TapeAudioRegionView::TapeAudioRegionView (ArdourCanvas::Group *parent, RouteTime
void
TapeAudioRegionView::init (Gdk::Color& basic_color, bool wfw)
{
- XMLNode *node;
-
- editor = 0;
- valid = true;
- in_destructor = false;
- _amplitude_above_axis = 1.0;
- zero_line = 0;
- wait_for_waves = wfw;
- _height = 0;
-
- _flags = 0;
-
- if ((node = _region.extra_xml ("GUI")) != 0) {
- set_flags (node);
- } else {
- _flags = WaveformVisible;
- store_flags ();
- }
-
- fade_in_handle = 0;
- fade_out_handle = 0;
- gain_line = 0;
- sync_mark = 0;
-
- compute_colors (basic_color);
-
- create_waves ();
-
- name_highlight->set_data ("regionview", this);
-
- reset_width_dependent_items ((double) _region.length() / samples_per_unit);
-
- set_height (trackview.height);
-
- region_muted ();
- region_resized (BoundsChanged);
- set_waveview_data_src();
- region_locked ();
-
- /* no events, no state changes */
-
- set_colors ();
-
- // ColorChanged.connect (mem_fun (*this, &AudioRegionView::color_handler));
+ AudioRegionView::init(basic_color, wfw);
/* every time the wave data changes and peaks are ready, redraw */
-
for (uint32_t n = 0; n < audio_region().n_channels(); ++n) {
audio_region().source(n).PeaksReady.connect (bind (mem_fun(*this, &TapeAudioRegionView::update), n));
diff --git a/libs/ardour/ardour/audio_diskstream.h b/libs/ardour/ardour/audio_diskstream.h
index c4a942a5d7..ec15cf1caf 100644
--- a/libs/ardour/ardour/audio_diskstream.h
+++ b/libs/ardour/ardour/audio_diskstream.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -14,8 +14,6 @@
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.
-
- $Id: diskstream.h 579 2006-06-12 19:56:37Z essej $
*/
#ifndef __ardour_audio_diskstream_h__
@@ -62,18 +60,12 @@ class AudioDiskstream : public Diskstream
AudioDiskstream (Session &, const string& name, Diskstream::Flag f = Recordable);
AudioDiskstream (Session &, const XMLNode&);
- void set_io (ARDOUR::IO& io);
-
+ // FIXME
AudioDiskstream& ref() { _refcnt++; return *this; }
- //void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
- //uint32_t refcnt() const { return _refcnt; }
float playback_buffer_load() const;
float capture_buffer_load() const;
- //void set_align_style (AlignStyle);
- //void set_persistent_align_style (AlignStyle);
-
string input_source (uint32_t n=0) const {
if (n < channels.size()) {
return channels[n].source ? channels[n].source->name() : "";
@@ -87,7 +79,6 @@ class AudioDiskstream : public Diskstream
}
void set_record_enabled (bool yn, void *src);
- //void set_speed (double);
float peak_power(uint32_t n=0) {
float x = channels[n].peak_power;
@@ -98,16 +89,13 @@ class AudioDiskstream : public Diskstream
return minus_infinity();
}
}
+
+ AudioPlaylist* audio_playlist () { return dynamic_cast<AudioPlaylist*>(_playlist); }
int use_playlist (Playlist *);
int use_new_playlist ();
int use_copy_playlist ();
- void start_scrub (jack_nframes_t where) {} // FIXME?
- void end_scrub () {} // FIXME?
-
- Playlist *playlist () { return _playlist; }
-
Sample *playback_buffer (uint32_t n=0) {
if (n < channels.size())
return channels[n].current_playback_buffer;
@@ -137,7 +125,6 @@ class AudioDiskstream : public Diskstream
void monitor_input (bool);
- // FIXME: these don't belong here
static void swap_by_ptr (Sample *first, Sample *last) {
while (first < last) {
Sample tmp = *first;
@@ -154,11 +141,6 @@ class AudioDiskstream : public Diskstream
}
}
- //void handle_input_change (IOChange, void *src);
-
- //static sigc::signal<void> DiskOverrun;
- //static sigc::signal<void> DiskUnderrun;
- //static sigc::signal<void,AudioDiskstream*> AudioDiskstreamCreated; // XXX use a ref with sigc2
static sigc::signal<void,list<AudioFileSource*>*> DeleteSources;
int set_loop (Location *loc);
@@ -168,8 +150,6 @@ class AudioDiskstream : public Diskstream
return _last_capture_regions;
}
- void handle_input_change (IOChange, void *src);
-
const PBD::ID& id() const { return _id; }
XMLNode* deprecated_io_node;
@@ -184,7 +164,6 @@ class AudioDiskstream : public Diskstream
void set_pending_overwrite(bool);
int overwrite_existing_buffers ();
- void reverse_scrub_buffer (bool to_forward) {} // FIXME?
void set_block_size (jack_nframes_t);
int internal_playback_seek (jack_nframes_t distance);
int can_internal_playback_seek (jack_nframes_t distance);
@@ -237,60 +216,30 @@ class AudioDiskstream : public Diskstream
jack_nframes_t curr_capture_cnt;
};
- typedef vector<ChannelInfo> ChannelList;
-
- /* the two central butler operations */
-
- int do_flush (char * workbuf, bool force = false);
- int do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf);
+ /* The two central butler operations */
+ int do_flush (Session::RunContext context, bool force = false);
+ int do_refill () { return _do_refill(_mixdown_buffer, _gain_buffer, _conversion_buffer); }
- virtual int non_realtime_do_refill() { return do_refill(0, 0, 0); }
+ int do_refill_with_alloc();
- int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt,
- ChannelInfo& channel_info, int channel, bool reversed);
-
- /* XXX fix this redundancy ... */
-
- //void playlist_changed (Change);
- //void playlist_modified ();
- void playlist_deleted (Playlist*);
- void session_controls_changed (Session::ControlType) {} // FIXME?
+ int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf,
+ jack_nframes_t& start, jack_nframes_t cnt,
+ ChannelInfo& channel_info, int channel, bool reversed);
void finish_capture (bool rec_monitors_input);
- void clean_up_capture (struct tm&, time_t, bool abort) {} // FIXME?
void transport_stopped (struct tm&, time_t, bool abort);
- struct CaptureInfo {
- uint32_t start;
- uint32_t frames;
- };
-
- vector<CaptureInfo*> capture_info;
- Glib::Mutex capture_info_lock;
-
void init (Diskstream::Flag);
void init_channel (ChannelInfo &chan);
void destroy_channel (ChannelInfo &chan);
int use_new_write_source (uint32_t n=0);
- int use_new_fade_source (uint32_t n=0) { return 0; } // FIXME?
int find_and_use_playlist (const string&);
void allocate_temporary_buffers ();
- int create_input_port () { return 0; } // FIXME?
- int connect_input_port () { return 0; } // FIXME?
- int seek_unlocked (jack_nframes_t which_sample) { return 0; } // FIXME?
-
- int ports_created () { return 0; } // FIXME?
-
- //bool realtime_set_speed (double, bool global_change);
- void non_realtime_set_speed ();
-
- std::list<Region*> _last_capture_regions;
- std::vector<AudioFileSource*> capturing_sources;
int use_pending_capture_data (XMLNode& node);
void get_input_sources ();
@@ -299,10 +248,26 @@ class AudioDiskstream : public Diskstream
void setup_destructive_playlist ();
void use_destructive_playlist ();
- ChannelList channels;
- AudioPlaylist* _playlist;
void engage_record_enable (void* src);
void disengage_record_enable (void* src);
+
+ // Working buffers for do_refill (butler thread)
+ static void allocate_working_buffers();
+ static void free_working_buffers();
+
+ static size_t _working_buffers_size;
+ static Sample* _mixdown_buffer;
+ static gain_t* _gain_buffer;
+ static char* _conversion_buffer;
+
+ // Uh, /really/ private? (death to friend classes)
+ int _do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf);
+
+
+ std::vector<AudioFileSource*> capturing_sources;
+
+ typedef vector<ChannelInfo> ChannelList;
+ ChannelList channels;
};
} // namespace ARDOUR
diff --git a/libs/ardour/ardour/diskstream.h b/libs/ardour/ardour/diskstream.h
index b595879264..ff25127ec9 100644
--- a/libs/ardour/ardour/diskstream.h
+++ b/libs/ardour/ardour/diskstream.h
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -52,7 +52,6 @@ class AudioEngine;
class Send;
class Session;
class Playlist;
-//class FileSource;
class IO;
/* FIXME: There are (obviously) far too many virtual functions in this ATM.
@@ -71,10 +70,10 @@ class Diskstream : public Stateful, public sigc::trackable
virtual int set_name (string str, void* src);
ARDOUR::IO* io() const { return _io; }
- virtual void set_io (ARDOUR::IO& io) = 0;
+ void set_io (ARDOUR::IO& io);
virtual Diskstream& ref() { _refcnt++; return *this; }
- void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
+ void unref() { if (_refcnt) _refcnt--; if (_refcnt == 0) delete this; }
uint32_t refcnt() const { return _refcnt; }
virtual float playback_buffer_load() const = 0;
@@ -105,17 +104,15 @@ class Diskstream : public Stateful, public sigc::trackable
virtual void punch_in() {}
virtual void punch_out() {}
- virtual void set_speed (double);
- virtual void non_realtime_set_speed () = 0;
+ void set_speed (double);
+ void non_realtime_set_speed ();
- virtual Playlist *playlist () = 0;
+ Playlist* playlist () { return _playlist; }
+
+ virtual int use_playlist (Playlist *);
virtual int use_new_playlist () = 0;
- virtual int use_playlist (Playlist *) = 0;
virtual int use_copy_playlist () = 0;
- virtual void start_scrub (jack_nframes_t where) = 0;
- virtual void end_scrub () = 0;
-
jack_nframes_t current_capture_start() const { return capture_start_frame; }
jack_nframes_t current_capture_end() const { return capture_start_frame + capture_captured; }
jack_nframes_t get_capture_start_frame (uint32_t n=0);
@@ -123,7 +120,7 @@ class Diskstream : public Stateful, public sigc::trackable
uint32_t n_channels() { return _n_channels; }
- static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; }
+ static jack_nframes_t disk_io_frames() { return disk_io_chunk_frames; }
static void set_disk_io_chunk_frames (uint32_t n) { disk_io_chunk_frames = n; }
/* Stateful */
@@ -144,7 +141,7 @@ class Diskstream : public Stateful, public sigc::trackable
std::list<Region*>& last_capture_regions () { return _last_capture_regions; }
- virtual void handle_input_change (IOChange, void *src);
+ void handle_input_change (IOChange, void *src);
sigc::signal<void,void*> RecordEnableChanged;
sigc::signal<void> SpeedChanged;
@@ -170,7 +167,6 @@ class Diskstream : public Stateful, public sigc::trackable
virtual void set_pending_overwrite (bool) = 0;
virtual int overwrite_existing_buffers () = 0;
- virtual void reverse_scrub_buffer (bool to_forward) = 0;
virtual void set_block_size (jack_nframes_t) = 0;
virtual int internal_playback_seek (jack_nframes_t distance) = 0;
virtual int can_internal_playback_seek (jack_nframes_t distance) = 0;
@@ -209,25 +205,21 @@ class Diskstream : public Stateful, public sigc::trackable
jack_nframes_t capture_val;
};
- /* the two central butler operations */
-
- virtual int do_flush (char * workbuf, bool force = false) = 0;
- //int do_refill (Sample *mixdown_buffer, float *gain_buffer, char *workbuf);
+ /* The two central butler operations */
+ virtual int do_flush (Session::RunContext context, bool force = false) = 0;
+ virtual int do_refill () = 0;
- virtual int non_realtime_do_refill() = 0;
+ /** For non-butler contexts (allocates temporary working buffers) */
+ virtual int do_refill_with_alloc() = 0;
- //int read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt,
- // ChannelInfo& channel_info, int channel, bool reversed);
/* XXX fix this redundancy ... */
virtual void playlist_changed (Change);
virtual void playlist_modified ();
- virtual void playlist_deleted (Playlist*) = 0;
- virtual void session_controls_changed (Session::ControlType) = 0;
+ virtual void playlist_deleted (Playlist*);
virtual void finish_capture (bool rec_monitors_input) = 0;
- virtual void clean_up_capture (struct tm&, time_t, bool abort) = 0;
virtual void transport_stopped (struct tm&, time_t, bool abort) = 0;
struct CaptureInfo {
@@ -237,37 +229,23 @@ class Diskstream : public Stateful, public sigc::trackable
virtual void init (Flag);
- //void init_channel (ChannelInfo &chan);
- //void destroy_channel (ChannelInfo &chan);
-
virtual int use_new_write_source (uint32_t n=0) = 0;
- virtual int use_new_fade_source (uint32_t n=0) = 0;
virtual int find_and_use_playlist (const string&) = 0;
- //void allocate_temporary_buffers ();
-
- virtual int create_input_port () = 0;
- virtual int connect_input_port () = 0;
- virtual int seek_unlocked (jack_nframes_t which_sample) = 0;
-
- virtual int ports_created () = 0;
+ virtual void allocate_temporary_buffers () = 0;
virtual bool realtime_set_speed (double, bool global_change);
- //void non_realtime_set_speed ();
std::list<Region*> _last_capture_regions;
- //std::vector<FileSource*> capturing_sources;
virtual int use_pending_capture_data (XMLNode& node) = 0;
virtual void get_input_sources () = 0;
virtual void check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record) = 0;
- //void set_align_style_from_io();
+ virtual void set_align_style_from_io() {}
virtual void setup_destructive_playlist () = 0;
- //void use_destructive_playlist ();
+ virtual void use_destructive_playlist () = 0;
- // Wouldn't hurt for this thing to do on a diet:
-
static jack_nframes_t disk_io_chunk_frames;
vector<CaptureInfo*> capture_info;
Glib::Mutex capture_info_lock;
@@ -279,6 +257,7 @@ class Diskstream : public Stateful, public sigc::trackable
ARDOUR::IO* _io;
uint32_t _n_channels;
PBD::ID _id;
+ Playlist* _playlist;
mutable gint _record_enabled;
double _visible_speed;
@@ -338,7 +317,6 @@ class Diskstream : public Stateful, public sigc::trackable
sigc::connection plgone_connection;
unsigned char _flags;
-
};
}; /* namespace ARDOUR */
diff --git a/libs/ardour/ardour/midi_diskstream.h b/libs/ardour/ardour/midi_diskstream.h
index b6121d1176..5998363d69 100644
--- a/libs/ardour/ardour/midi_diskstream.h
+++ b/libs/ardour/ardour/midi_diskstream.h
@@ -80,9 +80,6 @@ class MidiDiskstream : public Diskstream
int use_new_playlist ();
int use_copy_playlist ();
- void start_scrub (jack_nframes_t where) {} // FIXME?
- void end_scrub () {} // FIXME?
-
Playlist *playlist () { return _playlist; }
static sigc::signal<void,list<SMFSource*>*> DeleteSources;
@@ -106,7 +103,6 @@ class MidiDiskstream : public Diskstream
void set_pending_overwrite(bool);
int overwrite_existing_buffers ();
- void reverse_scrub_buffer (bool to_forward) {} // FIXME?
void set_block_size (jack_nframes_t);
int internal_playback_seek (jack_nframes_t distance);
int can_internal_playback_seek (jack_nframes_t distance);
@@ -134,12 +130,11 @@ class MidiDiskstream : public Diskstream
MidiPlaylist* _playlist;
- /* the two central butler operations */
-
- int do_flush (char * workbuf, bool force = false);
- int do_refill (RawMidi *mixdown_buffer, float *gain_buffer, char *workbuf);
+ /*Tthe two central butler operations */
+ int do_flush (Session::RunContext context, bool force = false) { return 0; }
+ int do_refill () { return 0; }
- virtual int non_realtime_do_refill() { return do_refill(0, 0, 0); }
+ int do_refill_with_alloc() { return 0; }
int read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jack_nframes_t& start, jack_nframes_t cnt, bool reversed);
@@ -148,10 +143,8 @@ class MidiDiskstream : public Diskstream
//void playlist_changed (Change);
//void playlist_modified ();
void playlist_deleted (Playlist*);
- void session_controls_changed (Session::ControlType) {} // FIXME?
void finish_capture (bool rec_monitors_input);
- void clean_up_capture (struct tm&, time_t, bool abort) {} // FIXME?
void transport_stopped (struct tm&, time_t, bool abort);
struct CaptureInfo {
@@ -162,18 +155,11 @@ class MidiDiskstream : public Diskstream
void init (Diskstream::Flag);
int use_new_write_source (uint32_t n=0);
- int use_new_fade_source (uint32_t n=0) { return 0; } // FIXME?
int find_and_use_playlist (const string&);
void allocate_temporary_buffers ();
- int create_input_port () { return 0; } // FIXME?
- int connect_input_port () { return 0; } // FIXME?
- int seek_unlocked (jack_nframes_t which_sample) { return 0; } // FIXME?
-
- int ports_created () { return 0; } // FIXME?
-
//bool realtime_set_speed (double, bool global_change);
void non_realtime_set_speed ();
diff --git a/libs/ardour/ardour/playlist.h b/libs/ardour/ardour/playlist.h
index ca760a5ad5..add253982f 100644
--- a/libs/ardour/ardour/playlist.h
+++ b/libs/ardour/ardour/playlist.h
@@ -110,16 +110,15 @@ class Playlist : public Stateful, public StateManager {
int set_state (const XMLNode&);
XMLNode& get_template ();
- sigc::signal<void,Region *> RegionAdded;
- sigc::signal<void,Region *> RegionRemoved;
-
+ sigc::signal<void,Region *> RegionAdded;
+ sigc::signal<void,Region *> RegionRemoved;
sigc::signal<void,Playlist*,bool> InUse;
- sigc::signal<void> Modified;
- sigc::signal<void> NameChanged;
- sigc::signal<void> LengthChanged;
- sigc::signal<void> LayeringChanged;
- sigc::signal<void,Playlist *> GoingAway;
- sigc::signal<void> StatePushed;
+ sigc::signal<void> Modified;
+ sigc::signal<void> NameChanged;
+ sigc::signal<void> LengthChanged;
+ sigc::signal<void> LayeringChanged;
+ sigc::signal<void,Playlist *> GoingAway;
+ sigc::signal<void> StatePushed;
static sigc::signal<void,Playlist*> PlaylistCreated;
diff --git a/libs/ardour/ardour/region.h b/libs/ardour/ardour/region.h
index 68ac55df67..a138f66042 100644
--- a/libs/ardour/ardour/region.h
+++ b/libs/ardour/ardour/region.h
@@ -145,6 +145,8 @@ class Region : public Stateful, public StateManager
bool overlap_equivalent (const Region&) const;
bool region_list_equivalent (const Region&) const;
virtual bool source_equivalent (const Region&) const = 0;
+
+ virtual bool speed_mismatch (float) const = 0;
/*virtual jack_nframes_t read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, char * workbuf, jack_nframes_t position, jack_nframes_t cnt,
diff --git a/libs/ardour/ardour/session.h b/libs/ardour/ardour/session.h
index 7bd24b96cc..dd8ec4806a 100644
--- a/libs/ardour/ardour/session.h
+++ b/libs/ardour/ardour/session.h
@@ -938,7 +938,7 @@ class Session : public sigc::trackable, public Stateful
/* buffers for gain and pan */
gain_t* gain_automation_buffer () const { return _gain_automation_buffer; }
- pan_t** pan_automation_buffer() const { return _pan_automation_buffer; }
+ pan_t** pan_automation_buffer () const { return _pan_automation_buffer; }
/* buffers for conversion */
enum RunContext {
diff --git a/libs/ardour/audio_diskstream.cc b/libs/ardour/audio_diskstream.cc
index a3345cf15a..5f6ce05016 100644
--- a/libs/ardour/audio_diskstream.cc
+++ b/libs/ardour/audio_diskstream.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2003 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -14,8 +14,6 @@
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.
-
- $Id: diskstream.cc 567 2006-06-07 14:54:12Z trutkin $
*/
#include <fstream>
@@ -23,6 +21,7 @@
#include <unistd.h>
#include <cmath>
#include <cerrno>
+#include <cassert>
#include <string>
#include <climits>
#include <fcntl.h>
@@ -57,10 +56,14 @@ using namespace PBD;
sigc::signal<void,list<AudioFileSource*>*> AudioDiskstream::DeleteSources;
+size_t AudioDiskstream::_working_buffers_size = 0;
+Sample* AudioDiskstream::_mixdown_buffer = 0;
+gain_t* AudioDiskstream::_gain_buffer = 0;
+char* AudioDiskstream::_conversion_buffer = 0;
+
AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream::Flag flag)
: Diskstream(sess, name, flag)
, deprecated_io_node(NULL)
- , _playlist(NULL)
{
/* prevent any write sources from being created */
@@ -77,7 +80,6 @@ AudioDiskstream::AudioDiskstream (Session &sess, const string &name, Diskstream:
AudioDiskstream::AudioDiskstream (Session& sess, const XMLNode& node)
: Diskstream(sess, node)
, deprecated_io_node(NULL)
- , _playlist(NULL)
{
in_set_state = true;
init (Recordable);
@@ -178,25 +180,33 @@ AudioDiskstream::~AudioDiskstream ()
{
Glib::Mutex::Lock lm (state_lock);
- if (_playlist)
- _playlist->unref ();
-
- for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
+ for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan)
destroy_channel((*chan));
- }
channels.clear();
}
void
-AudioDiskstream::handle_input_change (IOChange change, void *src)
+AudioDiskstream::allocate_working_buffers()
{
- Glib::Mutex::Lock lm (state_lock);
+ assert(disk_io_frames() > 0);
- if (!(input_change_pending & change)) {
- input_change_pending = IOChange (input_change_pending|change);
- _session.request_input_change_handling ();
- }
+ _working_buffers_size = disk_io_frames();
+ _mixdown_buffer = new Sample[_working_buffers_size];
+ _gain_buffer = new gain_t[_working_buffers_size];
+ _conversion_buffer = new char[_working_buffers_size * 4];
+}
+
+void
+AudioDiskstream::free_working_buffers()
+{
+ delete _mixdown_buffer;
+ delete _gain_buffer;
+ delete _conversion_buffer;
+ _working_buffers_size = 0;
+ _mixdown_buffer = 0;
+ _gain_buffer = 0;
+ _conversion_buffer = 0;
}
void
@@ -312,40 +322,7 @@ AudioDiskstream::use_playlist (Playlist* playlist)
{
assert(dynamic_cast<AudioPlaylist*>(playlist));
- {
- Glib::Mutex::Lock lm (state_lock);
-
- if (playlist == _playlist) {
- return 0;
- }
-
- plstate_connection.disconnect();
- plmod_connection.disconnect ();
- plgone_connection.disconnect ();
-
- if (_playlist) {
- _playlist->unref();
- }
-
- _playlist = dynamic_cast<AudioPlaylist*>(playlist);
- _playlist->ref();
-
- if (!in_set_state && recordable()) {
- reset_write_sources (false);
- }
-
- plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &AudioDiskstream::playlist_changed));
- plmod_connection = _playlist->Modified.connect (mem_fun (*this, &AudioDiskstream::playlist_modified));
- plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &AudioDiskstream::playlist_deleted));
- }
-
- if (!overwrite_queued) {
- _session.request_overwrite_buffer (this);
- overwrite_queued = true;
- }
-
- PlaylistChanged (); /* EMIT SIGNAL */
- _session.set_dirty ();
+ Diskstream::use_playlist(playlist);
return 0;
}
@@ -377,6 +354,8 @@ AudioDiskstream::use_new_playlist ()
int
AudioDiskstream::use_copy_playlist ()
{
+ assert(audio_playlist());
+
if (destructive()) {
return 0;
}
@@ -391,7 +370,7 @@ AudioDiskstream::use_copy_playlist ()
newname = Playlist::bump_name (_playlist->name(), _session);
- if ((playlist = new AudioPlaylist (*_playlist, newname)) != 0) {
+ if ((playlist = new AudioPlaylist (*audio_playlist(), newname)) != 0) {
playlist->set_orig_diskstream_id (id());
return use_playlist (playlist);
} else {
@@ -399,19 +378,6 @@ AudioDiskstream::use_copy_playlist ()
}
}
-
-void
-AudioDiskstream::playlist_deleted (Playlist* pl)
-{
- /* this catches an ordering issue with session destruction. playlists
- are destroyed before diskstreams. we have to invalidate any handles
- we have to the playlist.
- */
-
- _playlist = 0;
-}
-
-
void
AudioDiskstream::setup_destructive_playlist ()
{
@@ -461,36 +427,6 @@ AudioDiskstream::use_destructive_playlist ()
}
void
-AudioDiskstream::set_io (IO& io)
-{
- _io = &io;
- set_align_style_from_io ();
-}
-
-void
-AudioDiskstream::non_realtime_set_speed ()
-{
- if (_buffer_reallocation_required)
- {
- Glib::Mutex::Lock lm (state_lock);
- allocate_temporary_buffers ();
-
- _buffer_reallocation_required = false;
- }
-
- if (_seek_required) {
- if (speed() != 1.0f || speed() != -1.0f) {
- seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
- }
- else {
- seek (_session.transport_frame(), true);
- }
-
- _seek_required = false;
- }
-}
-
-void
AudioDiskstream::check_record_status (jack_nframes_t transport_frame, jack_nframes_t nframes, bool can_record)
{
int possibly_recording;
@@ -1054,9 +990,9 @@ AudioDiskstream::seek (jack_nframes_t frame, bool complete_refill)
file_frame = frame;
if (complete_refill) {
- while ((ret = non_realtime_do_refill ()) > 0);
+ while ((ret = do_refill_with_alloc ()) > 0) ;
} else {
- ret = non_realtime_do_refill ();
+ ret = do_refill_with_alloc ();
}
return ret;
@@ -1148,7 +1084,7 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
this_read = min(cnt,this_read);
- if (_playlist->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) {
+ if (audio_playlist()->read (buf+offset, mixdown_buffer, gain_buffer, workbuf, start, this_read, channel) != this_read) {
error << string_compose(_("AudioDiskstream %1: cannot read %2 from playlist at frame %3"), _id, this_read,
start) << endmsg;
return -1;
@@ -1182,14 +1118,27 @@ AudioDiskstream::read (Sample* buf, Sample* mixdown_buffer, float* gain_buffer,
}
int
-AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf)
+AudioDiskstream::do_refill_with_alloc()
+{
+ Sample* mix_buf = new Sample[disk_io_chunk_frames];
+ float* gain_buf = new float[disk_io_chunk_frames];
+ char* work_buf = new char[disk_io_chunk_frames * 4];
+
+ int ret = _do_refill(mix_buf, gain_buf, work_buf);
+
+ delete [] mix_buf;
+ delete [] gain_buf;
+ delete [] work_buf;
+
+ return ret;
+}
+
+int
+AudioDiskstream::_do_refill (Sample* mixdown_buffer, float* gain_buffer, char * workbuf)
{
int32_t ret = 0;
jack_nframes_t to_read;
RingBufferNPT<Sample>::rw_vector vector;
- bool free_mixdown;
- bool free_gain;
- bool free_workbuf;
bool reversed = (_visible_speed * _session.transport_speed()) < 0.0f;
jack_nframes_t total_space;
jack_nframes_t zero_fill;
@@ -1197,6 +1146,10 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w
ChannelList::iterator i;
jack_nframes_t ts;
+ assert(mixdown_buffer);
+ assert(gain_buffer);
+ assert(workbuf);
+
channels.front().playback_buf->get_write_vector (&vector);
if ((total_space = vector.len[0] + vector.len[1]) == 0) {
@@ -1303,33 +1256,6 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w
zero_fill = 0;
}
}
-
- /* Please note: the code to allocate buffers isn't run
- during normal butler thread operation. Its there
- for other times when we need to call do_refill()
- from somewhere other than the butler thread.
- */
-
- if (mixdown_buffer == 0) {
- mixdown_buffer = new Sample[disk_io_chunk_frames];
- free_mixdown = true;
- } else {
- free_mixdown = false;
- }
-
- if (gain_buffer == 0) {
- gain_buffer = new float[disk_io_chunk_frames];
- free_gain = true;
- } else {
- free_gain = false;
- }
-
- if (workbuf == 0) {
- workbuf = new char[disk_io_chunk_frames * 4];
- free_workbuf = true;
- } else {
- free_workbuf = false;
- }
jack_nframes_t file_frame_tmp = 0;
@@ -1398,22 +1324,15 @@ AudioDiskstream::do_refill (Sample* mixdown_buffer, float* gain_buffer, char * w
file_frame = file_frame_tmp;
out:
- if (free_mixdown) {
- delete [] mixdown_buffer;
- }
- if (free_gain) {
- delete [] gain_buffer;
- }
- if (free_workbuf) {
- delete [] workbuf;
- }
return ret;
}
int
-AudioDiskstream::do_flush (char * workbuf, bool force_flush)
+AudioDiskstream::do_flush (Session::RunContext context, bool force_flush)
{
+ char* workbuf = _session.conversion_buffer(context);
+
uint32_t to_write;
int32_t ret = 0;
RingBufferNPT<Sample>::rw_vector vector;
@@ -1570,7 +1489,7 @@ AudioDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_ca
*/
while (more_work && !err) {
- switch (do_flush ( _session.conversion_buffer(Session::TransportContext), true)) {
+ switch (do_flush (Session::TransportContext, true)) {
case 0:
more_work = false;
break;
diff --git a/libs/ardour/diskstream.cc b/libs/ardour/diskstream.cc
index 4e2bec9850..9fc2ded0ce 100644
--- a/libs/ardour/diskstream.cc
+++ b/libs/ardour/diskstream.cc
@@ -1,5 +1,5 @@
/*
- Copyright (C) 2000-2003 Paul Davis
+ Copyright (C) 2000-2006 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
@@ -55,7 +55,7 @@ using namespace std;
using namespace ARDOUR;
using namespace PBD;
-jack_nframes_t Diskstream::disk_io_chunk_frames;
+jack_nframes_t Diskstream::disk_io_chunk_frames = 0;
sigc::signal<void,Diskstream*> Diskstream::DiskstreamCreated;
//sigc::signal<void,list<AudioFileSource*>*> Diskstream::DeleteSources;
@@ -65,13 +65,14 @@ sigc::signal<void> Diskstream::DiskUnderrun;
Diskstream::Diskstream (Session &sess, const string &name, Flag flag)
: _name (name)
, _session (sess)
+ , _playlist(NULL)
{
init (flag);
}
Diskstream::Diskstream (Session& sess, const XMLNode& node)
: _session (sess)
-
+ , _playlist(NULL)
{
init (Recordable);
}
@@ -113,37 +114,28 @@ Diskstream::init (Flag f)
_read_data_count = 0;
_write_data_count = 0;
- /* there are no channels at this point, so these
- two calls just get speed_buffer_size and wrap_buffer
- size setup without duplicating their code.
- */
-
- //set_block_size (_session.get_block_size());
- //allocate_temporary_buffers ();
-
pending_overwrite = false;
overwrite_frame = 0;
overwrite_queued = false;
input_change_pending = NoChange;
- //add_channel ();
- _n_channels = 0;//1;
+ _n_channels = 0;
}
Diskstream::~Diskstream ()
{
- // Taken by child.. assure lock?
+ // Taken by derived class destrctors.. assure lock?
//Glib::Mutex::Lock lm (state_lock);
- //if (_playlist) {
- // _playlist->unref ();
- //}
+ if (_playlist)
+ _playlist->unref ();
+}
- //for (ChannelList::iterator chan = channels.begin(); chan != channels.end(); ++chan) {
- // destroy_channel((*chan));
- //}
-
- //channels.clear();
+void
+Diskstream::set_io (IO& io)
+{
+ _io = &io;
+ set_align_style_from_io ();
}
void
@@ -157,6 +149,29 @@ Diskstream::handle_input_change (IOChange change, void *src)
}
}
+void
+Diskstream::non_realtime_set_speed ()
+{
+ if (_buffer_reallocation_required)
+ {
+ Glib::Mutex::Lock lm (state_lock);
+ allocate_temporary_buffers ();
+
+ _buffer_reallocation_required = false;
+ }
+
+ if (_seek_required) {
+ if (speed() != 1.0f || speed() != -1.0f) {
+ seek ((jack_nframes_t) (_session.transport_frame() * (double) speed()), true);
+ }
+ else {
+ seek (_session.transport_frame(), true);
+ }
+
+ _seek_required = false;
+ }
+}
+
bool
Diskstream::realtime_set_speed (double sp, bool global)
{
@@ -223,7 +238,6 @@ Diskstream::set_align_style (AlignStyle a)
return;
}
-
if (a != _alignment_style) {
_alignment_style = a;
AlignmentStyleChanged ();
@@ -287,6 +301,47 @@ Diskstream::set_speed (double sp)
playlist_modified();
}
+int
+Diskstream::use_playlist (Playlist* playlist)
+{
+ {
+ Glib::Mutex::Lock lm (state_lock);
+
+ if (playlist == _playlist) {
+ return 0;
+ }
+
+ plstate_connection.disconnect();
+ plmod_connection.disconnect ();
+ plgone_connection.disconnect ();
+
+ if (_playlist) {
+ _playlist->unref();
+ }
+
+ _playlist = playlist;
+ _playlist->ref();
+
+ if (!in_set_state && recordable()) {
+ reset_write_sources (false);
+ }
+
+ plstate_connection = _playlist->StateChanged.connect (mem_fun (*this, &Diskstream::playlist_changed));
+ plmod_connection = _playlist->Modified.connect (mem_fun (*this, &Diskstream::playlist_modified));
+ plgone_connection = _playlist->GoingAway.connect (mem_fun (*this, &Diskstream::playlist_deleted));
+ }
+
+ if (!overwrite_queued) {
+ _session.request_overwrite_buffer (this);
+ overwrite_queued = true;
+ }
+
+ PlaylistChanged (); /* EMIT SIGNAL */
+ _session.set_dirty ();
+
+ return 0;
+}
+
void
Diskstream::playlist_changed (Change ignored)
{
@@ -302,6 +357,17 @@ Diskstream::playlist_modified ()
}
}
+void
+Diskstream::playlist_deleted (Playlist* pl)
+{
+ /* this catches an ordering issue with session destruction. playlists
+ are destroyed before diskstreams. we have to invalidate any handles
+ we have to the playlist.
+ */
+
+ _playlist = 0;
+}
+
int
Diskstream::set_name (string str, void *src)
{
diff --git a/libs/ardour/midi_diskstream.cc b/libs/ardour/midi_diskstream.cc
index a5853136ea..4602fc8f67 100644
--- a/libs/ardour/midi_diskstream.cc
+++ b/libs/ardour/midi_diskstream.cc
@@ -388,7 +388,7 @@ MidiDiskstream::read (RawMidi* buf, RawMidi* mixdown_buffer, char * workbuf, jac
{
return 0;
}
-
+/*
int
MidiDiskstream::do_refill (RawMidi* mixdown_buffer, float* gain_buffer, char * workbuf)
{
@@ -400,7 +400,7 @@ MidiDiskstream::do_flush (char * workbuf, bool force_flush)
{
return 0;
}
-
+*/
void
MidiDiskstream::transport_stopped (struct tm& when, time_t twhen, bool abort_capture)
{
diff --git a/libs/ardour/session.cc b/libs/ardour/session.cc
index fec674b671..011d1d6237 100644
--- a/libs/ardour/session.cc
+++ b/libs/ardour/session.cc
@@ -403,6 +403,8 @@ Session::~Session ()
for (map<RunContext,char*>::iterator i = _conversion_buffers.begin(); i != _conversion_buffers.end(); ++i) {
delete [] (i->second);
}
+
+ AudioDiskstream::free_working_buffers();
#undef TRACK_DESTRUCTION
#ifdef TRACK_DESTRUCTION
@@ -2105,7 +2107,7 @@ void
Session::add_diskstream (Diskstream* dstream)
{
/* need to do this in case we're rolling at the time, to prevent false underruns */
- dstream->non_realtime_do_refill();
+ dstream->do_refill_with_alloc();
{
Glib::RWLock::WriterLock lm (diskstream_lock);
diff --git a/libs/ardour/session_butler.cc b/libs/ardour/session_butler.cc
index f0a2af0a83..6509a783bb 100644
--- a/libs/ardour/session_butler.cc
+++ b/libs/ardour/session_butler.cc
@@ -170,11 +170,6 @@ Session::butler_thread_work ()
bool disk_work_outstanding = false;
DiskstreamList::iterator i;
- butler_mixdown_buffer = new Sample[AudioDiskstream::disk_io_frames()];
- butler_gain_buffer = new gain_t[AudioDiskstream::disk_io_frames()];
- // this buffer is used for temp conversion purposes in filesources
- char * conv_buffer = conversion_buffer(ButlerContext);
-
while (true) {
pfd[0].fd = butler_request_pipe[0];
pfd[0].events = POLLIN|POLLERR|POLLHUP;
@@ -256,16 +251,15 @@ Session::butler_thread_work ()
Glib::RWLock::ReaderLock dsm (diskstream_lock);
for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) {
- // cerr << "rah fondr " << (*i)->io()->name () << endl;
- AudioDiskstream* ads = dynamic_cast<AudioDiskstream*>(*i);
- if (!ads) continue; // FIXME
- switch (ads->do_refill (butler_mixdown_buffer, butler_gain_buffer, conv_buffer)) {
+ Diskstream* const ds = *i;
+
+ switch (ds->do_refill ()) {
case 0:
- bytes += ads->read_data_count();
+ bytes += ds->read_data_count();
break;
case 1:
- bytes += ads->read_data_count();
+ bytes += ds->read_data_count();
disk_work_outstanding = true;
break;
@@ -302,7 +296,7 @@ Session::butler_thread_work ()
for (i = diskstreams.begin(); !transport_work_requested() && butler_should_run && i != diskstreams.end(); ++i) {
// cerr << "write behind for " << (*i)->name () << endl;
- switch ((*i)->do_flush (conv_buffer)) {
+ switch ((*i)->do_flush (Session::ButlerContext)) {
case 0:
bytes += (*i)->write_data_count();
break;
diff --git a/libs/ardour/session_state.cc b/libs/ardour/session_state.cc
index 73ba391873..0809aae6eb 100644
--- a/libs/ardour/session_state.cc
+++ b/libs/ardour/session_state.cc
@@ -196,7 +196,8 @@ Session::first_stage_init (string fullpath, string snapshot_name)
/* allocate conversion buffers */
_conversion_buffers[ButlerContext] = new char[AudioDiskstream::disk_io_frames() * 4];
_conversion_buffers[TransportContext] = new char[AudioDiskstream::disk_io_frames() * 4];
-
+ AudioDiskstream::allocate_working_buffers();
+
/* default short fade = 15ms */
Crossfade::set_short_xfade_length ((jack_nframes_t) floor ((15.0 * frame_rate()) / 1000.0));