Skip to content

Commit

Permalink
BSE: implement Bus::volume_db and Bus::pan properties
Browse files Browse the repository at this point in the history
These properties allow changing the volume without changing the pan position
and changing the pan position without changing the volume. We implement
constant power panning.

Signed-off-by: Stefan Westerfeld <stefan@space.twc.de>
  • Loading branch information
swesterfeld committed Sep 13, 2018
1 parent e850a05 commit 752ee2a
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 21 deletions.
13 changes: 4 additions & 9 deletions bse/bseapi.idl
Expand Up @@ -977,11 +977,6 @@ sequence TrackPartSeq {
TrackPart parts;
};

Const BUS_VOLUME_MIN = 1.58489319246111e-05; /* -96dB */
Const BUS_VOLUME_MAX = 15.8489319246111; /* +24dB */
Const BUS_VOLUME_DEF = 1;
Const BUS_VOLUME_STEP = 0.1;

/// Interface for effect stacks and per-track audio signal routing to the master output.
interface Bus : SubSynth {
Error ensure_output (); ///< Ensure that a bus has an output connection.
Expand All @@ -996,10 +991,10 @@ interface Bus : SubSynth {
bool mute = Bool (_("Mute"), _("Mute: turn off the bus volume"), STANDARD SKIP_DEFAULT, false);
bool solo = Bool (_("Solo"), _("Solo: mute all other busses"), STANDARD SKIP_DEFAULT, false);
bool sync = Bool (_("Sync"), _("Synchronize left and right volume"), STANDARD SKIP_DEFAULT, true);
float64 left_volume = Range (_("Left Volume"), _("Volume adjustment in decibel of left bus channel"), STANDARD ":scale:db-volume",
BUS_VOLUME_MIN, BUS_VOLUME_MAX, BUS_VOLUME_STEP, BUS_VOLUME_DEF);
float64 right_volume = Range (_("Right Volume"), _("Volume adjustment in decibel of right bus channel"), STANDARD ":scale:db-volume",
BUS_VOLUME_MIN, BUS_VOLUME_MAX, BUS_VOLUME_STEP, BUS_VOLUME_DEF);
float64 left_volume = Range (_("Left Volume"), _("Volume factor of the left bus channel"), STANDARD ":scale:db-volume", 0, 1000, 0.1, 1);
float64 right_volume = Range (_("Right Volume"), _("Volume factor of the right bus channel"), STANDARD ":scale:db-volume", 0, 1000, 0.1, 1);
float64 volume_db = Range (_("Volume"), _("Total volume of both channels in decibel"), GUI ":scale:db-value", -96, 12, 5, 0);
float64 pan = Range (_("Pan [%]"), _("Pan position for stereo output"), GUI ":scale", -100, 100, 5, 0);
};
group _("Internals") {
bool master_output = Bool (_("Master Output"), "", STORAGE SKIP_DEFAULT, false);
Expand Down
117 changes: 105 additions & 12 deletions bse/bsebus.cc
Expand Up @@ -967,21 +967,13 @@ BusImpl::sync (bool val)

notify ("left_volume");
notify ("right_volume");
notify ("volume_db");
notify ("pan");
notify (prop);
}
self->saved_sync = self->synced;
}

static double
volume_clamp (double val)
{
/* keep in sync with bseapi.idl */
const double BUS_VOLUME_MIN = 1.58489319246111e-05; /* -96dB */
const double BUS_VOLUME_MAX = 15.8489319246111; /* +24dB */

return CLAMP (val, BUS_VOLUME_MIN, BUS_VOLUME_MAX);
}

double
BusImpl::left_volume() const
{
Expand All @@ -1000,14 +992,16 @@ BusImpl::left_volume (double val)
auto prop = "left_volume";
push_property_undo (prop);

self->left_volume = volume_clamp (val);
self->left_volume = CLAMP (val, 0, 1000);
if (self->synced)
{
self->right_volume = self->left_volume;
notify ("right_volume");
}
bus_volume_changed (self);

notify ("volume_db");
notify ("pan");
notify (prop);
}
}
Expand All @@ -1030,14 +1024,113 @@ BusImpl::right_volume (double val)
auto prop = "right_volume";
push_property_undo (prop);

self->right_volume = volume_clamp (val);
self->right_volume = CLAMP (val, 0, 1000);
if (self->synced)
{
self->left_volume = self->right_volume;
notify ("left_volume");
}
bus_volume_changed (self);

notify ("volume_db");
notify ("pan");
notify (prop);
}
}

void
BusImpl::lr_to_volume_pan (double &volume_out, double &pan_out) const
{
BseBus *self = const_cast<BusImpl*> (this)->as<BseBus*>();

// this implements constant power panning

const double total_volume = sqrt (self->left_volume * self->left_volume + self->right_volume * self->right_volume);

volume_out = bse_db_from_factor (total_volume / BSE_SQRT2, -96);

pan_out = acos (std::min (self->left_volume / total_volume, 1.0)) / M_PI * 400 - 100;
}

void
BusImpl::volume_pan_to_lr (double volume_in, double pan_in)
{
BseBus *self = const_cast<BusImpl*> (this)->as<BseBus*>();

volume_in = CLAMP (volume_in, -96, 12);
pan_in = CLAMP (pan_in, -100, 100);

// this implements constant power panning
const double vfactor = bse_db_to_factor (volume_in) * BSE_SQRT2;

pan_in = (pan_in + 100) / 400 * M_PI; /* -> [0,pi/2] */

self->left_volume = cos (pan_in) * vfactor;
self->right_volume = sin (pan_in) * vfactor;
}

double
BusImpl::volume_db() const
{
double volume, pan;
lr_to_volume_pan (volume, pan);
return volume;
}

void
BusImpl::volume_db (double val)
{
BseBus *self = as<BseBus*>();

if (val != volume_db())
{
auto prop = "volume_db";
push_property_undo (prop);

double volume, pan;

lr_to_volume_pan (volume, pan);
volume = val;
volume_pan_to_lr (volume, pan);

bus_volume_changed (self);

notify ("left_volume");
notify ("right_volume");
notify ("pan");
notify (prop);
}
}

double
BusImpl::pan() const
{
double volume, pan;
lr_to_volume_pan (volume, pan);
return pan;
}

void
BusImpl::pan (double val)
{
BseBus *self = as<BseBus*>();

if (val != pan())
{
auto prop = "pan";
push_property_undo (prop);

double volume, pan;

lr_to_volume_pan (volume, pan);
pan = val;
volume_pan_to_lr (volume, pan);

bus_volume_changed (self);

notify ("left_volume");
notify ("right_volume");
notify ("volume_db");
notify (prop);
}
}
Expand Down
8 changes: 8 additions & 0 deletions bse/bsebus.hh
Expand Up @@ -78,6 +78,10 @@ namespace Bse {
class BusImpl : public SubSynthImpl, public virtual BusIface {
protected:
virtual ~BusImpl ();

void lr_to_volume_pan (double &volume_out, double &pan_out) const;
void volume_pan_to_lr (double volume_in, double pan_in);

public:
explicit BusImpl (BseObject*);
virtual bool mute () const override;
Expand All @@ -90,6 +94,10 @@ public:
virtual void left_volume (double val) override;
virtual double right_volume () const override;
virtual void right_volume (double val) override;
virtual double volume_db () const override;
virtual void volume_db (double val) override;
virtual double pan () const override;
virtual void pan (double val) override;
virtual bool master_output () const override;
virtual void master_output (bool val) override;
virtual Error ensure_output () override;
Expand Down

0 comments on commit 752ee2a

Please sign in to comment.