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; set<boost::shared_ptr<Playlist> > affected_playlists;
pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result; 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) { for (list<RegionView*>::const_iterator i = selection->regions.by_layer().begin(); i != selection->regions.by_layer().end(); ++i) {
RegionView* rv; RegionView* rv;
@ -3227,7 +3226,7 @@ Editor::region_drag_motion_callback (ArdourCanvas::Item* item, GdkEvent* event)
/* hide any dependent views */ /* 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, /* this is subtle. raising the regionview itself won't help,
because raise_to_top() just puts the item on the top of 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; AnchorPoint _anchor_point;
bool _follow_overlap; bool _follow_overlap;
bool _fixed; bool _fixed;
int32_t layer_relation;
Curve _fade_in; Curve _fade_in;
Curve _fade_out; Curve _fade_out;
@ -165,7 +166,7 @@ class Crossfade : public PBD::StatefulDestructible, public boost::enable_shared_
void initialize (); void initialize ();
int compute (boost::shared_ptr<ARDOUR::AudioRegion>, boost::shared_ptr<ARDOUR::AudioRegion>, CrossfadeModel); int compute (boost::shared_ptr<ARDOUR::AudioRegion>, boost::shared_ptr<ARDOUR::AudioRegion>, CrossfadeModel);
bool update (bool force); bool update ();
void member_changed (ARDOUR::Change); void member_changed (ARDOUR::Change);
}; };

View file

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

View file

@ -89,8 +89,6 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<Audio
_follow_overlap = false; _follow_overlap = false;
cerr << "A: follow overlap = " << _follow_overlap << endl;
_active = Config->get_xfades_active (); _active = Config->get_xfades_active ();
_fixed = true; _fixed = true;
@ -111,8 +109,6 @@ Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioR
_active = act; _active = act;
initialize (); initialize ();
cerr << "K: follow overlap = " << _follow_overlap << endl;
} }
Crossfade::Crossfade (const Playlist& playlist, XMLNode& node) Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
@ -167,9 +163,6 @@ Crossfade::Crossfade (const Playlist& playlist, XMLNode& node)
if (set_state (node)) { if (set_state (node)) {
throw failed_constructor(); 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) 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 (); _in->suspend_fade_in ();
overlap_type = _in->coverage (_out->position(), _out->last_frame()); 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 // Let's make sure the fade isn't too long
set_length(_length); set_length(_length);
cerr << "B: follow overlap = " << _follow_overlap << endl;
} }
Crossfade::~Crossfade () Crossfade::~Crossfade ()
{ {
cerr << this << " Crossfade deleted\n";
notify_callbacks (); notify_callbacks ();
} }
@ -237,10 +227,210 @@ Crossfade::initialize ()
_fade_in.add (_length, 1.0); _fade_in.add (_length, 1.0);
_fade_in.thaw (); _fade_in.thaw ();
_in->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)); // _out->StateChanged.connect (sigc::mem_fun (*this, &Crossfade::member_changed));
overlap_type = _in->coverage (_out->position(), _out->last_frame()); 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 int
@ -409,192 +599,6 @@ Crossfade::compute (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioReg
return 0; 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 void
Crossfade::member_changed (Change what_changed) Crossfade::member_changed (Change what_changed)
{ {
@ -602,11 +606,19 @@ Crossfade::member_changed (Change what_changed)
Region::LayerChanged| Region::LayerChanged|
BoundsChanged); BoundsChanged);
if (what_changed & what_we_care_about) {
try {
if (what_changed & what_we_care_about) { if (what_changed & what_we_care_about) {
refresh (); refresh ();
} }
} }
catch (NoCrossfadeHere& err) {
// relax, Invalidated inside refresh()
}
}
}
XMLNode& XMLNode&
Crossfade::get_state () Crossfade::get_state ()
{ {

View file

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