/*
- Copyright (C) 2003 Paul Davis
+ Copyright (C) 2003-2006 Paul Davis
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
using namespace std;
using namespace ARDOUR;
-//using namespace sigc;
+using namespace PBD;
-jack_nframes_t Crossfade::_short_xfade_length = 0;
-Change Crossfade::ActiveChanged = ARDOUR::new_change();
+nframes_t Crossfade::_short_xfade_length = 0;
+Change Crossfade::ActiveChanged = new_change();
+Change Crossfade::FollowOverlapChanged = new_change();
/* XXX if and when we ever implement parallel processing of the process()
callback, these will need to be handled on a per-thread basis.
Sample* Crossfade::crossfade_buffer_in = 0;
void
-Crossfade::set_buffer_size (jack_nframes_t sz)
+Crossfade::set_buffer_size (nframes_t sz)
{
if (crossfade_buffer_out) {
delete [] crossfade_buffer_out;
return (_in == other._in) && (_out == other._out);
}
-Crossfade::Crossfade (ARDOUR::AudioRegion& in, ARDOUR::AudioRegion& out,
- jack_nframes_t length,
- jack_nframes_t position,
+Crossfade::Crossfade (boost::shared_ptr<AudioRegion> in, boost::shared_ptr<AudioRegion> out,
+ nframes_t length,
+ nframes_t position,
AnchorPoint ap)
: _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
- _in = ∈
- _out = &out;
+ _in = in;
+ _out = out;
_length = length;
_position = position;
_anchor_point = ap;
- _follow_overlap = false;
- _active = true;
+
+ switch (Config->get_xfade_model()) {
+ case ShortCrossfade:
+ _follow_overlap = false;
+ break;
+ default:
+ _follow_overlap = true;
+ }
+
+ _active = Config->get_xfades_active ();
_fixed = true;
initialize ();
}
-Crossfade::Crossfade (ARDOUR::AudioRegion& a, ARDOUR::AudioRegion& b, CrossfadeModel model, bool act)
+Crossfade::Crossfade (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model, bool act)
: _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
: _fade_in (0.0, 2.0, 1.0), // linear (gain coefficient) => -inf..+6dB
_fade_out (0.0, 2.0, 1.0) // linear (gain coefficient) => -inf..+6dB
{
- Region* r;
+ boost::shared_ptr<Region> r;
XMLProperty* prop;
- id_t id;
LocaleGuard lg (X_("POSIX"));
/* we have to find the in/out regions before we can do anything else */
throw failed_constructor();
}
- sscanf (prop->value().c_str(), "%llu", &id);
+ PBD::ID id (prop->value());
if ((r = playlist.find_region (id)) == 0) {
- error << compose (_("Crossfade: no \"in\" region %1 found in playlist %2"), id, playlist.name())
+ error << string_compose (_("Crossfade: no \"in\" region %1 found in playlist %2"), id, playlist.name())
<< endmsg;
throw failed_constructor();
}
- if ((_in = dynamic_cast<AudioRegion*> (r)) == 0) {
+ if ((_in = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
throw failed_constructor();
}
throw failed_constructor();
}
- sscanf (prop->value().c_str(), "%llu", &id);
+ PBD::ID id2 (prop->value());
- if ((r = playlist.find_region (id)) == 0) {
- error << compose (_("Crossfade: no \"out\" region %1 found in playlist %2"), id, playlist.name())
+ if ((r = playlist.find_region (id2)) == 0) {
+ error << string_compose (_("Crossfade: no \"out\" region %1 found in playlist %2"), id2, playlist.name())
<< endmsg;
throw failed_constructor();
}
-
- if ((_out = dynamic_cast<AudioRegion*> (r)) == 0) {
+
+ if ((_out = boost::dynamic_pointer_cast<AudioRegion> (r)) == 0) {
throw failed_constructor();
}
_length = 0;
+ _active = Config->get_xfades_active();
+
initialize();
if (set_state (node)) {
}
}
+Crossfade::Crossfade (const Crossfade &orig, boost::shared_ptr<AudioRegion> newin, boost::shared_ptr<AudioRegion> newout)
+ : _fade_in(orig._fade_in),
+ _fade_out(orig._fade_out)
+{
+ _active = orig._active;
+ _in_update = orig._in_update;
+ _length = orig._length;
+ _position = orig._position;
+ _anchor_point = orig._anchor_point;
+ _follow_overlap = orig._follow_overlap;
+ _fixed = orig._fixed;
+
+ _in = newin;
+ _out = newout;
+
+ // copied from Crossfade::initialize()
+ _in_update = false;
+
+ _out->suspend_fade_out ();
+ _in->suspend_fade_in ();
+
+ overlap_type = _in->coverage (_out->position(), _out->last_frame());
+
+ // Let's make sure the fade isn't too long
+ set_length(_length);
+}
+
+
Crossfade::~Crossfade ()
{
- for (StateMap::iterator i = states.begin(); i != states.end(); ++i) {
- delete *i;
- }
+ Invalidated (this);
}
void
_fade_in.add (_length, 1.0);
_fade_in.thaw ();
-// _in->StateChanged.connect (slot (*this, &Crossfade::member_changed));
-// _out->StateChanged.connect (slot (*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());
-
- save_state ("initial");
}
int
-Crossfade::compute (AudioRegion& a, AudioRegion& b, CrossfadeModel model)
+Crossfade::compute (boost::shared_ptr<AudioRegion> a, boost::shared_ptr<AudioRegion> b, CrossfadeModel model)
{
- AudioRegion* top;
- AudioRegion* bottom;
- jack_nframes_t short_xfade_length;
+ boost::shared_ptr<AudioRegion> top;
+ boost::shared_ptr<AudioRegion> bottom;
+ nframes_t short_xfade_length;
short_xfade_length = _short_xfade_length;
- if (a.layer() < b.layer()) {
- top = &b;
- bottom = &a;
+ if (a->layer() < b->layer()) {
+ top = b;
+ bottom = a;
} else {
- top = &a;
- bottom = &b;
+ top = a;
+ bottom = b;
}
/* first check for matching ends */
return 0;
}
-jack_nframes_t
+nframes_t
Crossfade::read_at (Sample *buf, Sample *mixdown_buffer,
- float *gain_buffer, jack_nframes_t start, jack_nframes_t cnt, uint32_t chan_n,
- jack_nframes_t read_frames, jack_nframes_t skip_frames)
+ float *gain_buffer, nframes_t start, nframes_t cnt, uint32_t chan_n,
+ nframes_t read_frames, nframes_t skip_frames)
{
- jack_nframes_t offset;
- jack_nframes_t to_write;
+ nframes_t offset;
+ nframes_t to_write;
if (!_active) {
return 0;
position and length, and so we know precisely how much data they could return.
*/
- for (jack_nframes_t n = 0; n < to_write; ++n) {
+ for (nframes_t n = 0; n < to_write; ++n) {
buf[n] = (crossfade_buffer_out[n] * fov[n]) + (crossfade_buffer_in[n] * fiv[n]);
}
}
OverlapType
-Crossfade::coverage (jack_nframes_t start, jack_nframes_t end) const
+Crossfade::coverage (nframes_t start, nframes_t end) const
{
- jack_nframes_t my_end = _position + _length;
+ nframes_t my_end = _position + _length;
if ((start >= _position) && (end <= my_end)) {
return OverlapInternal;
{
if (_active != yn) {
_active = yn;
- save_state (_("active changed"));
- send_state_changed (ActiveChanged);
+ StateChanged (ActiveChanged);
}
}
bool
Crossfade::update (bool force)
{
- jack_nframes_t newlen;
- bool save = false;
+ nframes_t newlen;
if (_follow_overlap) {
newlen = _out->first_frame() + _out->length() - _in->first_frame();
_length = newlen;
- save = true;
-
}
switch (_anchor_point) {
case StartOfIn:
if (_position != _in->first_frame()) {
_position = _in->first_frame();
- save = true;
}
break;
case EndOfIn:
if (_position != _in->last_frame() - _length) {
_position = _in->last_frame() - _length;
- save = true;
}
break;
case EndOfOut:
if (_position != _out->last_frame() - _length) {
_position = _out->last_frame() - _length;
- save = true;
}
}
- if (save) {
- save_state ("updated");
- }
-
/* UI's may need to know that the overlap changed even
though the xfade length did not.
*/
- send_state_changed (BoundsChanged); /* EMIT SIGNAL */
+ StateChanged (BoundsChanged); /* EMIT SIGNAL */
_in_update = false;
{
Change what_we_care_about = Change (Region::MuteChanged|
Region::LayerChanged|
- ARDOUR::BoundsChanged);
+ BoundsChanged);
if (what_changed & what_we_care_about) {
refresh ();
}
}
-Change
-Crossfade::restore_state (StateManager::State& state)
-{
- CrossfadeState* xfstate = dynamic_cast<CrossfadeState*> (&state);
- Change what_changed = Change (0);
-
- _in_update = true;
-
- xfstate->fade_in_memento ();
- xfstate->fade_out_memento ();
-
- if (_length != xfstate->length) {
- what_changed = Change (what_changed|LengthChanged);
- _length = xfstate->length;
- }
- if (_active != xfstate->active) {
- what_changed = Change (what_changed|ActiveChanged);
- _active = xfstate->active;
- }
- if (_position != xfstate->position) {
- what_changed = Change (what_changed|PositionChanged);
- _position = xfstate->position;
- }
-
- /* XXX what to do about notifications for these? I don't
- think (G)UI cares about them because they are
- implicit in the bounds.
- */
-
- _follow_overlap = xfstate->follow_overlap;
- _anchor_point = xfstate->anchor_point;
-
- _in_update = false;
-
- return Change (what_changed);
-}
-
-StateManager::State*
-Crossfade::state_factory (std::string why) const
-{
- CrossfadeState* state = new CrossfadeState (why);
-
- state->fade_in_memento = _fade_in.get_memento ();
- state->fade_out_memento = _fade_out.get_memento ();
- state->active = _active;
- state->length = _length;
- state->position = _position;
- state->follow_overlap = _follow_overlap;
- state->anchor_point = _anchor_point;
-
- return state;
-}
-
-UndoAction
-Crossfade::get_memento() const
-{
- return sigc::bind (mem_fun (*(const_cast<Crossfade *> (this)), &StateManager::use_state), _current_state_id);
-}
-
XMLNode&
Crossfade::get_state ()
{
char buf[64];
LocaleGuard lg (X_("POSIX"));
- snprintf (buf, sizeof(buf), "%" PRIu64, _out->id());
+ _out->id().print (buf, sizeof (buf));
node->add_property ("out", buf);
- snprintf (buf, sizeof(buf), "%" PRIu64, _in->id());
+ _in->id().print (buf, sizeof (buf));
node->add_property ("in", buf);
node->add_property ("active", (_active ? "yes" : "no"));
node->add_property ("follow-overlap", (_follow_overlap ? "yes" : "no"));
pnode = new XMLNode ("point");
- snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when));
+ snprintf (buf, sizeof (buf), "%" PRIu32, (nframes_t) floor ((*ii)->when));
pnode->add_property ("x", buf);
- snprintf (buf, sizeof (buf), "%f", (*ii)->value);
+ snprintf (buf, sizeof (buf), "%.12g", (*ii)->value);
pnode->add_property ("y", buf);
child->add_child_nocopy (*pnode);
}
pnode = new XMLNode ("point");
- snprintf (buf, sizeof (buf), "%" PRIu32, (jack_nframes_t) floor ((*ii)->when));
+ snprintf (buf, sizeof (buf), "%" PRIu32, (nframes_t) floor ((*ii)->when));
pnode->add_property ("x", buf);
- snprintf (buf, sizeof (buf), "%f", (*ii)->value);
+ snprintf (buf, sizeof (buf), "%.12g", (*ii)->value);
pnode->add_property ("y", buf);
child->add_child_nocopy (*pnode);
}
XMLNode* fo;
const XMLProperty* prop;
LocaleGuard lg (X_("POSIX"));
+ Change what_changed = Change (0);
+ nframes_t val;
if ((prop = node.property ("position")) != 0) {
- _position = atoi (prop->value().c_str());
+ sscanf (prop->value().c_str(), "%" PRIu32, &val);
+ if (val != _position) {
+ _position = val;
+ what_changed = Change (what_changed | PositionChanged);
+ }
} else {
warning << _("old-style crossfade information - no position information") << endmsg;
_position = _in->first_frame();
}
if ((prop = node.property ("active")) != 0) {
- _active = (prop->value() == "yes");
+ bool x = (prop->value() == "yes");
+ if (x != _active) {
+ _active = x;
+ what_changed = Change (what_changed | ActiveChanged);
+ }
} else {
_active = true;
}
if ((prop = node.property ("length")) != 0) {
- _length = atol (prop->value().c_str());
+ sscanf (prop->value().c_str(), "%" PRIu32, &val);
+ if (val != _length) {
+ _length = atol (prop->value().c_str());
+ what_changed = Change (what_changed | LengthChanged);
+ }
} else {
/* fade in */
+ _fade_in.freeze ();
_fade_in.clear ();
children = fi->children();
for (i = children.begin(); i != children.end(); ++i) {
if ((*i)->name() == "point") {
- jack_nframes_t x;
+ nframes_t x;
float y;
prop = (*i)->property ("x");
_fade_in.add (x, y);
}
}
+
+ _fade_in.thaw ();
/* fade out */
+ _fade_in.freeze ();
_fade_out.clear ();
children = fo->children();
for (i = children.begin(); i != children.end(); ++i) {
if ((*i)->name() == "point") {
- jack_nframes_t x;
+ nframes_t x;
float y;
XMLProperty* prop;
}
}
+ _fade_out.thaw ();
+
+ StateChanged (what_changed); /* EMIT SIGNAL */
+
return 0;
}
} else {
set_length (_out->first_frame() + _out->length() - _in->first_frame());
}
+
+ StateChanged (FollowOverlapChanged);
}
-jack_nframes_t
-Crossfade::set_length (jack_nframes_t len)
+nframes_t
+Crossfade::set_length (nframes_t len)
{
- jack_nframes_t limit;
+ nframes_t limit;
switch (_anchor_point) {
case StartOfIn:
_length = len;
- save_state ("length changed");
-
- send_state_changed (LengthChanged);
+ StateChanged (LengthChanged);
return len;
}
-jack_nframes_t
+nframes_t
Crossfade::overlap_length () const
{
if (_fixed) {
}
void
-Crossfade::set_short_xfade_length (jack_nframes_t n)
+Crossfade::set_short_xfade_length (nframes_t n)
{
_short_xfade_length = n;
}
+
+void
+Crossfade::invalidate ()
+{
+ Invalidated (this); /* EMIT SIGNAL */
+}