Skip to content

Commit

Permalink
make graph zoomable
Browse files Browse the repository at this point in the history
  • Loading branch information
magnetophon committed Apr 22, 2024
1 parent d110904 commit e133e7d
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 22 deletions.
7 changes: 4 additions & 3 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -192,9 +192,9 @@ 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, "zoom mode").class("fader-label");
ParamSlider::new(cx, LambData::params, |params| &params.zoom_mode)
.set_style(ParamSliderStyle::CurrentStepLabeled { even: true })
Label::new(cx, "GR graph time scale").class("fader-label");
ParamSlider::new(cx, LambData::params, |params| &params.time_scale)
.set_style(ParamSliderStyle::CurrentStep{ even: true })
.bottom(Pixels(6.0));
}) // graph + zoom
.height(Auto)
Expand All @@ -213,6 +213,7 @@ pub(crate) fn create(
ResizeHandle::new(cx);
})
}

///////////////////////////////////////////////////////////////////////////////
// AttackReleaseGraph //
///////////////////////////////////////////////////////////////////////////////
Expand Down
56 changes: 40 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::sync::{Arc, Mutex};
mod buffer;
mod dsp;
use buffer::*;
use cyma::utils::{PeakBuffer, MinimaBuffer, VisualizerBuffer};
use cyma::utils::{MinimaBuffer, PeakBuffer, VisualizerBuffer};

use default_boxed::DefaultBoxed;

Expand All @@ -32,25 +32,30 @@ pub struct Lamb {
level_buffer_r: Arc<Mutex<PeakBuffer>>,
gr_buffer_l: Arc<Mutex<MinimaBuffer>>,
gr_buffer_r: Arc<Mutex<MinimaBuffer>>,

/// If this is set at the start of the processing cycle, then the graph duration should be updated.
should_update_time_scale: Arc<AtomicBool>,
}
impl Default for Lamb {
fn default() -> Self {
let should_update_time_scale = Arc::new(AtomicBool::new(false));
Self {
params: Arc::new(LambParams::default()),

params: Arc::new(LambParams::new(should_update_time_scale.clone())),
// params: Arc::new(LambParams::default()),
dsp: dsp::LambRs::default_boxed(),

accum_buffer: TempBuffer::default(),

temp_output_buffer_l : f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_r : f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_gr_l : f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_gr_r : f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_l: f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_r: f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_gr_l: f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
temp_output_buffer_gr_r: f64::default_boxed_array::<MAX_SOUNDCARD_BUFFER_SIZE>(),
sample_rate: 48000.0,
level_buffer_l: Arc::new(Mutex::new(PeakBuffer::new(1068, 7.0, 0.0))),
level_buffer_r: Arc::new(Mutex::new(PeakBuffer::new(1068, 7.0, 0.0))),
gr_buffer_l: Arc::new(Mutex::new(MinimaBuffer::new(1068, 7.0, 0.0))),
gr_buffer_r: Arc::new(Mutex::new(MinimaBuffer::new(1068, 7.0, 0.0))),
level_buffer_l: Arc::new(Mutex::new(PeakBuffer::new(1114, 7.0, 0.0))),
level_buffer_r: Arc::new(Mutex::new(PeakBuffer::new(1114, 7.0, 0.0))),
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,
}
}
}
Expand Down Expand Up @@ -145,6 +150,7 @@ impl Plugin for Lamb {
fn reset(&mut self) {
// 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);
}

fn editor(&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
Expand Down Expand Up @@ -217,31 +223,49 @@ impl Plugin for Lamb {
);
let latency_samples = self.dsp.get_param(LATENCY_PI).expect("no latency read") as u32;
context.set_latency_samples(latency_samples);

let output = buffer.as_slice();
for i in 0..count as usize {
output[0][i] = self.temp_output_buffer_l[i] as f32;
output[1][i] = self.temp_output_buffer_r[i] as f32;
}

if self.params.editor_state.is_open() {
if self.should_update_time_scale.load(Ordering::Relaxed) {
let time_scale = match self.params.time_scale.value() {
TimeScale::HalfSec => 0.5,
TimeScale::OneSec => 1.0,
TimeScale::TwoSec => 2.0,
TimeScale::FourSec => 4.0,
TimeScale::EightSec => 8.0,
TimeScale::SixteenSec => 16.0,
TimeScale::ThirtytwoSec => 32.0,
TimeScale::SixtyfourSec => 64.0,
};
self.level_buffer_l.lock().unwrap().set_duration(time_scale);
self.level_buffer_r.lock().unwrap().set_duration(time_scale);
self.gr_buffer_l.lock().unwrap().set_duration(time_scale);
self.gr_buffer_r.lock().unwrap().set_duration(time_scale);
self.should_update_time_scale
.store(false, Ordering::Release);
};
for i in 0..count as usize {
self.level_buffer_l
.lock()
.unwrap()
.enqueue(self.temp_output_buffer_l[i] as f32 );
.enqueue(self.temp_output_buffer_l[i] as f32);
self.level_buffer_r
.lock()
.unwrap()
.enqueue(self.temp_output_buffer_r[i] as f32 );
.enqueue(self.temp_output_buffer_r[i] as f32);
self.gr_buffer_l
.lock()
.unwrap()
.enqueue(self.temp_output_buffer_gr_l[i]as f32 );
.enqueue(self.temp_output_buffer_gr_l[i] as f32);
self.gr_buffer_r
.lock()
.unwrap()
.enqueue(self.temp_output_buffer_gr_r[i]as f32 );
.enqueue(self.temp_output_buffer_gr_r[i] as f32);
}
}

Expand Down
49 changes: 46 additions & 3 deletions src/params.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use std::sync::atomic::{AtomicBool, Ordering};
use faust_types::ParamIndex;

#[derive(Params)]
struct LambParams {
// nr of params: 12
Expand Down Expand Up @@ -34,6 +36,9 @@ struct LambParams {
output_gain: FloatParam,
#[id = "zoom_mode"]
zoom_mode: EnumParam<ZoomMode>,
#[id = "time_scale"]
time_scale: EnumParam<TimeScale>,

/// The editor state, saved together with the parameter state so the custom scaling can be
/// restored.
#[persist = "editor-state"]
Expand All @@ -56,6 +61,34 @@ enum ZoomMode {
Absolute,
}

#[derive(Enum, Debug, PartialEq)]
enum TimeScale {
#[id = "0_5s"]
#[name = "0.5 seconds"]
HalfSec,
#[id = "1s"]
#[name = "1 second"]
OneSec,
#[id = "2s"]
#[name = "2 seconds"]
TwoSec,
#[id = "4s"]
#[name = "4 seconds"]
FourSec,
#[id = "8s"]
#[name = "8 seconds"]
EightSec,
#[id = "16s"]
#[name = "16 seconds"]
SixteenSec,
#[id = "32s"]
#[name = "32 seconds"]
ThirtytwoSec,
#[id = "64"]
#[name = "64 seconds"]
SixtyfourSec,
}

#[derive(Enum, Debug, PartialEq)]
enum LatencyMode {
/// Minimal, but variable latency
Expand Down Expand Up @@ -132,8 +165,10 @@ pub fn ratio_to_strength() -> Arc<dyn Fn(&str) -> Option<f32> + Send + Sync> {
})
}

impl Default for LambParams {
fn default() -> Self {
impl LambParams {
pub fn new(
should_update_time_scale: Arc<AtomicBool>,
) -> Self {
Self {
editor_state: editor::default_state(),

Expand Down Expand Up @@ -273,6 +308,15 @@ impl Default for LambParams {
zoom_mode: EnumParam::new("zoom_mode", ZoomMode::Relative)
.hide()
.hide_in_generic_ui(),
time_scale: EnumParam::new("time_scale", TimeScale::EightSec)
.with_callback(
{
let should_update_time_scale = should_update_time_scale.clone();
Arc::new(move |_| should_update_time_scale.store(true, Ordering::Release))
},
)
.hide()
.hide_in_generic_ui(),
}
}
}
Expand All @@ -295,4 +339,3 @@ pub const OUTPUT_GAIN_PI: ParamIndex = ParamIndex(14);
pub const GAIN_REDUCTION_LEFT_PI: ParamIndex = ParamIndex(15);
pub const GAIN_REDUCTION_RIGHT_PI: ParamIndex = ParamIndex(16);
pub const LATENCY_PI: ParamIndex = ParamIndex(17);
pub const ZOOM_MODE_PI: ParamIndex = ParamIndex(18);

0 comments on commit e133e7d

Please sign in to comment.