mirror of
https://github.com/Ardour/ardour.git
synced 2025-12-07 07:14:56 +01:00
Overhaul vari-speed shuttle control display
* keep shuttle and mouse position in sync when dragging * do not show speed options above max-transport-speed * use quadratic deflection with speed percentage * reduce knob width since the slider is rather narrow these days
This commit is contained in:
parent
00bd50882e
commit
89a85da52c
2 changed files with 68 additions and 20 deletions
|
|
@ -21,6 +21,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BASELINESTRETCH (1.25)
|
#define BASELINESTRETCH (1.25)
|
||||||
|
#define MARKER_SIZE (0.5) // * height
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
|
|
@ -331,7 +332,7 @@ ShuttleControl::map_transport_state ()
|
||||||
semi = std::max (-24, std::min (24, semi));
|
semi = std::max (-24, std::min (24, semi));
|
||||||
shuttle_fract = semitones_as_fract (semi, reverse);
|
shuttle_fract = semitones_as_fract (semi, reverse);
|
||||||
} else {
|
} else {
|
||||||
shuttle_fract = speed / shuttle_max_speed;
|
shuttle_fract = speed_as_fract (speed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -348,40 +349,57 @@ ShuttleControl::build_shuttle_context_menu ()
|
||||||
shuttle_context_menu = new Menu ();
|
shuttle_context_menu = new Menu ();
|
||||||
MenuList& items = shuttle_context_menu->items ();
|
MenuList& items = shuttle_context_menu->items ();
|
||||||
|
|
||||||
{
|
float max_transport_speed = Config->get_max_transport_speed ();
|
||||||
|
|
||||||
RadioMenuItem::Group speed_group;
|
RadioMenuItem::Group speed_group;
|
||||||
|
|
||||||
/* XXX this code assumes that Config->get_max_transport_speed() returns 8 */
|
|
||||||
Menu* speed_menu = manage (new Menu ());
|
Menu* speed_menu = manage (new Menu ());
|
||||||
MenuList& speed_items = speed_menu->items ();
|
MenuList& speed_items = speed_menu->items ();
|
||||||
|
|
||||||
|
if (max_transport_speed >= 8) {
|
||||||
speed_items.push_back (RadioMenuElem (speed_group, "8", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 8.0f)));
|
speed_items.push_back (RadioMenuElem (speed_group, "8", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 8.0f)));
|
||||||
if (shuttle_max_speed == 8.0) {
|
if (shuttle_max_speed == 8.0) {
|
||||||
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (max_transport_speed >= 6) {
|
||||||
speed_items.push_back (RadioMenuElem (speed_group, "6", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 6.0f)));
|
speed_items.push_back (RadioMenuElem (speed_group, "6", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 6.0f)));
|
||||||
if (shuttle_max_speed == 6.0) {
|
if (shuttle_max_speed == 6.0) {
|
||||||
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (max_transport_speed >= 4) {
|
||||||
speed_items.push_back (RadioMenuElem (speed_group, "4", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 4.0f)));
|
speed_items.push_back (RadioMenuElem (speed_group, "4", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 4.0f)));
|
||||||
if (shuttle_max_speed == 4.0) {
|
if (shuttle_max_speed == 4.0) {
|
||||||
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (max_transport_speed >= 3) {
|
||||||
speed_items.push_back (RadioMenuElem (speed_group, "3", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 3.0f)));
|
speed_items.push_back (RadioMenuElem (speed_group, "3", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 3.0f)));
|
||||||
if (shuttle_max_speed == 3.0) {
|
if (shuttle_max_speed == 3.0) {
|
||||||
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (max_transport_speed >= 2) {
|
||||||
speed_items.push_back (RadioMenuElem (speed_group, "2", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 2.0f)));
|
speed_items.push_back (RadioMenuElem (speed_group, "2", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 2.0f)));
|
||||||
if (shuttle_max_speed == 2.0) {
|
if (shuttle_max_speed == 2.0) {
|
||||||
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
if (max_transport_speed >= 1.5) {
|
||||||
speed_items.push_back (RadioMenuElem (speed_group, "1.5", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 1.5f)));
|
speed_items.push_back (RadioMenuElem (speed_group, "1.5", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 1.5f)));
|
||||||
if (shuttle_max_speed == 1.5) {
|
if (shuttle_max_speed == 1.5) {
|
||||||
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
assert (max_transport_speed >= 1);
|
||||||
|
speed_items.push_back (RadioMenuElem (speed_group, "1", sigc::bind (sigc::mem_fun (*this, &ShuttleControl::set_shuttle_max_speed), 1.f)));
|
||||||
|
if (shuttle_max_speed == 1) {
|
||||||
|
static_cast<RadioMenuItem*> (&speed_items.back ())->set_active ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
items.push_back (MenuElem (_("Maximum speed"), *speed_menu));
|
items.push_back (MenuElem (_("Maximum speed"), *speed_menu));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -390,6 +408,9 @@ ShuttleControl::set_shuttle_max_speed (float speed)
|
||||||
if (_ignore_change) {
|
if (_ignore_change) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert (speed <= Config->get_max_transport_speed ());
|
||||||
|
|
||||||
Config->set_shuttle_max_speed (speed);
|
Config->set_shuttle_max_speed (speed);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,7 +523,10 @@ ShuttleControl::mouse_shuttle (double x, bool force)
|
||||||
center, negative values indicate left of center
|
center, negative values indicate left of center
|
||||||
*/
|
*/
|
||||||
|
|
||||||
shuttle_fract = distance_from_center / center; // center == half the width
|
float marker_size = round (get_height () * MARKER_SIZE);
|
||||||
|
float avail_width = get_width () - marker_size;
|
||||||
|
|
||||||
|
shuttle_fract = 2 * distance_from_center / avail_width;
|
||||||
use_shuttle_fract (force);
|
use_shuttle_fract (force);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -563,17 +587,38 @@ ShuttleControl::semitones_as_speed (int semi, bool reverse)
|
||||||
}
|
}
|
||||||
|
|
||||||
float
|
float
|
||||||
ShuttleControl::semitones_as_fract (int semi, bool reverse)
|
ShuttleControl::semitones_as_fract (int semi, bool reverse) const
|
||||||
{
|
{
|
||||||
float speed = semitones_as_speed (semi, reverse);
|
return semitones_as_speed (semi, reverse) / shuttle_max_speed;
|
||||||
return speed / 4.0; /* 4.0 is the maximum speed for a 24 semitone shift */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ShuttleControl::fract_as_semitones (float fract, bool& reverse)
|
ShuttleControl::fract_as_semitones (float fract, bool& reverse) const
|
||||||
{
|
{
|
||||||
|
/* -1 <= fract <= 1 */
|
||||||
assert (fract != 0.0);
|
assert (fract != 0.0);
|
||||||
return speed_as_semitones (fract * 4.0, reverse);
|
return speed_as_semitones (fract * shuttle_max_speed, reverse);
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
ShuttleControl::speed_as_fract (float speed) const
|
||||||
|
{
|
||||||
|
float fract = speed / shuttle_max_speed;
|
||||||
|
if (fract < 0) {
|
||||||
|
return -sqrtf (-fract);
|
||||||
|
} else {
|
||||||
|
return sqrtf (fract);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
ShuttleControl::fract_as_speed (float fract) const
|
||||||
|
{
|
||||||
|
if (fract < 0) {
|
||||||
|
return -fract * fract * shuttle_max_speed;
|
||||||
|
} else {
|
||||||
|
return fract * fract * shuttle_max_speed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
@ -595,6 +640,7 @@ ShuttleControl::use_shuttle_fract (bool force, bool zero_ok)
|
||||||
last_shuttle_request = now;
|
last_shuttle_request = now;
|
||||||
|
|
||||||
double speed = 0;
|
double speed = 0;
|
||||||
|
float warped_fract = shuttle_fract * shuttle_fract;
|
||||||
|
|
||||||
if (Config->get_shuttle_units () == Semitones) {
|
if (Config->get_shuttle_units () == Semitones) {
|
||||||
if (shuttle_fract != 0.0) {
|
if (shuttle_fract != 0.0) {
|
||||||
|
|
@ -605,8 +651,7 @@ ShuttleControl::use_shuttle_fract (bool force, bool zero_ok)
|
||||||
speed = 0.0;
|
speed = 0.0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
shuttle_fract = shuttle_fract * shuttle_fract * shuttle_fract; // ^3 preserves the sign;
|
speed = fract_as_speed (shuttle_fract);
|
||||||
speed = shuttle_max_speed * shuttle_fract;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
requested_speed = speed;
|
requested_speed = speed;
|
||||||
|
|
@ -673,7 +718,7 @@ ShuttleControl::render (Cairo::RefPtr<Cairo::Context> const& ctx, cairo_rectangl
|
||||||
|
|
||||||
/* marker */
|
/* marker */
|
||||||
float visual_fraction = std::max (-1.0f, std::min (1.0f, speed / shuttle_max_speed));
|
float visual_fraction = std::max (-1.0f, std::min (1.0f, speed / shuttle_max_speed));
|
||||||
float marker_size = round (get_height () * 0.66);
|
float marker_size = round (get_height () * MARKER_SIZE);
|
||||||
float avail_width = get_width () - marker_size;
|
float avail_width = get_width () - marker_size;
|
||||||
float x = 0.5 * (get_width () + visual_fraction * avail_width - marker_size);
|
float x = 0.5 * (get_width () + visual_fraction * avail_width - marker_size);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -101,11 +101,14 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static int speed_as_semitones (float, bool&);
|
int fract_as_semitones (float, bool&) const;
|
||||||
static int fract_as_semitones (float, bool&);
|
float semitones_as_fract (int, bool) const;
|
||||||
|
|
||||||
|
float speed_as_fract (float) const;
|
||||||
|
float fract_as_speed (float) const;
|
||||||
|
|
||||||
|
static int speed_as_semitones (float, bool&);
|
||||||
static float semitones_as_speed (int, bool);
|
static float semitones_as_speed (int, bool);
|
||||||
static float semitones_as_fract (int, bool);
|
|
||||||
|
|
||||||
static int speed_as_cents (float, bool&);
|
static int speed_as_cents (float, bool&);
|
||||||
static float cents_as_speed (int, bool);
|
static float cents_as_speed (int, bool);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue