Fairly major change to the way in which crossfades are handled;

they are now done with region fades, rather than separate objects.
After this commit, Ardour will try to convert your session files
to the new crossfade format, but will make a backup in your
session folder first.

If you have works in progress using Ardour 3 it is
***STRONGLY RECOMMENDED*** that you back up session files before
updating to this commit.


git-svn-id: svn://localhost/ardour2/branches/3.0@11986 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Carl Hetherington 2012-04-16 16:32:22 +00:00
parent 02c498a8fa
commit a2897ecef6
65 changed files with 1152 additions and 3820 deletions

View File

@ -46,7 +46,6 @@
#include "selection.h"
#include "public_editor.h"
#include "ardour_ui.h"
#include "crossfade_view.h"
#include "rgb_macros.h"
#include "gui_thread.h"
#include "utils.h"
@ -61,32 +60,12 @@ using namespace Editing;
AudioStreamView::AudioStreamView (AudioTimeAxisView& tv)
: StreamView (tv)
{
crossfades_visible = tv.session()->config.get_xfades_visible ();
color_handler ();
_amplitude_above_axis = 1.0;
Config->ParameterChanged.connect (*this, invalidator (*this), ui_bind (&AudioStreamView::parameter_changed, this, _1), gui_context());
}
AudioStreamView::~AudioStreamView ()
{
for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) {
delete xi->second;
}
}
int
AudioStreamView::set_samples_per_unit (gdouble spp)
{
StreamView::set_samples_per_unit(spp);
for (CrossfadeViewList::iterator xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) {
xi->second->set_samples_per_unit (spp);
}
return 0;
}
int
AudioStreamView::set_amplitude_above_axis (gdouble app)
{
@ -209,163 +188,10 @@ AudioStreamView::add_region_view_internal (boost::shared_ptr<Region> r, bool wai
return region_view;
}
void
AudioStreamView::remove_region_view (boost::weak_ptr<Region> weak_r)
{
ENSURE_GUI_THREAD (*this, &AudioStreamView::remove_region_view, weak_r);
boost::shared_ptr<Region> r (weak_r.lock());
if (!r) {
return;
}
if (!_trackview.session()->deletion_in_progress()) {
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end();) {
CrossfadeViewList::iterator tmp;
tmp = i;
++tmp;
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(r);
if (ar && i->second->crossfade->involves (ar)) {
delete i->second;
crossfade_views.erase (i);
}
i = tmp;
}
}
StreamView::remove_region_view(r);
}
void
AudioStreamView::undisplay_track ()
{
StreamView::undisplay_track ();
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
delete i->second;
}
crossfade_views.clear ();
}
void
AudioStreamView::playlist_layered (boost::weak_ptr<Track> wtr)
{
boost::shared_ptr<Track> tr (wtr.lock());
if (!tr) {
return;
}
StreamView::playlist_layered (wtr);
/* make sure xfades are on top and all the regionviews are stacked correctly. */
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
i->second->get_canvas_group()->raise_to_top();
}
}
void
AudioStreamView::playlist_switched (boost::weak_ptr<Track> wtr)
{
boost::shared_ptr<Track> tr (wtr.lock());
if (!tr) {
return;
}
playlist_connections.drop_connections ();
StreamView::playlist_switched (tr);
boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (tr->playlist());
if (apl) {
apl->NewCrossfade.connect (playlist_connections, invalidator (*this), ui_bind (&AudioStreamView::add_crossfade, this, _1), gui_context());
}
}
void
AudioStreamView::add_crossfade (boost::weak_ptr<Crossfade> wc)
{
boost::shared_ptr<Crossfade> crossfade (wc.lock());
if (!crossfade) {
return;
}
AudioRegionView* lview = 0;
AudioRegionView* rview = 0;
/* first see if we already have a CrossfadeView for this Crossfade */
CrossfadeViewList::iterator i = crossfade_views.find (crossfade);
if (i != crossfade_views.end()) {
if (!crossfades_visible) {
i->second->hide();
} else {
i->second->show ();
}
i->second->set_valid (true);
return;
}
/* create a new one */
for (list<RegionView *>::iterator i = region_views.begin(); i != region_views.end(); ++i) {
AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*i);
if (!lview && arv && (arv->region() == crossfade->out())) {
lview = arv;
}
if (!rview && arv && (arv->region() == crossfade->in())) {
rview = arv;
}
}
CrossfadeView *cv = new CrossfadeView (_trackview.canvas_display (),
_trackview,
crossfade,
_samples_per_unit,
region_color,
*lview, *rview);
cv->set_valid (true);
crossfade->Invalidated.connect (*this, invalidator (*this), ui_bind (&AudioStreamView::remove_crossfade, this, _1), gui_context());
crossfade_views[cv->crossfade] = cv;
if (!crossfades_visible) {
cv->hide ();
}
update_content_height (cv);
}
void
AudioStreamView::remove_crossfade (boost::shared_ptr<Region> r)
{
ENSURE_GUI_THREAD (*this, &AudioStreamView::remove_crossfade, r)
boost::shared_ptr<Crossfade> xfade = boost::dynamic_pointer_cast<Crossfade> (r);
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
if (i->second->crossfade == xfade) {
delete i->second;
crossfade_views.erase (i);
break;
}
}
}
void
AudioStreamView::redisplay_track ()
{
list<RegionView *>::iterator i;
CrossfadeViewList::iterator xi, tmpx;
// Flag region views as invalid and disable drawing
for (i = region_views.begin(); i != region_views.end(); ++i) {
@ -373,41 +199,11 @@ AudioStreamView::redisplay_track ()
(*i)->enable_display (false);
}
// Flag crossfade views as invalid
for (xi = crossfade_views.begin(); xi != crossfade_views.end(); ++xi) {
xi->second->set_valid (false);
if (xi->second->visible()) {
xi->second->show ();
}
}
// Add and display region and crossfade views, and flag them as valid
// Add and display views, and flag them as valid
if (_trackview.is_audio_track()) {
_trackview.track()->playlist()->foreach_region(
sigc::hide_return (sigc::mem_fun (*this, &StreamView::add_region_view))
);
boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist>(
_trackview.track()->playlist()
);
if (apl) {
apl->foreach_crossfade (sigc::mem_fun (*this, &AudioStreamView::add_crossfade));
}
}
// Remove invalid crossfade views
for (xi = crossfade_views.begin(); xi != crossfade_views.end();) {
tmpx = xi;
tmpx++;
if (!xi->second->valid()) {
delete xi->second;
crossfade_views.erase (xi);
}
xi = tmpx;
}
// Stack regions by layer, and remove invalid regions
@ -600,14 +396,6 @@ AudioStreamView::setup_rec_box ()
}
}
void
AudioStreamView::foreach_crossfadeview (void (CrossfadeView::*pmf)(void))
{
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
(i->second->*pmf) ();
}
}
void
AudioStreamView::rec_peak_range_ready (framepos_t start, framecnt_t cnt, boost::weak_ptr<Source> weak_src)
{
@ -744,40 +532,6 @@ AudioStreamView::hide_all_fades ()
}
}
void
AudioStreamView::show_all_xfades ()
{
foreach_crossfadeview (&CrossfadeView::show);
crossfades_visible = true;
}
void
AudioStreamView::hide_all_xfades ()
{
foreach_crossfadeview (&CrossfadeView::hide);
crossfades_visible = false;
}
void
AudioStreamView::hide_xfades_involving (AudioRegionView& rv)
{
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
if (i->second->crossfade->involves (rv.audio_region())) {
i->second->fake_hide ();
}
}
}
void
AudioStreamView::reveal_xfades_involving (AudioRegionView& rv)
{
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
if (i->second->crossfade->involves (rv.audio_region()) && i->second->visible()) {
i->second->show ();
}
}
}
void
AudioStreamView::color_handler ()
{
@ -796,45 +550,6 @@ AudioStreamView::color_handler ()
}
}
void
AudioStreamView::update_contents_height ()
{
StreamView::update_contents_height ();
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
update_content_height (i->second);
}
}
void
AudioStreamView::update_content_height (CrossfadeView* cv)
{
switch (_layer_display) {
case Overlaid:
cv->set_y (0);
cv->set_heights (height, height);
break;
case Stacked:
case Expanded:
layer_t const inl = cv->crossfade->in()->layer ();
layer_t const outl = cv->crossfade->out()->layer ();
layer_t const high = max (inl, outl);
layer_t const low = min (inl, outl);
const double h = child_height ();
if (_layer_display == Stacked) {
cv->set_y ((_layers - high - 1) * h);
cv->set_heights ((high - low + 1) * h, h);
} else {
cv->set_y (((_layers - high) * 2 - 1) * h);
cv->set_heights (((high - low) * 2 + 1) * h, h);
}
}
}
void
AudioStreamView::parameter_changed (string const & p)
{
@ -847,13 +562,3 @@ AudioStreamView::parameter_changed (string const & p)
}
}
void
AudioStreamView::horizontal_position_changed ()
{
/* we only `draw' the bit of the curve that is visible, so we need to update here */
for (CrossfadeViewList::iterator i = crossfade_views.begin(); i != crossfade_views.end(); ++i) {
i->second->horizontal_position_changed ();
}
}

View File

@ -36,7 +36,6 @@ namespace Gdk {
namespace ARDOUR {
class Route;
class Crossfade;
class PeakData;
class AudioRegion;
class Source;
@ -47,33 +46,21 @@ class Selectable;
class AudioTimeAxisView;
class AudioRegionView;
class RegionSelection;
class CrossfadeView;
class Selection;
class AudioStreamView : public StreamView
{
public:
AudioStreamView (AudioTimeAxisView&);
~AudioStreamView ();
int set_samples_per_unit (gdouble spp);
void horizontal_position_changed ();
int set_amplitude_above_axis (gdouble app);
gdouble get_amplitude_above_axis () { return _amplitude_above_axis; }
void set_show_waveforms (bool yn);
void foreach_crossfadeview (void (CrossfadeView::*pmf)(void));
void show_all_fades ();
void hide_all_fades ();
void show_all_xfades ();
void hide_all_xfades ();
void hide_xfades_involving (AudioRegionView&);
void reveal_xfades_involving (AudioRegionView&);
RegionView* create_region_view (boost::shared_ptr<ARDOUR::Region>, bool, bool);
private:
@ -82,32 +69,18 @@ class AudioStreamView : public StreamView
void update_rec_regions (ARDOUR::framepos_t, ARDOUR::framecnt_t);
RegionView* add_region_view_internal (boost::shared_ptr<ARDOUR::Region>, bool wait_for_waves, bool recording = false);
void remove_region_view (boost::weak_ptr<ARDOUR::Region> );
void remove_audio_region_view (boost::shared_ptr<ARDOUR::AudioRegion> );
void undisplay_track ();
void redisplay_track ();
void playlist_layered (boost::weak_ptr<ARDOUR::Track>);
void playlist_switched (boost::weak_ptr<ARDOUR::Track>);
void add_crossfade (boost::weak_ptr<ARDOUR::Crossfade>);
void remove_crossfade (boost::shared_ptr<ARDOUR::Region>);
void color_handler ();
void update_contents_height ();
void update_content_height (CrossfadeView *);
void parameter_changed (std::string const &);
void set_waveform_shape (ARDOUR::WaveformShape);
void set_waveform_scale (ARDOUR::WaveformScale);
double _amplitude_above_axis;
typedef std::map<boost::shared_ptr<ARDOUR::Crossfade>, CrossfadeView*> CrossfadeViewList;
CrossfadeViewList crossfade_views;
bool crossfades_visible;
std::map<boost::shared_ptr<ARDOUR::Source>, bool> rec_data_ready_map;
bool outline_region;

View File

@ -55,7 +55,6 @@
#include "audio_time_axis.h"
#include "automation_line.h"
#include "canvas_impl.h"
#include "crossfade_view.h"
#include "enums.h"
#include "gui_thread.h"
#include "automation_time_axis.h"
@ -176,22 +175,6 @@ AudioTimeAxisView::hide ()
TimeAxisView::hide ();
}
void
AudioTimeAxisView::append_extra_display_menu_items ()
{
using namespace Menu_Helpers;
MenuList& items = display_menu->items();
// crossfade stuff
if (!Profile->get_sae() && is_track ()) {
items.push_back (MenuElem (_("Hide All Crossfades"), sigc::bind (sigc::mem_fun(*this, &AudioTimeAxisView::hide_all_xfades), true)));
items.push_back (MenuElem (_("Show All Crossfades"), sigc::bind (sigc::mem_fun(*this, &AudioTimeAxisView::show_all_xfades), true)));
items.push_back (SeparatorElem ());
}
}
void
AudioTimeAxisView::create_automation_child (const Evoral::Parameter& param, bool show)
{
@ -365,54 +348,6 @@ AudioTimeAxisView::hide_all_automation (bool apply_to_selection)
}
}
void
AudioTimeAxisView::show_all_xfades (bool apply_to_selection)
{
if (apply_to_selection) {
_editor.get_selection().tracks.foreach_audio_time_axis (boost::bind (&AudioTimeAxisView::show_all_xfades, _1, false));
} else {
AudioStreamView* asv = audio_view ();
if (asv) {
asv->show_all_xfades ();
}
}
}
void
AudioTimeAxisView::hide_all_xfades (bool apply_to_selection)
{
if (apply_to_selection) {
_editor.get_selection().tracks.foreach_audio_time_axis (boost::bind (&AudioTimeAxisView::hide_all_xfades, _1, false));
} else {
AudioStreamView* asv = audio_view ();
if (asv) {
asv->hide_all_xfades ();
}
}
}
void
AudioTimeAxisView::hide_dependent_views (TimeAxisViewItem& tavi)
{
AudioStreamView* asv = audio_view();
AudioRegionView* rv;
if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
asv->hide_xfades_involving (*rv);
}
}
void
AudioTimeAxisView::reveal_dependent_views (TimeAxisViewItem& tavi)
{
AudioStreamView* asv = audio_view();
AudioRegionView* rv;
if (asv && (rv = dynamic_cast<AudioRegionView*>(&tavi)) != 0) {
asv->reveal_xfades_involving (*rv);
}
}
void
AudioTimeAxisView::route_active_changed ()
{

View File

@ -73,10 +73,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
AudioStreamView* audio_view();
void set_show_waveforms_recording (bool yn);
void show_all_xfades (bool apply_to_selection = false);
void hide_all_xfades (bool apply_to_selection = false);
void hide_dependent_views (TimeAxisViewItem&);
void reveal_dependent_views (TimeAxisViewItem&);
/* Overridden from parent to store display state */
guint32 show_at (double y, int& nth, Gtk::VBox *parent);
@ -94,7 +90,6 @@ class AudioTimeAxisView : public RouteTimeAxisView
void route_active_changed ();
void append_extra_display_menu_items ();
Gtk::Menu* build_mode_menu();
void build_automation_action_menu (bool);

View File

@ -1,302 +0,0 @@
/*
Copyright (C) 2003 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <algorithm>
#include "ardour/region.h"
#include <gtkmm2ext/doi.h>
#include "canvas-simplerect.h"
#include "canvas-curve.h"
#include "crossfade_view.h"
#include "global_signals.h"
#include "gui_thread.h"
#include "rgb_macros.h"
#include "audio_time_axis.h"
#include "public_editor.h"
#include "audio_region_view.h"
#include "utils.h"
#include "canvas_impl.h"
#include "ardour_ui.h"
using namespace ARDOUR;
using namespace PBD;
using namespace Editing;
using namespace Gnome;
using namespace Canvas;
PBD::Signal1<void,CrossfadeView*> CrossfadeView::CatchDeletion;
CrossfadeView::CrossfadeView (ArdourCanvas::Group *parent,
RouteTimeAxisView &tv,
boost::shared_ptr<Crossfade> xf,
double spu,
Gdk::Color& basic_color,
AudioRegionView& lview,
AudioRegionView& rview)
: TimeAxisViewItem ("xfade" /*xf.name()*/, *parent, tv, spu, basic_color, xf->position(),
xf->length(), false, false, TimeAxisViewItem::Visibility (TimeAxisViewItem::ShowFrame)),
crossfade (xf),
left_view (lview),
right_view (rview),
_all_in_view (false),
_child_height (0)
{
_valid = true;
_visible = true;
fade_in = new Line (*group);
fade_in->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine.get();
fade_in->property_width_pixels() = 1;
fade_out = new Line (*group);
fade_out->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_CrossfadeLine.get();
fade_out->property_width_pixels() = 1;
/* no frame around the xfade or overlap rects */
frame->property_outline_what() = 0;
/* never show the vestigial frame */
vestigial_frame->hide();
show_vestigial = false;
group->signal_event().connect (sigc::bind (sigc::mem_fun (tv.editor(), &PublicEditor::canvas_crossfade_view_event), group, this));
PropertyChange all_crossfade_properties;
all_crossfade_properties.add (ARDOUR::Properties::active);
all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
crossfade_changed (all_crossfade_properties);
crossfade->PropertyChanged.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_changed, this, _1), gui_context());
crossfade->FadesChanged.connect (*this, invalidator (*this), ui_bind (&CrossfadeView::crossfade_fades_changed, this), gui_context());
ColorsChanged.connect (sigc::mem_fun (*this, &CrossfadeView::color_handler));
}
CrossfadeView::~CrossfadeView ()
{
CatchDeletion (this) ; /* EMIT_SIGNAL */
}
void
CrossfadeView::reset_width_dependent_items (double pixel_width)
{
TimeAxisViewItem::reset_width_dependent_items (pixel_width);
active_changed ();
if (pixel_width < 5) {
fade_in->hide();
fade_out->hide();
}
}
void
CrossfadeView::set_heights (double fade_height, double child_height)
{
if (child_height > TimeAxisViewItem::NAME_HIGHLIGHT_THRESH) {
fade_height -= NAME_HIGHLIGHT_SIZE;
child_height -= NAME_HIGHLIGHT_SIZE;
}
TimeAxisViewItem::set_height (fade_height);
_child_height = child_height;
redraw_curves ();
}
void
CrossfadeView::crossfade_changed (const PropertyChange& what_changed)
{
bool need_redraw_curves = false;
if (what_changed.contains (ARDOUR::bounds_change)) {
set_position (crossfade->position(), this);
set_duration (crossfade->length(), this);
/* set_duration will call reset_width_dependent_items which in turn will call redraw_curves via active_changed,
so no need for us to call it */
need_redraw_curves = false;
}
if (what_changed.contains (ARDOUR::Properties::follow_overlap)) {
need_redraw_curves = true;
}
if (what_changed.contains (ARDOUR::Properties::active)) {
/* calls redraw_curves */
active_changed ();
} else if (need_redraw_curves) {
redraw_curves ();
}
}
/** Set up our fade_in and fade_out curves to contain points for the currently visible portion
* of the crossfade.
*/
void
CrossfadeView::redraw_curves ()
{
if (!crossfade->following_overlap()) {
/* curves should not be visible */
fade_in->hide ();
fade_out->hide ();
return;
}
if (_height < 0) {
/* no space allocated yet */
return;
}
PublicEditor& editor = get_time_axis_view().editor ();
framepos_t const editor_left = editor.leftmost_position ();
framepos_t const editor_right = editor_left + editor.current_page_frames ();
framepos_t const xfade_left = crossfade->position ();
framepos_t const xfade_right = xfade_left + crossfade->length ();
/* Work out the range of our frames that are visible */
framepos_t const min_frames = std::max (editor_left, xfade_left);
framepos_t const max_frames = std::min (editor_right, xfade_right);
_all_in_view = (editor_left <= xfade_left && editor_right >= xfade_right);
/* Hence the number of points that we will render */
int32_t const npoints = editor.frame_to_pixel (max_frames - min_frames);
if (!_visible || !crossfade->active() || npoints < 3) {
fade_in->hide();
fade_out->hide();
return;
} else {
fade_in->show();
fade_out->show();
}
Points* points = get_canvas_points ("xfade edit redraw", npoints);
float* vec = new float[npoints];
crossfade->fade_in().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
/* Work out the offset from the start of the crossfade to the visible part, in pixels */
double xoff = 0;
if (crossfade->position() < editor.leftmost_position()) {
xoff = editor.frame_to_pixel (min_frames) - editor.frame_to_pixel (crossfade->position ());
}
for (int i = 0, pci = 0; i < npoints; ++i) {
Art::Point &p = (*points)[pci++];
p.set_x (xoff + i + 1);
double const ho = crossfade->in()->layer() > crossfade->out()->layer() ? _child_height : _height;
p.set_y (ho - ((_child_height - 2) * vec[i]));
}
fade_in->property_points() = *points;
crossfade->fade_out().curve().get_vector (min_frames - crossfade->position(), max_frames - crossfade->position(), vec, npoints);
for (int i = 0, pci = 0; i < npoints; ++i) {
Art::Point &p = (*points)[pci++];
p.set_x (xoff + i + 1);
double const ho = crossfade->in()->layer() < crossfade->out()->layer() ? _child_height : _height;
p.set_y (ho - ((_child_height - 2) * vec[i]));
}
fade_out->property_points() = *points;
delete [] vec;
delete points;
/* XXX this is ugly, but it will have to wait till Crossfades are reimplented
as regions. This puts crossfade views on top of a track, above all regions.
*/
group->raise_to_top();
}
void
CrossfadeView::active_changed ()
{
if (crossfade->active()) {
frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_ActiveCrossfade.get();
} else {
frame->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_InactiveCrossfade.get();
}
redraw_curves ();
}
void
CrossfadeView::color_handler ()
{
active_changed ();
}
void
CrossfadeView::set_valid (bool yn)
{
_valid = yn;
}
void
CrossfadeView::show ()
{
_visible = true;
group->show();
redraw_curves ();
}
void
CrossfadeView::hide ()
{
group->hide();
_visible = false;
}
void
CrossfadeView::fake_hide ()
{
group->hide();
}
void
CrossfadeView::crossfade_fades_changed ()
{
redraw_curves ();
}
void
CrossfadeView::horizontal_position_changed ()
{
/* If the crossfade curves are entirely within the editor's visible space, there is
no need to redraw them here as they will be completely drawn (as distinct from
the other case where the horizontal position change will uncover `undrawn'
sections).
*/
if (!_all_in_view) {
redraw_curves ();
}
}

View File

@ -90,7 +90,6 @@
#include "canvas-noevent-text.h"
#include "canvas_impl.h"
#include "crossfade_edit.h"
#include "crossfade_view.h"
#include "debug.h"
#include "editing.h"
#include "editor.h"
@ -303,7 +302,6 @@ Editor::Editor ()
clicked_regionview = 0;
clicked_axisview = 0;
clicked_routeview = 0;
clicked_crossfadeview = 0;
clicked_control_point = 0;
last_update_frame = 0;
pre_press_cursor = 0;
@ -340,7 +338,6 @@ Editor::Editor ()
have_pending_keyboard_selection = false;
_follow_playhead = true;
_stationary_playhead = false;
_xfade_visibility = true;
editor_ruler_menu = 0;
no_ruler_shown_update = false;
marker_menu = 0;
@ -1514,10 +1511,6 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
}
break;
case CrossfadeViewItem:
build_menu_function = &Editor::build_track_crossfade_context_menu;
break;
case StreamItem:
if (clicked_routeview->track()) {
build_menu_function = &Editor::build_track_context_menu;
@ -1563,9 +1556,6 @@ Editor::popup_track_context_menu (int button, int32_t time, ItemType item_type,
case SelectionItem:
break;
case CrossfadeViewItem:
break;
case StreamItem:
break;
@ -1650,11 +1640,6 @@ Editor::build_track_region_context_menu ()
region_edit_menu_split_item = 0;
region_edit_menu_split_multichannel_item = 0;
/* we might try to use items that are currently attached to a crossfade menu,
so clear that, too.
*/
track_crossfade_context_menu.items().clear ();
RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (clicked_axisview);
if (rtv) {
@ -1671,54 +1656,6 @@ Editor::build_track_region_context_menu ()
return &track_region_context_menu;
}
Menu*
Editor::build_track_crossfade_context_menu ()
{
using namespace Menu_Helpers;
MenuList& edit_items = track_crossfade_context_menu.items();
edit_items.clear ();
/* we might try to use items that are currently attached to a crossfade menu,
so clear that, too.
*/
track_region_context_menu.items().clear ();
AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (clicked_axisview);
if (atv) {
boost::shared_ptr<Track> tr;
boost::shared_ptr<Playlist> pl;
boost::shared_ptr<AudioPlaylist> apl;
if ((tr = atv->track()) && ((pl = tr->playlist()) != 0) && ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) != 0)) {
AudioPlaylist::Crossfades xfades;
framepos_t where;
bool ignored;
/* The xfade menu is a bit of a special case, as we always use the mouse position
to decide whether or not to display it (rather than the edit point). No particularly
strong reasons for this, other than it is a bit surprising to right-click on a xfade
and not get a menu.
*/
mouse_frame (where, ignored);
apl->crossfades_at (where, xfades);
bool const many = xfades.size() > 1;
for (AudioPlaylist::Crossfades::iterator i = xfades.begin(); i != xfades.end(); ++i) {
add_crossfade_context_items (atv->audio_view(), (*i), edit_items, many);
}
add_region_context_items (edit_items, tr);
}
}
add_dstream_context_items (edit_items);
return &track_crossfade_context_menu;
}
void
Editor::analyze_region_selection ()
{
@ -1769,73 +1706,6 @@ Editor::build_track_selection_context_menu ()
return &track_selection_context_menu;
}
/** Add context menu items relevant to crossfades.
* @param edit_items List to add the items to.
*/
void
Editor::add_crossfade_context_items (AudioStreamView* view, boost::shared_ptr<Crossfade> xfade, Menu_Helpers::MenuList& edit_items, bool many)
{
using namespace Menu_Helpers;
Menu *xfade_menu = manage (new Menu);
MenuList& items = xfade_menu->items();
xfade_menu->set_name ("ArdourContextMenu");
string str;
if (xfade->active()) {
str = _("Mute");
} else {
str = _("Unmute");
}
items.push_back (
MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_active), &view->trackview(), boost::weak_ptr<Crossfade> (xfade)))
);
items.push_back (
MenuElem (_("Edit..."), sigc::bind (sigc::mem_fun (*this, &Editor::edit_xfade), boost::weak_ptr<Crossfade> (xfade)))
);
if (xfade->can_follow_overlap()) {
if (xfade->following_overlap()) {
str = _("Convert to Short");
} else {
str = _("Convert to Full");
}
items.push_back (
MenuElem (str, sigc::bind (sigc::mem_fun (*this, &Editor::toggle_xfade_length), &view->trackview(), xfade))
);
}
if (many) {
str = xfade->out()->name();
str += "->";
str += xfade->in()->name();
} else {
str = _("Crossfade");
}
edit_items.push_back (MenuElem (str, *xfade_menu));
edit_items.push_back (SeparatorElem());
}
void
Editor::xfade_edit_left_region ()
{
if (clicked_crossfadeview) {
clicked_crossfadeview->left_view.show_region_editor ();
}
}
void
Editor::xfade_edit_right_region ()
{
if (clicked_crossfadeview) {
clicked_crossfadeview->right_view.show_region_editor ();
}
}
void
Editor::add_region_context_items (Menu_Helpers::MenuList& edit_items, boost::shared_ptr<Track> track)
{
@ -2391,12 +2261,6 @@ Editor::set_state (const XMLNode& node, int /*version*/)
_regions->reset_sort_type ((RegionListSortType) string_2_enum (prop->value(), st), true);
}
if ((prop = node.property ("xfades-visible"))) {
bool yn = string_is_affirmative (prop->value());
_xfade_visibility = !yn;
// set_xfade_visibility (yn);
}
if ((prop = node.property ("show-editor-mixer"))) {
Glib::RefPtr<Action> act = ActionManager::get_action (X_("Editor"), X_("show-editor-mixer"));
@ -2523,7 +2387,6 @@ Editor::get_state ()
node->add_property ("maximised", _maximised ? "yes" : "no");
node->add_property ("follow-playhead", _follow_playhead ? "yes" : "no");
node->add_property ("stationary-playhead", _stationary_playhead ? "yes" : "no");
node->add_property ("xfades-visible", _xfade_visibility ? "yes" : "no");
node->add_property ("region-list-sort-type", enum_2_string (_regions->sort_type ()));
node->add_property ("mouse-mode", enum2str(mouse_mode));
node->add_property ("internal-edit", _internal_editing ? "yes" : "no");
@ -3745,80 +3608,6 @@ Editor::set_stationary_playhead (bool yn)
}
}
void
Editor::toggle_xfade_active (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
{
boost::shared_ptr<Crossfade> xfade (wxfade.lock());
if (!xfade) {
return;
}
vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
_session->begin_reversible_command (_("Change crossfade active state"));
for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
(*i)->clear_changes ();
(*i)->set_active (!(*i)->active());
_session->add_command (new StatefulDiffCommand (*i));
}
_session->commit_reversible_command ();
}
void
Editor::toggle_xfade_length (RouteTimeAxisView* tv, boost::weak_ptr<Crossfade> wxfade)
{
boost::shared_ptr<Crossfade> xfade (wxfade.lock());
if (!xfade) {
return;
}
vector<boost::shared_ptr<Crossfade> > all = get_equivalent_crossfades (*tv, xfade, ARDOUR::Properties::edit.property_id);
/* This can't be a StatefulDiffCommand as the fade shapes are not
managed by the Stateful properties system.
*/
_session->begin_reversible_command (_("Change crossfade length"));
for (vector<boost::shared_ptr<Crossfade> >::iterator i = all.begin(); i != all.end(); ++i) {
XMLNode& before = (*i)->get_state ();
(*i)->set_follow_overlap (!(*i)->following_overlap());
XMLNode& after = (*i)->get_state ();
_session->add_command (new MementoCommand<Crossfade> (*i->get(), &before, &after));
}
_session->commit_reversible_command ();
}
void
Editor::edit_xfade (boost::weak_ptr<Crossfade> wxfade)
{
boost::shared_ptr<Crossfade> xfade (wxfade.lock());
if (!xfade) {
return;
}
CrossfadeEditor cew (_session, xfade, xfade->fade_in().get_min_y(), 1.0);
ensure_float (cew);
switch (cew.run ()) {
case RESPONSE_ACCEPT:
break;
default:
return;
}
cew.apply ();
PropertyChange all_crossfade_properties;
all_crossfade_properties.add (ARDOUR::Properties::active);
all_crossfade_properties.add (ARDOUR::Properties::follow_overlap);
xfade->PropertyChanged (all_crossfade_properties);
}
PlaylistSelector&
Editor::playlist_selector () const
{
@ -4396,19 +4185,6 @@ Editor::idle_visual_changer ()
double const last_time_origin = horizontal_position ();
if (p & VisualChange::TimeOrigin) {
/* This is a bit of a hack, but set_frames_per_unit
below will (if called) end up with the
CrossfadeViews looking at Editor::leftmost_frame,
and if we're changing origin and zoom in the same
operation it will be the wrong value unless we
update it here.
*/
leftmost_frame = pending_visual_change.time_origin;
assert (leftmost_frame >= 0);
}
if (p & VisualChange::ZoomLevel) {
set_frames_per_unit (pending_visual_change.frames_per_unit);
@ -5382,7 +5158,6 @@ Editor::session_going_away ()
clicked_regionview = 0;
clicked_axisview = 0;
clicked_routeview = 0;
clicked_crossfadeview = 0;
entered_regionview = 0;
entered_track = 0;
last_update_frame = 0;
@ -5506,7 +5281,6 @@ Editor::setup_fade_images ()
_fade_out_images[FadeSlow] = new Gtk::Image (get_icon_path (X_("crossfade-out-long-cut")));
}
/** @return Gtk::manage()d menu item for a given action from `editor_actions' */
Gtk::MenuItem&
Editor::action_menu_item (std::string const & name)

View File

@ -83,7 +83,6 @@ namespace ARDOUR {
class NamedSelection;
class Session;
class Filter;
class Crossfade;
class ChanCount;
class MidiOperator;
class Track;
@ -106,7 +105,6 @@ class AutomationTimeAxisView;
class BundleManager;
class ButtonJoiner;
class ControlPoint;
class CrossfadeView;
class DragManager;
class GroupedButtons;
class GUIObjectState;
@ -370,12 +368,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void toggle_measure_visibility ();
void toggle_logo_visibility ();
/* fades/xfades */
/* fades */
void toggle_region_fades (int dir);
void update_region_fade_visibility ();
bool xfade_visibility() const { return _xfade_visibility; }
void update_xfade_visibility ();
/* redirect shared ops menu. caller must free returned menu */
@ -632,16 +628,12 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
RegionView* clicked_regionview;
RegionSelection latest_regionviews;
uint32_t clicked_selection;
CrossfadeView* clicked_crossfadeview;
ControlPoint* clicked_control_point;
void sort_track_selection (TrackViewList&);
void get_equivalent_regions (RegionView* rv, std::vector<RegionView*> &, PBD::PropertyID) const;
RegionSelection get_equivalent_regions (RegionSelection &, PBD::PropertyID) const;
std::vector<boost::shared_ptr<ARDOUR::Crossfade> > get_equivalent_crossfades (
RouteTimeAxisView&, boost::shared_ptr<ARDOUR::Crossfade>, PBD::PropertyID
) const;
void mapover_tracks (sigc::slot<void,RouteTimeAxisView&,uint32_t> sl, TimeAxisView*, PBD::PropertyID) const;
void mapover_tracks_with_unique_playlists (sigc::slot<void,RouteTimeAxisView&,uint32_t> sl, TimeAxisView*, PBD::PropertyID) const;
@ -650,9 +642,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void mapped_use_new_playlist (RouteTimeAxisView&, uint32_t, std::vector<boost::shared_ptr<ARDOUR::Playlist> > const &);
void mapped_use_copy_playlist (RouteTimeAxisView&, uint32_t, std::vector<boost::shared_ptr<ARDOUR::Playlist> > const &);
void mapped_clear_playlist (RouteTimeAxisView&, uint32_t);
void mapped_get_equivalent_crossfades (
RouteTimeAxisView&, uint32_t, boost::shared_ptr<ARDOUR::Crossfade>, std::vector<boost::shared_ptr<ARDOUR::Crossfade> >*
) const;
void button_selection (ArdourCanvas::Item* item, GdkEvent* event, ItemType item_type);
bool button_release_can_deselect;
@ -675,7 +664,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
Gtk::Menu track_context_menu;
Gtk::Menu track_region_context_menu;
Gtk::Menu track_selection_context_menu;
Gtk::Menu track_crossfade_context_menu;
Gtk::MenuItem* region_edit_menu_split_item;
Gtk::MenuItem* region_edit_menu_split_multichannel_item;
@ -689,12 +677,10 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
Gtk::Menu* build_track_context_menu ();
Gtk::Menu* build_track_bus_context_menu ();
Gtk::Menu* build_track_region_context_menu ();
Gtk::Menu* build_track_crossfade_context_menu ();
Gtk::Menu* build_track_selection_context_menu ();
void add_dstream_context_items (Gtk::Menu_Helpers::MenuList&);
void add_bus_context_items (Gtk::Menu_Helpers::MenuList&);
void add_region_context_items (Gtk::Menu_Helpers::MenuList&, boost::shared_ptr<ARDOUR::Track>);
void add_crossfade_context_items (AudioStreamView*, boost::shared_ptr<ARDOUR::Crossfade>, Gtk::Menu_Helpers::MenuList&, bool many);
void add_selection_context_items (Gtk::Menu_Helpers::MenuList&);
Gtk::MenuItem* _popup_region_menu_item;
@ -1386,7 +1372,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
bool canvas_selection_rect_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*);
bool canvas_selection_start_trim_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*);
bool canvas_selection_end_trim_event (GdkEvent* event,ArdourCanvas::Item*, SelectionRect*);
bool canvas_crossfade_view_event (GdkEvent* event,ArdourCanvas::Item*, CrossfadeView*);
bool canvas_fade_in_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*);
bool canvas_fade_in_handle_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*);
bool canvas_fade_out_event (GdkEvent* event,ArdourCanvas::Item*, AudioRegionView*);
@ -1864,10 +1849,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
void nudge_track (bool use_edit_point, bool forwards);
/* xfades */
bool _xfade_visibility;
#ifdef WITH_CMT
void handle_new_imageframe_time_axis_view(const std::string & track_name, void* src) ;
void handle_new_imageframe_marker_time_axis_view(const std::string & track_name, TimeAxisView* marked_track) ;
@ -1909,12 +1890,6 @@ class Editor : public PublicEditor, public PBD::ScopedConnectionList, public ARD
ImageFrameSocketHandler* image_socket_listener ;
#endif
void toggle_xfade_active (RouteTimeAxisView *, boost::weak_ptr<ARDOUR::Crossfade>);
void toggle_xfade_length (RouteTimeAxisView *, boost::weak_ptr<ARDOUR::Crossfade>);
void edit_xfade (boost::weak_ptr<ARDOUR::Crossfade>);
void xfade_edit_left_region ();
void xfade_edit_right_region ();
static const int32_t default_width = 995;
static const int32_t default_height = 765;

View File

@ -1428,8 +1428,6 @@ Editor::parameter_changed (std::string p)
update_punch_range_view (true);
} else if (p == "timecode-format") {
update_just_timecode ();
} else if (p == "xfades-visible") {
update_xfade_visibility ();
} else if (p == "show-region-fades") {
update_region_fade_visibility ();
} else if (p == "edit-mode") {

View File

@ -35,7 +35,6 @@
#include "audio_region_view.h"
#include "audio_streamview.h"
#include "canvas-noevent-text.h"
#include "crossfade_view.h"
#include "audio_time_axis.h"
#include "region_gain_line.h"
#include "automation_line.h"
@ -517,127 +516,6 @@ struct DescendingRegionLayerSorter {
}
};
bool
Editor::canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item* item, CrossfadeView* xfv)
{
/* we handle only button 3 press/release events */
switch (event->type) {
case GDK_BUTTON_PRESS:
clicked_crossfadeview = xfv;
clicked_axisview = &clicked_crossfadeview->get_time_axis_view();
clicked_routeview = dynamic_cast<RouteTimeAxisView*>(clicked_axisview);
if (event->button.button == 3) {
return button_press_handler (item, event, CrossfadeViewItem);
}
break;
case GDK_BUTTON_RELEASE:
if (event->button.button == 3) {
bool ret = button_release_handler (item, event, CrossfadeViewItem);
return ret;
}
break;
default:
break;
}
/* XXX do not forward double clicks */
if (event->type == GDK_2BUTTON_PRESS) {
return false;
}
/* proxy for an underlying regionview */
/* XXX really need to check if we are in the name highlight,
and proxy to that when required.
XXX or in the trim rectangles
*/
TimeAxisView& tv (xfv->get_time_axis_view());
AudioTimeAxisView* atv;
if ((atv = dynamic_cast<AudioTimeAxisView*>(&tv)) != 0) {
if (atv->is_audio_track()) {
boost::shared_ptr<AudioPlaylist> pl;
if ((pl = boost::dynamic_pointer_cast<AudioPlaylist> (atv->track()->playlist())) != 0) {
boost::shared_ptr<RegionList> rl = pl->regions_at (event_frame (event));
if (!rl->empty()) {
if (atv->layer_display() == Overlaid) {
/* we're in overlaid mode; proxy to the uppermost region view */
DescendingRegionLayerSorter cmp;
rl->sort (cmp);
RegionView* rv = atv->view()->find_view (rl->front());
/* proxy */
return canvas_region_view_event (event, rv->get_canvas_group(), rv);
} else {
/* we're in stacked mode; proxy to the region view under the mouse */
double cx = 0;
double cy = 0;
switch (event->type) {
case GDK_BUTTON_PRESS:
case GDK_BUTTON_RELEASE:
cx = event->button.x;
cy = event->button.y;
break;
case GDK_MOTION_NOTIFY:
cx = event->motion.x;
cy = event->motion.y;
break;
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
cx = event->crossing.x;
cy = event->crossing.y;
break;
default:
/* XXX: this may be wrong for some events */
cx = event->button.x;
cy = event->button.y;
}
/* position of the event within the track */
atv->view()->canvas_item()->w2i (cx, cy);
/* hence layer that we're over */
double const c = atv->view()->child_height ();
layer_t const l = pl->top_layer () + 1 - (cy / c);
/* hence region */
RegionList::iterator i = rl->begin();
while (i != rl->end() && (*i)->layer() != l) {
++i;
}
if (i != rl->end()) {
RegionView* rv = atv->view()->find_view (*i);
/* proxy */
return canvas_region_view_event (event, rv->get_canvas_group(), rv);
}
}
}
}
}
}
return TRUE;
}
bool
Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, ControlPoint* cp)
{

View File

@ -4117,7 +4117,7 @@ AutomationRangeDrag::setup (list<boost::shared_ptr<AutomationLine> > const & lin
/* check this range against all the AudioRanges that we are using */
list<AudioRange>::const_iterator k = _ranges.begin ();
while (k != _ranges.end()) {
if (k->coverage (r.first, r.second) != OverlapNone) {
if (k->coverage (r.first, r.second) != Evoral::OverlapNone) {
break;
}
++k;

View File

@ -2510,7 +2510,7 @@ static void
add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
{
switch (rv->region()->coverage (ar->start, ar->end - 1)) {
case OverlapNone:
case Evoral::OverlapNone:
break;
default:
rs->push_back (rv);
@ -3263,7 +3263,7 @@ Editor::trim_region_to_location (const Location& loc, const char* str)
/* require region to span proposed trim */
switch (rv->region()->coverage (loc.start(), loc.end())) {
case OverlapInternal:
case Evoral::OverlapInternal:
break;
default:
continue;
@ -5245,24 +5245,6 @@ Editor::update_region_fade_visibility ()
}
}
/** Update crossfade visibility after its configuration has been changed */
void
Editor::update_xfade_visibility ()
{
_xfade_visibility = _session->config.get_xfades_visible ();
for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
if (v) {
if (_xfade_visibility) {
v->show_all_xfades ();
} else {
v->hide_all_xfades ();
}
}
}
}
void
Editor::set_edit_point ()
{

View File

@ -38,7 +38,6 @@
#include "audio_streamview.h"
#include "automation_line.h"
#include "control_point.h"
#include "crossfade_view.h"
#include "editor_regions.h"
#include "editor_cursors.h"
#include "midi_region_view.h"
@ -478,32 +477,6 @@ Editor::mapped_get_equivalent_regions (RouteTimeAxisView& tv, uint32_t, RegionVi
}
}
void
Editor::mapped_get_equivalent_crossfades (
RouteTimeAxisView& tv, uint32_t, boost::shared_ptr<Crossfade> basis, vector<boost::shared_ptr<Crossfade> >* equivs
) const
{
boost::shared_ptr<Playlist> pl;
vector<boost::shared_ptr<Crossfade> > results;
boost::shared_ptr<Track> tr;
if ((tr = tv.track()) == 0) {
/* bus */
return;
}
if ((pl = tr->playlist()) != 0) {
boost::shared_ptr<AudioPlaylist> apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl);
if (apl) {
apl->get_equivalent_crossfades (basis, *equivs);
}
}
/* We might have just checked basis for equivalency with itself, so we need to remove dupes */
sort (equivs->begin (), equivs->end ());
unique (equivs->begin (), equivs->end ());
}
void
Editor::get_equivalent_regions (RegionView* basis, vector<RegionView*>& equivalent_regions, PBD::PropertyID property) const
{
@ -537,19 +510,6 @@ Editor::get_equivalent_regions (RegionSelection & basis, PBD::PropertyID prop) c
return equivalent;
}
vector<boost::shared_ptr<Crossfade> >
Editor::get_equivalent_crossfades (RouteTimeAxisView& v, boost::shared_ptr<Crossfade> c, PBD::PropertyID prop) const
{
vector<boost::shared_ptr<Crossfade> > e;
mapover_tracks_with_unique_playlists (
sigc::bind (sigc::mem_fun (*this, &Editor::mapped_get_equivalent_crossfades), c, &e),
&v,
prop
);
return e;
}
int
Editor::get_regionview_count_from_region_list (boost::shared_ptr<Region> region)
{
@ -700,7 +660,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
/* 2. figure out the boundaries for our search for new objects */
switch (clicked_regionview->region()->coverage (first_frame, last_frame)) {
case OverlapNone:
case Evoral::OverlapNone:
if (last_frame < clicked_regionview->region()->first_frame()) {
first_frame = last_frame;
last_frame = clicked_regionview->region()->last_frame();
@ -710,7 +670,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
}
break;
case OverlapExternal:
case Evoral::OverlapExternal:
if (last_frame < clicked_regionview->region()->first_frame()) {
first_frame = last_frame;
last_frame = clicked_regionview->region()->last_frame();
@ -720,7 +680,7 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
}
break;
case OverlapInternal:
case Evoral::OverlapInternal:
if (last_frame < clicked_regionview->region()->first_frame()) {
first_frame = last_frame;
last_frame = clicked_regionview->region()->last_frame();
@ -730,8 +690,8 @@ Editor::set_selected_regionview_from_click (bool press, Selection::Operation op)
}
break;
case OverlapStart:
case OverlapEnd:
case Evoral::OverlapStart:
case Evoral::OverlapEnd:
/* nothing to do except add clicked region to selection, since it
overlaps with the existing selection in this track.
*/

View File

@ -63,7 +63,6 @@
#include "automation_time_axis.h"
#include "canvas-note-event.h"
#include "canvas_impl.h"
#include "crossfade_view.h"
#include "editor.h"
#include "enums.h"
#include "ghostregion.h"

View File

@ -73,7 +73,6 @@ class Selection;
class AutomationLine;
class ControlPoint;
class SelectionRect;
class CrossfadeView;
class RouteTimeAxisView;
class RegionView;
class AudioRegionView;
@ -315,7 +314,6 @@ class PublicEditor : public Gtk::Window, public PBD::StatefulDestructible {
virtual bool canvas_selection_rect_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0;
virtual bool canvas_selection_start_trim_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0;
virtual bool canvas_selection_end_trim_event (GdkEvent* event, ArdourCanvas::Item*, SelectionRect*) = 0;
virtual bool canvas_crossfade_view_event (GdkEvent* event, ArdourCanvas::Item*, CrossfadeView*) = 0;
virtual bool canvas_fade_in_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*) = 0;
virtual bool canvas_fade_in_handle_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*) = 0;
virtual bool canvas_fade_out_event (GdkEvent* event, ArdourCanvas::Item*, AudioRegionView*) = 0;

View File

@ -68,7 +68,6 @@
#include "route_time_axis.h"
#include "automation_time_axis.h"
#include "canvas_impl.h"
#include "crossfade_view.h"
#include "enums.h"
#include "gui_thread.h"
#include "keyboard.h"

View File

@ -547,7 +547,7 @@ StreamView::get_selectables (framepos_t start, framepos_t end, double top, doubl
layer_ok = (min_layer <= l && l <= max_layer);
}
if ((*i)->region()->coverage (start, end) != OverlapNone && layer_ok) {
if ((*i)->region()->coverage (start, end) != Evoral::OverlapNone && layer_ok) {
results.push_back (*i);
}
}

View File

@ -142,7 +142,7 @@ protected:
void diskstream_changed ();
void layer_regions ();
virtual void playlist_switched (boost::weak_ptr<ARDOUR::Track>);
void playlist_switched (boost::weak_ptr<ARDOUR::Track>);
virtual void color_handler () = 0;

View File

@ -55,9 +55,9 @@ TimeSelection::consolidate ()
continue;
}
if ((*a).coverage ((*b).start, (*b).end) != OverlapNone) {
(*a).start = std::min ((*a).start, (*b).start);
(*a).end = std::max ((*a).end, (*b).end);
if (a->coverage (b->start, b->end) != Evoral::OverlapNone) {
a->start = std::min (a->start, b->start);
a->end = std::max (a->end, b->end);
erase (b);
changed = true;
goto restart;

View File

@ -67,8 +67,6 @@ gtk2_ardour_sources = [
'configinfo.cc',
'control_point.cc',
'control_point_dialog.cc',
'crossfade_edit.cc',
'crossfade_view.cc',
'curvetest.cc',
'debug.cc',
'diamond.cc',

View File

@ -33,96 +33,32 @@ class Region;
class AudioRegion;
class Source;
namespace Properties {
/* fake the type, since crossfades are handled by SequenceProperty which doesn't
care about such things.
*/
extern PBD::PropertyDescriptor<bool> crossfades;
}
class AudioPlaylist;
class CrossfadeListProperty : public PBD::SequenceProperty<std::list<boost::shared_ptr<Crossfade> > >
{
public:
CrossfadeListProperty (AudioPlaylist &);
void get_content_as_xml (boost::shared_ptr<Crossfade>, XMLNode &) const;
boost::shared_ptr<Crossfade> get_content_from_xml (XMLNode const &) const;
private:
CrossfadeListProperty* clone () const;
CrossfadeListProperty* create () const;
/* copy construction only by ourselves */
CrossfadeListProperty (CrossfadeListProperty const & p);
friend class AudioPlaylist;
/* we live and die with our playlist, no lifetime management needed */
AudioPlaylist& _playlist;
};
class AudioPlaylist : public ARDOUR::Playlist
{
public:
typedef std::list<boost::shared_ptr<Crossfade> > Crossfades;
static void make_property_quarks ();
AudioPlaylist (Session&, const XMLNode&, bool hidden = false);
AudioPlaylist (Session&, std::string name, bool hidden = false);
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, std::string name, bool hidden = false);
AudioPlaylist (boost::shared_ptr<const AudioPlaylist>, framepos_t start, framecnt_t cnt, std::string name, bool hidden = false);
~AudioPlaylist ();
void clear (bool with_signals=true);
framecnt_t read (Sample *dst, Sample *mixdown, float *gain_buffer, framepos_t start, framecnt_t cnt, uint32_t chan_n=0);
int set_state (const XMLNode&, int version);
PBD::Signal1<void,boost::shared_ptr<Crossfade> > NewCrossfade;
void foreach_crossfade (boost::function<void (boost::shared_ptr<Crossfade>)>);
void crossfades_at (framepos_t frame, Crossfades&);
bool destroy_region (boost::shared_ptr<Region>);
void update (const CrossfadeListProperty::ChangeRecord &);
boost::shared_ptr<Crossfade> find_crossfade (const PBD::ID &) const;
void get_equivalent_crossfades (boost::shared_ptr<Crossfade>, std::vector<boost::shared_ptr<Crossfade> > &);
protected:
/* playlist "callbacks" */
void notify_crossfade_added (boost::shared_ptr<Crossfade>);
void flush_notifications (bool);
void finalize_split_region (boost::shared_ptr<Region> orig, boost::shared_ptr<Region> left, boost::shared_ptr<Region> right);
void refresh_dependents (boost::shared_ptr<Region> region);
void check_dependents (boost::shared_ptr<Region> region, bool norefresh);
void remove_dependents (boost::shared_ptr<Region> region);
void copy_dependents (const std::vector<TwoRegions>&, Playlist*) const;
void check_crossfades (Evoral::Range<framepos_t>);
void pre_combine (std::vector<boost::shared_ptr<Region> >&);
void post_combine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>);
void pre_uncombine (std::vector<boost::shared_ptr<Region> >&, boost::shared_ptr<Region>);
private:
CrossfadeListProperty _crossfades;
Crossfades _pending_xfade_adds;
void crossfade_invalidated (boost::shared_ptr<Region>);
XMLNode& state (bool full_state);
int set_state (const XMLNode&, int version);
void dump () const;
bool region_changed (const PBD::PropertyChange&, boost::shared_ptr<Region>);
void crossfade_changed (const PBD::PropertyChange&);
void add_crossfade (boost::shared_ptr<Crossfade>);
void source_offset_changed (boost::shared_ptr<AudioRegion> region);
};

View File

@ -34,7 +34,8 @@
#include "ardour/region.h"
class XMLNode;
class AudioRegionTest;
class PlaylistReadTest;
namespace ARDOUR {
@ -92,6 +93,8 @@ class AudioRegion : public Region
boost::shared_ptr<AutomationList> fade_out() { return _fade_out; }
boost::shared_ptr<AutomationList> envelope() { return _envelope; }
Evoral::Range<framepos_t> body_range () const;
virtual framecnt_t read_peaks (PeakData *buf, framecnt_t npeaks,
framecnt_t offset, framecnt_t cnt,
uint32_t chan_n=0, double samples_per_unit= 1.0) const;
@ -137,6 +140,9 @@ class AudioRegion : public Region
void set_fade_out (FadeShape, framecnt_t);
void set_fade_out (boost::shared_ptr<AutomationList>);
void set_default_fade_in ();
void set_default_fade_out ();
void set_envelope_active (bool yn);
void set_default_envelope ();
@ -182,6 +188,9 @@ class AudioRegion : public Region
AudioRegion (SourceList &);
private:
friend class ::AudioRegionTest;
friend class ::PlaylistReadTest;
PBD::Property<bool> _envelope_active;
PBD::Property<bool> _default_fade_in;
PBD::Property<bool> _default_fade_out;
@ -195,8 +204,6 @@ class AudioRegion : public Region
void init ();
void set_default_fades ();
void set_default_fade_in ();
void set_default_fade_out ();
void recompute_gain_at_end ();
void recompute_gain_at_start ();

View File

@ -1,180 +0,0 @@
/*
Copyright (C) 2000 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __ardour_overlap_h__
#define __ardour_overlap_h__
#include <vector>
#include <algorithm>
#include <boost/shared_ptr.hpp>
#include "pbd/undo.h"
#include "pbd/statefuldestructible.h"
#include "ardour/ardour.h"
#include "ardour/audioregion.h"
#include "evoral/Curve.hpp"
namespace ARDOUR {
namespace Properties {
/* "active" is defined elsewhere but we use it with crossfade also */
extern PBD::PropertyDescriptor<bool> active;
extern PBD::PropertyDescriptor<bool> follow_overlap;
}
enum AnchorPoint {
StartOfIn,
EndOfIn,
EndOfOut
};
class Playlist;
class Crossfade : public ARDOUR::AudioRegion
{
public:
class NoCrossfadeHere: std::exception {
public:
virtual const char *what() const throw() { return "no crossfade should be constructed here"; }
};
/* constructor for "fixed" xfades at each end of an internal overlap */
Crossfade (boost::shared_ptr<ARDOUR::AudioRegion> in, boost::shared_ptr<ARDOUR::AudioRegion> out,
framecnt_t initial_length,
AnchorPoint);
/* constructor for xfade between two regions that are overlapped in any way
except the "internal" case.
*/
Crossfade (boost::shared_ptr<ARDOUR::AudioRegion> in, boost::shared_ptr<ARDOUR::AudioRegion> out, CrossfadeModel, bool active);
/* copy constructor to copy a crossfade with new regions. used (for example)
when a playlist copy is made
*/
Crossfade (boost::shared_ptr<Crossfade>, boost::shared_ptr<ARDOUR::AudioRegion>, boost::shared_ptr<ARDOUR::AudioRegion>);
/* the usual XML constructor */
Crossfade (const Playlist&, XMLNode const &);
virtual ~Crossfade();
static void make_property_quarks ();
XMLNode& get_state (void);
int set_state (const XMLNode&, int version);
boost::shared_ptr<ARDOUR::AudioRegion> in() const { return _in; }
boost::shared_ptr<ARDOUR::AudioRegion> out() const { return _out; }
framecnt_t read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, framepos_t position, framecnt_t cnt,
uint32_t chan_n) const;
bool refresh ();
uint32_t upper_layer () const {
return std::max (_in->layer(), _out->layer());
}
uint32_t lower_layer () const {
return std::min (_in->layer(), _out->layer());
}
bool involves (boost::shared_ptr<ARDOUR::AudioRegion> region) const {
return _in == region || _out == region;
}
bool involves (boost::shared_ptr<ARDOUR::AudioRegion> a, boost::shared_ptr<ARDOUR::AudioRegion> b) const {
return (_in == a && _out == b) || (_in == b && _out == a);
}
framecnt_t overlap_length() const;
PBD::Signal1<void,boost::shared_ptr<Region> > Invalidated;
OverlapType coverage (framepos_t start, framepos_t end) const;
static void set_buffer_size (framecnt_t);
bool active () const { return _active; }
void set_active (bool yn);
bool following_overlap() const { return _follow_overlap; }
bool can_follow_overlap() const;
void set_follow_overlap (bool yn);
AutomationList& fade_in() { return _fade_in; }
AutomationList& fade_out() { return _fade_out; }
framecnt_t set_xfade_length (framecnt_t);
bool is_dependent() const { return true; }
bool depends_on (boost::shared_ptr<Region> other) const {
return other == _in || other == _out;
}
static framecnt_t short_xfade_length() { return _short_xfade_length; }
static void set_short_xfade_length (framecnt_t n);
/** emitted when the actual fade curves change, as opposed to one of the Stateful properties */
PBD::Signal0<void> FadesChanged;
private:
friend struct CrossfadeComparePtr;
friend class AudioPlaylist;
static framecnt_t _short_xfade_length;
boost::shared_ptr<ARDOUR::AudioRegion> _in;
boost::shared_ptr<ARDOUR::AudioRegion> _out;
PBD::Property<bool> _active;
PBD::Property<bool> _follow_overlap;
bool _in_update;
OverlapType overlap_type;
AnchorPoint _anchor_point;
bool _fixed;
int32_t layer_relation;
mutable AutomationList _fade_in;
mutable AutomationList _fade_out;
static Sample* crossfade_buffer_out;
static Sample* crossfade_buffer_in;
void initialize ();
void register_properties ();
int compute (boost::shared_ptr<ARDOUR::AudioRegion>, boost::shared_ptr<ARDOUR::AudioRegion>, CrossfadeModel);
bool update ();
bool operator== (const ARDOUR::Crossfade&);
protected:
framecnt_t read_raw_internal (Sample*, framepos_t, framecnt_t, int) const;
};
} // namespace ARDOUR
#endif /* __ardour_overlap_h__ */

View File

@ -1,52 +0,0 @@
/*
Copyright (C) 2011 Paul Davis
Author: Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "pbd/id.h"
#include "pbd/memento_command.h"
class XMLNode;
namespace ARDOUR {
class Crossfade;
class Playlist;
class SessionPlaylists;
/** A MementoCommandBinder for Crossfades; required because the undo record
* may contain details of crossfades that have subsequently been deleted.
* This class allows recovery of a crossfade from an ID once it has been
* recreated by a previous undo step.
*/
class CrossfadeBinder : public MementoCommandBinder<ARDOUR::Crossfade>
{
public:
CrossfadeBinder (boost::shared_ptr<ARDOUR::SessionPlaylists>, PBD::ID);
CrossfadeBinder (XMLNode *, boost::shared_ptr<SessionPlaylists>);
ARDOUR::Crossfade* get () const;
std::string type_name () const;
void add_state (XMLNode *);
private:
boost::shared_ptr<ARDOUR::SessionPlaylists> _playlists;
PBD::ID _id;
};
}

View File

@ -243,8 +243,10 @@ class Diskstream : public SessionObject, public PublicDiskstream
virtual void use_destructive_playlist () {}
virtual void prepare_to_stop (framepos_t pos);
void calculate_record_range(OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
framecnt_t& rec_nframes, framecnt_t& rec_offset);
void calculate_record_range (
Evoral::OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
framecnt_t& rec_nframes, framecnt_t& rec_offset
);
static framecnt_t disk_io_chunk_frames;
std::vector<CaptureInfo*> capture_info;

View File

@ -63,12 +63,6 @@ public:
protected:
/* playlist "callbacks" */
void finalize_split_region (boost::shared_ptr<Region> original, boost::shared_ptr<Region> left, boost::shared_ptr<Region> right);
void check_dependents (boost::shared_ptr<Region> region, bool norefresh);
void refresh_dependents (boost::shared_ptr<Region> region);
void remove_dependents (boost::shared_ptr<Region> region);
private:

View File

@ -153,7 +153,8 @@ public:
boost::shared_ptr<RegionList> regions_at (framepos_t frame);
uint32_t count_regions_at (framepos_t) const;
boost::shared_ptr<RegionList> regions_touched (framepos_t start, framepos_t end);
boost::shared_ptr<RegionList> regions_to_read (framepos_t start, framepos_t end);
boost::shared_ptr<RegionList> regions_with_start_within (Evoral::Range<framepos_t>);
boost::shared_ptr<RegionList> regions_with_end_within (Evoral::Range<framepos_t>);
uint32_t region_use_count (boost::shared_ptr<Region>) const;
boost::shared_ptr<Region> find_region (const PBD::ID&) const;
boost::shared_ptr<Region> top_region_at (framepos_t frame);
@ -170,7 +171,7 @@ public:
void foreach_region (boost::function<void (boost::shared_ptr<Region>)>);
XMLNode& get_state ();
int set_state (const XMLNode&, int version);
virtual int set_state (const XMLNode&, int version);
XMLNode& get_template ();
PBD::Signal1<void,bool> InUse;
@ -322,10 +323,7 @@ public:
void splice_locked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
void splice_unlocked (framepos_t at, framecnt_t distance, boost::shared_ptr<Region> exclude);
virtual void finalize_split_region (boost::shared_ptr<Region> /*original*/, boost::shared_ptr<Region> /*left*/, boost::shared_ptr<Region> /*right*/) {}
virtual void check_dependents (boost::shared_ptr<Region> /*region*/, bool /*norefresh*/) {}
virtual void refresh_dependents (boost::shared_ptr<Region> /*region*/) {}
virtual void check_crossfades (Evoral::Range<framepos_t>) {}
virtual void remove_dependents (boost::shared_ptr<Region> /*region*/) {}
virtual XMLNode& state (bool);
@ -351,14 +349,6 @@ public:
void _split_region (boost::shared_ptr<Region>, framepos_t position);
typedef std::pair<boost::shared_ptr<Region>, boost::shared_ptr<Region> > TwoRegions;
virtual void copy_dependents (const std::vector<TwoRegions>&, Playlist*) const { }
struct RegionInfo {
boost::shared_ptr<Region> region;
framepos_t position;
framecnt_t length;
framepos_t start;
};
/* this is called before we create a new compound region */
virtual void pre_combine (std::vector<boost::shared_ptr<Region> >&) {}
@ -372,6 +362,7 @@ public:
private:
void setup_layering_indices (RegionList const &) const;
void coalesce_and_check_crossfades (std::list<Evoral::Range<framepos_t> >);
boost::shared_ptr<RegionList> find_regions_at (framepos_t);
};

View File

@ -141,6 +141,14 @@ class Region
framepos_t first_frame () const { return _position; }
framepos_t last_frame () const { return _position + _length - 1; }
Evoral::Range<framepos_t> last_range () const {
return Evoral::Range<framepos_t> (_last_position, _last_position + _last_length - 1);
}
Evoral::Range<framepos_t> range () const {
return Evoral::Range<framepos_t> (first_frame(), last_frame());
}
bool hidden () const { return _hidden; }
bool muted () const { return _muted; }
bool opaque () const { return _opaque; }
@ -168,8 +176,14 @@ class Region
return first_frame() <= frame && frame <= last_frame();
}
OverlapType coverage (framepos_t start, framepos_t end) const {
return ARDOUR::coverage (first_frame(), last_frame(), start, end);
/** @return coverage of this region with the given range;
* OverlapInternal: the range is internal to this region.
* OverlapStart: the range overlaps the start of this region.
* OverlapEnd: the range overlaps the end of this region.
* OverlapExternal: the range overlaps all of this region.
*/
Evoral::OverlapType coverage (framepos_t start, framepos_t end) const {
return Evoral::coverage (first_frame(), last_frame(), start, end);
}
bool equivalent (boost::shared_ptr<const Region>) const;

View File

@ -36,6 +36,8 @@
#include "pbd/id.h"
#include "evoral/Range.hpp"
#include "ardour/chan_count.h"
#include <map>
@ -101,17 +103,6 @@ namespace ARDOUR {
ARDOUR::ChanCount after;
};
enum OverlapType {
OverlapNone, // no overlap
OverlapInternal, // the overlap is 100% with the object
OverlapStart, // overlap covers start, but ends within
OverlapEnd, // overlap begins within and covers end
OverlapExternal // overlap extends to (at least) begin+end
};
ARDOUR::OverlapType coverage (framepos_t sa, framepos_t ea,
framepos_t sb, framepos_t eb);
/* policies for inserting/pasting material where overlaps
might be an issue.
*/
@ -278,6 +269,9 @@ namespace ARDOUR {
}
};
/* XXX: slightly unfortunate that there is this and Evoral::Range<>,
but this has a uint32_t id which Evoral::Range<> does not.
*/
struct AudioRange {
framepos_t start;
framepos_t end;
@ -295,8 +289,8 @@ namespace ARDOUR {
return start == other.start && end == other.end;
}
OverlapType coverage (framepos_t s, framepos_t e) const {
return ARDOUR::coverage (start, end, s, e);
Evoral::OverlapType coverage (framepos_t s, framepos_t e) const {
return Evoral::coverage (start, end, s, e);
}
};

View File

@ -457,7 +457,7 @@ AudioDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecn
if (record_enabled()) {
OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
calculate_record_range (ot, transport_frame, nframes, rec_nframes, rec_offset);
if (rec_nframes && !was_recording) {

File diff suppressed because it is too large Load Diff

View File

@ -345,16 +345,17 @@ framecnt_t
AudioRegion::read (Sample* buf, framepos_t timeline_position, framecnt_t cnt, int channel) const
{
/* raw read, no fades, no gain, nada */
/* XXX: xfade: passes no mixbuf... */
return _read_at (_sources, _length, buf, 0, 0, _position + timeline_position, cnt, channel, ReadOps (0));
}
framecnt_t
AudioRegion::read_at (Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
framepos_t file_position, framecnt_t cnt, uint32_t chan_n) const
framepos_t position, framecnt_t cnt, uint32_t chan_n) const
{
/* regular diskstream/butler read complete with fades etc */
return _read_at (_sources, _length, buf, mixdown_buffer, gain_buffer,
file_position, cnt, chan_n, ReadOps (~0));
position, cnt, chan_n, ReadOps (~0));
}
framecnt_t
@ -369,7 +370,9 @@ AudioRegion::master_read_at (Sample *buf, Sample *mixdown_buffer, float *gain_bu
buf, mixdown_buffer, gain_buffer, position, cnt, chan_n, ReadOps (0));
}
/** @param position Position within the session */
/** @param position Position within the session to read from.
* @param cnt Number of frames to read.
*/
framecnt_t
AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit,
Sample *buf, Sample *mixdown_buffer, float *gain_buffer,
@ -378,44 +381,27 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit,
uint32_t chan_n,
ReadOps rops) const
{
/* We are reading data from this region into buf (possibly via mixdown_buffer).
The caller has verified that we cover the desired section.
*/
assert (cnt >= 0);
frameoffset_t internal_offset;
frameoffset_t buf_offset;
framecnt_t to_read;
bool raw = (rops == ReadOpsNone);
if (n_channels() == 0) {
return 0;
}
if (muted() && !raw) {
if (muted() && rops != ReadOpsNone) {
return 0; /* read nothing */
}
/* precondition: caller has verified that we cover the desired section */
/* WORK OUT WHERE TO GET DATA FROM */
if (position < _position) {
internal_offset = 0;
buf_offset = _position - position;
/* if this fails then the requested section is entirely
before the position of this region. An error in xfade
construction that was fixed in oct 2011 (rev 10259)
led to this being the case. We don't want to crash
when this error is encountered, so just settle
on displaying an error.
*/
if (cnt < buf_offset) {
error << "trying to read region " << name() << " @ " << position << " which is outside region bounds "
<< _position << " .. " << last_frame() << " (len = " << length() << ')'
<< endmsg;
return 0; // read nothing
}
cnt -= buf_offset;
} else {
internal_offset = position - _position;
buf_offset = 0;
}
framecnt_t to_read;
assert (position >= _position);
frameoffset_t const internal_offset = position - _position;
if (internal_offset >= limit) {
return 0; /* read nothing */
@ -425,46 +411,26 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit,
return 0; /* read nothing */
}
if (opaque() || raw) {
/* overwrite whatever is there */
mixdown_buffer = buf + buf_offset;
} else {
mixdown_buffer += buf_offset;
}
if (chan_n < n_channels()) {
/* COMPUTE DETAILS OF ANY FADES INVOLVED IN THIS READ */
boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[chan_n]);
if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */
}
/* Amount of fade in that we are dealing with in this read */
framecnt_t fade_in_limit = 0;
} else {
/* Offset from buf / mixdown_buffer of the start
of any fade out that we are dealing with
*/
frameoffset_t fade_out_offset = 0;
/* Amount of fade in that we are dealing with in this read */
framecnt_t fade_out_limit = 0;
/* track is N-channel, this region has less channels; silence the ones
we don't have.
*/
if (Config->get_replicate_missing_region_channels()) {
/* track is N-channel, this region has less channels, so use a relevant channel
*/
uint32_t channel = n_channels() % chan_n;
boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[channel]);
if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */
}
} else {
memset (mixdown_buffer, 0, sizeof (Sample) * cnt);
}
}
framecnt_t fade_interval_start = 0;
if (rops & ReadOpsFades) {
/* fade in */
/* Fade in */
if (_fade_in_active && _session.config.get_use_region_fades()) {
framecnt_t fade_in_length = (framecnt_t) _fade_in->back()->when;
@ -472,20 +438,11 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit,
/* see if this read is within the fade in */
if (internal_offset < fade_in_length) {
framecnt_t fi_limit;
fi_limit = min (to_read, fade_in_length - internal_offset);
_fade_in->curve().get_vector (internal_offset, internal_offset+fi_limit, gain_buffer, fi_limit);
for (framecnt_t n = 0; n < fi_limit; ++n) {
mixdown_buffer[n] *= gain_buffer[n];
}
fade_in_limit = min (to_read, fade_in_length - internal_offset);
}
}
/* fade out */
/* Fade out */
if (_fade_out_active && _session.config.get_use_region_fades()) {
@ -508,28 +465,50 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit,
*/
framecnt_t fade_out_length = (framecnt_t) _fade_out->back()->when;
framecnt_t fade_interval_start = max(internal_offset, limit-fade_out_length);
fade_interval_start = max (internal_offset, limit - framecnt_t (_fade_out->back()->when));
framecnt_t fade_interval_end = min(internal_offset + to_read, limit);
if (fade_interval_end > fade_interval_start) {
/* (part of the) the fade out is in this buffer */
framecnt_t fo_limit = fade_interval_end - fade_interval_start;
framecnt_t curve_offset = fade_interval_start - (limit-fade_out_length);
framecnt_t fade_offset = fade_interval_start - internal_offset;
_fade_out->curve().get_vector (curve_offset, curve_offset+fo_limit, gain_buffer, fo_limit);
for (framecnt_t n = 0, m = fade_offset; n < fo_limit; ++n, ++m) {
mixdown_buffer[m] *= gain_buffer[n];
}
/* (part of the) the fade out is in this buffer */
fade_out_limit = fade_interval_end - fade_interval_start;
fade_out_offset = fade_interval_start - internal_offset;
}
}
}
/* Regular gain curves and scaling */
/* READ DATA FROM THE SOURCE INTO mixdown_buffer.
We can never read directly into buf, since it may contain data
from a transparent region `above' this one in the stack; we
must always mix.
*/
if (chan_n < n_channels()) {
boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[chan_n]);
if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */
}
} else {
/* track is N-channel, this region has fewer channels; silence the ones
we don't have.
*/
if (Config->get_replicate_missing_region_channels()) {
/* track is N-channel, this region has less channels, so use a relevant channel
*/
uint32_t channel = n_channels() % chan_n;
boost::shared_ptr<AudioSource> src = boost::dynamic_pointer_cast<AudioSource> (srcs[channel]);
if (src->read (mixdown_buffer, _start + internal_offset, to_read) != to_read) {
return 0; /* "read nothing" */
}
}
}
/* APPLY REGULAR GAIN CURVES AND SCALING TO mixdown_buffer */
if ((rops & ReadOpsOwnAutomation) && envelope_active()) {
_envelope->curve().get_vector (internal_offset, internal_offset + to_read, gain_buffer, to_read);
@ -544,27 +523,34 @@ AudioRegion::_read_at (const SourceList& srcs, framecnt_t limit,
}
}
} else if ((rops & ReadOpsOwnScaling) && _scale_amplitude != 1.0f) {
apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
}
// XXX this should be using what in 2.0 would have been:
// Session::apply_gain_to_buffer (mixdown_buffer, to_read, _scale_amplitude);
for (framecnt_t n = 0; n < to_read; ++n) {
mixdown_buffer[n] *= _scale_amplitude;
/* APPLY FADES TO THE DATA IN mixdown_buffer AND MIX THE RESULTS INTO buf */
if (fade_in_limit != 0) {
_fade_in->curve().get_vector (internal_offset, internal_offset + fade_in_limit, gain_buffer, fade_in_limit);
for (framecnt_t n = 0; n < fade_in_limit; ++n) {
buf[n] += mixdown_buffer[n] * gain_buffer[n];
}
}
if (!opaque() && (buf != mixdown_buffer)) {
/* gack. the things we do for users.
*/
buf += buf_offset;
for (framecnt_t n = 0; n < to_read; ++n) {
buf[n] += mixdown_buffer[n];
if (fade_out_limit != 0) {
framecnt_t const curve_offset = fade_interval_start - (limit - _fade_out->back()->when);
_fade_out->curve().get_vector (curve_offset, curve_offset + fade_out_limit, gain_buffer, fade_out_limit);
for (framecnt_t n = 0, m = fade_out_offset; n < fade_out_limit; ++n, ++m) {
buf[m] += mixdown_buffer[m] * gain_buffer[n];
}
}
/* MIX THE REGION BODY FROM mixdown_buffer INTO buf */
mix_buffers_no_gain (buf + fade_in_limit, mixdown_buffer + fade_in_limit, to_read - fade_in_limit - fade_out_limit);
return to_read;
}
@ -1519,7 +1505,11 @@ AudioRegion::find_silence (Sample threshold, framecnt_t min_length, InterThreadI
return silent_periods;
}
Evoral::Range<framepos_t>
AudioRegion::body_range () const
{
return Evoral::Range<framepos_t> (first_frame() + _fade_in->back()->when, last_frame() - _fade_out->back()->when);
}
extern "C" {

View File

@ -24,7 +24,6 @@
#include "pbd/error.h"
#include "pbd/pthread_utils.h"
#include "ardour/butler.h"
#include "ardour/crossfade.h"
#include "ardour/io.h"
#include "ardour/midi_diskstream.h"
#include "ardour/session.h"
@ -86,8 +85,6 @@ Butler::start_thread()
MidiDiskstream::set_readahead_frames ((framecnt_t) (Config->get_midi_readahead() * rate));
Crossfade::set_buffer_size (audio_dstream_playback_buffer_size);
should_run = false;
if (pipe (request_pipe)) {

File diff suppressed because it is too large Load Diff

View File

@ -1,63 +0,0 @@
/*
Copyright (C) 2011 Paul Davis
Author: Carl Hetherington <cth@carlh.net>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include "ardour/crossfade_binder.h"
#include "ardour/session_playlists.h"
#include "ardour/crossfade.h"
using namespace ARDOUR;
CrossfadeBinder::CrossfadeBinder (boost::shared_ptr<SessionPlaylists> playlists, PBD::ID id)
: _playlists (playlists)
, _id (id)
{
}
CrossfadeBinder::CrossfadeBinder (XMLNode* node, boost::shared_ptr<SessionPlaylists> playlists)
: _playlists (playlists)
{
XMLProperty* id = node->property ("crossfade-id");
assert (id);
_id = PBD::ID (id->value ());
}
ARDOUR::Crossfade *
CrossfadeBinder::get () const
{
ARDOUR::Crossfade* c = _playlists->find_crossfade (_id).get ();
assert (c);
return c;
}
std::string
CrossfadeBinder::type_name () const
{
return "ARDOUR::Crossfade";
}
void
CrossfadeBinder::add_state (XMLNode* node)
{
node->add_property ("crossfade-id", _id.to_s ());
}

View File

@ -685,15 +685,15 @@ Diskstream::route_going_away ()
}
void
Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
framecnt_t & rec_nframes, framecnt_t & rec_offset)
Diskstream::calculate_record_range (Evoral::OverlapType ot, framepos_t transport_frame, framecnt_t nframes,
framecnt_t & rec_nframes, framecnt_t & rec_offset)
{
switch (ot) {
case OverlapNone:
case Evoral::OverlapNone:
rec_nframes = 0;
break;
case OverlapInternal:
case Evoral::OverlapInternal:
/* ---------- recrange
|---| transrange
*/
@ -701,7 +701,7 @@ Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, f
rec_offset = 0;
break;
case OverlapStart:
case Evoral::OverlapStart:
/* |--------| recrange
-----| transrange
*/
@ -711,7 +711,7 @@ Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, f
}
break;
case OverlapEnd:
case Evoral::OverlapEnd:
/* |--------| recrange
|-------- transrange
*/
@ -719,7 +719,7 @@ Diskstream::calculate_record_range(OverlapType ot, framepos_t transport_frame, f
rec_offset = 0;
break;
case OverlapExternal:
case Evoral::OverlapExternal:
/* |--------| recrange
-------------- transrange
*/

View File

@ -53,7 +53,6 @@ setup_enum_writer ()
vector<int> i;
vector<string> s;
OverlapType _OverlapType;
AlignStyle _AlignStyle;
AlignChoice _AlignChoice;
MeterPoint _MeterPoint;
@ -132,13 +131,6 @@ setup_enum_writer ()
#define REGISTER_ENUM(e) i.push_back (e); s.push_back (#e)
#define REGISTER_CLASS_ENUM(t,e) i.push_back (t::e); s.push_back (#e)
REGISTER_ENUM (OverlapNone);
REGISTER_ENUM (OverlapInternal);
REGISTER_ENUM (OverlapStart);
REGISTER_ENUM (OverlapEnd);
REGISTER_ENUM (OverlapExternal);
REGISTER (_OverlapType);
REGISTER_ENUM (GainAutomation);
REGISTER_ENUM (PanAzimuthAutomation);
REGISTER_ENUM (PanElevationAutomation);

View File

@ -493,82 +493,6 @@ ARDOUR::setup_fpu ()
#endif
}
ARDOUR::OverlapType
ARDOUR::coverage (framepos_t sa, framepos_t ea,
framepos_t sb, framepos_t eb)
{
/* OverlapType returned reflects how the second (B)
range overlaps the first (A).
The diagrams show various relative placements
of A and B for each OverlapType.
Notes:
Internal: the start points cannot coincide
External: the start and end points can coincide
Start: end points can coincide
End: start points can coincide
XXX Logically, Internal should disallow end
point equality.
*/
/*
|--------------------| A
|------| B
|-----------------| B
"B is internal to A"
*/
if ((sb > sa) && (eb <= ea)) {
return OverlapInternal;
}
/*
|--------------------| A
----| B
-----------------------| B
--| B
"B overlaps the start of A"
*/
if ((eb >= sa) && (eb <= ea)) {
return OverlapStart;
}
/*
|---------------------| A
|----------------- B
|----------------------- B
|- B
"B overlaps the end of A"
*/
if ((sb > sa) && (sb <= ea)) {
return OverlapEnd;
}
/*
|--------------------| A
-------------------------- B
|----------------------- B
----------------------| B
|--------------------| B
"B overlaps all of A"
*/
if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
return OverlapExternal;
}
return OverlapNone;
}
string
ARDOUR::translation_kill_path ()
{

View File

@ -19,6 +19,7 @@
*/
#include <stdio.h>
#include <cmath>
#include <xmmintrin.h>
#include "pbd/compose.h"
#include "pbd/debug_rt_alloc.h"

View File

@ -339,7 +339,7 @@ MidiDiskstream::process (framepos_t transport_frame, pframes_t nframes, framecnt
adjust_capture_position = 0;
if (nominally_recording || (re && was_recording && _session.get_record_enabled() && _session.config.get_punch_in())) {
OverlapType ot = coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
Evoral::OverlapType ot = Evoral::coverage (first_recordable_frame, last_recordable_frame, transport_frame, transport_frame + nframes);
calculate_record_range(ot, transport_frame, nframes, rec_nframes, rec_offset);

View File

@ -128,13 +128,13 @@ MidiPlaylist::read (Evoral::EventSink<framepos_t>& dst, framepos_t start, framec
*/
switch ((*i)->coverage (start, end)) {
case OverlapStart:
case OverlapInternal:
case OverlapExternal:
case Evoral::OverlapStart:
case Evoral::OverlapInternal:
case Evoral::OverlapExternal:
regs.push_back (*i);
break;
case OverlapEnd:
case Evoral::OverlapEnd:
/* this region ends within the read range */
regs.push_back (*i);
ended.push_back (*i);
@ -316,26 +316,6 @@ MidiPlaylist::remove_dependents (boost::shared_ptr<Region> region)
}
}
void
MidiPlaylist::refresh_dependents (boost::shared_ptr<Region> /*r*/)
{
/* MIDI regions have no dependents (crossfades) */
}
void
MidiPlaylist::finalize_split_region (boost::shared_ptr<Region> /*original*/, boost::shared_ptr<Region> /*left*/, boost::shared_ptr<Region> /*right*/)
{
/* No MIDI crossfading (yet?), so nothing to do here */
}
void
MidiPlaylist::check_dependents (boost::shared_ptr<Region> /*r*/, bool /*norefresh*/)
{
/* MIDI regions have no dependents (crossfades) */
}
int
MidiPlaylist::set_state (const XMLNode& node, int version)
{

View File

@ -210,35 +210,35 @@ Playlist::Playlist (boost::shared_ptr<const Playlist> other, framepos_t start, f
framepos_t position = 0;
framecnt_t len = 0;
string new_name;
OverlapType overlap;
Evoral::OverlapType overlap;
region = *i;
overlap = region->coverage (start, end);
switch (overlap) {
case OverlapNone:
case Evoral::OverlapNone:
continue;
case OverlapInternal:
case Evoral::OverlapInternal:
offset = start - region->position();
position = 0;
len = cnt;
break;
case OverlapStart:
case Evoral::OverlapStart:
offset = 0;
position = region->position() - start;
len = end - region->position();
break;
case OverlapEnd:
case Evoral::OverlapEnd:
offset = start - region->position();
position = 0;
len = region->length() - offset;
break;
case OverlapExternal:
case Evoral::OverlapExternal:
offset = 0;
position = region->position() - start;
len = region->length();
@ -561,7 +561,6 @@ Playlist::notify_region_added (boost::shared_ptr<Region> r)
void
Playlist::flush_notifications (bool from_undo)
{
set<boost::shared_ptr<Region> > dependent_checks_needed;
set<boost::shared_ptr<Region> >::iterator s;
bool regions_changed = false;
@ -575,6 +574,10 @@ Playlist::flush_notifications (bool from_undo)
regions_changed = true;
}
/* XXX: it'd be nice if we could use pending_bounds for
RegionsExtended and RegionsMoved.
*/
/* we have no idea what order the regions ended up in pending
bounds (it could be based on selection order, for example).
so, to preserve layering in the "most recently moved is higher"
@ -584,24 +587,26 @@ Playlist::flush_notifications (bool from_undo)
// RegionSortByLayer cmp;
// pending_bounds.sort (cmp);
list<Evoral::Range<framepos_t> > crossfade_ranges;
for (RegionList::iterator r = pending_bounds.begin(); r != pending_bounds.end(); ++r) {
dependent_checks_needed.insert (*r);
crossfade_ranges.push_back ((*r)->last_range ());
crossfade_ranges.push_back ((*r)->range ());
}
for (s = pending_removes.begin(); s != pending_removes.end(); ++s) {
crossfade_ranges.push_back ((*s)->range ());
remove_dependents (*s);
// cerr << _name << " sends RegionRemoved\n";
RegionRemoved (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
}
for (s = pending_adds.begin(); s != pending_adds.end(); ++s) {
// cerr << _name << " sends RegionAdded\n";
/* don't emit RegionAdded signal until relayering is done,
so that the region is fully setup by the time
anyone hear's that its been added
*/
dependent_checks_needed.insert (*s);
}
crossfade_ranges.push_back ((*s)->range ());
/* don't emit RegionAdded signal until relayering is done,
so that the region is fully setup by the time
anyone hears that its been added
*/
}
if (
((regions_changed || pending_contents_change) && !in_set_state) ||
@ -621,11 +626,12 @@ Playlist::flush_notifications (bool from_undo)
RegionAdded (boost::weak_ptr<Region> (*s)); /* EMIT SIGNAL */
}
for (s = dependent_checks_needed.begin(); s != dependent_checks_needed.end(); ++s) {
check_dependents (*s, false);
}
coalesce_and_check_crossfades (crossfade_ranges);
if (!pending_range_moves.empty ()) {
/* We don't need to check crossfades for these as pending_bounds has
already covered it.
*/
RangesMoved (pending_range_moves, from_undo);
}
@ -754,7 +760,7 @@ Playlist::flush_notifications (bool from_undo)
notify_region_added (region);
if (!holding_state ()) {
check_dependents (region, false);
check_crossfades (region->range ());
}
region->PropertyChanged.connect_same_thread (region_state_changed_connections, boost::bind (&Playlist::region_changed_proxy, this, _1, boost::weak_ptr<Region> (region)));
@ -879,7 +885,7 @@ Playlist::flush_notifications (bool from_undo)
boost::shared_ptr<Region> current;
string new_name;
RegionList::iterator tmp;
OverlapType overlap;
Evoral::OverlapType overlap;
framepos_t pos1, pos2, pos3, pos4;
in_partition = true;
@ -915,7 +921,7 @@ Playlist::flush_notifications (bool from_undo)
continue;
}
if ((overlap = current->coverage (start, end)) == OverlapNone) {
if ((overlap = current->coverage (start, end)) == Evoral::OverlapNone) {
continue;
}
@ -924,7 +930,7 @@ Playlist::flush_notifications (bool from_undo)
pos3 = end;
pos4 = current->last_frame();
if (overlap == OverlapInternal) {
if (overlap == Evoral::OverlapInternal) {
/* split: we need 3 new regions, the front, middle and end.
cut: we need 2 regions, the front and end.
*/
@ -986,7 +992,7 @@ Playlist::flush_notifications (bool from_undo)
thawlist.push_back (current);
current->cut_end (pos2 - 1);
} else if (overlap == OverlapEnd) {
} else if (overlap == Evoral::OverlapEnd) {
/*
start end
@ -1026,7 +1032,7 @@ Playlist::flush_notifications (bool from_undo)
thawlist.push_back (current);
current->cut_end (pos2 - 1);
} else if (overlap == OverlapStart) {
} else if (overlap == Evoral::OverlapStart) {
/* split: we need 2 regions: the front and the end.
cut: just trim current to skip the cut area
@ -1069,7 +1075,7 @@ Playlist::flush_notifications (bool from_undo)
current->suspend_property_changes ();
thawlist.push_back (current);
current->trim_front (pos3);
} else if (overlap == OverlapExternal) {
} else if (overlap == Evoral::OverlapExternal) {
/* split: no split required.
cut: remove the region.
@ -1098,9 +1104,7 @@ Playlist::flush_notifications (bool from_undo)
in_partition = false;
}
for (RegionList::iterator i = new_regions.begin(); i != new_regions.end(); ++i) {
check_dependents (*i, false);
}
check_crossfades (Evoral::Range<framepos_t> (start, end));
}
boost::shared_ptr<Playlist>
@ -1381,9 +1385,6 @@ Playlist::flush_notifications (bool from_undo)
add_region_internal (left, region->position());
add_region_internal (right, region->position() + before);
finalize_split_region (region, left, right);
remove_region_internal (region);
_splicing = old_sp;
@ -1508,7 +1509,10 @@ Playlist::flush_notifications (bool from_undo)
} else {
notify_contents_changed ();
relayer ();
check_dependents (region, false);
list<Evoral::Range<framepos_t> > xf;
xf.push_back (Evoral::Range<framepos_t> (region->last_range()));
xf.push_back (Evoral::Range<framepos_t> (region->range()));
coalesce_and_check_crossfades (xf);
}
}
}
@ -1556,7 +1560,7 @@ Playlist::flush_notifications (bool from_undo)
}
if (what_changed.contains (our_interests) && !what_changed.contains (pos_and_length)) {
check_dependents (region, false);
check_crossfades (region->range ());
}
if (what_changed.contains (Properties::position) && !what_changed.contains (Properties::length)) {
@ -1703,148 +1707,13 @@ Playlist::regions_at (framepos_t frame)
return region;
}
boost::shared_ptr<RegionList>
Playlist::regions_to_read (framepos_t start, framepos_t end)
{
/* Caller must hold lock */
RegionList covering;
set<framepos_t> to_check;
set<boost::shared_ptr<Region> > unique;
to_check.insert (start);
to_check.insert (end);
DEBUG_TRACE (DEBUG::AudioPlayback, ">>>>> REGIONS TO READ\n");
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
/* find all/any regions that span start+end */
switch ((*i)->coverage (start, end)) {
case OverlapNone:
break;
case OverlapInternal:
covering.push_back (*i);
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OInternal)\n", (*i)->name()));
break;
case OverlapStart:
to_check.insert ((*i)->position());
if ((*i)->position() != 0) {
to_check.insert ((*i)->position()-1);
}
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
covering.push_back (*i);
break;
case OverlapEnd:
to_check.insert ((*i)->last_frame());
to_check.insert ((*i)->last_frame()+1);
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OEnd)\n", (*i)->name()));
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
covering.push_back (*i);
break;
case OverlapExternal:
covering.push_back (*i);
to_check.insert ((*i)->position());
if ((*i)->position() != 0) {
to_check.insert ((*i)->position()-1);
}
to_check.insert ((*i)->last_frame());
to_check.insert ((*i)->last_frame()+1);
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("toread: will cover %1 (OExt)\n", (*i)->name()));
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->position(), (*i)->name()));
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("\ttoread: will check %1 for %2\n", (*i)->last_frame(), (*i)->name()));
break;
}
/* don't go too far */
if ((*i)->position() > end) {
break;
}
}
boost::shared_ptr<RegionList> rlist (new RegionList);
/* find all the regions that cover each position .... */
if (covering.size() == 1) {
rlist->push_back (covering.front());
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("Just one covering region (%1)\n", covering.front()->name()));
} else {
RegionList here;
for (set<framepos_t>::iterator t = to_check.begin(); t != to_check.end(); ++t) {
here.clear ();
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("++++ Considering %1\n", *t));
for (RegionList::iterator x = covering.begin(); x != covering.end(); ++x) {
if ((*x)->covers (*t)) {
here.push_back (*x);
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 covers %2\n",
(*x)->name(),
(*t)));
} else {
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("region %1 does NOT covers %2\n",
(*x)->name(),
(*t)));
}
}
RegionSortByLayer cmp;
here.sort (cmp);
/* ... and get the top/transparent regions at "here" */
for (RegionList::reverse_iterator c = here.rbegin(); c != here.rend(); ++c) {
unique.insert (*c);
if ((*c)->opaque()) {
/* the other regions at this position are hidden by this one */
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("%1 is opaque, ignore all others\n",
(*c)->name()));
break;
}
}
}
for (set<boost::shared_ptr<Region> >::iterator s = unique.begin(); s != unique.end(); ++s) {
rlist->push_back (*s);
}
if (rlist->size() > 1) {
/* now sort by time order */
RegionSortByPosition cmp;
rlist->sort (cmp);
}
}
DEBUG_TRACE (DEBUG::AudioPlayback, string_compose ("<<<<< REGIONS TO READ returns %1\n", rlist->size()));
return rlist;
}
boost::shared_ptr<RegionList>
Playlist::find_regions_at (framepos_t frame)
{
/* Caller must hold lock */
boost::shared_ptr<RegionList> rlist (new RegionList);
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if ((*i)->covers (frame)) {
rlist->push_back (*i);
@ -1854,6 +1723,40 @@ Playlist::find_regions_at (framepos_t frame)
return rlist;
}
boost::shared_ptr<RegionList>
Playlist::regions_with_start_within (Evoral::Range<framepos_t> range)
{
RegionLock rlock (this);
boost::shared_ptr<RegionList> rlist (new RegionList);
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if ((*i)->first_frame() >= range.from && (*i)->first_frame() <= range.to) {
rlist->push_back (*i);
}
}
return rlist;
}
boost::shared_ptr<RegionList>
Playlist::regions_with_end_within (Evoral::Range<framepos_t> range)
{
RegionLock rlock (this);
boost::shared_ptr<RegionList> rlist (new RegionList);
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if ((*i)->last_frame() >= range.from && (*i)->last_frame() <= range.to) {
rlist->push_back (*i);
}
}
return rlist;
}
/** @param start Range start.
* @param end Range end.
* @return regions which have some part within this range.
*/
boost::shared_ptr<RegionList>
Playlist::regions_touched (framepos_t start, framepos_t end)
{
@ -1861,12 +1764,12 @@ Playlist::regions_touched (framepos_t start, framepos_t end)
boost::shared_ptr<RegionList> rlist (new RegionList);
for (RegionList::iterator i = regions.begin(); i != regions.end(); ++i) {
if ((*i)->coverage (start, end) != OverlapNone) {
if ((*i)->coverage (start, end) != Evoral::OverlapNone) {
rlist->push_back (*i);
}
}
return rlist;
return rlist;
}
framepos_t
@ -2205,7 +2108,7 @@ Playlist::regions_touched (framepos_t start, framepos_t end)
*/
for (RegionList::iterator r = regions.begin(); r != regions.end(); ++r) {
check_dependents (*r, false);
check_crossfades ((*r)->range ());
}
}
@ -2674,6 +2577,8 @@ Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
_shuffling = true;
Evoral::Range<framepos_t> old_range = region->range ();
{
RegionLock rlock (const_cast<Playlist*> (this));
@ -2772,7 +2677,11 @@ Playlist::shuffle (boost::shared_ptr<Region> region, int dir)
if (moved) {
relayer ();
check_dependents (region, false);
list<Evoral::Range<framepos_t> > xf;
xf.push_back (old_range);
xf.push_back (region->range ());
coalesce_and_check_crossfades (xf);
notify_contents_changed();
}
@ -2936,10 +2845,6 @@ Playlist::combine (const RegionList& r)
pre_combine (copies);
/* add any dependent regions to the new playlist */
copy_dependents (old_and_new_regions, pl.get());
/* now create a new PlaylistSource for each channel in the new playlist */
SourceList sources;
@ -3081,13 +2986,13 @@ Playlist::uncombine (boost::shared_ptr<Region> target)
modified_region = false;
switch (original->coverage (adjusted_start, adjusted_end)) {
case OverlapNone:
case Evoral::OverlapNone:
/* original region does not cover any part
of the current state of the compound region
*/
continue;
case OverlapInternal:
case Evoral::OverlapInternal:
/* overlap is just a small piece inside the
* original so trim both ends
*/
@ -3095,13 +3000,13 @@ Playlist::uncombine (boost::shared_ptr<Region> target)
modified_region = true;
break;
case OverlapExternal:
case Evoral::OverlapExternal:
/* overlap fully covers original, so leave it
as is
*/
break;
case OverlapEnd:
case Evoral::OverlapEnd:
/* overlap starts within but covers end,
so trim the front of the region
*/
@ -3109,7 +3014,7 @@ Playlist::uncombine (boost::shared_ptr<Region> target)
modified_region = true;
break;
case OverlapStart:
case Evoral::OverlapStart:
/* overlap covers start but ends within, so
* trim the end of the region.
*/
@ -3152,10 +3057,6 @@ Playlist::uncombine (boost::shared_ptr<Region> target)
add_region ((*i), (*i)->position());
}
/* now move dependent regions back from the compound to this playlist */
pl->copy_dependents (old_and_new_regions, this);
in_partition = false;
thaw ();
}
@ -3178,3 +3079,34 @@ Playlist::set_orig_track_id (const PBD::ID& id)
{
_orig_track_id = id;
}
void
Playlist::coalesce_and_check_crossfades (list<Evoral::Range<framepos_t> > ranges)
{
/* XXX: it's a shame that this coalesce algorithm also exists in
TimeSelection::consolidate().
*/
/* XXX: xfade: this is implemented in Evoral::RangeList */
restart:
for (list<Evoral::Range<framepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
for (list<Evoral::Range<framepos_t> >::iterator j = ranges.begin(); j != ranges.end(); ++j) {
if (i == j) {
continue;
}
if (Evoral::coverage (i->from, i->to, j->from, j->to) != Evoral::OverlapNone) {
i->from = min (i->from, j->from);
i->to = max (i->to, j->to);
ranges.erase (j);
goto restart;
}
}
}
for (list<Evoral::Range<framepos_t> >::iterator i = ranges.begin(); i != ranges.end(); ++i) {
check_crossfades (*i);
}
}

