mo' better fixins fer xfades, plus reinstate hiding xfades during drags

git-svn-id: svn://localhost/ardour2/trunk@1325 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
Paul Davis 2007-01-14 01:25:12 +00:00
parent a7a6f464ad
commit 56cd926425
5 changed files with 227 additions and 209 deletions

View file

@ -2799,7 +2799,6 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
set<boost::shared_ptr<Playlist> > affected_playlists;
pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
// TODO: Crossfades need to be copied!
for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
RegionView* rv;
@ -2807,7 +2806,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
boost::shared_ptr<Playlist> to_playlist = rv->region()->playlist();
RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*>(&rv->get_time_axis_view());
insert_result = affected_playlists.insert (to_playlist);
if (insert_result.second) {
session->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
@ -3227,7 +3226,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
/* hide any dependent views */
// rv->get_time_axis_view().hide_dependent_views (*rv);
rv->get_time_axis_view().hide_dependent_views (*rv);
/* this is subtle. raising the regionview itself won't help,
because raise_to_top() just puts the item on the top of

View file

@ -157,6 +157,7 @@ class Crossfade : public PBD::StatefulDestructible, public boost::enable_shared_
AnchorPoint _anchor_point;
bool _follow_overlap;
bool _fixed;
int32_t layer_relation;
Curve _fade_in;
Curve _fade_out;
@ -165,7 +166,7 @@ class Crossfade : public PBD::StatefulDestructible, public boost::enable_shared_
void initialize ();
int compute (boost::shared_ptr<ARDOUR::AudioRegion>, boost::shared_ptr<ARDOUR::AudioRegion>, CrossfadeModel);
bool update (bool force);
bool update ();
void member_changed (ARDOUR::Change);
};

View file

@ -274,9 +274,14 @@ AudioPlaylist::refresh_dependents (boost::shared_ptr<Region> r)
if ((*x)->involves (ar)) {
if (find (updated.begin(), updated.end(), *x) == updated.end()) {
if ((*x)->refresh ()) {
/* not invalidated by the refresh */
updated.insert (*x);
try {
if ((*x)->refresh ()) {
updated.insert (*x);
}
}
catch (Crossfade::NoCrossfadeHere& err) {
// relax, Invalidated during refresh
}
}
}
@ -348,6 +353,7 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
refresh_dependents (r);
}
if (!Config->get_auto_xfade()) {
return;
}
@ -405,7 +411,6 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
xfade_length = min ((nframes_t) 720, top->length());
xfade = boost::shared_ptr<Crossfade> (new Crossfade (top, bottom, xfade_length, top->first_frame(), StartOfIn));
cerr << "StartOfIn is " << xfade << endl;
add_crossfade (xfade);
if (top_region_at (top->last_frame() - 1) == top) {
@ -415,7 +420,6 @@ AudioPlaylist::check_dependents (boost::shared_ptr<Region> r, bool norefresh)
*/
xfade = boost::shared_ptr<Crossfade> (new Crossfade (bottom, top, xfade_length, top->last_frame() - xfade_length, EndOfOut));
cerr << "EndofOut is " << xfade << endl;
add_crossfade (xfade);
}
break;

View file

@ -89,8 +89,6 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
_follow_overlap = false;
cerr << "A: follow overlap = " << _follow_overlap << endl;
_active = Config->get_xfades_active ();
_fixed = true;
@ -111,8 +109,6 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
_active = act;
initialize ();
cerr << "K: follow overlap = " << _follow_overlap << endl;
}
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
@ -167,9 +163,6 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
if (set_state (node)) {
throw failed_constructor();
}
cerr << "D: follow overlap = " << _follow_overlap << endl;
}
Crossfade::Crossfade (const Crossfade &orig, boost::shared_ptr<AudioRegion> newin, boost::shared_ptr<AudioRegion> newout)
@ -194,18 +187,15 @@ Crossfade::Crossfade (const Crossfade &orig, boost::shared_ptr<AudioRegion> newi
_in->suspend_fade_in ();
overlap_type = _in->coverage (_out->position(), _out->last_frame());
layer_relation = (int32_t) (_in->layer() - _out->layer());
// Let's make sure the fade isn't too long
set_length(_length);
cerr << "B: follow overlap = " << _follow_overlap << endl;
}
Crossfade::~Crossfade ()
{
cerr << this << " Crossfade deleted\n";
notify_callbacks ();
}
@ -237,12 +227,212 @@ Crossfade::initialize ()
_fade_in.add (_length, 1.0);
_fade_in.thaw ();
_in->StateChanged.connect (sigc::mem_fun (*this, &Crossfade::member_changed));
_out->StateChanged.connect (sigc::mem_fun (*this, &Crossfade::member_changed));
// _in->StateChanged.connect (sigc::mem_fun (*this, &Crossfade::member_changed));
// _out->StateChanged.connect (sigc::mem_fun (*this, &Crossfade::member_changed));
overlap_type = _in->coverage (_out->position(), _out->last_frame());
layer_relation = (int32_t) (_in->layer() - _out->layer());
}
nframes_t
Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, nframes_t start, nframes_t cnt, uint32_t chan_n,
nframes_t read_frames, nframes_t skip_frames)
{
nframes_t offset;
nframes_t to_write;
if (!_active) {
return 0;
}
if (start < _position) {
/* handle an initial section of the read area that we do not
cover.
*/
offset = _position - start;
if (offset < cnt) {
cnt -= offset;
} else {
return 0;
}
start = _position;
buf += offset;
to_write = min (_length, cnt);
} else {
to_write = min (_length - (start - _position), cnt);
}
offset = start - _position;
_out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
_in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
float* fiv = new float[to_write];
float* fov = new float[to_write];
_fade_in.get_vector (offset, offset+to_write, fiv, to_write);
_fade_out.get_vector (offset, offset+to_write, fov, to_write);
/* note: although we have not explicitly taken into account the return values
from _out->read_at() or _in->read_at(), the length() function does this
implicitly. why? because it computes a value based on the in+out regions'
position and length, and so we know precisely how much data they could return.
*/
for (nframes_t n = 0; n < to_write; ++n) {
buf[n] = (crossfade_buffer_out[n] * fov[n]) + (crossfade_buffer_in[n] * fiv[n]);
}
delete [] fov;
delete [] fiv;
return to_write;
}
OverlapType
Crossfade::coverage (nframes_t start, nframes_t end) const
{
nframes_t my_end = _position + _length;
if ((start >= _position) && (end <= my_end)) {
return OverlapInternal;
}
if ((end >= _position) && (end <= my_end)) {
return OverlapStart;
}
if ((start >= _position) && (start <= my_end)) {
return OverlapEnd;
}
if ((_position >= start) && (_position <= end) && (my_end <= end)) {
return OverlapExternal;
}
return OverlapNone;
}
void
Crossfade::set_active (bool yn)
{
if (_active != yn) {
_active = yn;
StateChanged (ActiveChanged);
}
}
bool
Crossfade::refresh ()
{
/* crossfades must be between non-muted regions */
if (_out->muted() || _in->muted()) {
Invalidated (shared_from_this());
return false;
}
/* layer ordering cannot change */
int32_t new_layer_relation = (int32_t) (_in->layer() - _out->layer());
if (new_layer_relation * layer_relation < 0) { // different sign, layers rotated
Invalidated (shared_from_this());
return false;
}
OverlapType ot = _in->coverage (_out->first_frame(), _out->last_frame());
if (ot == OverlapNone) {
Invalidated (shared_from_this());
return false;
}
bool send_signal;
if (ot != overlap_type) {
if (_follow_overlap) {
try {
compute (_in, _out, Config->get_xfade_model());
}
catch (NoCrossfadeHere& err) {
Invalidated (shared_from_this());
return false;
}
send_signal = true;
} else {
Invalidated (shared_from_this());
return false;
}
} else {
send_signal = update ();
}
if (send_signal) {
StateChanged (BoundsChanged); /* EMIT SIGNAL */
}
_in_update = false;
return true;
}
bool
Crossfade::update ()
{
nframes_t newlen;
if (_follow_overlap) {
newlen = _out->first_frame() + _out->length() - _in->first_frame();
} else {
newlen = _length;
}
if (newlen == 0) {
Invalidated (shared_from_this());
return false;
}
_in_update = true;
if ((_follow_overlap && newlen != _length) || (_length > newlen)) {
double factor = newlen / (double) _length;
_fade_out.x_scale (factor);
_fade_in.x_scale (factor);
_length = newlen;
}
switch (_anchor_point) {
case StartOfIn:
_position = _in->first_frame();
break;
case EndOfIn:
_position = _in->last_frame() - _length;
break;
case EndOfOut:
_position = _out->last_frame() - _length;
}
return true;
}
int
Crossfade::compute (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model)
{
@ -409,192 +599,6 @@ Crossfade::compute (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioReg
return 0;
}
nframes_t
Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
float *gain_buffer, nframes_t start, nframes_t cnt, uint32_t chan_n,
nframes_t read_frames, nframes_t skip_frames)
{
nframes_t offset;
nframes_t to_write;
if (!_active) {
return 0;
}
if (start < _position) {
/* handle an initial section of the read area that we do not
cover.
*/
offset = _position - start;
if (offset < cnt) {
cnt -= offset;
} else {
return 0;
}
start = _position;
buf += offset;
to_write = min (_length, cnt);
} else {
to_write = min (_length - (start - _position), cnt);
}
offset = start - _position;
_out->read_at (crossfade_buffer_out, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
_in->read_at (crossfade_buffer_in, mixdown_buffer, gain_buffer, start, to_write, chan_n, read_frames, skip_frames);
float* fiv = new float[to_write];
float* fov = new float[to_write];
_fade_in.get_vector (offset, offset+to_write, fiv, to_write);
_fade_out.get_vector (offset, offset+to_write, fov, to_write);
/* note: although we have not explicitly taken into account the return values
from _out->read_at() or _in->read_at(), the length() function does this
implicitly. why? because it computes a value based on the in+out regions'
position and length, and so we know precisely how much data they could return.
*/
for (nframes_t n = 0; n < to_write; ++n) {
buf[n] = (crossfade_buffer_out[n] * fov[n]) + (crossfade_buffer_in[n] * fiv[n]);
}
delete [] fov;
delete [] fiv;
return to_write;
}
OverlapType
Crossfade::coverage (nframes_t start, nframes_t end) const
{
nframes_t my_end = _position + _length;
if ((start >= _position) && (end <= my_end)) {
return OverlapInternal;
}
if ((end >= _position) && (end <= my_end)) {
return OverlapStart;
}
if ((start >= _position) && (start <= my_end)) {
return OverlapEnd;
}
if ((_position >= start) && (_position <= end) && (my_end <= end)) {
return OverlapExternal;
}
return OverlapNone;
}
void
Crossfade::set_active (bool yn)
{
if (_active != yn) {
_active = yn;
StateChanged (ActiveChanged);
}
}
bool
Crossfade::refresh ()
{
/* crossfades must be between non-muted regions */
if (_out->muted() || _in->muted()) {
Invalidated (shared_from_this());
return false;
}
// if (_in->layer() < _out->layer()) {
// cerr << this << " layer change, invalidated, in on " << _in->layer() << " out on " << _out->layer() << endl;
// Invalidated (shared_from_this());
// return false;
// }
/* overlap type must be Start, End or External */
OverlapType ot;
ot = _in->coverage (_out->first_frame(), _out->last_frame());
/* overlap type must not have altered */
if (ot != overlap_type) {
cerr << this << " Invalid B\n";
Invalidated (shared_from_this());
return false;
}
/* time to update */
return update (false);
}
bool
Crossfade::update (bool force)
{
nframes_t newlen;
cerr << this << " update, " << _in->name() << " + " << _out->name() << " length = " << _length << endl;
if (_follow_overlap) {
newlen = _out->first_frame() + _out->length() - _in->first_frame();
cerr << "\tmodify length\n";
} else {
newlen = _length;
}
if (newlen == 0) {
cerr << this << " Invalid C\n";
Invalidated (shared_from_this());
return false;
}
_in_update = true;
if (force || (_follow_overlap && newlen != _length) || (_length > newlen)) {
double factor = newlen / (double) _length;
_fade_out.x_scale (factor);
_fade_in.x_scale (factor);
_length = newlen;
}
cerr << "\tFover = " << _follow_overlap << endl;
switch (_anchor_point) {
case StartOfIn:
_position = _in->first_frame();
break;
case EndOfIn:
_position = _in->last_frame() - _length;
break;
case EndOfOut:
_position = _out->last_frame() - _length;
}
/* UI's may need to know that the overlap changed even
though the xfade length did not.
*/
StateChanged (BoundsChanged); /* EMIT SIGNAL */
_in_update = false;
return true;
}
void
Crossfade::member_changed (Change what_changed)
{
@ -603,7 +607,15 @@ Crossfade::member_changed (Change what_changed)
BoundsChanged);
if (what_changed & what_we_care_about) {
refresh ();
try {
if (what_changed & what_we_care_about) {
refresh ();
}
}
catch (NoCrossfadeHere& err) {
// relax, Invalidated inside refresh()
}
}
}

View file

@ -1695,6 +1695,7 @@ Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region>
region->set_layer (target_layer);
#if 0
/* now check all dependents */
for (list<LayerInfo>::iterator x = layerinfo.begin(); x != layerinfo.end(); ++x) {
@ -1702,6 +1703,7 @@ Playlist::move_region_to_layer (layer_t target_layer, boost::shared_ptr<Region>
}
check_dependents (region, false);
#endif
return 0;
}