X-Git-Url: https://main.carlh.net/gitweb/?a=blobdiff_plain;f=libs%2Fardour%2Fpanner.cc;h=73326e12a4537cd82214eb7ce13a40dd57731535;hb=1aadfeba45e943123b6577bfca4635892be0d9e1;hp=0c3b0a291f8296cee94084bad6ad3c22f9ccde22;hpb=7bd41538d951c3e476655df741adfbebbb990bde;p=ardour.git diff --git a/libs/ardour/panner.cc b/libs/ardour/panner.cc index 0c3b0a291f..73326e12a4 100644 --- a/libs/ardour/panner.cc +++ b/libs/ardour/panner.cc @@ -15,9 +15,11 @@ along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - $Id$ */ +#define __STDC_FORMAT_MACROS 1 +#include + #include #include #include @@ -30,20 +32,25 @@ #include -#include -#include -#include +#include "pbd/error.h" +#include "pbd/failed_constructor.h" +#include "pbd/xml++.h" +#include "pbd/enumwriter.h" + +#include "evoral/Curve.hpp" -#include -#include -#include +#include "ardour/session.h" +#include "ardour/panner.h" +#include "ardour/utils.h" +#include "ardour/audio_buffer.h" -#include -#include +#include "ardour/runtime_functions.h" +#include "ardour/buffer_set.h" +#include "ardour/audio_buffer.h" #include "i18n.h" -#include +#include "pbd/mathfix.h" using namespace std; using namespace ARDOUR; @@ -62,16 +69,20 @@ static pan_t direct_control_to_pan (double fract) { return fract; } -static double direct_pan_to_control (pan_t val) { - return val; -} -StreamPanner::StreamPanner (Panner& p) - : parent (p), - _control (*this) +//static double direct_pan_to_control (pan_t val) { +// return val; +//} + +StreamPanner::StreamPanner (Panner& p, Evoral::Parameter param) + : parent (p) { + assert(param.type() != NullAutomation); + _muted = false; + _control = boost::dynamic_pointer_cast( parent.control( param, true ) ); + x = 0.5; y = 0.5; z = 0.5; @@ -82,29 +93,16 @@ StreamPanner::~StreamPanner () } void -StreamPanner::PanControllable::set_value (float val) +Panner::PanControllable::set_value (float val) { - panner.set_position (direct_control_to_pan (val)); + panner.streampanner(parameter().id()).set_position (direct_control_to_pan (val)); + AutomationControl::set_value(val); } float -StreamPanner::PanControllable::get_value (void) const +Panner::PanControllable::get_value (void) const { - float xpos; - panner.get_effective_position (xpos); - return direct_pan_to_control (xpos); -} - -bool -StreamPanner::PanControllable::can_send_feedback () const -{ - AutoState astate = panner.get_parent().automation_state (); - - if ((astate == Play) || (astate == Touch && !panner.get_parent().touching())) { - return true; - } - - return false; + return AutomationControl::get_value(); } void @@ -127,7 +125,7 @@ StreamPanner::set_position (float xpos, bool link_call) x = xpos; update (); Changed (); - _control.Changed (); + _control->Changed (); } } @@ -184,8 +182,8 @@ StreamPanner::add_state (XMLNode& node) /*---------------------------------------------------------------------- */ -BaseStereoPanner::BaseStereoPanner (Panner& p) - : StreamPanner (p), _automation (0.0, 1.0, 0.5) +BaseStereoPanner::BaseStereoPanner (Panner& p, Evoral::Parameter param) + : StreamPanner (p, param) { } @@ -193,81 +191,16 @@ BaseStereoPanner::~BaseStereoPanner () { } -void -BaseStereoPanner::snapshot (jack_nframes_t now) -{ - if (_automation.automation_state() == Write || _automation.automation_state() == Touch) { - _automation.rt_add (now, x); - } -} - -void -BaseStereoPanner::transport_stopped (jack_nframes_t frame) -{ - _automation.reposition_for_rt_add (frame); - - if (_automation.automation_state() != Off) { - - if (_automation.automation_write()) { - _automation.save_state (_("automation write pass")); - } - - set_position (_automation.eval (frame)); - } -} - -void -BaseStereoPanner::set_automation_style (AutoStyle style) -{ - _automation.set_automation_style (style); -} - -void -BaseStereoPanner::set_automation_state (AutoState state) -{ - if (state != _automation.automation_state()) { - - _automation.set_automation_state (state); - - if (state != Off) { - set_position (_automation.eval (parent.session().transport_frame())); - } - } -} - -int -BaseStereoPanner::save (ostream& out) const -{ - LocaleGuard lg (X_("POSIX")); - - /* force a single format for numeric data to ease session interchange - across national boundaries. - */ - - out << "begin" << endl; - - for (AutomationList::const_iterator i = _automation.const_begin(); i != _automation.const_end(); ++i) { - out << '\t' << (jack_nframes_t) floor ((*i)->when) << ' ' << (*i)->value << endl; - if (!out) { - error << string_compose (_("error writing pan automation file (%s)"), strerror (errno)) << endmsg; - return -1; - } - } - out << "end" << endl; - - return 0; -} - int BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) { char line[128]; LocaleGuard lg (X_("POSIX")); - _automation.clear (); + _control->list()->clear (); while (in.getline (line, sizeof (line), '\n')) { - jack_nframes_t when; + nframes_t when; double value; ++linecnt; @@ -281,21 +214,20 @@ BaseStereoPanner::load (istream& in, string path, uint32_t& linecnt) continue; } - _automation.add (when, value, true); + _control->list()->fast_simple_add (when, value); } /* now that we are done loading */ - _automation.save_state (_("loaded from disk")); - _automation.StateChanged (Change (0)); + ((AutomationList*)_control->list().get())->StateChanged (); return 0; } void -BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, jack_nframes_t nframes) +BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) { - assert(obufs.count().get(DataType::AUDIO) == 2); + assert(obufs.count().n_audio() == 2); pan_t delta; Sample* dst; @@ -305,18 +237,18 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain return; } - Sample* const src = srcbuf.data(nframes); + Sample* const src = srcbuf.data(); /* LEFT */ - dst = obufs.get_audio(0).data(nframes); + dst = obufs.get_audio(0).data(); if (fabsf ((delta = (left - desired_left))) > 0.002) { // about 1 degree of arc /* interpolate over 64 frames or nframes, whichever is smaller */ - jack_nframes_t limit = min ((jack_nframes_t)64, nframes); - jack_nframes_t n; + nframes_t limit = min ((nframes_t)64, nframes); + nframes_t n; delta = -(delta / (float) (limit)); @@ -328,7 +260,7 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain pan = left * gain_coeff; - Session::mix_buffers_with_gain(dst+n,src+n,nframes-n,pan); + mix_buffers_with_gain (dst+n,src+n,nframes-n,pan); } else { @@ -339,7 +271,7 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain if (pan != 0.0f) { - Session::mix_buffers_with_gain(dst,src,nframes,pan); + mix_buffers_with_gain(dst,src,nframes,pan); /* mark that we wrote into the buffer */ @@ -349,7 +281,7 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain } else { - Session::mix_buffers_no_gain(dst,src,nframes); + mix_buffers_no_gain(dst,src,nframes); /* mark that we wrote into the buffer */ @@ -359,14 +291,14 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain /* RIGHT */ - dst = obufs.get_audio(1).data(nframes); + dst = obufs.get_audio(1).data(); if (fabsf ((delta = (right - desired_right))) > 0.002) { // about 1 degree of arc /* interpolate over 64 frames or nframes, whichever is smaller */ - jack_nframes_t limit = min ((jack_nframes_t)64, nframes); - jack_nframes_t n; + nframes_t limit = min ((nframes_t)64, nframes); + nframes_t n; delta = -(delta / (float) (limit)); @@ -378,7 +310,7 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain pan = right * gain_coeff; - Session::mix_buffers_with_gain(dst+n,src+n,nframes-n,pan); + mix_buffers_with_gain(dst+n,src+n,nframes-n,pan); /* XXX it would be nice to mark the buffer as written to */ @@ -391,14 +323,14 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain if (pan != 0.0f) { - Session::mix_buffers_with_gain(dst,src,nframes,pan); + mix_buffers_with_gain(dst,src,nframes,pan); /* XXX it would be nice to mark the buffer as written to */ } } else { - Session::mix_buffers_no_gain(dst,src,nframes); + mix_buffers_no_gain(dst,src,nframes); /* XXX it would be nice to mark the buffer as written to */ } @@ -407,8 +339,8 @@ BaseStereoPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain /*---------------------------------------------------------------------- */ -EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p) - : BaseStereoPanner (p) +EqualPowerStereoPanner::EqualPowerStereoPanner (Panner& p, Evoral::Parameter param) + : BaseStereoPanner (p, param) { update (); @@ -447,22 +379,23 @@ EqualPowerStereoPanner::update () desired_right = panR * (scale * panR + 1.0f - scale); effective_x = x; + //_control->set_value(x); } void EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& obufs, - jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, + nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers) { - assert(obufs.count().get(DataType::AUDIO) == 2); + assert(obufs.count().n_audio() == 2); Sample* dst; pan_t* pbuf; - Sample* const src = srcbuf.data(nframes); + Sample* const src = srcbuf.data(); /* fetch positional data */ - if (!_automation.rt_safe_get_vector (start, end, buffers[0], nframes)) { + if (!_control->list()->curve().rt_safe_get_vector (start, end, buffers[0], nframes)) { /* fallback */ if (!_muted) { distribute (srcbuf, obufs, 1.0, nframes); @@ -472,8 +405,9 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob /* store effective pan position. do this even if we are muted */ - if (nframes > 0) + if (nframes > 0) { effective_x = buffers[0][nframes-1]; + } if (_muted) { return; @@ -486,7 +420,7 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob const float pan_law_attenuation = -3.0f; const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f); - for (jack_nframes_t n = 0; n < nframes; ++n) { + for (nframes_t n = 0; n < nframes; ++n) { float panR = buffers[0][n]; float panL = 1 - panR; @@ -497,10 +431,10 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob /* LEFT */ - dst = obufs.get_audio(0).data(nframes); + dst = obufs.get_audio(0).data(); pbuf = buffers[0]; - for (jack_nframes_t n = 0; n < nframes; ++n) { + for (nframes_t n = 0; n < nframes; ++n) { dst[n] += src[n] * pbuf[n]; } @@ -508,10 +442,10 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob /* RIGHT */ - dst = obufs.get_audio(1).data(nframes); + dst = obufs.get_audio(1).data(); pbuf = buffers[1]; - for (jack_nframes_t n = 0; n < nframes; ++n) { + for (nframes_t n = 0; n < nframes; ++n) { dst[n] += src[n] * pbuf[n]; } @@ -519,9 +453,9 @@ EqualPowerStereoPanner::distribute_automated (AudioBuffer& srcbuf, BufferSet& ob } StreamPanner* -EqualPowerStereoPanner::factory (Panner& parent) +EqualPowerStereoPanner::factory (Panner& parent, Evoral::Parameter param) { - return new EqualPowerStereoPanner (parent); + return new EqualPowerStereoPanner (parent, param); } XMLNode& @@ -540,18 +474,13 @@ EqualPowerStereoPanner::state (bool full_state) snprintf (buf, sizeof (buf), "%.12g", x); root->add_property (X_("x"), buf); root->add_property (X_("type"), EqualPowerStereoPanner::name); - if (full_state) { - snprintf (buf, sizeof (buf), "0x%x", _automation.automation_state()); - } else { - /* never store automation states other than off in a template */ - snprintf (buf, sizeof (buf), "0x%x", ARDOUR::Off); - } - root->add_property (X_("automation-state"), buf); - snprintf (buf, sizeof (buf), "0x%x", _automation.automation_style()); - root->add_property (X_("automation-style"), buf); + + // XXX: dont save automation here... its part of the automatable panner now. StreamPanner::add_state (*root); + root->add_child_nocopy (_control->get_state ()); + return *root; } @@ -559,7 +488,6 @@ int EqualPowerStereoPanner::set_state (const XMLNode& node) { const XMLProperty* prop; - int x; float pos; LocaleGuard lg (X_("POSIX")); @@ -568,29 +496,32 @@ EqualPowerStereoPanner::set_state (const XMLNode& node) set_position (pos, true); } - if ((prop = node.property (X_("automation-state")))) { - sscanf (prop->value().c_str(), "0x%x", &x); - _automation.set_automation_state ((AutoState) x); + StreamPanner::set_state (node); + + for (XMLNodeConstIterator iter = node.children().begin(); iter != node.children().end(); ++iter) { - if (x != Off) { - set_position (_automation.eval (parent.session().transport_frame())); - } - } + if ((*iter)->name() == X_("Controllable")) { + if ((prop = (*iter)->property("name")) != 0 && prop->value() == "panner") { + _control->set_state (**iter); + } + + } else if ((*iter)->name() == X_("Automation")) { - if ((prop = node.property (X_("automation-style")))) { - sscanf (prop->value().c_str(), "0x%x", &x); - _automation.set_automation_style ((AutoStyle) x); + _control->alist()->set_state (*((*iter)->children().front())); + + if (_control->alist()->automation_state() != Off) { + set_position (_control->list()->eval (parent.session().transport_frame())); + } + } } - StreamPanner::set_state (node); - return 0; } /*----------------------------------------------------------------------*/ -Multi2dPanner::Multi2dPanner (Panner& p) - : StreamPanner (p), _automation (0.0, 1.0, 0.5) // XXX useless +Multi2dPanner::Multi2dPanner (Panner& p, Evoral::Parameter param) + : StreamPanner (p, param) { update (); } @@ -599,30 +530,6 @@ Multi2dPanner::~Multi2dPanner () { } -void -Multi2dPanner::snapshot (jack_nframes_t now) -{ - // how? -} - -void -Multi2dPanner::transport_stopped (jack_nframes_t frame) -{ - //what? -} - -void -Multi2dPanner::set_automation_style (AutoStyle style) -{ - //what? -} - -void -Multi2dPanner::set_automation_state (AutoState state) -{ - // what? -} - void Multi2dPanner::update () { @@ -656,7 +563,7 @@ Multi2dPanner::update () } void -Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, jack_nframes_t nframes) +Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_coeff, nframes_t nframes) { Sample* dst; pan_t pan; @@ -667,20 +574,20 @@ Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co return; } - Sample* const src = srcbuf.data(nframes); + Sample* const src = srcbuf.data(); for (n = 0, o = parent.outputs.begin(); o != parent.outputs.end(); ++o, ++n) { - dst = obufs.get_audio(n).data(nframes); + dst = obufs.get_audio(n).data(); #ifdef CAN_INTERP if (fabsf ((delta = (left_interp - desired_left))) > 0.002) { // about 1 degree of arc /* interpolate over 64 frames or nframes, whichever is smaller */ - jack_nframes_t limit = min ((jack_nframes_t)64, nframes); - jack_nframes_t n; + nframes_t limit = min ((nframes_t)64, nframes); + nframes_t n; delta = -(delta / (float) (limit)); @@ -691,10 +598,7 @@ Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co } pan = left * gain_coeff; - - for (; n < nframes; ++n) { - dst[n] += src[n] * pan; - } + mix_buffers_with_gain(dst+n,src+n,nframes-n,pan); } else { @@ -704,20 +608,10 @@ Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co if ((pan *= gain_coeff) != 1.0f) { if (pan != 0.0f) { - - for (jack_nframes_t n = 0; n < nframes; ++n) { - dst[n] += src[n] * pan; - } - + mix_buffers_with_gain(dst,src,nframes,pan); } - - } else { - - for (jack_nframes_t n = 0; n < nframes; ++n) { - dst[n] += src[n]; - } - + mix_buffers_no_gain(dst,src,nframes); } #endif #ifdef CAN_INTERP @@ -730,7 +624,7 @@ Multi2dPanner::distribute (AudioBuffer& srcbuf, BufferSet& obufs, gain_t gain_co void Multi2dPanner::distribute_automated (AudioBuffer& src, BufferSet& obufs, - jack_nframes_t start, jack_nframes_t end, jack_nframes_t nframes, + nframes_t start, nframes_t end, nframes_t nframes, pan_t** buffers) { if (_muted) { @@ -743,9 +637,9 @@ Multi2dPanner::distribute_automated (AudioBuffer& src, BufferSet& obufs, } StreamPanner* -Multi2dPanner::factory (Panner& p) +Multi2dPanner::factory (Panner& p, Evoral::Parameter param) { - return new Multi2dPanner (p); + return new Multi2dPanner (p, param); } int @@ -754,12 +648,6 @@ Multi2dPanner::load (istream& in, string path, uint32_t& linecnt) return 0; } -int -Multi2dPanner::save (ostream& out) const -{ - return 0; -} - XMLNode& Multi2dPanner::get_state (void) { @@ -779,6 +667,8 @@ Multi2dPanner::state (bool full_state) root->add_property (X_("y"), buf); root->add_property (X_("type"), Multi2dPanner::name); + /* XXX no meaningful automation yet */ + return *root; } @@ -813,9 +703,11 @@ Multi2dPanner::set_state (const XMLNode& node) /*---------------------------------------------------------------------- */ Panner::Panner (string name, Session& s) - : _session (s) + : Processor(s, name) { + //set_name_old_auto (name); set_name (name); + _linked = false; _link_direction = SameDirection; _bypassed = false; @@ -845,16 +737,6 @@ Panner::set_link_direction (LinkDirection ld) } } -void -Panner::set_name (string str) -{ - automation_path = _session.automation_dir(); - automation_path += _session.snap_name(); - automation_path += "-pan-"; - automation_path += legalize_for_path (str); - automation_path += ".automation"; -} - void Panner::set_bypassed (bool yn) @@ -866,19 +748,98 @@ Panner::set_bypassed (bool yn) } +void +Panner::reset_to_default () +{ + vector positions; + + switch (outputs.size()) { + case 0: + case 1: + return; + } + + if (outputs.size() == 2) { + switch (_streampanners.size()) { + case 1: + _streampanners.front()->set_position (0.5); + _streampanners.front()->pan_control()->list()->reset_default (0.5); + return; + break; + case 2: + _streampanners.front()->set_position (0.0); + _streampanners.front()->pan_control()->list()->reset_default (0.0); + _streampanners.back()->set_position (1.0); + _streampanners.back()->pan_control()->list()->reset_default (1.0); + return; + default: + break; + } + } + + vector::iterator o; + vector::iterator p; + + for (o = outputs.begin(), p = _streampanners.begin(); o != outputs.end() && p != _streampanners.end(); ++o, ++p) { + (*p)->set_position ((*o).x, (*o).y); + } +} + +void +Panner::reset_streampanner (uint32_t which) +{ + if (which >= _streampanners.size() || which >= outputs.size()) { + return; + } + + switch (outputs.size()) { + case 0: + case 1: + return; + + case 2: + switch (_streampanners.size()) { + case 1: + /* stereo out, 1 stream, default = middle */ + _streampanners.front()->set_position (0.5); + _streampanners.front()->pan_control()->list()->reset_default (0.5); + break; + case 2: + /* stereo out, 2 streams, default = hard left/right */ + if (which == 0) { + _streampanners.front()->set_position (0.0); + _streampanners.front()->pan_control()->list()->reset_default (0.0); + } else { + _streampanners.back()->set_position (1.0); + _streampanners.back()->pan_control()->list()->reset_default (1.0); + } + break; + } + return; + + default: + _streampanners[which]->set_position (outputs[which].x, outputs[which].y); + } +} + void Panner::reset (uint32_t nouts, uint32_t npans) { uint32_t n; bool changed = false; + bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2)); + /* if new and old config don't need panning, or if + the config hasn't changed, we're done. + */ - if (nouts < 2 || (nouts == outputs.size() && npans == size())) { + if (do_not_and_did_not_need_panning || + ((nouts == outputs.size()) && (npans == _streampanners.size()))) { return; } - n = size(); - clear (); + n = _streampanners.size(); + clear_panners (); if (n != npans) { changed = true; @@ -891,24 +852,30 @@ Panner::reset (uint32_t nouts, uint32_t npans) changed = true; } + if (nouts < 2) { + /* no need for panning with less than 2 outputs */ + goto send_changed; + } + switch (nouts) { case 0: + /* XXX: this can never happen */ break; case 1: + /* XXX: this can never happen */ fatal << _("programming error:") << X_("Panner::reset() called with a single output") << endmsg; /*NOTREACHED*/ break; - case 2: - /* line */ + case 2: // line outputs.push_back (Output (0, 0)); outputs.push_back (Output (1.0, 0)); for (n = 0; n < npans; ++n) { - push_back (new EqualPowerStereoPanner (*this)); + _streampanners.push_back (new EqualPowerStereoPanner (*this, Evoral::Parameter(PanAutomation, 0, n))); } break; @@ -918,7 +885,7 @@ Panner::reset (uint32_t nouts, uint32_t npans) outputs.push_back (Output (1.0, 1.0)); for (n = 0; n < npans; ++n) { - push_back (new Multi2dPanner (*this)); + _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n))); } break; @@ -930,7 +897,7 @@ Panner::reset (uint32_t nouts, uint32_t npans) outputs.push_back (Output (0, 1.0)); for (n = 0; n < npans; ++n) { - push_back (new Multi2dPanner (*this)); + _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n))); } break; @@ -943,7 +910,7 @@ Panner::reset (uint32_t nouts, uint32_t npans) outputs.push_back (Output (0.5, 0.75)); for (n = 0; n < npans; ++n) { - push_back (new Multi2dPanner (*this)); + _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n))); } break; @@ -955,13 +922,13 @@ Panner::reset (uint32_t nouts, uint32_t npans) } for (n = 0; n < npans; ++n) { - push_back (new Multi2dPanner (*this)); + _streampanners.push_back (new Multi2dPanner (*this, Evoral::Parameter(PanAutomation, 0, n))); } break; } - for (iterator x = begin(); x != end(); ++x) { + for (std::vector::iterator x = _streampanners.begin(); x != _streampanners.end(); ++x) { (*x)->update (); } @@ -977,21 +944,22 @@ Panner::reset (uint32_t nouts, uint32_t npans) float left; float right; - front()->get_position (left); - back()->get_position (right); + _streampanners.front()->get_position (left); + _streampanners.back()->get_position (right); if (changed || ((left == 0.5) && (right == 0.5))) { - front()->set_position (0.0); - front()->automation().reset_default (0.0); + _streampanners.front()->set_position (0.0); + _streampanners.front()->pan_control()->list()->reset_default (0.0); - back()->set_position (1.0); - back()->automation().reset_default (1.0); + _streampanners.back()->set_position (1.0); + _streampanners.back()->pan_control()->list()->reset_default (1.0); changed = true; } } + send_changed: if (changed) { Changed (); /* EMIT SIGNAL */ } @@ -1003,29 +971,31 @@ void Panner::remove (uint32_t which) { vector::iterator i; - for (i = begin(); i != end() && which; ++i, --which); + for (i = _streampanners.begin(); i != _streampanners.end() && which; ++i, --which) {} - if (i != end()) { + if (i != _streampanners.end()) { delete *i; - erase (i); + _streampanners.erase (i); } } + +/** Remove all our StreamPanners */ void -Panner::clear () +Panner::clear_panners () { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { delete *i; } - vector::clear (); + _streampanners.clear (); } void Panner::set_automation_style (AutoStyle style) { - for (vector::iterator i = begin(); i != end(); ++i) { - (*i)->set_automation_style (style); + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { + ((AutomationList*)(*i)->pan_control()->list().get())->set_automation_style (style); } _session.set_dirty (); } @@ -1033,8 +1003,8 @@ Panner::set_automation_style (AutoStyle style) void Panner::set_automation_state (AutoState state) { - for (vector::iterator i = begin(); i != end(); ++i) { - (*i)->set_automation_state (state); + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { + ((AutomationList*)(*i)->pan_control()->list().get())->set_automation_state (state); } _session.set_dirty (); } @@ -1042,148 +1012,35 @@ Panner::set_automation_state (AutoState state) AutoState Panner::automation_state () const { + boost::shared_ptr l; if (!empty()) { - return front()->automation().automation_state (); - } else { - return Off; + boost::shared_ptr control = _streampanners.front()->pan_control(); + if (control) { + l = boost::dynamic_pointer_cast(control->list()); + } } + + return l ? l->automation_state() : Off; } AutoStyle Panner::automation_style () const { + boost::shared_ptr l; if (!empty()) { - return front()->automation().automation_style (); - } else { - return Absolute; - } -} - -void -Panner::transport_stopped (jack_nframes_t frame) -{ - for (vector::iterator i = begin(); i != end(); ++i) { - (*i)->transport_stopped (frame); - } -} - -void -Panner::snapshot (jack_nframes_t now) -{ - for (vector::iterator i = begin(); i != end(); ++i) { - (*i)->snapshot (now); - } -} - -void -Panner::clear_automation () -{ - for (vector::iterator i = begin(); i != end(); ++i) { - (*i)->automation().clear (); - } - _session.set_dirty (); -} - -int -Panner::save () const -{ - ofstream out (automation_path.c_str()); - - if (!out) { - error << string_compose (_("cannot open pan automation file \"%1\" for saving (%2)"), automation_path, strerror (errno)) - << endmsg; - return -1; - } - - out << X_("version ") << current_automation_version_number << endl; - - for (vector::const_iterator i = begin(); i != end(); ++i) { - if ((*i)->save (out)) { - return -1; - } - } - - return 0; -} - -int -Panner::load () -{ - char line[128]; - uint32_t linecnt = 0; - float version; - iterator sp; - LocaleGuard lg (X_("POSIX")); - - if (automation_path.length() == 0) { - return 0; - } - - if (access (automation_path.c_str(), F_OK)) { - return 0; - } - - ifstream in (automation_path.c_str()); - - if (!in) { - error << string_compose (_("cannot open pan automation file %1 (%2)"), - automation_path, strerror (errno)) - << endmsg; - return -1; - } - - sp = begin(); - - while (in.getline (line, sizeof(line), '\n')) { - - if (++linecnt == 1) { - if (memcmp (line, X_("version"), 7) == 0) { - if (sscanf (line, "version %f", &version) != 1) { - error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg; - return -1; - } - } else { - error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"), - automation_path, line) << endmsg; - return -1; - } - - if (version != current_automation_version_number) { - error << string_compose(_("mismatched pan automation event file version (%1)"), version) << endmsg; - return -1; - } - - continue; - } - - if (strlen (line) == 0 || line[0] == '#') { - continue; - } - - if (strcmp (line, "begin") == 0) { - - if (sp == end()) { - error << string_compose (_("too many panner states found in pan automation file %1"), - automation_path) - << endmsg; - return -1; - } - - if ((*sp)->load (in, automation_path, linecnt)) { - return -1; - } - - ++sp; + boost::shared_ptr control = _streampanners.front()->pan_control(); + if (control) { + l = boost::dynamic_pointer_cast(control->list()); } } - return 0; + return l ? l->automation_style() : Absolute; } struct PanPlugins { string name; uint32_t nouts; - StreamPanner* (*factory)(Panner&); + StreamPanner* (*factory)(Panner&, Evoral::Parameter); }; PanPlugins pan_plugins[] = { @@ -1201,19 +1058,15 @@ Panner::get_state (void) XMLNode& Panner::state (bool full) { - XMLNode* root = new XMLNode (X_("Panner")); - char buf[32]; + XMLNode& node = Processor::state(full); - for (iterator p = begin(); p != end(); ++p) { - root->add_child_nocopy ((*p)->state (full)); - } + node.add_property ("type", "panner"); - root->add_property (X_("linked"), (_linked ? "yes" : "no")); - snprintf (buf, sizeof (buf), "%d", _link_direction); - root->add_property (X_("link_direction"), buf); - root->add_property (X_("bypassed"), (bypassed() ? "yes" : "no")); + char buf[32]; - /* add each output */ + node.add_property (X_("linked"), (_linked ? "yes" : "no")); + node.add_property (X_("link_direction"), enum_2_string (_link_direction)); + node.add_property (X_("bypassed"), (bypassed() ? "yes" : "no")); for (vector::iterator o = outputs.begin(); o != outputs.end(); ++o) { XMLNode* onode = new XMLNode (X_("Output")); @@ -1221,16 +1074,15 @@ Panner::state (bool full) onode->add_property (X_("x"), buf); snprintf (buf, sizeof (buf), "%.12g", (*o).y); onode->add_property (X_("y"), buf); - root->add_child_nocopy (*onode); + node.add_child_nocopy (*onode); } - if (full) { - if (save () == 0) { - root->add_property (X_("automation"), Glib::path_get_basename (automation_path)); - } + for (vector::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { + node.add_child_nocopy ((*i)->state (full)); } - return *root; + + return node; } int @@ -1240,10 +1092,18 @@ Panner::set_state (const XMLNode& node) XMLNodeConstIterator niter; const XMLProperty *prop; uint32_t i; + uint32_t num_panners = 0; StreamPanner* sp; LocaleGuard lg (X_("POSIX")); - clear (); + clear_panners (); + + Processor::set_state(node); + + ChanCount ins = ChanCount::ZERO; + ChanCount outs = ChanCount::ZERO; + + // XXX: this might not be necessary anymore outputs.clear (); if ((prop = node.property (X_("linked"))) != 0) { @@ -1254,10 +1114,10 @@ Panner::set_state (const XMLNode& node) if ((prop = node.property (X_("bypassed"))) != 0) { set_bypassed (prop->value() == "yes"); } - + if ((prop = node.property (X_("link_direction"))) != 0) { - sscanf (prop->value().c_str(), "%d", &i); - set_link_direction ((LinkDirection) (i)); + LinkDirection ld; /* here to provide type information */ + set_link_direction (LinkDirection (string_2_enum (prop->value(), ld))); } nlist = node.children(); @@ -1289,13 +1149,14 @@ Panner::set_state (const XMLNode& node) /* note that we assume that all the stream panners are of the same type. pretty good - assumption, but its still an assumption. + assumption, but it's still an assumption. */ - sp = pan_plugins[i].factory (*this); + sp = pan_plugins[i].factory (*this, Evoral::Parameter(PanAutomation, 0, num_panners)); + num_panners++; if (sp->set_state (**niter) == 0) { - push_back (sp); + _streampanners.push_back (sp); } break; @@ -1318,26 +1179,24 @@ Panner::set_state (const XMLNode& node) } } - /* don't try to load automation if it wasn't marked as existing */ + reset (outputs.size (), num_panners); + /* don't try to do old-school automation loading if it wasn't marked as existing */ if ((prop = node.property (X_("automation")))) { /* automation path is relative */ - automation_path = _session.automation_dir(); - automation_path += prop->value (); + automation_path = Glib::build_filename(_session.automation_dir(), prop->value ()); } return 0; } - - bool Panner::touching () const { - for (vector::const_iterator i = begin(); i != end(); ++i) { - if ((*i)->automation().touching ()) { + for (vector::const_iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { + if (((AutomationList*)(*i)->pan_control()->list().get())->touching ()) { return true; } } @@ -1357,7 +1216,7 @@ Panner::set_position (float xpos, StreamPanner& orig) if (_link_direction == SameDirection) { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { if (*i == &orig) { (*i)->set_position (xpos, true); } else { @@ -1370,7 +1229,7 @@ Panner::set_position (float xpos, StreamPanner& orig) } else { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { if (*i == &orig) { (*i)->set_position (xpos, true); } else { @@ -1396,7 +1255,7 @@ Panner::set_position (float xpos, float ypos, StreamPanner& orig) if (_link_direction == SameDirection) { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { if (*i == &orig) { (*i)->set_position (xpos, ypos, true); } else { @@ -1414,7 +1273,7 @@ Panner::set_position (float xpos, float ypos, StreamPanner& orig) } else { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { if (*i == &orig) { (*i)->set_position (xpos, ypos, true); } else { @@ -1446,7 +1305,7 @@ Panner::set_position (float xpos, float ypos, float zpos, StreamPanner& orig) if (_link_direction == SameDirection) { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { if (*i == &orig) { (*i)->set_position (xpos, ypos, zpos, true); } else { @@ -1467,7 +1326,7 @@ Panner::set_position (float xpos, float ypos, float zpos, StreamPanner& orig) } else { - for (vector::iterator i = begin(); i != end(); ++i) { + for (vector::iterator i = _streampanners.begin(); i != _streampanners.end(); ++i) { if (*i == &orig) { (*i)->set_position (xpos, ypos, true); } else { @@ -1489,11 +1348,11 @@ Panner::set_position (float xpos, float ypos, float zpos, StreamPanner& orig) } void -Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, jack_nframes_t nframes, jack_nframes_t offset, gain_t gain_coeff) +Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, nframes_t nframes, gain_t gain_coeff) { - if (outbufs.count().get(DataType::AUDIO) == 0) { + if (outbufs.count().n_audio() == 0) { // Don't want to lose audio... - assert(inbufs.count().get(DataType::AUDIO) == 0); + assert(inbufs.count().n_audio() == 0); return; } @@ -1502,7 +1361,7 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, jack_nf assert(!empty()); - if (outbufs.count().get(DataType::AUDIO) == 1) { + if (outbufs.count().n_audio() == 1) { AudioBuffer& dst = outbufs.get_audio(0); @@ -1510,19 +1369,21 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, jack_nf /* only one output, and gain was zero, so make it silent */ - dst.silence(offset); + dst.silence (nframes); } else if (gain_coeff == 1.0f){ /* mix all buffers into the output */ // copy the first - dst.read_from(inbufs.get_audio(0), nframes, offset); + dst.read_from(inbufs.get_audio(0), nframes); // accumulate starting with the second - BufferSet::audio_iterator i = inbufs.audio_begin(); - for (++i; i != inbufs.audio_end(); ++i) { - dst.accumulate_from(*i, nframes, offset); + if (inbufs.count().n_audio() > 0) { + BufferSet::audio_iterator i = inbufs.audio_begin(); + for (++i; i != inbufs.audio_end(); ++i) { + dst.accumulate_from(*i, nframes); + } } } else { @@ -1530,39 +1391,39 @@ Panner::distribute_no_automation (BufferSet& inbufs, BufferSet& outbufs, jack_nf /* mix all buffers into the output, scaling them all by the gain */ // copy the first - dst.read_from(inbufs.get_audio(0), nframes, offset); + dst.read_from(inbufs.get_audio(0), nframes); // accumulate (with gain) starting with the second - BufferSet::audio_iterator i = inbufs.audio_begin(); - for (++i; i != inbufs.audio_end(); ++i) { - dst.accumulate_with_gain_from(*i, nframes, offset, gain_coeff); + if (inbufs.count().n_audio() > 0) { + BufferSet::audio_iterator i = inbufs.audio_begin(); + for (++i; i != inbufs.audio_end(); ++i) { + dst.accumulate_with_gain_from(*i, nframes, gain_coeff); + } } } return; } - - // More than 1 output, we should have 1 panner for each input - assert(size() == inbufs.count().get(DataType::AUDIO)); /* the terrible silence ... */ for (BufferSet::audio_iterator i = outbufs.audio_begin(); i != outbufs.audio_end(); ++i) { - i->silence(nframes, offset); + i->silence(nframes); } BufferSet::audio_iterator i = inbufs.audio_begin(); - for (iterator pan = begin(); pan != end(); ++pan, ++i) { + + for (vector::iterator pan = _streampanners.begin(); pan != _streampanners.end() && i != inbufs.audio_end(); ++pan, ++i) { (*pan)->distribute (*i, outbufs, gain_coeff, nframes); } } void -Panner::distribute (BufferSet& inbufs, BufferSet& outbufs, jack_nframes_t start_frame, jack_nframes_t end_frame, jack_nframes_t nframes, jack_nframes_t offset) +Panner::run_out_of_place (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes) { - if (outbufs.count().get(DataType::AUDIO) == 0) { + if (outbufs.count().n_audio() == 0) { // Failing to deliver audio we were asked to deliver is a bug - assert(inbufs.count().get(DataType::AUDIO) == 0); + assert(inbufs.count().n_audio() == 0); return; } @@ -1580,41 +1441,120 @@ Panner::distribute (BufferSet& inbufs, BufferSet& outbufs, jack_nframes_t start_ gain_coeff = speed_quietning; } - distribute_no_automation(inbufs, outbufs, nframes, offset, gain_coeff); + distribute_no_automation(inbufs, outbufs, nframes, gain_coeff); return; } // Otherwise.. let the automation flow, baby - if (outbufs.count().get(DataType::AUDIO) == 1) { + if (outbufs.count().n_audio() == 1) { AudioBuffer& dst = outbufs.get_audio(0); // FIXME: apply gain automation? // copy the first - dst.read_from(inbufs.get_audio(0), nframes, offset); + dst.read_from(inbufs.get_audio(0), nframes); // accumulate starting with the second BufferSet::audio_iterator i = inbufs.audio_begin(); for (++i; i != inbufs.audio_end(); ++i) { - dst.accumulate_from(*i, nframes, offset); + dst.accumulate_from(*i, nframes); } return; } // More than 1 output, we should have 1 panner for each input - assert(size() == inbufs.count().get(DataType::AUDIO)); + //assert(_streampanners.size() == inbufs.count().n_audio()); /* the terrible silence ... */ for (BufferSet::audio_iterator i = outbufs.audio_begin(); i != outbufs.audio_end(); ++i) { - i->silence(nframes, offset); + i->silence(nframes); } BufferSet::audio_iterator i = inbufs.audio_begin(); - for (iterator pan = begin(); pan != end(); ++pan, ++i) { + for (vector::iterator pan = _streampanners.begin(); pan != _streampanners.end(); ++pan, ++i) { (*pan)->distribute_automated (*i, outbufs, start_frame, end_frame, nframes, _session.pan_automation_buffer()); } } +/* old school automation handling */ + +/* +void +Panner::set_name (string str) +{ + automation_path = Glib::build_filename(_session.automation_dir(), + _session.snap_name() + "-pan-" + legalize_for_path (str) + ".automation"); +} +*/ + +int +Panner::load () +{ + char line[128]; + uint32_t linecnt = 0; + float version; + vector::iterator sp; + LocaleGuard lg (X_("POSIX")); + + if (automation_path.length() == 0) { + return 0; + } + + if (access (automation_path.c_str(), F_OK)) { + return 0; + } + + ifstream in (automation_path.c_str()); + + if (!in) { + error << string_compose (_("cannot open pan automation file %1 (%2)"), + automation_path, strerror (errno)) + << endmsg; + return -1; + } + + sp = _streampanners.begin(); + + while (in.getline (line, sizeof(line), '\n')) { + + if (++linecnt == 1) { + if (memcmp (line, X_("version"), 7) == 0) { + if (sscanf (line, "version %f", &version) != 1) { + error << string_compose(_("badly formed version number in pan automation event file \"%1\""), automation_path) << endmsg; + return -1; + } + } else { + error << string_compose(_("no version information in pan automation event file \"%1\" (first line = %2)"), + automation_path, line) << endmsg; + return -1; + } + + continue; + } + + if (strlen (line) == 0 || line[0] == '#') { + continue; + } + + if (strcmp (line, "begin") == 0) { + + if (sp == _streampanners.end()) { + error << string_compose (_("too many panner states found in pan automation file %1"), + automation_path) + << endmsg; + return -1; + } + + if ((*sp)->load (in, automation_path, linecnt)) { + return -1; + } + + ++sp; + } + } + + return 0; +}