View File

@ -1312,7 +1312,7 @@ Region::send_change (const PropertyChange& what_changed)
bool
Region::overlap_equivalent (boost::shared_ptr<const Region> other) const
{
return coverage (other->first_frame(), other->last_frame()) != OverlapNone;
return coverage (other->first_frame(), other->last_frame()) != Evoral::OverlapNone;
}
bool

View File

@ -66,7 +66,6 @@
#include "ardour/click.h"
#include "ardour/configuration.h"
#include "ardour/control_protocol_manager.h"
#include "ardour/crossfade.h"
#include "ardour/cycle_timer.h"
#include "ardour/data_type.h"
#include "ardour/debug.h"
@ -328,8 +327,6 @@ Session::destroy ()
delete *i;
}
Crossfade::set_buffer_size (0);
/* not strictly necessary, but doing it here allows the shared_ptr debugging to work */
playlists.reset ();

View File

@ -35,7 +35,6 @@
#include "ardour/audioengine.h"
#include "ardour/butler.h"
#include "ardour/configuration.h"
#include "ardour/crossfade.h"
#include "ardour/io.h"
#include "ardour/midi_diskstream.h"
#include "ardour/session.h"

View File

@ -34,8 +34,6 @@
#include "ardour/session_playlists.h"
#include "ardour/region_factory.h"
#include "ardour/midi_automation_list_binder.h"
#include "ardour/crossfade_binder.h"
#include "ardour/crossfade.h"
#include "pbd/error.h"
#include "pbd/id.h"
#include "pbd/statefuldestructible.h"
@ -143,19 +141,6 @@ Session::memento_command_factory(XMLNode *n)
cerr << "Alist " << id << " not found\n";
} else if (obj_T == "ARDOUR::Crossfade") {
if (have_id) {
boost::shared_ptr<Crossfade> c = playlists->find_crossfade (id);
if (c) {
return new MementoCommand<Crossfade> (*c.get(), before, after);
}
} else {
return new MementoCommand<Crossfade> (
new CrossfadeBinder (n, playlists),
before, after
);
}
} else if (registry.count(id)) { // For Editor and AutomationLine which are off-limits herea
return new MementoCommand<PBD::StatefulDestructible>(*registry[id], before, after);
}

View File

@ -47,6 +47,8 @@
#include "i18n.h"
#include <xmmintrin.h>
using namespace ARDOUR;
using namespace PBD;
using namespace std;

View File

@ -83,7 +83,6 @@
#include "ardour/butler.h"
#include "ardour/configuration.h"
#include "ardour/control_protocol_manager.h"
#include "ardour/crossfade.h"
#include "ardour/cycle_timer.h"
#include "ardour/directory_names.h"
#include "ardour/filename_extensions.h"
@ -232,7 +231,6 @@ Session::first_stage_init (string fullpath, string snapshot_name)
/* default short fade = 15ms */
Crossfade::set_short_xfade_length ((framecnt_t) floor (config.get_short_xfade_seconds() * frame_rate()));
SndFileSource::setup_standard_crossfades (*this, frame_rate());
last_mmc_step.tv_sec = 0;

View File

@ -0,0 +1,85 @@
#include "ardour/playlist.h"
#include "ardour/region.h"
#include "ardour/audioregion.h"
#include "audio_region_test.h"
#include "test_globals.h"
CPPUNIT_TEST_SUITE_REGISTRATION (AudioRegionTest);
using namespace std;
using namespace ARDOUR;
void
AudioRegionTest::readTest ()
{
int const N = 1024;
Sample buf[N];
Sample mbuf[N];
float gbuf[N];
int const P = 100;
boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
/* Simple read: 256 frames from start of region, no fades */
/* gbuf should be ignored; set it to 0 to ensure that it is */
for (int i = 0; i < N; ++i) {
gbuf[i] = 0;
}
ar->set_position (P);
ar->set_length (1024);
for (int i = 0; i < N; ++i) {
buf[i] = 0;
}
ar->_read_at (ar->_sources, ar->_length, buf, mbuf, gbuf, P, 256, 0, AudioRegion::ReadOps (0));
check_staircase (buf, 0, 256);
for (int i = 0; i < N; ++i) {
buf[i] = 0;
}
/* Offset read: 256 frames from 128 frames into the region, no fades */
ar->_read_at (ar->_sources, ar->_length, buf, mbuf, gbuf, P + 128, 256, 0, AudioRegion::ReadOps (0));
check_staircase (buf, 128, 256);
/* Simple read with a fade-in: 256 frames from start of region, with fades */
ar->set_default_fade_in ();
CPPUNIT_ASSERT_EQUAL (double (64), ar->_fade_in->back()->when);
for (int i = 0; i < N; ++i) {
buf[i] = 0;
}
ar->read_at (buf, mbuf, gbuf, P, 256, 0);
for (int i = 0; i < 64; ++i) {
/* XXX: this isn't very accurate, but close enough for now; needs investigation */
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * i / 63.0), buf[i], 1e-4);
}
for (int i = 64; i < P; ++i) {
CPPUNIT_ASSERT_EQUAL (i, int (buf[i]));
}
/* Offset read: 256 frames from 128 frames into the region, with fades
(though the fade should not affect it, as it is finished before the read starts)
*/
for (int i = 0; i < N; ++i) {
buf[i] = 0;
}
ar->read_at (buf, mbuf, gbuf, P + 128, 256, 0);
check_staircase (buf, 128, 256);
}
void
AudioRegionTest::check_staircase (Sample* b, int offset, int N)
{
for (int i = 0; i < N; ++i) {
int const j = i + offset;
CPPUNIT_ASSERT_EQUAL (j, int (b[i]));
}
}

