*/
-#define __STDC_FORMAT_MACROS 1
#include <inttypes.h>
#include <cmath>
#include <locale.h>
#include <unistd.h>
#include <float.h>
+#include <iomanip>
#include <glibmm.h>
string EqualPowerStereoPanner::name = "Equal Power Stereo";
string Multi2dPanner::name = "Multiple (2D)";
-/* this is a default mapper of control values to a pan position
+/* this is a default mapper of control values to a pan position
others can be imagined.
*/
-static pan_t direct_control_to_pan (double fract) {
+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, Evoral::Parameter param)
: parent (p)
{
- assert(param.type() != NullAutomation);
+ assert (param.type() != NullAutomation);
_muted = false;
_mono = false;
- _control = boost::dynamic_pointer_cast<AutomationControl>( parent.control( param, true ) );
+ /* get our AutomationControl from our parent Panner, creating it if required */
+ _control = boost::dynamic_pointer_cast<AutomationControl> (parent.control (param, true));
- x = 0.5;
- y = 0.5;
- z = 0.5;
+ _x = 0.5;
+ _y = 0.5;
+ _z = 0.5;
}
StreamPanner::~StreamPanner ()
}
void
-Panner::PanControllable::set_value (float val)
+Panner::PanControllable::set_value (double val)
{
- panner.streampanner(parameter().id()).set_position (direct_control_to_pan (val));
+ panner.streampanner (parameter().id()).set_position (direct_control_to_pan (val));
AutomationControl::set_value(val);
}
-float
+double
Panner::PanControllable::get_value (void) const
{
return AutomationControl::get_value();
parent.set_position (xpos, *this);
}
- if (x != xpos) {
- x = xpos;
+ if (_x != xpos) {
+ _x = xpos;
update ();
Changed ();
_control->Changed ();
parent.set_position (xpos, ypos, *this);
}
- if (x != xpos || y != ypos) {
-
- x = xpos;
- y = ypos;
+ if (_x != xpos || _y != ypos) {
+ _x = xpos;
+ _y = ypos;
update ();
Changed ();
+ _control->Changed ();
}
}
parent.set_position (xpos, ypos, zpos, *this);
}
- if (x != xpos || y != ypos || z != zpos) {
- x = xpos;
- y = ypos;
- z = zpos;
+ if (_x != xpos || _y != ypos || _z != zpos) {
+ _x = xpos;
+ _y = ypos;
+ _z = zpos;
update ();
Changed ();
+ _control->Changed ();
}
}
set_muted (string_is_affirmative (prop->value()));
}
+ if ((prop = node.property (X_("mono")))) {
+ set_mono (string_is_affirmative (prop->value()));
+ }
+
return 0;
}
StreamPanner::add_state (XMLNode& node)
{
node.add_property (X_("muted"), (muted() ? "yes" : "no"));
+ node.add_property (X_("mono"), (_mono ? "yes" : "no"));
}
void
BaseStereoPanner::BaseStereoPanner (Panner& p, Evoral::Parameter param)
: StreamPanner (p, param)
+ , left (0.5)
+ , right (0.5)
+ , left_interp (left)
+ , right_interp (right)
{
}
x == 1 => hard right
*/
- float panR = x;
- float panL = 1 - panR;
+ float const panR = _x;
+ float const panL = 1 - panR;
- const float pan_law_attenuation = -3.0f;
- const float scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
+ float const pan_law_attenuation = -3.0f;
+ float const scale = 2.0f - 4.0f * powf (10.0f,pan_law_attenuation/20.0f);
desired_left = panL * (scale * panL + 1.0f - scale);
desired_right = panR * (scale * panR + 1.0f - scale);
- effective_x = x;
+ effective_x = _x;
//_control->set_value(x);
}
nframes_t start, nframes_t end, nframes_t nframes,
pan_t** buffers)
{
- assert(obufs.count().n_audio() == 2);
+ assert (obufs.count().n_audio() == 2);
Sample* dst;
pan_t* pbuf;
for (nframes_t n = 0; n < nframes; ++n) {
- float panR = buffers[0][n];
- float panL = 1 - panR;
+ float const panR = buffers[0][n];
+ float const panL = 1 - panR;
buffers[0][n] = panL * (scale * panL + 1.0f - scale);
buffers[1][n] = panR * (scale * panR + 1.0f - scale);
char buf[64];
LocaleGuard lg (X_("POSIX"));
- snprintf (buf, sizeof (buf), "%.12g", x);
+ snprintf (buf, sizeof (buf), "%.12g", _x);
root->add_property (X_("x"), buf);
root->add_property (X_("type"), EqualPowerStereoPanner::name);
EqualPowerStereoPanner::set_state (const XMLNode& node, int version)
{
const XMLProperty* prop;
- float pos;
LocaleGuard lg (X_("POSIX"));
if ((prop = node.property (X_("x")))) {
- pos = atof (prop->value().c_str());
+ const float pos = atof (prop->value().c_str());
set_position (pos, true);
}
{
static const float BIAS = FLT_MIN;
uint32_t i;
- uint32_t nouts = parent.outputs.size();
+ uint32_t const nouts = parent.nouts ();
float dsq[nouts];
float f, fr;
vector<pan_t> pans;
f = 0.0f;
for (i = 0; i < nouts; i++) {
- dsq[i] = ((x - parent.outputs[i].x) * (x - parent.outputs[i].x) + (y - parent.outputs[i].y) * (y - parent.outputs[i].y) + BIAS);
+ dsq[i] = ((_x - parent.output(i).x) * (_x - parent.output(i).x) + (_y - parent.output(i).y) * (_y - parent.output(i).y) + BIAS);
if (dsq[i] < 0.0) {
dsq[i] = 0.0;
}
fr = 1.0 / sqrtf(f);
#endif
for (i = 0; i < nouts; ++i) {
- parent.outputs[i].desired_pan = 1.0f - (dsq[i] * fr);
+ parent.output(i).desired_pan = 1.0f - (dsq[i] * fr);
}
- effective_x = x;
+ effective_x = _x;
}
void
{
Sample* dst;
pan_t pan;
- vector<Panner::Output>::iterator o;
- uint32_t n;
if (_muted) {
return;
Sample* const src = srcbuf.data();
-
- for (n = 0, o = parent.outputs.begin(); o != parent.outputs.end(); ++o, ++n) {
+ uint32_t const N = parent.nouts ();
+ for (uint32_t n = 0; n < N; ++n) {
+ Panner::Output& o = parent.output (n);
dst = obufs.get_audio(n).data();
} else {
#else
- pan = (*o).desired_pan;
+ pan = o.desired_pan;
if ((pan *= gain_coeff) != 1.0f) {
if (pan != 0.0f) {
mix_buffers_with_gain(dst,src,nframes,pan);
}
+
} else {
mix_buffers_no_gain(dst,src,nframes);
}
char buf[64];
LocaleGuard lg (X_("POSIX"));
- snprintf (buf, sizeof (buf), "%.12g", x);
+ snprintf (buf, sizeof (buf), "%.12g", _x);
root->add_property (X_("x"), buf);
- snprintf (buf, sizeof (buf), "%.12g", y);
+ snprintf (buf, sizeof (buf), "%.12g", _y);
root->add_property (X_("y"), buf);
root->add_property (X_("type"), Multi2dPanner::name);
newy = atof (prop->value().c_str());
}
- if (x < 0 || y < 0) {
+ if (_x < 0 || _y < 0) {
error << _("badly-formed positional data for Multi2dPanner - ignored")
<< endmsg;
return -1;
Panner::Panner (string name, Session& s)
: SessionObject (s, name)
- , AutomatableControls (s)
+ , Automatable (s)
{
//set_name_old_auto (name);
set_name (name);
bool changed = false;
bool do_not_and_did_not_need_panning = ((nouts < 2) && (outputs.size() < 2));
- //cout << "Reset panner for " << nouts << " " << npans << "\n";
-
/* if new and old config don't need panning, or if
the config hasn't changed, we're done.
*/
node->add_child_nocopy ((*i)->state (full));
}
+ node->add_child_nocopy (get_automation_xml_state ());
return *node;
}
automation_path = Glib::build_filename(_session.automation_dir(), prop->value ());
}
+ for (niter = nlist.begin(); niter != nlist.end(); ++niter) {
+ if ((*niter)->name() == X_("Automation")) {
+ set_automation_xml_state (**niter, Evoral::Parameter (PanAutomation));
+ }
+ }
+
return 0;
}
}
void
-Panner::run (BufferSet& inbufs, BufferSet& outbufs, sframes_t start_frame, sframes_t end_frame, nframes_t nframes)
+Panner::run (BufferSet& inbufs, BufferSet& outbufs, framepos_t start_frame, framepos_t end_frame, nframes_t nframes)
{
if (outbufs.count().n_audio() == 0) {
// Failing to deliver audio we were asked to deliver is a bug
// Speed quietning
gain_t gain_coeff = 1.0;
- if (fabsf(_session.transport_speed()) > 1.5f) {
+ if (fabsf(_session.transport_speed()) > 1.5f && Config->get_quieten_at_speed ()) {
gain_coeff = speed_quietning;
}
(*i)->set_mono (yn);
}
}
+
+string
+Panner::value_as_string (double v)
+{
+ if (Panner::equivalent (v, 0.5)) {
+ return _("C");
+ } else if (equivalent (v, 0)) {
+ return _("L");
+ } else if (equivalent (v, 1)) {
+ return _("R");
+ } else if (v < 0.5) {
+ stringstream s;
+ s << fixed << setprecision (0) << _("L") << ((0.5 - v) * 200) << "%";
+ return s.str();
+ } else {
+ stringstream s;
+ s << fixed << setprecision (0) << _("R") << ((v -0.5) * 200) << "%";
+ return s.str ();
+ }
+
+ return "";
+}