Limit Diopser frequency range in safe mode
This commit is contained in:
parent
afd8830636
commit
035e345e21
|
@ -142,15 +142,26 @@ fn spectrum_analyzer(cx: &mut Context) {
|
||||||
|
|
||||||
VStack::new(cx, |cx| {
|
VStack::new(cx, |cx| {
|
||||||
ZStack::new(cx, |cx| {
|
ZStack::new(cx, |cx| {
|
||||||
analyzer::SpectrumAnalyzer::new(cx, Data::spectrum, Data::sample_rate)
|
analyzer::SpectrumAnalyzer::new(cx, Data::spectrum, Data::sample_rate, {
|
||||||
.width(Percentage(100.0))
|
let safe_mode_clamper = Data::safe_mode_clamper.get(cx);
|
||||||
.height(Percentage(100.0));
|
move |t| safe_mode_clamper.filter_frequency_renormalize_display(t)
|
||||||
|
})
|
||||||
|
.width(Percentage(100.0))
|
||||||
|
.height(Percentage(100.0));
|
||||||
|
|
||||||
xy_pad::XyPad::new(
|
xy_pad::XyPad::new(
|
||||||
cx,
|
cx,
|
||||||
Data::params,
|
Data::params,
|
||||||
|params| ¶ms.filter_frequency,
|
|params| ¶ms.filter_frequency,
|
||||||
|params| ¶ms.filter_resonance,
|
|params| ¶ms.filter_resonance,
|
||||||
|
{
|
||||||
|
let safe_mode_clamper = Data::safe_mode_clamper.get(cx);
|
||||||
|
move |t| safe_mode_clamper.filter_frequency_renormalize_display(t)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
let safe_mode_clamper = Data::safe_mode_clamper.get(cx);
|
||||||
|
move |t| safe_mode_clamper.filter_frequency_renormalize_event(t)
|
||||||
|
},
|
||||||
)
|
)
|
||||||
.width(Percentage(100.0))
|
.width(Percentage(100.0))
|
||||||
.height(Percentage(100.0));
|
.height(Percentage(100.0));
|
||||||
|
|
|
@ -31,6 +31,11 @@ pub struct SpectrumAnalyzer {
|
||||||
spectrum: Arc<Mutex<SpectrumOutput>>,
|
spectrum: Arc<Mutex<SpectrumOutput>>,
|
||||||
sample_rate: Arc<AtomicF32>,
|
sample_rate: Arc<AtomicF32>,
|
||||||
|
|
||||||
|
/// A function that the x-parameter's/frequency parameter's normalized value to a `[0, 1]` value
|
||||||
|
/// that is used to display the parameter. This range may end up zooming in on a part of the
|
||||||
|
/// parameter's original range when safe mode is enabled.
|
||||||
|
x_renormalize_display: Box<dyn Fn(f32) -> f32>,
|
||||||
|
|
||||||
/// The same range as that used by the filter frequency parameter. We'll use this to make sure
|
/// The same range as that used by the filter frequency parameter. We'll use this to make sure
|
||||||
/// we draw the spectrum analyzer's ticks at locations that match the frequency parameter linked
|
/// we draw the spectrum analyzer's ticks at locations that match the frequency parameter linked
|
||||||
/// to the X-Y pad's X-axis.
|
/// to the X-Y pad's X-axis.
|
||||||
|
@ -43,6 +48,7 @@ impl SpectrumAnalyzer {
|
||||||
cx: &mut Context,
|
cx: &mut Context,
|
||||||
spectrum: LSpectrum,
|
spectrum: LSpectrum,
|
||||||
sample_rate: LRate,
|
sample_rate: LRate,
|
||||||
|
x_renormalize_display: impl Fn(f32) -> f32 + Clone + 'static,
|
||||||
) -> Handle<Self>
|
) -> Handle<Self>
|
||||||
where
|
where
|
||||||
LSpectrum: Lens<Target = Arc<Mutex<SpectrumOutput>>>,
|
LSpectrum: Lens<Target = Arc<Mutex<SpectrumOutput>>>,
|
||||||
|
@ -53,6 +59,7 @@ impl SpectrumAnalyzer {
|
||||||
sample_rate: sample_rate.get(cx),
|
sample_rate: sample_rate.get(cx),
|
||||||
|
|
||||||
frequency_range: params::filter_frequency_range(),
|
frequency_range: params::filter_frequency_range(),
|
||||||
|
x_renormalize_display: Box::new(x_renormalize_display),
|
||||||
}
|
}
|
||||||
.build(
|
.build(
|
||||||
cx,
|
cx,
|
||||||
|
@ -86,7 +93,9 @@ impl View for SpectrumAnalyzer {
|
||||||
for (bin_idx, magnetude) in spectrum.iter().enumerate() {
|
for (bin_idx, magnetude) in spectrum.iter().enumerate() {
|
||||||
// We'll match up the bin's x-coordinate with the filter frequency parameter
|
// We'll match up the bin's x-coordinate with the filter frequency parameter
|
||||||
let frequency = (bin_idx as f32 / spectrum.len() as f32) * nyquist;
|
let frequency = (bin_idx as f32 / spectrum.len() as f32) * nyquist;
|
||||||
let t = self.frequency_range.normalize(frequency);
|
// NOTE: This takes the safe-mode switch into acocunt. When it is enabled, the range is
|
||||||
|
// zoomed in to match the X-Y pad.
|
||||||
|
let t = (self.x_renormalize_display)(self.frequency_range.normalize(frequency));
|
||||||
if t <= 0.0 || t >= 1.0 {
|
if t <= 0.0 || t >= 1.0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,11 +25,19 @@ pub struct SafeModeClamper {
|
||||||
/// The maximum value for the filter stages parameter when safe mode is enabled, normalized as a
|
/// The maximum value for the filter stages parameter when safe mode is enabled, normalized as a
|
||||||
/// `[0, 1]` value of the original full range.
|
/// `[0, 1]` value of the original full range.
|
||||||
filter_stages_restricted_normalized_max: f32,
|
filter_stages_restricted_normalized_max: f32,
|
||||||
|
|
||||||
|
/// The minimum value for the filter frequency parameter when safe mode is enabled, normalized
|
||||||
|
/// as a `[0, 1]` value of the original full range.
|
||||||
|
filter_frequency_restricted_normalized_min: f32,
|
||||||
|
/// The maximum value for the filter frequency parameter when safe mode is enabled, normalized
|
||||||
|
/// as a `[0, 1]` value of the original full range.
|
||||||
|
filter_frequency_restricted_normalized_max: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SafeModeClamper {
|
impl SafeModeClamper {
|
||||||
pub fn new(params: Arc<DiopserParams>) -> Self {
|
pub fn new(params: Arc<DiopserParams>) -> Self {
|
||||||
let filter_stages_range = params::filter_stages_range();
|
let filter_stages_range = params::filter_stages_range();
|
||||||
|
let filter_frequency_range = params::filter_frequency_range();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
enabled: params.safe_mode.clone(),
|
enabled: params.safe_mode.clone(),
|
||||||
|
@ -39,6 +47,11 @@ impl SafeModeClamper {
|
||||||
.normalize(params::FILTER_STAGES_RESTRICTED_MIN),
|
.normalize(params::FILTER_STAGES_RESTRICTED_MIN),
|
||||||
filter_stages_restricted_normalized_max: filter_stages_range
|
filter_stages_restricted_normalized_max: filter_stages_range
|
||||||
.normalize(params::FILTER_STAGES_RESTRICTED_MAX),
|
.normalize(params::FILTER_STAGES_RESTRICTED_MAX),
|
||||||
|
|
||||||
|
filter_frequency_restricted_normalized_min: filter_frequency_range
|
||||||
|
.normalize(params::FILTER_FREQUENCY_RESTRICTED_MIN),
|
||||||
|
filter_frequency_restricted_normalized_max: filter_frequency_range
|
||||||
|
.normalize(params::FILTER_FREQUENCY_RESTRICTED_MAX),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,6 +114,35 @@ impl SafeModeClamper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The same as
|
||||||
|
/// [`filter_stages_renormalize_display()`][Self::filter_stages_renormalize_display()], but for
|
||||||
|
/// filter freqnecy.
|
||||||
|
pub fn filter_frequency_renormalize_display(&self, t: f32) -> f32 {
|
||||||
|
if self.status() {
|
||||||
|
let renormalized = (t - self.filter_frequency_restricted_normalized_min)
|
||||||
|
/ (self.filter_frequency_restricted_normalized_max
|
||||||
|
- self.filter_frequency_restricted_normalized_min);
|
||||||
|
|
||||||
|
// This clamping may be necessary when safe mode is enabled but the effects from
|
||||||
|
// `restrict_range()` have not been processed yet
|
||||||
|
renormalized.clamp(0.0, 1.0)
|
||||||
|
} else {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The same as [`filter_stages_renormalize_event()`][Self::filter_stages_renormalize_event()],
|
||||||
|
/// but for filter freqnecy.
|
||||||
|
pub fn filter_frequency_renormalize_event(&self, t: f32) -> f32 {
|
||||||
|
if self.status() {
|
||||||
|
t * (self.filter_frequency_restricted_normalized_max
|
||||||
|
- self.filter_frequency_restricted_normalized_min)
|
||||||
|
+ self.filter_frequency_restricted_normalized_min
|
||||||
|
} else {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// CLamp the parameter values to the restricted range when enabling safe mode. This assumes
|
/// CLamp the parameter values to the restricted range when enabling safe mode. This assumes
|
||||||
/// there's no active automation gesture for these parameters.
|
/// there's no active automation gesture for these parameters.
|
||||||
fn restrict_range(&self, cx: &mut EventContext) {
|
fn restrict_range(&self, cx: &mut EventContext) {
|
||||||
|
@ -116,5 +158,21 @@ impl SafeModeClamper {
|
||||||
.upcast(),
|
.upcast(),
|
||||||
);
|
);
|
||||||
cx.emit(ParamEvent::EndSetParameter(&self.params.filter_stages).upcast());
|
cx.emit(ParamEvent::EndSetParameter(&self.params.filter_stages).upcast());
|
||||||
|
|
||||||
|
cx.emit(ParamEvent::BeginSetParameter(&self.params.filter_frequency).upcast());
|
||||||
|
cx.emit(
|
||||||
|
ParamEvent::SetParameter(
|
||||||
|
&self.params.filter_frequency,
|
||||||
|
self.params
|
||||||
|
.filter_frequency
|
||||||
|
.unmodulated_plain_value()
|
||||||
|
.clamp(
|
||||||
|
params::FILTER_FREQUENCY_RESTRICTED_MIN,
|
||||||
|
params::FILTER_FREQUENCY_RESTRICTED_MAX,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.upcast(),
|
||||||
|
);
|
||||||
|
cx.emit(ParamEvent::EndSetParameter(&self.params.filter_frequency).upcast());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ const HANDLE_WIDTH_PX: f32 = 20.0;
|
||||||
/// An X-Y pad that controlers two parameters at the same time by binding them to one of the two
|
/// An X-Y pad that controlers two parameters at the same time by binding them to one of the two
|
||||||
/// axes. This specific implementation has a tooltip for the X-axis parmaeter and allows
|
/// axes. This specific implementation has a tooltip for the X-axis parmaeter and allows
|
||||||
/// Alt+clicking to enter a specific value.
|
/// Alt+clicking to enter a specific value.
|
||||||
|
///
|
||||||
|
/// The x-parameter's range is restricted when safe mode is enabled. See `RestrictedParamSlider` for
|
||||||
|
/// more details.
|
||||||
#[derive(Lens)]
|
#[derive(Lens)]
|
||||||
pub struct XyPad {
|
pub struct XyPad {
|
||||||
x_param_base: ParamWidgetBase,
|
x_param_base: ParamWidgetBase,
|
||||||
|
@ -41,6 +44,14 @@ pub struct XyPad {
|
||||||
/// frequencies when holding Alt while dragging.
|
/// frequencies when holding Alt while dragging.
|
||||||
/// NOTE: This is hardcoded to work with the filter frequency parameter.
|
/// NOTE: This is hardcoded to work with the filter frequency parameter.
|
||||||
frequency_range: FloatRange,
|
frequency_range: FloatRange,
|
||||||
|
/// Renormalizes the x-parameter's normalized value to a `[0, 1]` value that is used to display
|
||||||
|
/// the parameter. This range may end up zooming in on a part of the parameter's original range
|
||||||
|
/// when safe mode is enabled.
|
||||||
|
x_renormalize_display: Box<dyn Fn(f32) -> f32>,
|
||||||
|
/// The inverse of `renormalize_display`. This is used to map a normalized `[0, 1]` screen
|
||||||
|
/// coordinate back to a `[0, 1]` normalized parameter value. These values may be different when
|
||||||
|
/// safe mode is enabled.
|
||||||
|
x_renormalize_event: Box<dyn Fn(f32) -> f32>,
|
||||||
|
|
||||||
/// Will be set to `true` when the X-Y pad gets Alt+Click'ed. This will replace the handle with
|
/// Will be set to `true` when the X-Y pad gets Alt+Click'ed. This will replace the handle with
|
||||||
/// a text input box.
|
/// a text input box.
|
||||||
|
@ -92,11 +103,16 @@ impl XyPad {
|
||||||
/// Creates a new [`XyPad`] for the given parameter. See
|
/// Creates a new [`XyPad`] for the given parameter. See
|
||||||
/// [`ParamSlider`][nih_plug_vizia::widgets::ParamSlider] for more information on this
|
/// [`ParamSlider`][nih_plug_vizia::widgets::ParamSlider] for more information on this
|
||||||
/// function's arguments.
|
/// function's arguments.
|
||||||
|
///
|
||||||
|
/// The x-parameter's range is restricted when safe mode is enabled. See `RestrictedParamSlider`
|
||||||
|
/// for more details.
|
||||||
pub fn new<L, Params, P1, P2, FMap1, FMap2>(
|
pub fn new<L, Params, P1, P2, FMap1, FMap2>(
|
||||||
cx: &mut Context,
|
cx: &mut Context,
|
||||||
params: L,
|
params: L,
|
||||||
params_to_x_param: FMap1,
|
params_to_x_param: FMap1,
|
||||||
params_to_y_param: FMap2,
|
params_to_y_param: FMap2,
|
||||||
|
x_renormalize_display: impl Fn(f32) -> f32 + Clone + 'static,
|
||||||
|
x_renormalize_event: impl Fn(f32) -> f32 + 'static,
|
||||||
) -> Handle<Self>
|
) -> Handle<Self>
|
||||||
where
|
where
|
||||||
L: Lens<Target = Params> + Clone,
|
L: Lens<Target = Params> + Clone,
|
||||||
|
@ -111,6 +127,8 @@ impl XyPad {
|
||||||
y_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_y_param),
|
y_param_base: ParamWidgetBase::new(cx, params.clone(), params_to_y_param),
|
||||||
|
|
||||||
frequency_range: params::filter_frequency_range(),
|
frequency_range: params::filter_frequency_range(),
|
||||||
|
x_renormalize_display: Box::new(x_renormalize_display.clone()),
|
||||||
|
x_renormalize_event: Box::new(x_renormalize_event),
|
||||||
|
|
||||||
text_input_active: false,
|
text_input_active: false,
|
||||||
drag_active: false,
|
drag_active: false,
|
||||||
|
@ -133,9 +151,16 @@ impl XyPad {
|
||||||
params,
|
params,
|
||||||
params_to_y_param,
|
params_to_y_param,
|
||||||
move |cx, y_param_data| {
|
move |cx, y_param_data| {
|
||||||
let x_position_lens = x_param_data.make_lens(|param| {
|
// The x-parameter's range is clamped when safe mode is enabled
|
||||||
Percentage(param.unmodulated_normalized_value() * 100.0)
|
let x_position_lens = {
|
||||||
});
|
let x_renormalize_display = x_renormalize_display.clone();
|
||||||
|
x_param_data.make_lens(move |param| {
|
||||||
|
Percentage(
|
||||||
|
x_renormalize_display(param.unmodulated_normalized_value())
|
||||||
|
* 100.0,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
};
|
||||||
let y_position_lens = y_param_data.make_lens(|param| {
|
let y_position_lens = y_param_data.make_lens(|param| {
|
||||||
// NOTE: The y-axis increments downards, and we want high values at
|
// NOTE: The y-axis increments downards, and we want high values at
|
||||||
// the top and low values at the bottom
|
// the top and low values at the bottom
|
||||||
|
@ -144,8 +169,11 @@ impl XyPad {
|
||||||
|
|
||||||
// Another handle is drawn below the regular handle to show the
|
// Another handle is drawn below the regular handle to show the
|
||||||
// modualted value
|
// modualted value
|
||||||
let modulated_x_position_lens = x_param_data.make_lens(|param| {
|
let modulated_x_position_lens = x_param_data.make_lens(move |param| {
|
||||||
Percentage(param.modulated_normalized_value() * 100.0)
|
Percentage(
|
||||||
|
x_renormalize_display(param.modulated_normalized_value())
|
||||||
|
* 100.0,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
let modulated_y_position_lens = y_param_data.make_lens(|param| {
|
let modulated_y_position_lens = y_param_data.make_lens(|param| {
|
||||||
Percentage((1.0 - param.modulated_normalized_value()) * 100.0)
|
Percentage((1.0 - param.modulated_normalized_value()) * 100.0)
|
||||||
|
@ -311,8 +339,10 @@ impl XyPad {
|
||||||
snap_to_whole_notes: bool,
|
snap_to_whole_notes: bool,
|
||||||
) {
|
) {
|
||||||
// When snapping to whole notes, we'll transform the normalized value back to unnormalized
|
// When snapping to whole notes, we'll transform the normalized value back to unnormalized
|
||||||
// (this is hardcoded for the filter frequency parameter)
|
// (this is hardcoded for the filter frequency parameter). These coordinate mappings also
|
||||||
let mut x_value = util::remap_current_entity_x_coordinate(cx, x_pos);
|
// need to respect the restricted ranges from the safe mode button.
|
||||||
|
let mut x_value =
|
||||||
|
(self.x_renormalize_event)(util::remap_current_entity_x_coordinate(cx, x_pos));
|
||||||
if snap_to_whole_notes {
|
if snap_to_whole_notes {
|
||||||
let x_freq = self.frequency_range.unnormalize(x_value);
|
let x_freq = self.frequency_range.unnormalize(x_value);
|
||||||
|
|
||||||
|
@ -523,14 +553,16 @@ impl View for XyPad {
|
||||||
});
|
});
|
||||||
|
|
||||||
// These positions should be compensated for the DPI scale so it remains
|
// These positions should be compensated for the DPI scale so it remains
|
||||||
// consistent
|
// consistent. When the range is restricted the `delta_x` should also change
|
||||||
|
// accordingly.
|
||||||
let start_x = util::remap_current_entity_x_t(
|
let start_x = util::remap_current_entity_x_t(
|
||||||
cx,
|
cx,
|
||||||
granular_drag_status.x_starting_value,
|
(self.x_renormalize_display)(granular_drag_status.x_starting_value),
|
||||||
);
|
);
|
||||||
let delta_x = ((*x - granular_drag_status.starting_x_coordinate)
|
let delta_x = (*x - granular_drag_status.starting_x_coordinate)
|
||||||
* GRANULAR_DRAG_MULTIPLIER)
|
* GRANULAR_DRAG_MULTIPLIER
|
||||||
* dpi_scale;
|
* dpi_scale;
|
||||||
|
|
||||||
let start_y = util::remap_current_entity_y_t(
|
let start_y = util::remap_current_entity_y_t(
|
||||||
cx,
|
cx,
|
||||||
// NOTE: Just like above, the corodinates go from top to bottom
|
// NOTE: Just like above, the corodinates go from top to bottom
|
||||||
|
@ -576,37 +608,71 @@ impl View for XyPad {
|
||||||
*remaining_scroll_x += scroll_x;
|
*remaining_scroll_x += scroll_x;
|
||||||
*remaining_scroll_y += scroll_y;
|
*remaining_scroll_y += scroll_y;
|
||||||
|
|
||||||
for (param_base, scrolled_lines) in [
|
// This is a pretty crude way to avoid scrolling outside of the safe mode range
|
||||||
(&self.x_param_base, remaining_scroll_x),
|
let clamp_x_value =
|
||||||
(&self.y_param_base, remaining_scroll_y),
|
|value| (self.x_renormalize_event)((self.x_renormalize_display)(value));
|
||||||
] {
|
|
||||||
if scrolled_lines.abs() >= 1.0 {
|
|
||||||
let use_finer_steps = cx.modifiers.shift();
|
|
||||||
|
|
||||||
// Scrolling while dragging needs to be taken into account here
|
if remaining_scroll_x.abs() >= 1.0 {
|
||||||
if !self.drag_active {
|
let use_finer_steps = cx.modifiers.shift();
|
||||||
param_base.begin_set_parameter(cx);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut current_value = param_base.unmodulated_normalized_value();
|
// Scrolling while dragging needs to be taken into account here
|
||||||
|
if !self.drag_active {
|
||||||
|
self.x_param_base.begin_set_parameter(cx);
|
||||||
|
}
|
||||||
|
|
||||||
while *scrolled_lines >= 1.0 {
|
let mut current_value = self.x_param_base.unmodulated_normalized_value();
|
||||||
current_value =
|
|
||||||
param_base.next_normalized_step(current_value, use_finer_steps);
|
|
||||||
param_base.set_normalized_value(cx, current_value);
|
|
||||||
*scrolled_lines -= 1.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
while *scrolled_lines <= -1.0 {
|
while *remaining_scroll_x >= 1.0 {
|
||||||
current_value =
|
current_value = self
|
||||||
param_base.previous_normalized_step(current_value, use_finer_steps);
|
.x_param_base
|
||||||
param_base.set_normalized_value(cx, current_value);
|
.next_normalized_step(current_value, use_finer_steps);
|
||||||
*scrolled_lines += 1.0;
|
self.x_param_base
|
||||||
}
|
.set_normalized_value(cx, clamp_x_value(current_value));
|
||||||
|
*remaining_scroll_x -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
if !self.drag_active {
|
while *remaining_scroll_x <= -1.0 {
|
||||||
param_base.end_set_parameter(cx);
|
current_value = self
|
||||||
}
|
.x_param_base
|
||||||
|
.previous_normalized_step(current_value, use_finer_steps);
|
||||||
|
self.x_param_base
|
||||||
|
.set_normalized_value(cx, clamp_x_value(current_value));
|
||||||
|
*remaining_scroll_x += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.drag_active {
|
||||||
|
self.x_param_base.end_set_parameter(cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if remaining_scroll_y.abs() >= 1.0 {
|
||||||
|
let use_finer_steps = cx.modifiers.shift();
|
||||||
|
|
||||||
|
// Scrolling while dragging needs to be taken into account here
|
||||||
|
if !self.drag_active {
|
||||||
|
self.y_param_base.begin_set_parameter(cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut current_value = self.y_param_base.unmodulated_normalized_value();
|
||||||
|
|
||||||
|
while *remaining_scroll_y >= 1.0 {
|
||||||
|
current_value = self
|
||||||
|
.y_param_base
|
||||||
|
.next_normalized_step(current_value, use_finer_steps);
|
||||||
|
self.y_param_base.set_normalized_value(cx, current_value);
|
||||||
|
*remaining_scroll_y -= 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
while *remaining_scroll_y <= -1.0 {
|
||||||
|
current_value = self
|
||||||
|
.y_param_base
|
||||||
|
.previous_normalized_step(current_value, use_finer_steps);
|
||||||
|
self.y_param_base.set_normalized_value(cx, current_value);
|
||||||
|
*remaining_scroll_y += 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.drag_active {
|
||||||
|
self.y_param_base.end_set_parameter(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -40,6 +40,11 @@ pub fn filter_frequency_range() -> FloatRange {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The filter frequency parameters minimum value in safe mode.
|
||||||
|
pub const FILTER_FREQUENCY_RESTRICTED_MIN: f32 = 20.0;
|
||||||
|
/// The filter frequency parameters maximum value in safe mode.
|
||||||
|
pub const FILTER_FREQUENCY_RESTRICTED_MAX: f32 = 22_000.0;
|
||||||
|
|
||||||
pub fn normalize_automation_precision(step_size: u32) -> f32 {
|
pub fn normalize_automation_precision(step_size: u32) -> f32 {
|
||||||
(MAX_AUTOMATION_STEP_SIZE - step_size) as f32
|
(MAX_AUTOMATION_STEP_SIZE - step_size) as f32
|
||||||
/ (MAX_AUTOMATION_STEP_SIZE - MIN_AUTOMATION_STEP_SIZE) as f32
|
/ (MAX_AUTOMATION_STEP_SIZE - MIN_AUTOMATION_STEP_SIZE) as f32
|
||||||
|
|
Loading…
Reference in a new issue