View File

@ -0,0 +1,15 @@
#include "ardour/types.h"
#include "test_needing_playlist_and_regions.h"
class AudioRegionTest : public TestNeedingPlaylistAndRegions
{
CPPUNIT_TEST_SUITE (AudioRegionTest);
CPPUNIT_TEST (readTest);
CPPUNIT_TEST_SUITE_END ();
public:
void readTest ();
private:
void check_staircase (ARDOUR::Sample *, int, int);
};

View File

@ -0,0 +1,171 @@
#include "ardour/playlist.h"
#include "ardour/region.h"
#include "ardour/audioplaylist.h"
#include "ardour/audioregion.h"
#include "ardour/session.h"
#include "playlist_read_test.h"
#include "test_globals.h"
CPPUNIT_TEST_SUITE_REGISTRATION (PlaylistReadTest);
using namespace std;
using namespace ARDOUR;
void
PlaylistReadTest::setUp ()
{
TestNeedingPlaylistAndRegions::setUp ();
_N = 1024;
_buf = new Sample[_N];
_mbuf = new Sample[_N];
_gbuf = new float[_N];
_session->config.set_auto_xfade (false);
_apl = boost::dynamic_pointer_cast<AudioPlaylist> (_playlist);
for (int i = 0; i < _N; ++i) {
_buf[i] = 0;
}
}
void
PlaylistReadTest::tearDown ()
{
delete[] _buf;
delete[] _mbuf;
delete[] _gbuf;
_apl.reset ();
TestNeedingPlaylistAndRegions::tearDown ();
}
void
PlaylistReadTest::singleReadTest ()
{
/* Single-region read with fades */
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
ar0->set_name ("ar0");
_apl->add_region (ar0, 0);
ar0->set_default_fade_in ();
ar0->set_default_fade_out ();
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
ar0->set_length (1024);
_apl->read (_buf, _mbuf, _gbuf, 0, 256, 0);
for (int i = 0; i < 64; ++i) {
/* Note: this specific float casting is necessary so that the rounding
is done here the same as it is done in AudioPlaylist.
*/
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / 63.0)), _buf[i], 1e-16);
}
for (int i = 64; i < 256; ++i) {
CPPUNIT_ASSERT_EQUAL (i, int (_buf[i]));
}
}
void
PlaylistReadTest::overlappingReadTest ()
{
/* Overlapping read; ar0 and ar1 are both 1024 frames long, ar0 starts at 0,
ar1 starts at 128. We test a read from 0 to 256, which should consist
of the start of ar0, with its fade in, followed by ar1's fade in (mixed with ar0)
and some more of ar1.
*/
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
ar0->set_name ("ar0");
_apl->add_region (ar0, 0);
ar0->set_default_fade_in ();
ar0->set_default_fade_out ();
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
ar0->set_length (1024);
boost::shared_ptr<AudioRegion> ar1 = boost::dynamic_pointer_cast<AudioRegion> (_region[1]);
ar1->set_name ("ar1");
_apl->add_region (ar1, 128);
ar1->set_default_fade_in ();
ar1->set_default_fade_out ();
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_in->back()->when);
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_out->back()->when);
ar1->set_length (1024);
_apl->read (_buf, _mbuf, _gbuf, 0, 256, 0);
/* ar0's fade in */
for (int i = 0; i < 64; ++i) {
/* Note: this specific float casting is necessary so that the rounding
is done here the same as it is done in AudioPlaylist.
*/
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * float (i / 63.0)), _buf[i], 1e-16);
}
/* bit of ar0 */
for (int i = 64; i < 128; ++i) {
CPPUNIT_ASSERT_EQUAL (i, int (_buf[i]));
}
/* ar1's fade in */
for (int i = 0; i < 64; ++i) {
/* Similar carry-on to above with float rounding */
CPPUNIT_ASSERT_DOUBLES_EQUAL (i + 128 + float (i * float (i / 63.0)), _buf[i + 128], 1e-4);
}
}
void
PlaylistReadTest::transparentReadTest ()
{
boost::shared_ptr<AudioRegion> ar0 = boost::dynamic_pointer_cast<AudioRegion> (_region[0]);
ar0->set_name ("ar0");
_apl->add_region (ar0, 0);
ar0->set_default_fade_in ();
ar0->set_default_fade_out ();
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_in->back()->when);
CPPUNIT_ASSERT_EQUAL (double (64), ar0->_fade_out->back()->when);
ar0->set_length (1024);
boost::shared_ptr<AudioRegion> ar1 = boost::dynamic_pointer_cast<AudioRegion> (_region[1]);
ar1->set_name ("ar1");
_apl->add_region (ar1, 0);
ar1->set_default_fade_in ();
ar1->set_default_fade_out ();
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_in->back()->when);
CPPUNIT_ASSERT_EQUAL (double (64), ar1->_fade_out->back()->when);
ar1->set_length (1024);
ar1->set_opaque (false);
_apl->read (_buf, _mbuf, _gbuf, 0, 1024, 0);
/* ar0 and ar1 fade-ins, mixed */
for (int i = 0; i < 64; ++i) {
float const fade = i / 63.0;
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * fade) * 2, _buf[i], 1e-16);
}
/* ar0 and ar1 bodies, mixed */
for (int i = 64; i < (1024 - 64); ++i) {
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * 2), _buf[i], 1e-16);
}
/* ar0 and ar1 fade-outs, mixed */
for (int i = (1024 - 64); i < 1024; ++i) {
float const fade = (1023 - i) / 63.0;
CPPUNIT_ASSERT_DOUBLES_EQUAL (float (i * fade) * 2, _buf[i], 1e-16);
}
}
void
PlaylistReadTest::check_staircase (Sample* b, int offset, int N)
{
for (int i = 0; i < N; ++i) {
int const j = i + offset;
CPPUNIT_ASSERT_EQUAL (j, int (b[i]));
}
}

View File

@ -0,0 +1,27 @@
#include "ardour/types.h"
#include "test_needing_playlist_and_regions.h"
class PlaylistReadTest : public TestNeedingPlaylistAndRegions
{
CPPUNIT_TEST_SUITE (PlaylistReadTest);
CPPUNIT_TEST (singleReadTest);
CPPUNIT_TEST (transparentReadTest);
CPPUNIT_TEST_SUITE_END ();
public:
void setUp ();
void tearDown ();
void singleReadTest ();
void overlappingReadTest ();
void transparentReadTest ();
private:
int _N;
ARDOUR::Sample* _buf;
ARDOUR::Sample* _mbuf;
float* _gbuf;
boost::shared_ptr<ARDOUR::AudioPlaylist> _apl;
void check_staircase (ARDOUR::Sample *, int, int);
};

