diff options
author | Paul Davis <paul@linuxaudiosystems.com> | 2010-11-26 17:43:03 +0000 |
---|---|---|
committer | Paul Davis <paul@linuxaudiosystems.com> | 2010-11-26 17:43:03 +0000 |
commit | 553cf2982c4905c5a08f305ce2772beaa8c50324 (patch) | |
tree | d23a7bad787a2d5bc1a909a14e9869fcfb405ae8 /gtk2_ardour | |
parent | 1539ac1b9661f0c0bb313d8f0d9a72b6dc95aaf1 (diff) |
one step closer to working vbap panning
git-svn-id: svn://localhost/ardour2/branches/3.0@8091 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour')
-rw-r--r-- | gtk2_ardour/panner2d.cc | 261 | ||||
-rw-r--r-- | gtk2_ardour/panner2d.h | 67 | ||||
-rw-r--r-- | gtk2_ardour/panner_ui.cc | 27 |
3 files changed, 140 insertions, 215 deletions
diff --git a/gtk2_ardour/panner2d.cc b/gtk2_ardour/panner2d.cc index 39501122b2..2864bfe607 100644 --- a/gtk2_ardour/panner2d.cc +++ b/gtk2_ardour/panner2d.cc @@ -41,14 +41,11 @@ using namespace ARDOUR; using namespace PBD; using Gtkmm2ext::Keyboard; -Panner2d::Target::Target (float xa, float ya, const char *txt) - : x (xa, 0.0, 1.0, 0.01, 0.1) - , y (ya, 0.0, 1.0, 0.01, 0.1) - , azimuth (M_PI/2.0, 0.0, 2.0 * M_PI, 0.1, 0.5) +Panner2d::Target::Target (const AngularVector& a, const char *txt) + : position (a) , text (txt) , _selected (false) { - azimuth.set_value ((random() / (double) INT_MAX) * (2.0 * M_PI)); } Panner2d::Target::~Target () @@ -64,10 +61,6 @@ Panner2d::Target::set_text (const char* txt) Panner2d::Panner2d (boost::shared_ptr<Panner> p, int32_t h) : panner (p), width (0), height (h) { - allow_x = false; - allow_y = false; - allow_target = false; - panner->StateChanged.connect (state_connection, invalidator (*this), boost::bind (&Panner2d::handle_state_change, this), gui_context()); panner->Changed.connect (change_connection, invalidator (*this), boost::bind (&Panner2d::handle_position_change, this), gui_context()); @@ -90,7 +83,7 @@ Panner2d::reset (uint32_t n_inputs) /* pucks */ while (pucks.size() < n_inputs) { - add_puck ("", 0.0, 0.0); + add_puck ("", AngularVector()); } if (pucks.size() > n_inputs) { @@ -128,25 +121,14 @@ Panner2d::reset (uint32_t n_inputs) } for (uint32_t i = existing_pucks; i < n_inputs; ++i) { - float x, y; - double dx, dy; - - panner->streampanner (i).get_position (x, y); - - dx = x; - dy = y; - clamp_to_circle (dx, dy); - - pucks[i]->x.set_value (dx); - pucks[i]->y.set_value (dy); - + pucks[i]->position = panner->streampanner (i).get_position (); pucks[i]->visible = true; } /* add all outputs */ while (targets.size() < panner->nouts()) { - add_target (0.0, 0.0); + add_target (AngularVector()); } if (targets.size() > panner->nouts()) { @@ -166,25 +148,13 @@ Panner2d::reset (uint32_t n_inputs) snprintf (buf, sizeof (buf), "%d", n+1); targets[n]->set_text (buf); - targets[n]->x.set_value (panner->output(n).x); - targets[n]->y.set_value (panner->output(n).y); + targets[n]->position = panner->output(n).position; targets[n]->visible = true; } - allow_x_motion (true); - allow_y_motion (true); - allow_target_motion (true); - queue_draw (); } -Gtk::Adjustment& -Panner2d::azimuth (uint32_t which) -{ - assert (which < pucks.size()); - return pucks[which]->azimuth; -} - void Panner2d::on_size_allocate (Gtk::Allocation& alloc) { @@ -200,16 +170,9 @@ Panner2d::on_size_allocate (Gtk::Allocation& alloc) } int -Panner2d::add_puck (const char* text, float x, float y) +Panner2d::add_puck (const char* text, const AngularVector& a) { - double dx, dy; - - dx = x; - dy = y; - - clamp_to_circle (dx, dy); - - Target* puck = new Target (dx, dy, text); + Target* puck = new Target (a, text); pucks.push_back (puck); puck->visible = true; @@ -217,9 +180,9 @@ Panner2d::add_puck (const char* text, float x, float y) } int -Panner2d::add_target (float x, float y) +Panner2d::add_target (const AngularVector& a) { - Target* target = new Target (x, y, ""); + Target* target = new Target (a, ""); targets.push_back (target); target->visible = true; queue_draw (); @@ -242,57 +205,53 @@ Panner2d::handle_position_change () ENSURE_GUI_THREAD (*this, &Panner2d::handle_position_change) for (n = 0; n < pucks.size(); ++n) { - float x, y; - panner->streampanner(n).get_position (x, y); - pucks[n]->x.set_value (x); - pucks[n]->y.set_value (y); + pucks[n]->position = panner->streampanner(n).get_position (); } for (n = 0; n < targets.size(); ++n) { - targets[n]->x.set_value (panner->output(n).x); - targets[n]->y.set_value (panner->output(n).y); + targets[n]->position = panner->output(n).position; } queue_draw (); } void -Panner2d::move_puck (int which, float x, float y) +Panner2d::move_puck (int which, const AngularVector& a) { if (which >= int (targets.size())) { return; } - targets[which]->x.set_value (x); - targets[which]->y.set_value (y); + targets[which]->position = a; queue_draw (); } Panner2d::Target * Panner2d::find_closest_object (gdouble x, gdouble y, int& which) const { - gdouble efx, efy; - gdouble cx, cy; Target *closest = 0; Target *candidate; float distance; float best_distance = FLT_MAX; int pwhich; - efx = x/(width-1.0); - efy = 1.0 - (y/(height-1.0)); /* convert from X Window origin */ - which = 0; pwhich = 0; + cerr << "@ " << x << ", " << y << endl; + for (Targets::const_iterator i = pucks.begin(); i != pucks.end(); ++i, ++pwhich) { candidate = *i; - cx = candidate->x.get_value(); - cy = candidate->y.get_value(); + CartesianVector c; + + candidate->position.cartesian (c); + cart_to_gtk (c); + + distance = sqrt ((c.x - x) * (c.x - x) + + (c.y - y) * (c.y - y)); - distance = sqrt ((cx - efx) * (cx - efx) + - (cy - efy) * (cy - efy)); + cerr << "\tConsider candiate " << candidate->text << " @ " << c.x << ", " << c.y << ", " << c.z << " distance = " << distance << endl; if (distance < best_distance) { closest = candidate; @@ -301,10 +260,13 @@ Panner2d::find_closest_object (gdouble x, gdouble y, int& which) const } } - if (best_distance > 0.05) { // arbitrary + + if (best_distance > 20) { // arbitrary return 0; } + cerr << "the winner is " << closest->text << endl; + return closest; } @@ -328,7 +290,6 @@ bool Panner2d::on_expose_event (GdkEventExpose *event) { gint x, y; - float fx, fy; cairo_t* cr; cr = gdk_cairo_create (get_window()->gobj()); @@ -386,25 +347,26 @@ Panner2d::on_expose_event (GdkEventExpose *event) if (puck->visible) { /* redraw puck */ - fx = min (puck->x.get_value(), 1.0); - fx = max (fx, -1.0f); - x = (gint) floor (width * fx - 4); - - fy = min (fy, 1.0f); - fy = max (fy, -1.0f); - - /* translate back to X Window abomination coordinates */ - fy = -(puck->y.get_value() - 1.0); - - y = (gint) floor (height * fy - 4); + CartesianVector c; + + puck->position.cartesian (c); + cart_to_gtk (c); + x = (gint) floor (c.x); + y = (gint) floor (c.y); + + /* XXX need to shift circles so that they are centered on the circle */ + cairo_arc (cr, x, y, arc_radius, 0, 2.0 * M_PI); cairo_set_source_rgb (cr, 0.8, 0.2, 0.1); cairo_close_path (cr); cairo_fill (cr); cairo_move_to (cr, x + 6, y + 6); - cairo_show_text (cr, puck->text.c_str()); + + char buf[256]; + snprintf (buf, sizeof (buf), "%s:%d", puck->text.c_str(), (int) lrint (puck->position.azi)); + cairo_show_text (cr, buf); } } @@ -419,14 +381,14 @@ Panner2d::on_expose_event (GdkEventExpose *event) if (target->visible) { - fx = min (target->x.get_value(), 1.0); - fx = max (fx, -1.0f); - x = (gint) floor (width * fx); - - fy = min (target->y.get_value(), 1.0); - fy = max (fy, -1.0f); - y = (gint) floor (height * fy); + CartesianVector c; + + target->position.cartesian (c); + cart_to_gtk (c); + x = (int) floor (c.x); + y = (int) floor (c.y); + snprintf (buf, sizeof (buf), "%d", n); cairo_set_source_rgb (cr, 0.0, 0.8, 0.1); @@ -434,6 +396,7 @@ Panner2d::on_expose_event (GdkEventExpose *event) cairo_fill (cr); cairo_move_to (cr, x+6, y+6); cairo_show_text (cr, buf); + } } } @@ -541,88 +504,80 @@ Panner2d::handle_motion (gint evx, gint evy, GdkModifierType state) if (state & GDK_BUTTON1_MASK && !(state & GDK_BUTTON2_MASK)) { - double fx = evx; - double fy = evy; + CartesianVector c; bool need_move = false; + + drag_target->position.cartesian (c); + cart_to_gtk (c); - clamp_to_circle (fx, fy); - - if ((fx != drag_target->x.get_value()) || (fy != drag_target->y.get_value())) { + if ((evx != c.x) || (evy != c.y)) { need_move = true; } if (need_move) { - drag_target->x.set_value (fx); - drag_target->y.set_value (fy); - - panner->streampanner (drag_index).set_position (drag_target->x.get_value(), drag_target->y.get_value(), false); - queue_draw (); - } + CartesianVector cp (evx, evy, 0.0); - } else if ((state & GDK_BUTTON2_MASK) && !(state & GDK_BUTTON1_MASK)) { + /* canonicalize position */ - int xdelta = drag_x - evx; - int ydelta = drag_x - evy; + gtk_to_cart (cp); - drag_target->azimuth.set_value (drag_target->azimuth.get_value() + (2 * M_PI) * ((float)ydelta)/height * ((float) -xdelta)/height); - queue_draw (); - } + /* position actual signal on circle */ + + clamp_to_circle (cp.x, cp.y); + + /* generate an angular representation and set drag target (GUI) position */ + + cp.angular (drag_target->position); /* sets drag target position */ + + panner->streampanner (drag_index).set_position (drag_target->position); + + queue_draw (); + } + } return true; } void -Panner2d::cart_to_azi_ele (double x, double y, double& azi, double& ele) +Panner2d::cart_to_gtk (CartesianVector& c) const { - x = min (x, (double) width); - x = max (x, 0.0); - x = x / (width-1.0); - - y = min (y, (double) height); - y = max (y, 0.0); - y = y / (height-1.0); - - /* at this point, new_x and new_y are in the range [ 0.0 .. 1.0 ], with - (0,0) at the upper left corner (thank you, X Window) - - we need to translate to (0,0) at center + /* "c" uses a coordinate space that is: + + center = 0.0 + dimension = 2.0 * 2.0 + so max values along each axis are -1..+1 + + GTK uses a coordinate space that is: + + top left = 0.0 + dimension = width * height + so max values along each axis are 0,width and + 0,height */ - - x -= 0.5; - y = (1.0 - y) - 0.5; - PBD::cart_to_azi_ele (x, y, 0.0, azi, ele); + c.x = (width / 2) * (c.x + 1); + c.y = (height / 2) * (1 - c.y); + + /* XXX z-axis not handled - 2D for now */ } void -Panner2d::azi_ele_to_cart (double azi, double ele, double& x, double& y) +Panner2d::gtk_to_cart (CartesianVector& c) const { - double z; + c.x = (c.x / (width / 2.0)) - 1.0; + c.y = -((c.y / (height / 2.0)) - 1.0); - PBD::azi_ele_to_cart (azi, ele, x, y, z); - - /* xp,yp,zp use a (0,0) == center and 2.0 unit dimension. so convert - back to (0,0) and 1.0 unit dimension - */ - - x /= 2.0; - y /= 2.0; - z /= 2.0; - - /* and now convert back to (0,0) == upper left corner */ - - x += 0.5; - y += 0.5; - z += 0.5; + /* XXX z-axis not handled - 2D for now */ } void Panner2d::clamp_to_circle (double& x, double& y) { double azi, ele; - - cart_to_azi_ele (x, y, azi, ele); - azi_ele_to_cart (azi, ele, x, y); + double z = 0.0; + + PBD::cart_to_azi_ele (x, y, z, azi, ele); + PBD::azi_ele_to_cart (azi, ele, x, y, z); } void @@ -631,24 +586,6 @@ Panner2d::toggle_bypass () panner->set_bypassed (!panner->bypassed()); } -void -Panner2d::allow_x_motion (bool yn) -{ - allow_x = yn; -} - -void -Panner2d::allow_target_motion (bool yn) -{ - allow_target = yn; -} - -void -Panner2d::allow_y_motion (bool yn) -{ - allow_y = yn; -} - Panner2dWindow::Panner2dWindow (boost::shared_ptr<Panner> p, int32_t h, uint32_t inputs) : widget (p, h) , reset_button (_("Reset")) @@ -694,10 +631,11 @@ Panner2dWindow::reset (uint32_t n_inputs) { widget.reset (n_inputs); +#if 0 while (spinners.size() < n_inputs) { - spinners.push_back (new Gtk::SpinButton (widget.azimuth (spinners.size()))); - spinner_box.pack_start (*spinners.back(), false, false); - spinners.back()->set_digits (4); + // spinners.push_back (new Gtk::SpinButton (widget.azimuth (spinners.size()))); + //spinner_box.pack_start (*spinners.back(), false, false); + //spinners.back()->set_digits (4); spinners.back()->show (); } @@ -706,4 +644,5 @@ Panner2dWindow::reset (uint32_t n_inputs) delete spinners.back(); spinners.erase (--spinners.end()); } +#endif } diff --git a/gtk2_ardour/panner2d.h b/gtk2_ardour/panner2d.h index fe8305343e..e1572c11b2 100644 --- a/gtk2_ardour/panner2d.h +++ b/gtk2_ardour/panner2d.h @@ -32,6 +32,8 @@ #include <gtkmm/spinbutton.h> #include <gtkmm/adjustment.h> +#include "pbd/cartesian.h" + namespace ARDOUR { class Panner; } @@ -53,22 +55,21 @@ class Panner2d : public Gtk::DrawingArea Panner2d (boost::shared_ptr<ARDOUR::Panner>, int32_t height); ~Panner2d (); - void allow_x_motion(bool); - void allow_y_motion(bool); void allow_target_motion (bool); - int add_target (float x, float y); - int add_puck (const char* text, float x, float y); - void move_puck (int, float x, float y); + int add_target (const PBD::AngularVector&); + int add_puck (const char* text, const PBD::AngularVector&); + void move_puck (int which, const PBD::AngularVector&); void reset (uint32_t n_inputs); - Gtk::Adjustment& azimuth (uint32_t which); - boost::shared_ptr<ARDOUR::Panner> get_panner() const { return panner; } sigc::signal<void,int> PuckMoved; sigc::signal<void,int> TargetMoved; + void cart_to_gtk (PBD::CartesianVector&) const; + void gtk_to_cart (PBD::CartesianVector&) const; + protected: bool on_expose_event (GdkEventExpose *); bool on_button_press_event (GdkEventButton *); @@ -79,25 +80,23 @@ class Panner2d : public Gtk::DrawingArea private: class Target { public: - Gtk::Adjustment x; - Gtk::Adjustment y; - Gtk::Adjustment azimuth; - bool visible; - std::string text; - - Target (float xa, float ya, const char* txt = 0); - ~Target (); - - void set_text (const char*); - void set_selected (bool yn) { - _selected = yn; - } - bool selected() const { - return _selected; - } - + PBD::AngularVector position; + bool visible; + std::string text; + + Target (const PBD::AngularVector&, const char* txt = 0); + ~Target (); + + void set_text (const char*); + void set_selected (bool yn) { + _selected = yn; + } + bool selected() const { + return _selected; + } + private: - bool _selected; + bool _selected; }; boost::shared_ptr<ARDOUR::Panner> panner; @@ -108,14 +107,12 @@ class Panner2d : public Gtk::DrawingArea Targets pucks; Target *drag_target; - int drag_x; - int drag_y; + int drag_x; + int drag_y; int drag_index; - bool allow_x; - bool allow_y; - bool allow_target; - int width; - int height; + bool allow_target; + int width; + int height; bool bypassflag; @@ -133,12 +130,6 @@ class Panner2d : public Gtk::DrawingArea PBD::ScopedConnection state_connection; PBD::ScopedConnection change_connection; - /* cartesian coordinates in GTK units ; return azimuth & elevation in degrees */ - void cart_to_azi_ele (double x, double y, double& azi, double& eli); - - /* azimuth & elevation in degrees; return cartesian coordinates in GTK units */ - void azi_ele_to_cart (double azi, double eli, double& x, double& y); - /* cartesian coordinates in GTK units ; adjust to same but on a circle of radius 1.0 and centered in the middle of our area */ diff --git a/gtk2_ardour/panner_ui.cc b/gtk2_ardour/panner_ui.cc index 25580f0f51..358e99c88b 100644 --- a/gtk2_ardour/panner_ui.cc +++ b/gtk2_ardour/panner_ui.cc @@ -666,23 +666,18 @@ PannerUI::pan_value_changed (uint32_t which) if (twod_panner) { - float x; - float y; - _panner->streampanner(which).get_position (x, y); - in_pan_update = true; - twod_panner->move_puck (which, x, y); + twod_panner->move_puck (which, _panner->streampanner(which).get_position()); in_pan_update = false; } else if (_panner->npanners() > 0 && which < _panner->npanners()) { - float xpos; - float val = pan_adjustments[which]->get_value (); - - _panner->streampanner(which).get_position (xpos); + AngularVector model = _panner->streampanner(which).get_position(); + double fract = pan_adjustments[which]->get_value(); + AngularVector view (BaseStereoPanner::lr_fract_to_azimuth (fract), 0.0); - if (!Panner::equivalent (val, xpos)) { + if (!Panner::equivalent (model, view)) { in_pan_update = true; - pan_adjustments[which]->set_value (xpos); + pan_adjustments[which]->set_value (BaseStereoPanner::azimuth_to_lr_fract (model.azi)); in_pan_update = false; } } @@ -701,7 +696,6 @@ PannerUI::update_pan_bars (bool only_if_aplay) */ for (i = pan_adjustments.begin(), n = 0; i != pan_adjustments.end(); ++i, ++n) { - float xpos, val; if (only_if_aplay) { boost::shared_ptr<AutomationList> alist (_panner->streampanner(n).pan_control()->alist()); @@ -711,11 +705,12 @@ PannerUI::update_pan_bars (bool only_if_aplay) } } - _panner->streampanner(n).get_effective_position (xpos); - val = (*i)->get_value (); + AngularVector model = _panner->streampanner(n).get_effective_position(); + double fract = (*i)->get_value(); + AngularVector view (BaseStereoPanner::lr_fract_to_azimuth (fract), 0.0); - if (!Panner::equivalent (val, xpos)) { - (*i)->set_value (xpos); + if (!Panner::equivalent (model, view)) { + (*i)->set_value (BaseStereoPanner::azimuth_to_lr_fract (model.azi)); } } |