diff --git a/src/editor.rs b/src/editor.rs index 78c4db0..cfd66bc 100644 --- a/src/editor.rs +++ b/src/editor.rs @@ -95,34 +95,35 @@ pub(crate) fn create( HStack::new(cx, |cx| { // first VStack::new(cx, |cx| { + // bypass and latency_mode HStack::new(cx, |cx| { - // bypass and latency_mode + // label & slider VStack::new(cx, |cx| { - // label & slider Label::new(cx, "bypass").class("fader-label"); ParamButton::new(cx, LambData::params, |params| ¶ms.bypass) .with_label("") .for_bypass() - .width(Percentage(95.0)) - .right(Percentage(5.0)); - }) // label & slider + .width(Percentage(100.0)); + // label & slider + }) .height(Auto) .class("center"); - // label & slider + // bypass and latency_mode VStack::new(cx, |cx| { Label::new(cx, "latency mode").class("fader-label"); ParamSlider::new(cx, LambData::params, |params| { ¶ms.latency_mode }) .set_style(ParamSliderStyle::CurrentStepLabeled { even: true }) - .width(Percentage(95.0)) - .left(Percentage(5.0)); + .width(Percentage(100.0)); }) // label & slider + .width(Stretch(1.0)) .height(Auto) .class("center"); }) // bypass and latency_mode - .height(Auto) - .width(Percentage(100.0)); // level + time + .col_between(Percentage(5.0)) + .width(Percentage(100.0)) + .height(Auto); // bypass & latency_mode Label::new(cx, "ratio").class("fader-label"); ParamSlider::new(cx, LambData::params, |params| ¶ms.strength); Label::new(cx, "threshold").class("fader-label"); @@ -131,8 +132,7 @@ pub(crate) fn create( ParamSlider::new(cx, LambData::params, |params| ¶ms.knee); }) // first .height(Auto) - .class("center") - .right(Percentage(2.5)); + .class("center"); // second VStack::new(cx, |cx| { Label::new(cx, "lookahead").class("fader-label"); @@ -148,9 +148,7 @@ pub(crate) fn create( .set_style(ParamSliderStyle::FromLeft); }) // second .height(Auto) - .class("center") - .left(Percentage(1.25)) - .right(Percentage(1.25)); + .class("center"); // third VStack::new(cx, |cx| { Label::new(cx, "attack").class("fader-label"); @@ -164,9 +162,9 @@ pub(crate) fn create( .set_style(ParamSliderStyle::FromLeft); }) // third .height(Auto) - .class("center") - .left(Percentage(2.5)); + .class("center"); }) + .col_between(Percentage(2.5)) .height(Auto) .width(Percentage(100.0)); // three colomns @@ -174,9 +172,10 @@ pub(crate) fn create( ParamSlider::new(cx, LambData::params, |params| ¶ms.output_gain) .bottom(Pixels(6.0)); }) // parameters - .width(Percentage(75.0)) + // .width(Percentage(72.5)) + .width(Stretch(3.0)) .height(Auto) - .right(Percentage(2.5)) + // .right(Percentage(2.5)) .class("center"); // graph + zoom VStack::new(cx, |cx| { @@ -192,24 +191,47 @@ pub(crate) fn create( Label::new(cx, "").class("fader-label"); // spacer AttackReleaseGraph::new(cx, LambData::params).height(Pixels(200.0)); // .height(Pixels(260.0)); - Label::new(cx, "GR graph time scale").class("fader-label"); - ParamSlider::new(cx, LambData::params, |params| ¶ms.time_scale) - .set_style(ParamSliderStyle::CurrentStep { even: true }) - .bottom(Pixels(6.0)); + Label::new(cx, "gain reduction graph").class("fader-label"); + HStack::new(cx, |cx| { + ParamSlider::new(cx, LambData::params, |params| ¶ms.time_scale) + .width(Stretch(1.0)) + .set_style(ParamSliderStyle::CurrentStep { even: true }) + .bottom(Pixels(6.0)); + ParamSlider::new(cx, LambData::params, |params| ¶ms.in_out) + .set_style(ParamSliderStyle::CurrentStepLabeled { even: true }) + .width(Stretch(1.0)) + .bottom(Pixels(6.0)); + HStack::new(cx, |cx| { + ParamButton::new(cx, LambData::params, |params| ¶ms.show_left) + .with_label("left") + .width(Stretch(1.0)) + .bottom(Pixels(6.0)); + ParamButton::new(cx, LambData::params, |params| ¶ms.show_right) + .with_label("right") + .width(Stretch(1.0)) + .bottom(Pixels(6.0)); + }) + .width(Stretch(1.0)) + // .width(Percentage(100.0)) + ; + }) + .width(Percentage(100.0)) + .col_between(Percentage(5.0)); }) // graph + zoom + .width(Stretch(1.0)) .height(Auto) .class("center"); }) // parameters + graph + .col_between(Percentage(2.5)) .height(Auto) .width(Percentage(100.0)); - - peak_graph(cx); + peak_graph(cx, params.show_left.value(), params.show_right.value()); }) // everything - .width(Percentage(95.0)) - .height(Auto) - .left(Percentage(2.5)) - .right(Percentage(2.5)) - .class("center"); + .width(Percentage(95.0)) + .height(Auto) + .left(Percentage(2.5)) + .right(Percentage(2.5)) + .class("center"); ResizeHandle::new(cx); }) } @@ -376,7 +398,7 @@ impl>> View } /// Draws a peak graph with a grid backdrop, unit ruler, and a peak meter to side. -fn peak_graph(cx: &mut Context) { +fn peak_graph(cx: &mut Context, show_left: bool, show_right: bool) { HStack::new(cx, |cx| { ZStack::new(cx, |cx| { Grid::new( @@ -386,46 +408,53 @@ fn peak_graph(cx: &mut Context) { vec![0.0, -6.0, -12.0, -18.0, -24.0], Orientation::Horizontal, ) - .color(Color::rgba(160, 160, 160, 60)); + .color(Color::rgba(160, 160, 160, 60)); - // level - Graph::new( - cx, - LambData::level_buffer_l, - (METER_MIN, METER_MAX), - ValueScaling::Decibels, - ) - .color(Color::rgba(0, 0, 255, 30)) - .background_color(Color::rgba(0, 0, 0, 40)); + if show_left { + println!("left"); + // level + Graph::new( + cx, + LambData::level_buffer_l, + (METER_MIN, METER_MAX), + ValueScaling::Decibels, + ) + .color(Color::rgba(0, 0, 255, 30)) + .background_color(Color::rgba(0, 0, 0, 40)); - Graph::new( - cx, - LambData::level_buffer_r, - (METER_MIN, METER_MAX), - ValueScaling::Decibels, - ) + // gain reduction + Graph::new( + cx, + LambData::gr_buffer_l, + (METER_MIN, METER_MAX), + ValueScaling::Decibels, + ) + .color(Color::rgba(0, 0, 255, 255)) + .background_color(Color::rgba(250, 250, 250, 40)) + .fill_from(0.0); + }; + if show_right { + println!("right"); + // level + Graph::new( + cx, + LambData::level_buffer_r, + (METER_MIN, METER_MAX), + ValueScaling::Decibels, + ) .color(Color::rgba(255, 0, 0, 30)) .background_color(Color::rgba(0, 0, 0, 40)); - - // gain reduction - Graph::new( - cx, - LambData::gr_buffer_l, - (METER_MIN, METER_MAX), - ValueScaling::Decibels, - ) - .color(Color::rgba(0, 0, 255, 255)) - .background_color(Color::rgba(250, 250, 250, 40)) - .fill_from(0.0); - Graph::new( - cx, - LambData::gr_buffer_r, - (METER_MIN, METER_MAX), - ValueScaling::Decibels, - ) - .color(Color::rgba(255, 0, 0, 255)) - .background_color(Color::rgba(250, 250, 250, 40)) - .fill_from(0.0); + // gain reduction + Graph::new( + cx, + LambData::gr_buffer_r, + (METER_MIN, METER_MAX), + ValueScaling::Decibels, + ) + .color(Color::rgba(255, 0, 0, 255)) + .background_color(Color::rgba(250, 250, 250, 40)) + .fill_from(0.0); + }; }); ZStack::new(cx, |cx| { diff --git a/src/lib.rs b/src/lib.rs index 0fd9fb5..2948dfd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,12 +35,20 @@ pub struct Lamb { /// If this is set at the start of the processing cycle, then the graph duration should be updated. should_update_time_scale: Arc, + should_update_show_left: Arc, + should_update_show_right: Arc, } impl Default for Lamb { fn default() -> Self { let should_update_time_scale = Arc::new(AtomicBool::new(false)); + let should_update_show_left = Arc::new(AtomicBool::new(false)); + let should_update_show_right = Arc::new(AtomicBool::new(false)); Self { - params: Arc::new(LambParams::new(should_update_time_scale.clone())), + params: Arc::new(LambParams::new( + should_update_time_scale.clone(), + should_update_show_left.clone(), + should_update_show_right.clone(), + )), // params: Arc::new(LambParams::default()), dsp: dsp::LambRs::default_boxed(), @@ -56,6 +64,8 @@ impl Default for Lamb { gr_buffer_l: Arc::new(Mutex::new(MinimaBuffer::new(1114, 7.0, 0.0))), gr_buffer_r: Arc::new(Mutex::new(MinimaBuffer::new(1114, 7.0, 0.0))), should_update_time_scale, + should_update_show_left, + should_update_show_right, } } } @@ -151,6 +161,8 @@ impl Plugin for Lamb { // Reset buffers and envelopes here. This can be called from the audio thread and may not // allocate. You can remove this function if you do not need it. self.should_update_time_scale.store(true, Ordering::Release); + self.should_update_show_left.store(true, Ordering::Release); + self.should_update_show_right.store(true, Ordering::Release); } fn editor(&mut self, _async_executor: AsyncExecutor) -> Option> { @@ -211,6 +223,22 @@ impl Plugin for Lamb { self.dsp .set_param(OUTPUT_GAIN_PI, self.params.output_gain.value() as f64); + // works, but is out of allignment + // if self.params.editor_state.is_open() { + // if self.params.in_out.value() {} + // else { + // println!("pre"); + // self.level_buffer_l + // .lock() + // .unwrap() + // .enqueue_buffer(buffer, None); + // self.level_buffer_r + // .lock() + // .unwrap() + // .enqueue_buffer(buffer, None); + // }; + // }; + self.dsp.compute( count, &self.accum_buffer.slice2d(), @@ -249,15 +277,38 @@ impl Plugin for Lamb { self.should_update_time_scale .store(false, Ordering::Release); }; + + if self.params.in_out.value() { + for i in 0..count as usize { + self.level_buffer_l + .lock() + .unwrap() + .enqueue(self.temp_output_buffer_l[i] as f32); + self.level_buffer_r + .lock() + .unwrap() + .enqueue(self.temp_output_buffer_r[i] as f32); + } + } else { + let gain_db = + 0.0 - (self.params.input_gain.value() + self.params.output_gain.value()); + let gain = if self.params.bypass.value() { + 1.0 + } else { + 10f32.powf(gain_db / 20.0) + }; + for i in 0..count as usize { + self.level_buffer_l.lock().unwrap().enqueue( + (self.temp_output_buffer_l[i] / self.temp_output_buffer_gr_l[i]) as f32 + * gain, + ); + self.level_buffer_r.lock().unwrap().enqueue( + (self.temp_output_buffer_r[i] / self.temp_output_buffer_gr_r[i]) as f32 + * gain, + ); + } + }; for i in 0..count as usize { - self.level_buffer_l - .lock() - .unwrap() - .enqueue(self.temp_output_buffer_l[i] as f32); - self.level_buffer_r - .lock() - .unwrap() - .enqueue(self.temp_output_buffer_r[i] as f32); self.gr_buffer_l .lock() .unwrap() diff --git a/src/params.rs b/src/params.rs index 006975e..8d6e021 100644 --- a/src/params.rs +++ b/src/params.rs @@ -38,6 +38,12 @@ struct LambParams { zoom_mode: EnumParam, #[id = "time_scale"] time_scale: EnumParam, + #[id = "in_out"] + in_out: BoolParam, + #[id = "show_left"] + show_left: BoolParam, + #[id = "show_right"] + show_right: BoolParam, /// The editor state, saved together with the parameter state so the custom scaling can be /// restored. @@ -165,8 +171,41 @@ pub fn ratio_to_strength() -> Arc Option + Send + Sync> { }) } +// .with_value_to_string(bool_to_in_out()) +// .with_string_to_value(in_out_to_bool()) +// pub fn bool_to_in_out() + +/// Display 'post' or 'pre' depending on whether the parameter is true or false. +pub fn v2s_bool_in_out() -> Arc String + Send + Sync> { + Arc::new(move |value| { + if value { + String::from("post") + } else { + String::from("pre") + } + }) +} + +/// Parse a string in the same format as [`v2s_bool_in_out()`]. +pub fn s2v_bool_in_out() -> Arc Option + Send + Sync> { + Arc::new(|string| { + let string = string.trim(); + if string.eq_ignore_ascii_case("post") { + Some(true) + } else if string.eq_ignore_ascii_case("pre") { + Some(false) + } else { + None + } + }) +} + impl LambParams { - pub fn new(should_update_time_scale: Arc) -> Self { + pub fn new( + should_update_time_scale: Arc, + should_update_show_left: Arc, + should_update_show_right: Arc, + ) -> Self { Self { editor_state: editor::default_state(), @@ -194,8 +233,7 @@ impl LambParams { }, ) .with_value_to_string(strength_to_ratio()) - .with_string_to_value(ratio_to_strength()), // .with_unit(" %") - // .with_step_size(1.0) + .with_string_to_value(ratio_to_strength()), thresh: FloatParam::new( "thresh", -1.0, @@ -313,6 +351,25 @@ impl LambParams { }) .hide() .hide_in_generic_ui(), + in_out: BoolParam::new("in_out", true) + .with_value_to_string(v2s_bool_in_out()) + .with_string_to_value(s2v_bool_in_out()) + .hide() + .hide_in_generic_ui(), + show_left: BoolParam::new("show_left", true) + .with_callback({ + let should_update_show_left = should_update_show_left.clone(); + Arc::new(move |_| should_update_show_left.store(true, Ordering::Release)) + }) + .hide() + .hide_in_generic_ui(), + show_right: BoolParam::new("show_right", true) + .with_callback({ + let should_update_show_right = should_update_show_right.clone(); + Arc::new(move |_| should_update_show_right.store(true, Ordering::Release)) + }) + .hide() + .hide_in_generic_ui(), } } }