Abstraction cleanups/polish, towards merging with trunk

git-svn-id: svn://localhost/ardour2/branches/midi@720 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard
2006-07-30 03:25:38 +00:00
parent 8277d134b9
commit 9d5d82b4df
27 changed files with 972 additions and 1446 deletions

View File

@@ -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 ();
}
@@ -365,38 +294,19 @@ 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;
@@ -432,18 +342,10 @@ AudioRegionView::reset_width_dependent_items (double pixel_width)
reset_fade_shapes ();
}
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];
@@ -769,18 +649,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 ()
{
@@ -795,89 +663,6 @@ AudioRegionView::show_region_editor ()
editor->get_window()->raise();
}
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)
{
@@ -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)
{
@@ -1243,21 +1012,6 @@ AudioRegionView::add_ghost (AutomationTimeAxisView& atv)
return ghost;
}
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 ()
{

View File

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

View File

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

View File

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

View File

@@ -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 */
RouteTimeAxisView::build_automation_action_menu ();
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));
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
@@ -393,16 +318,6 @@ AudioTimeAxisView::set_waveform_shape (WaveformShape shape)
map_frozen ();
}
void
AudioTimeAxisView::set_selected_regionviews (RegionSelection& regions)
{
AudioStreamView* asv = audio_view();
if (asv) {
asv->set_selected_regionviews (regions);
}
}
void
AudioTimeAxisView::add_gain_automation_child ()
{
@@ -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,36 +540,12 @@ 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 ()
{
@@ -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()) {

View File

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

View File

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

View File

@@ -29,6 +29,7 @@ namespace ARDOUR {
class Session;
class PluginManager;
class Plugin;
class PluginInfo;
}
class PluginSelector : public ArdourDialog

View File

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

View File

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

View File

@@ -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;
@@ -373,6 +384,97 @@ RouteTimeAxisView::automation_click ()
automation_action_menu->popup (1, 0);
}
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)
{
@@ -759,6 +861,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)
{
@@ -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();
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 ()
{
@@ -460,36 +426,6 @@ AudioDiskstream::use_destructive_playlist ()
/* the source list will never be reset for a destructive track */
}
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)
{
@@ -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;

View File

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

View File

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

View File

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

View File

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

View File

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