View File

@ -41,15 +41,6 @@ TempoTest::recomputeMapTest ()
Meter meterB (3, 4);
map.add_meter (meterB, BBT_Time (4, 1, 0));
cout << "\n\n\n";
for (list<MetricSection*>::iterator i = map.metrics.begin(); i != map.metrics.end(); ++i) {
if (dynamic_cast<TempoSection*> (*i)) {
cout << "\tTempo MS @ " << (*i)->start() << " " << (*i)->frame() << "\n";
} else {
cout << "\tMeter MS @ " << (*i)->start() << " " << (*i)->frame() << "\n";
}
}
list<MetricSection*>::iterator i = map.metrics.begin();
CPPUNIT_ASSERT_EQUAL (framepos_t (0), (*i)->frame ());

View File

@ -0,0 +1,4 @@
#include "test_globals.h"
int const Fs = 44100;
int const sinusoid_frequency = 440;

View File

@ -0,0 +1,3 @@
extern int const Fs;
extern int const sinusoid_frequency;

View File

@ -3,7 +3,9 @@
#include "ardour/source_factory.h"
#include "ardour/region.h"
#include "ardour/region_factory.h"
#include "ardour/sndfilesource.h"
#include "test_needing_playlist_and_regions.h"
#include "test_globals.h"
using namespace std;
using namespace PBD;
@ -14,9 +16,25 @@ TestNeedingPlaylistAndRegions::setUp ()
{
TestNeedingSession::setUp ();
/* This is important, otherwise createWritable will mark the source immutable (hence unwritable) */
unlink ("libs/ardour/test/test.wav");
string const test_wav_path = "libs/ardour/test/test.wav";
_playlist = PlaylistFactory::create (DataType::AUDIO, *_session, "test");
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, 44100);
_source = SourceFactory::createWritable (DataType::AUDIO, *_session, test_wav_path, "", false, Fs);
/* Write a staircase to the source */
boost::shared_ptr<SndFileSource> s = boost::dynamic_pointer_cast<SndFileSource> (_source);
assert (s);
int const signal_length = 4096;
Sample staircase[signal_length];
for (int i = 0; i < signal_length; ++i) {
staircase[i] = i;
}
s->write (staircase, signal_length);
PropertyList plist;
plist.add (Properties::start, 0);

View File

@ -18,7 +18,7 @@ LIBARDOUR_VERSION = "%s.%s.%s" % (MAJOR, MINOR, MICRO)
LIBARDOUR_LIB_VERSION = '3.0.0'
# default state file version for this build
CURRENT_SESSION_FILE_VERSION = 3000
CURRENT_SESSION_FILE_VERSION = 3001
# Variables for 'waf dist'
APPNAME = 'libardour3'
@ -70,8 +70,6 @@ libardour_sources = [
'config_text.cc',
'control_protocol_manager.cc',
'control_protocol_search_path.cc',
'crossfade.cc',
'crossfade_binder.cc',
'cycle_timer.cc',
'data_type.cc',
'default_click.cc',
@ -408,8 +406,7 @@ def build(bld):
obj.source += [ 'audio_unit.cc' ]
if Options.options.fpu_optimization:
if (bld.env['build_target'] == 'i386'
or bld.env['build_target'] == 'i686'):
if (bld.env['build_target'] == 'i386' or bld.env['build_target'] == 'i686'):
obj.source += [ 'sse_functions_xmm.cc', 'sse_functions.s' ]
elif bld.env['build_target'] == 'x86_64':
obj.source += [ 'sse_functions_xmm.cc', 'sse_functions_64bit.s' ]
@ -430,6 +427,8 @@ def build(bld):
test/dummy_lxvst.cc
test/test_needing_session.cc
test/test_needing_playlist_and_regions.cc
test/test_globals.cc
test/audio_region_test.cc
test/bbt_test.cc
test/tempo_test.cc
test/interpolation_test.cc
@ -439,6 +438,7 @@ def build(bld):
test/framepos_plus_beats_test.cc
test/framepos_minus_beats_test.cc
test/playlist_layering_test.cc
test/playlist_read_test.cc
test/testrunner.cc
'''.split()

View File

@ -26,6 +26,7 @@
#include <glibmm/thread.h>
#include "pbd/signals.h"
#include "evoral/types.hpp"
#include "evoral/Range.hpp"
#include "evoral/Parameter.hpp"
namespace Evoral {

View File

@ -0,0 +1,219 @@
/* This file is part of Evoral.
* Copyright (C) 2008 David Robillard <http://drobilla.net>
* Copyright (C) 2000-2008 Paul Davis
*
* Evoral is free software; you can redistribute it and/or modify it under the
* terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* Evoral is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef EVORAL_RANGE_HPP
#define EVORAL_RANGE_HPP
#include <list>
namespace Evoral {
enum OverlapType {
OverlapNone, // no overlap
OverlapInternal, // the overlap is 100% with the object
OverlapStart, // overlap covers start, but ends within
OverlapEnd, // overlap begins within and covers end
OverlapExternal // overlap extends to (at least) begin+end
};
template<typename T>
OverlapType coverage (T sa, T ea, T sb, T eb) {
/* OverlapType returned reflects how the second (B)
range overlaps the first (A).
The diagrams show various relative placements
of A and B for each OverlapType.
Notes:
Internal: the start points cannot coincide
External: the start and end points can coincide
Start: end points can coincide
End: start points can coincide
XXX Logically, Internal should disallow end
point equality.
*/
/*
|--------------------| A
|------| B
|-----------------| B
"B is internal to A"
*/
if ((sb > sa) && (eb <= ea)) {
return OverlapInternal;
}
/*
|--------------------| A
----| B
-----------------------| B
--| B
"B overlaps the start of A"
*/
if ((eb >= sa) && (eb <= ea)) {
return OverlapStart;
}
/*
|---------------------| A
|----------------- B
|----------------------- B
|- B
"B overlaps the end of A"
*/
if ((sb > sa) && (sb <= ea)) {
return OverlapEnd;
}
/*
|--------------------| A
-------------------------- B
|----------------------- B
----------------------| B
|--------------------| B
"B overlaps all of A"
*/
if ((sa >= sb) && (sa <= eb) && (ea <= eb)) {
return OverlapExternal;
}
return OverlapNone;
}
/** Type to describe a time range */
template<typename T>
struct Range {
Range (T f, T t) : from (f), to (t) {}
T from; ///< start of the range
T to; ///< end of the range
};
template<typename T>
bool operator== (Range<T> a, Range<T> b) {
return a.from == b.from && a.to == b.to;
}
template<typename T>
class RangeList {
public:
RangeList () : _dirty (false) {}
typedef std::list<Range<T> > List;
List const & get () {
coalesce ();
return _list;
}
void add (Range<T> const & range) {
_dirty = true;
_list.push_back (range);
}
bool empty () const {
return _list.empty ();
}
private:
void coalesce () {
if (!_dirty) {
return;
}
restart:
for (typename List::iterator i = _list.begin(); i != _list.end(); ++i) {
for (typename List::iterator j = _list.begin(); j != _list.end(); ++j) {
if (i == j) {
continue;
}
if (coverage (i->from, i->to, j->from, j->to) != OverlapNone) {
i->from = std::min (i->from, j->from);
i->to = std::max (i->to, j->to);
_list.erase (j);
goto restart;
}
}
}
_dirty = false;
}
List _list;
bool _dirty;
};
/** Type to describe the movement of a time range */
template<typename T>
struct RangeMove {
RangeMove (T f, double l, T t) : from (f), length (l), to (t) {}
T from; ///< start of the range
double length; ///< length of the range
T to; ///< new start of the range
};
template<typename T>
RangeList<T> subtract (Range<T> range, RangeList<T> sub)
{
RangeList<T> result;
if (sub.empty ()) {
result.add (range);
return result;
}
T x = range.from;
typename RangeList<T>::List s = sub.get ();
for (typename RangeList<T>::List::const_iterator i = s.begin(); i != s.end(); ++i) {
if (coverage (range.from, range.to, i->from, i->to) == OverlapNone) {
continue;
}
Range<T> clamped (std::max (range.from, i->from), std::min (range.to, i->to));
if (clamped.from != x) {
result.add (Range<T> (x, clamped.from - 1));
}
x = clamped.to;
}
if (s.back().to < range.to) {
result.add (Range<T> (x, range.to));
}
return result;
}
}
#endif

View File

@ -46,23 +46,6 @@ static inline bool musical_time_equal (MusicalTime a, MusicalTime b) {
/** Type of an event (opaque, mapped by application) */
typedef uint32_t EventType;
/** Type to describe a time range */
template<typename T>
struct Range {
Range (T f, T t) : from (f), to (t) {}
T from; ///< start of the range
T to; ///< end of the range
};
/** Type to describe the movement of a time range */
template<typename T>
struct RangeMove {
RangeMove (T f, double l, T t) : from (f), length (l), to (t) {}
T from; ///< start of the range
double length; ///< length of the range
T to; ///< new start of the range
};
} // namespace Evoral
namespace PBD {

View File

@ -1,14 +1,14 @@
#!/bin/sh
srcdir=`pwd`
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$srcdir/../../build/default/libs/evoral:$srcdir/../../build/default/libs/pbd
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$srcdir/../../build/libs/evoral:$srcdir/../../build/libs/pbd
if [ ! -f './test/testdata/TakeFive.mid' ]; then
echo "This script must be run from within the libs/evoral directory";
exit 1;
fi
# Make symlink to TakeFive.mid in build directory
cd ../../build/default/libs/evoral
cd ../../build/libs/evoral
mkdir -p ./test/testdata
ln -fs $srcdir/test/testdata/TakeFive.mid \
./test/testdata/TakeFive.mid

View File

@ -465,6 +465,8 @@ ControlList::fast_simple_add (double when, double value)
/* to be used only for loading pre-sorted data from saved state */
_events.insert (_events.end(), new ControlEvent (when, value));
assert(_events.back());
mark_dirty ();
}
void

View File

@ -190,7 +190,7 @@ Curve::get_vector (double x0, double x1, float *vec, int32_t veclen)
void
Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
{
double rx, dx, lx, hx, max_x, min_x;
double rx, lx, hx, max_x, min_x;
int32_t i;
int32_t original_veclen;
int32_t npoints;
@ -276,26 +276,34 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
/* linear interpolation between 2 points */
/* XXX I'm not sure that this is the right thing to
do here. but its not a common case for the envisaged
uses.
/* XXX: this numerator / denominator stuff is pretty grim, but it's the only
way I could get the maths to be accurate; doing everything with pure doubles
gives ~1e-17 errors in the vec[i] computation.
*/
/* gradient of the line */
double const m_num = _list.events().back()->value - _list.events().front()->value;
double const m_den = _list.events().back()->when - _list.events().front()->when;
/* y intercept of the line */
double const c = double (_list.events().back()->value) - (m_num * _list.events().back()->when / m_den);
/* dx that we are using */
double dx_num = 0;
double dx_den = 1;
if (veclen > 1) {
dx = (hx - lx) / (veclen - 1) ;
dx_num = hx - lx;
dx_den = veclen - 1;
}
if (veclen > 1) {
for (int i = 0; i < veclen; ++i) {
vec[i] = (lx * (m_num / m_den) + m_num * i * dx_num / (m_den * dx_den)) + c;
}
} else {
dx = 0; // not used
vec[i] = lx;
}
double slope = (_list.events().back()->value - _list.events().front()->value)/
(_list.events().back()->when - _list.events().front()->when);
double yfrac = dx*slope;
vec[0] = _list.events().front()->value + slope * (lx - _list.events().front()->when);
for (i = 1; i < veclen; ++i) {
vec[i] = vec[i-1] + yfrac;
}
return;
}
@ -305,10 +313,9 @@ Curve::_get_vector (double x0, double x1, float *vec, int32_t veclen)
rx = lx;
double dx = 0;
if (veclen > 1) {
dx = (hx - lx) / (veclen - 1);
} else {
dx = 0;
}
for (i = 0; i < veclen; ++i, rx += dx) {

View File

@ -0,0 +1,84 @@
#include "RangeTest.hpp"
#include "evoral/Range.hpp"
CPPUNIT_TEST_SUITE_REGISTRATION (RangeTest);
using namespace Evoral;
void
RangeTest::coalesceTest ()
{
RangeList<int> fred;
fred.add (Range<int> (2, 4));
fred.add (Range<int> (5, 6));
fred.add (Range<int> (6, 8));
RangeList<int>::List jim = fred.get ();
RangeList<int>::List::iterator i = jim.begin ();
CPPUNIT_ASSERT_EQUAL (2, i->from);
CPPUNIT_ASSERT_EQUAL (4, i->to);
++i;
CPPUNIT_ASSERT_EQUAL (5, i->from);
CPPUNIT_ASSERT_EQUAL (8, i->to);
}
void
RangeTest::subtractTest1 ()
{
Range<int> fred (0, 10);
RangeList<int> jim;
jim.add (Range<int> (2, 4));
jim.add (Range<int> (7, 8));
RangeList<int> sheila = subtract (fred, jim);
RangeList<int>::List s = sheila.get ();
CPPUNIT_ASSERT_EQUAL (size_t (3), s.size ());
RangeList<int>::List::iterator i = s.begin ();
CPPUNIT_ASSERT_EQUAL (0, i->from);
CPPUNIT_ASSERT_EQUAL (1, i->to);
++i;
CPPUNIT_ASSERT_EQUAL (4, i->from);
CPPUNIT_ASSERT_EQUAL (6, i->to);
++i;
CPPUNIT_ASSERT_EQUAL (8, i->from);
CPPUNIT_ASSERT_EQUAL (10, i->to);
}
void
RangeTest::subtractTest2 ()
{
Range<int> fred (0, 10);
RangeList<int> jim;
jim.add (Range<int> (12, 19));
RangeList<int> sheila = subtract (fred, jim);
RangeList<int>::List s = sheila.get ();
CPPUNIT_ASSERT_EQUAL (size_t (1), s.size ());
RangeList<int>::List::iterator i = s.begin ();
CPPUNIT_ASSERT_EQUAL (0, i->from);
CPPUNIT_ASSERT_EQUAL (10, i->to);
}
void
RangeTest::subtractTest3 ()
{
Range<int> fred (0, 10);
RangeList<int> jim;
jim.add (Range<int> (0, 12));
RangeList<int> sheila = subtract (fred, jim);
RangeList<int>::List s = sheila.get ();
CPPUNIT_ASSERT_EQUAL (size_t (0), s.size ());
}

View File

@ -0,0 +1,19 @@
#include <cppunit/TestFixture.h>
#include <cppunit/extensions/HelperMacros.h>
class RangeTest : public CppUnit::TestFixture
{
CPPUNIT_TEST_SUITE (RangeTest);
CPPUNIT_TEST (coalesceTest);
CPPUNIT_TEST (subtractTest1);
CPPUNIT_TEST (subtractTest3);
CPPUNIT_TEST_SUITE_END ();
public:
void coalesceTest ();
void subtractTest1 ();
void subtractTest2 ();
void subtractTest3 ();
};

View File

@ -124,6 +124,7 @@ def build(bld):
obj.source = '''
test/SequenceTest.cpp
test/SMFTest.cpp
test/RangeTest.cpp
test/testrunner.cpp
'''
obj.includes = ['.', './src']