mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-06 14:54:56 +01:00
take reverse width into account when labelling signals in panner2d ; better way to draw the width arc
git-svn-id: svn://localhost/ardour2/branches/3.0@8956 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
parent
36f9a82cef
commit
6dcb20af78
5 changed files with 92 additions and 79 deletions
|
|
@ -68,6 +68,7 @@ Panner2d::Panner2d (boost::shared_ptr<Panner> p, int32_t h)
|
||||||
, position (AngularVector (0.0, 0.0), "")
|
, position (AngularVector (0.0, 0.0), "")
|
||||||
, width (0)
|
, width (0)
|
||||||
, height (h)
|
, height (h)
|
||||||
|
, last_width (0)
|
||||||
{
|
{
|
||||||
panner->StateChanged.connect (connections, invalidator (*this), boost::bind (&Panner2d::handle_state_change, this), gui_context());
|
panner->StateChanged.connect (connections, invalidator (*this), boost::bind (&Panner2d::handle_state_change, this), gui_context());
|
||||||
|
|
||||||
|
|
@ -106,27 +107,7 @@ Panner2d::reset (uint32_t n_inputs)
|
||||||
pucks.resize (n_inputs);
|
pucks.resize (n_inputs);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (n_inputs) {
|
label_pucks ();
|
||||||
case 0:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
pucks[0]->set_text ("");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
pucks[0]->set_text ("R");
|
|
||||||
pucks[1]->set_text ("L");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
for (uint32_t i = 0; i < n_inputs; ++i) {
|
|
||||||
char buf[64];
|
|
||||||
snprintf (buf, sizeof (buf), "%" PRIu32, i + 1);
|
|
||||||
pucks[i]->set_text (buf);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < n_inputs; ++i) {
|
for (uint32_t i = 0; i < n_inputs; ++i) {
|
||||||
pucks[i]->position = panner->signal_position (i);
|
pucks[i]->position = panner->signal_position (i);
|
||||||
|
|
@ -210,10 +191,49 @@ Panner2d::handle_state_change ()
|
||||||
queue_draw ();
|
queue_draw ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Panner2d::label_pucks ()
|
||||||
|
{
|
||||||
|
double w = panner->pannable()->pan_width_control->get_value();
|
||||||
|
uint32_t sz = pucks.size();
|
||||||
|
|
||||||
|
switch (sz) {
|
||||||
|
case 0:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
pucks[0]->set_text ("");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
if (w >= 0.0) {
|
||||||
|
pucks[0]->set_text ("R");
|
||||||
|
pucks[1]->set_text ("L");
|
||||||
|
} else {
|
||||||
|
pucks[0]->set_text ("L");
|
||||||
|
pucks[1]->set_text ("R");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
for (uint32_t i = 0; i < sz; ++i) {
|
||||||
|
char buf[64];
|
||||||
|
if (w >= 0.0) {
|
||||||
|
snprintf (buf, sizeof (buf), "%" PRIu32, i + 1);
|
||||||
|
} else {
|
||||||
|
snprintf (buf, sizeof (buf), "%" PRIu32, sz - i);
|
||||||
|
}
|
||||||
|
pucks[i]->set_text (buf);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
Panner2d::handle_position_change ()
|
Panner2d::handle_position_change ()
|
||||||
{
|
{
|
||||||
uint32_t n;
|
uint32_t n;
|
||||||
|
double w = panner->pannable()->pan_width_control->get_value();
|
||||||
|
|
||||||
position.position = AngularVector (panner->pannable()->pan_azimuth_control->get_value() * 360.0, 0.0);
|
position.position = AngularVector (panner->pannable()->pan_azimuth_control->get_value() * 360.0, 0.0);
|
||||||
|
|
||||||
|
|
@ -221,6 +241,13 @@ Panner2d::handle_position_change ()
|
||||||
pucks[i]->position = panner->signal_position (i);
|
pucks[i]->position = panner->signal_position (i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (w * last_width <= 0) {
|
||||||
|
/* changed sign */
|
||||||
|
label_pucks ();
|
||||||
|
}
|
||||||
|
|
||||||
|
last_width = w;
|
||||||
|
|
||||||
vector<Speaker>& speakers (panner->get_speakers()->speakers());
|
vector<Speaker>& speakers (panner->get_speakers()->speakers());
|
||||||
|
|
||||||
for (n = 0; n < targets.size(); ++n) {
|
for (n = 0; n < targets.size(); ++n) {
|
||||||
|
|
@ -274,9 +301,17 @@ Panner2d::find_closest_object (gdouble x, gdouble y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (best_distance > 20) { // arbitrary
|
if (height > 100) {
|
||||||
return 0;
|
/* "big" */
|
||||||
}
|
if (best_distance > 30) { // arbitrary
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* "small" */
|
||||||
|
if (best_distance > 10) { // arbitrary
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return closest;
|
return closest;
|
||||||
}
|
}
|
||||||
|
|
@ -326,7 +361,7 @@ Panner2d::on_expose_event (GdkEventExpose *event)
|
||||||
|
|
||||||
/* horizontal line of "crosshairs" */
|
/* horizontal line of "crosshairs" */
|
||||||
|
|
||||||
cairo_set_source_rgb (cr, 0.0, 0.1, 0.7);
|
cairo_set_source_rgba (cr, 0.282, 0.517, 0.662, 1.0);
|
||||||
cairo_move_to (cr, 0.5, height/2.0+0.5);
|
cairo_move_to (cr, 0.5, height/2.0+0.5);
|
||||||
cairo_line_to (cr, width+0.5, height/2+0.5);
|
cairo_line_to (cr, width+0.5, height/2+0.5);
|
||||||
cairo_stroke (cr);
|
cairo_stroke (cr);
|
||||||
|
|
@ -359,54 +394,18 @@ Panner2d::on_expose_event (GdkEventExpose *event)
|
||||||
if (pucks.size() > 1) {
|
if (pucks.size() > 1) {
|
||||||
/* arc to show "diffusion" */
|
/* arc to show "diffusion" */
|
||||||
|
|
||||||
cairo_move_to (cr, width/2, height/2);
|
double width_angle = fabs (panner->pannable()->pan_width_control->get_value()) * 2 * M_PI;
|
||||||
|
double position_angle = (2 * M_PI) - panner->pannable()->pan_azimuth_control->get_value() * 2 * M_PI;
|
||||||
double max_angle = 0.0;
|
|
||||||
double min_angle = DBL_MAX;
|
|
||||||
|
|
||||||
for (Targets::iterator i = pucks.begin(); i != pucks.end(); ++i) {
|
|
||||||
max_angle = max ((*i)->position.azi, max_angle);
|
|
||||||
min_angle = min ((*i)->position.azi, min_angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* if the angle between the max & min is bigger than 180, flip
|
|
||||||
them to use the opposite angle for the display. this
|
|
||||||
matches the psycho-acoustic perception of this condition
|
|
||||||
too, in almost all conditions that VBAP will handle.
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (fabs (max_angle - min_angle) > 180.0) {
|
|
||||||
swap (max_angle, min_angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* convert to radians */
|
|
||||||
|
|
||||||
min_angle = (min_angle / 360.0) * 2.0 * M_PI;
|
|
||||||
max_angle = (max_angle / 360.0) * 2.0 * M_PI;
|
|
||||||
|
|
||||||
/* cairo has coordinates increasing in a clockwise direction */
|
|
||||||
|
|
||||||
max_angle = (2 * M_PI) - max_angle;
|
|
||||||
min_angle = (2 * M_PI) - min_angle;
|
|
||||||
|
|
||||||
/* the above transformation will have reversed the min/max relationship */
|
|
||||||
|
|
||||||
swap (min_angle, max_angle);
|
|
||||||
|
|
||||||
if (min_angle > max_angle) {
|
|
||||||
/* swapped because they span the zero position: draw two arc segments to span zero.
|
|
||||||
XXX there must be a way to get cairo to do this in a single call
|
|
||||||
*/
|
|
||||||
cairo_arc_negative (cr, width/2, height/2, dimen/2.0, max_angle, 0.0);
|
|
||||||
cairo_arc_negative (cr, width/2, height/2, dimen/2.0, 0.0, min_angle);
|
|
||||||
} else {
|
|
||||||
cairo_arc (cr, width/2, height/2, dimen/2.0, min_angle, max_angle);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
cairo_save (cr);
|
||||||
|
cairo_translate (cr, width/2, height/2);
|
||||||
|
cairo_rotate (cr, position_angle - width_angle);
|
||||||
|
cairo_move_to (cr, 0, 0);
|
||||||
|
cairo_arc_negative (cr, 0, 0, dimen/2.0, width_angle * 2.0, 0.0);
|
||||||
cairo_close_path (cr);
|
cairo_close_path (cr);
|
||||||
cairo_set_source_rgba (cr, 1.0, 0.419, 0.419, 0.45);
|
cairo_set_source_rgba (cr, 1.0, 0.419, 0.419, 0.45);
|
||||||
cairo_fill (cr);
|
cairo_fill (cr);
|
||||||
|
cairo_restore (cr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!panner->bypassed()) {
|
if (!panner->bypassed()) {
|
||||||
|
|
@ -426,7 +425,6 @@ Panner2d::on_expose_event (GdkEventExpose *event)
|
||||||
|
|
||||||
if (pucks.size() > 1) {
|
if (pucks.size() > 1) {
|
||||||
for (Targets::iterator i = pucks.begin(); i != pucks.end(); ++i) {
|
for (Targets::iterator i = pucks.begin(); i != pucks.end(); ++i) {
|
||||||
|
|
||||||
Target* puck = *i;
|
Target* puck = *i;
|
||||||
|
|
||||||
if (puck->visible) {
|
if (puck->visible) {
|
||||||
|
|
|
||||||
|
|
@ -117,6 +117,7 @@ class Panner2d : public Gtk::DrawingArea
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
int dimen;
|
int dimen;
|
||||||
|
double last_width;
|
||||||
|
|
||||||
bool bypassflag;
|
bool bypassflag;
|
||||||
|
|
||||||
|
|
@ -130,6 +131,7 @@ class Panner2d : public Gtk::DrawingArea
|
||||||
void toggle_bypass ();
|
void toggle_bypass ();
|
||||||
void handle_state_change ();
|
void handle_state_change ();
|
||||||
void handle_position_change ();
|
void handle_position_change ();
|
||||||
|
void label_pucks ();
|
||||||
|
|
||||||
PBD::ScopedConnectionList connections;
|
PBD::ScopedConnectionList connections;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ LV2Plugin::init (LV2World& world, SLV2Plugin plugin, framecnt_t rate)
|
||||||
|
|
||||||
if (_instance == 0) {
|
if (_instance == 0) {
|
||||||
error << _("LV2: Failed to instantiate plugin ")
|
error << _("LV2: Failed to instantiate plugin ")
|
||||||
<< slv2_plugin_get_uri(plugin) << endl;
|
<< slv2_value_as_string (slv2_plugin_get_uri(plugin)) << endmsg;
|
||||||
throw failed_constructor();
|
throw failed_constructor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +130,7 @@ LV2Plugin::init (LV2World& world, SLV2Plugin plugin, framecnt_t rate)
|
||||||
if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
|
if (slv2_plugin_has_feature(plugin, world.in_place_broken)) {
|
||||||
error << string_compose(
|
error << string_compose(
|
||||||
_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
|
_("LV2: \"%1\" cannot be used, since it cannot do inplace processing"),
|
||||||
slv2_value_as_string(_name));
|
slv2_value_as_string(_name)) << endmsg;
|
||||||
slv2_value_free(_name);
|
slv2_value_free(_name);
|
||||||
slv2_value_free(_author);
|
slv2_value_free(_author);
|
||||||
throw failed_constructor();
|
throw failed_constructor();
|
||||||
|
|
|
||||||
|
|
@ -870,6 +870,8 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
|
||||||
{
|
{
|
||||||
assert (processor != _meter);
|
assert (processor != _meter);
|
||||||
assert (processor != _main_outs);
|
assert (processor != _main_outs);
|
||||||
|
|
||||||
|
DEBUG_TRACE (DEBUG::Processors, string_compose ("%1 adding processor %2\n", name(), processor->name()));
|
||||||
|
|
||||||
ChanCount old_pms = processor_max_streams;
|
ChanCount old_pms = processor_max_streams;
|
||||||
|
|
||||||
|
|
@ -916,7 +918,6 @@ Route::add_processor (boost::shared_ptr<Processor> processor, ProcessorList::ite
|
||||||
if (configure_processors_unlocked (err)) {
|
if (configure_processors_unlocked (err)) {
|
||||||
pstate.restore ();
|
pstate.restore ();
|
||||||
configure_processors_unlocked (0); // it worked before we tried to add it ...
|
configure_processors_unlocked (0); // it worked before we tried to add it ...
|
||||||
cerr << "configure failed\n";
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,8 @@ VBAPanner::update ()
|
||||||
|
|
||||||
/* panner width control is [-1.0 .. 1.0]; we ignore sign, and map to [0 .. 360] degrees
|
/* panner width control is [-1.0 .. 1.0]; we ignore sign, and map to [0 .. 360] degrees
|
||||||
so that a width of 1 corresponds to a signal equally present from all directions,
|
so that a width of 1 corresponds to a signal equally present from all directions,
|
||||||
and a width of zero corresponds to a point source from the "center" (above)
|
and a width of zero corresponds to a point source from the "center" (above) point
|
||||||
|
on the perimeter of the speaker array.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
double w = fabs (_pannable->pan_width_control->get_value()) * 360.0;
|
double w = fabs (_pannable->pan_width_control->get_value()) * 360.0;
|
||||||
|
|
@ -123,13 +124,24 @@ VBAPanner::update ()
|
||||||
double degree_step_per_signal = (max_dir - min_dir) / (_signals.size() - 1);
|
double degree_step_per_signal = (max_dir - min_dir) / (_signals.size() - 1);
|
||||||
double signal_direction = min_dir;
|
double signal_direction = min_dir;
|
||||||
|
|
||||||
for (vector<Signal*>::iterator s = _signals.begin(); s != _signals.end(); ++s) {
|
if (w >= 0.0) {
|
||||||
|
for (vector<Signal*>::iterator s = _signals.begin(); s != _signals.end(); ++s) {
|
||||||
|
|
||||||
Signal* signal = *s;
|
Signal* signal = *s;
|
||||||
|
|
||||||
|
signal->direction = AngularVector (signal_direction, 0.0);
|
||||||
|
compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele);
|
||||||
|
signal_direction += degree_step_per_signal;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (vector<Signal*>::reverse_iterator s = _signals.rbegin(); s != _signals.rend(); ++s) {
|
||||||
|
|
||||||
signal->direction = AngularVector (signal_direction, 0.0);
|
Signal* signal = *s;
|
||||||
compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele);
|
|
||||||
signal_direction += degree_step_per_signal;
|
signal->direction = AngularVector (signal_direction, 0.0);
|
||||||
|
compute_gains (signal->desired_gains, signal->desired_outputs, signal->direction.azi, signal->direction.ele);
|
||||||
|
signal_direction += degree_step_per_signal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (_signals.size() == 1) {
|
} else if (_signals.size() == 1) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue