Skip to content

Commit

Permalink
wip add instant/toggle for mutes and dry/wet
Browse files Browse the repository at this point in the history
  • Loading branch information
magnetophon committed Oct 25, 2024
1 parent 209fc01 commit 7284e0a
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 69 deletions.
131 changes: 85 additions & 46 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ impl Model for Data {}

// Makes sense to also define this here, makes it a bit easier to keep track of
pub fn default_state() -> Arc<ViziaState> {
ViziaState::new(|| (1168, 584))
ViziaState::new(|| (1220, 610))
}

pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dyn Editor>> {
Expand All @@ -50,58 +50,46 @@ pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dy
HStack::new(cx, |cx| {
VStack::new(cx, |cx| {
Label::new(cx, "global").class("global-title");
// dry/wet
// wet gain
// drive
// mutes
//
// attack
// release
// min tap
// max tap
HStack::new(cx, |cx| {
// HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
// make_column(cx, "gain", |cx| {
let gain_params = Data::params.map(|p| p.global.gain_params.clone());
GenericUi::new_custom(cx, gain_params, |cx, param_ptr| {
HStack::new(cx, |cx| {
Label::new(cx, unsafe { param_ptr.name() }).class("label");
GenericUi::draw_widget(cx, gain_params, param_ptr);
})
.class("row");
});
HStack::new(cx, |cx| {
Label::new(cx, "dry/wet").class("slider-label");
ParamSlider::new(cx, Data::params, |params| &params.global.dry_wet)
.class("widget");
//was out gain
})
.class("row");
})
.class("column");

// make_column(cx, "timing", |cx| {
HStack::new(cx, |cx| {
let timing_params = Data::params.map(|p| p.global.timing_params.clone());
GenericUi::new_custom(cx, timing_params, |cx, param_ptr| {
let param_name = unsafe { param_ptr.name() };

// Check if the parameter is `max_tap_seconds` and replace with specific logic
if param_name == "max tap" {
HStack::new(cx, |cx| {
Label::new(cx, param_name).class("label");
ParamSlider::new(cx, Data::params, |params| {
&params.global.timing_params.max_tap_seconds
})
.set_style(ParamSliderStyle::FromLeft)
.class("widget");
})
.class("row");
} else {
// Default widget drawing for others
HStack::new(cx, |cx| {
Label::new(cx, param_name).class("label");
GenericUi::draw_widget(cx, timing_params, param_ptr);
})
.class("row");
}
});
HStack::new(cx, |cx| {
Label::new(cx, "attack").class("slider-label");
ParamSlider::new(cx, Data::params, |params| &params.global.attack_ms)
.class("widget");
// was drive
})
.class("row");
})
.class("column");
// });
})
.class("param-group");

HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "attack").class("slider-label");
ParamSlider::new(cx, Data::params, |params| &params.global.attack_ms)
Label::new(cx, "out gain").class("slider-label");
ParamSlider::new(cx, Data::params, |params| &params.global.output_gain)
.class("widget");
//was mutes
})
.class("row");
})
Expand All @@ -111,6 +99,63 @@ pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dy
Label::new(cx, "release").class("slider-label");
ParamSlider::new(cx, Data::params, |params| &params.global.release_ms)
.class("widget");
// was dry wet
})
.class("row");
})
.class("column");
})
.class("param-group");

HStack::new(cx, |cx| {
// HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "drive").class("slider-label");
ParamSlider::new(cx, Data::params, |params| {
&params.global.global_drive
})
.class("widget");
// was min_tap
})
.class("row");
})
.class("column");
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "min tap").class("slider-label");
ParamSlider::new(cx, Data::params, |params| {
&params.global.min_tap_milliseconds
})
.class("widget");
// was max tap
})
.class("row");
})
.class("column");
})
.class("param-group");
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "mutes").class("slider-label");
ParamSlider::new(cx, Data::params, |params| &params.global.mute_mode)
.set_style(ParamSliderStyle::CurrentStepLabeled { even: true })
.class("widget");
// was attack
})
.class("row");
})
.class("column");
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "max tap").class("slider-label");
ParamSlider::new(cx, Data::params, |params| {
&params.global.max_tap_seconds
})
.set_style(ParamSliderStyle::FromLeft)
.class("widget");
// was release
})
.class("row");
}) // TODO: make into a class
Expand Down Expand Up @@ -196,7 +241,6 @@ pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dy
Label::new(cx, "filters").class("dsp-title");

HStack::new(cx, |cx| {
// make_column(cx, "velocity tracking", |cx| {
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "vel>cut").class("slider-label");
Expand All @@ -208,7 +252,6 @@ pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dy
.class("row");
})
.class("column");
// make_column(cx, "note tracking", |cx| {
HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Label::new(cx, "note>cut").class("slider-label");
Expand All @@ -223,10 +266,6 @@ pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dy
})
.class("param-group");

// })
// .class("attack-release");
// .class("cutoff-tracking");

HStack::new(cx, |cx| {
make_column(cx, "low velocity", |cx| {
let velocity_low_params = Data::params.map(|p| p.taps.velocity_low.clone());
Expand Down
104 changes: 81 additions & 23 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ const MUTE_IN: usize = 0;
const MUTE_OUT: usize = 1;
const RESET_TAPS: usize = 2;
const LOCK_TAPS: usize = 3;
const MAX_HAAS_MS: f32 = 5.0;

struct Del2 {
params: Arc<Del2Params>,
Expand Down Expand Up @@ -128,23 +129,64 @@ struct Del2Params {

/// Contains the global parameters.
#[derive(Params)]
pub struct GlobalParams {
#[nested(id_prefix = "timing_params", group = "timing_params")]
pub timing_params: Arc<TimingParams>,
#[nested(id_prefix = "gain_params", group = "gain_params")]
pub gain_params: Arc<GainParams>,
struct GlobalParams {
#[id = "dry_wet"]
dry_wet: FloatParam,
#[id = "output_gain"]
pub output_gain: FloatParam,
#[id = "global_drive"]
pub global_drive: FloatParam,
#[id = "mute_mode"]
mute_mode: BoolParam,
#[id = "attack_ms"]
attack_ms: FloatParam,
/// The amplitude envelope release time. This is the same for every voice.
#[id = "release_ms"]
release_ms: FloatParam,
#[id = "min_tap_milliseconds"]
pub min_tap_milliseconds: FloatParam,
#[id = "max_tap_seconds"]
pub max_tap_seconds: FloatParam,
}

impl GlobalParams {
pub fn new() -> Self {
GlobalParams {
timing_params: Arc::new(TimingParams::new()),
gain_params: Arc::new(GainParams::new()),
// timing_params: Arc::new(TimingParams::new()),
// gain_params: Arc::new(GainParams::new()),
dry_wet: FloatParam::new("mix", 1.0, FloatRange::Linear { min: 0.0, max: 1.0 })
.with_unit("%")
.with_smoother(SmoothingStyle::Linear(15.0))
.with_value_to_string(formatters::v2s_f32_percentage(0))
.with_string_to_value(formatters::s2v_f32_percentage()),
output_gain: FloatParam::new(
"out gain",
util::db_to_gain(0.0),
FloatRange::Skewed {
min: util::db_to_gain(-30.0),
max: util::db_to_gain(30.0),
factor: FloatRange::gain_skew_factor(-30.0, 30.0),
},
)
.with_smoother(SmoothingStyle::Logarithmic(50.0))
.with_unit(" dB")
.with_value_to_string(formatters::v2s_f32_gain_to_db(1))
.with_string_to_value(formatters::s2v_f32_gain_to_db()),
global_drive: FloatParam::new(
"drive",
util::db_to_gain(0.0),
FloatRange::Skewed {
min: util::db_to_gain(-30.0),
max: util::db_to_gain(30.0),
factor: FloatRange::gain_skew_factor(-30.0, 30.0),
},
)
.with_smoother(SmoothingStyle::Logarithmic(50.0))
.with_unit(" dB")
.with_value_to_string(formatters::v2s_f32_gain_to_db(1))
.with_string_to_value(formatters::s2v_f32_gain_to_db()),
mute_mode: BoolParam::new("mute mode", true).with_value_to_string(Arc::new(|value| {
String::from(if value { "toggle" } else { "instant" })
})),

attack_ms: FloatParam::new(
"Attack",
Expand All @@ -168,6 +210,28 @@ impl GlobalParams {
)
.with_value_to_string(Del2::v2s_f32_ms_then_s(3))
.with_string_to_value(Del2::s2v_f32_ms_then_s()),
min_tap_milliseconds: FloatParam::new(
"min tap",
10.0,
FloatRange::Skewed {
min: 1.0,
max: 1000.0,
factor: FloatRange::skew_factor(-1.5),
},
)
.with_step_size(0.1)
.with_unit(" ms"),
max_tap_seconds: FloatParam::new(
"max tap",
3.0,
FloatRange::Skewed {
min: 0.5,
max: MAX_TAP_SECONDS as f32,
factor: FloatRange::skew_factor(-0.8),
},
)
.with_step_size(0.1)
.with_unit(" s"),
}
}
}
Expand Down Expand Up @@ -590,15 +654,9 @@ impl Del2 {
fn update_timing_params(&mut self) {
let sample_rate = self.sample_rate as f32;
self.delay_data.max_tap_samples =
(sample_rate * self.params.global.timing_params.max_tap_seconds.value()) as u32;
self.min_tap_samples = (sample_rate
* self
.params
.global
.timing_params
.min_tap_milliseconds
.value()
* 0.001) as u32;
(sample_rate * self.params.global.max_tap_seconds.value()) as u32;
self.min_tap_samples =
(sample_rate * self.params.global.min_tap_milliseconds.value() * 0.001) as u32;
}

fn process_midi_events(&mut self, context: &mut impl ProcessContext<Self>) {
Expand Down Expand Up @@ -706,7 +764,7 @@ impl Del2 {
self.should_update_filter.store(true, Ordering::Release);
}
// Handle ActionTrigger events
// lock pattern is handled at the start
// LOCK_TAPS is handled at the start
if self.is_playing_action(MUTE_IN) {
self.enabled_actions.toggle(MUTE_IN);
self.last_played_notes
Expand Down Expand Up @@ -894,7 +952,7 @@ impl Del2 {
}

fn pan_to_haas_samples(pan: f32, sample_rate: f32) -> (i32, i32) {
let delay_samples = (pan.abs() * (5.0 / 1000.0) * sample_rate) as i32;
let delay_samples = (pan.abs() * (MAX_HAAS_MS / 1000.0) * sample_rate) as i32;
if pan < 0.0 {
(0, delay_samples) // Pan left: delay right
} else {
Expand Down Expand Up @@ -959,12 +1017,12 @@ impl Del2 {
// No idea how...
// Loop through each sample, processing two channels at a time
for i in (0..block_len).step_by(2) {
let output_gain1 = self.params.global.gain_params.output_gain.smoothed.next();
let output_gain2 = self.params.global.gain_params.output_gain.smoothed.next();
let output_gain1 = self.params.global.output_gain.smoothed.next();
let output_gain2 = self.params.global.output_gain.smoothed.next();
let drive = self.filter_params[tap].clone().drive;

let pre_filter_gain1 = self.params.global.gain_params.global_drive.smoothed.next();
let pre_filter_gain2 = self.params.global.gain_params.global_drive.smoothed.next();
let pre_filter_gain1 = self.params.global.global_drive.smoothed.next();
let pre_filter_gain2 = self.params.global.global_drive.smoothed.next();

// Calculate post-filter gains, including the fade effect
let post_filter_gain1 = output_gain1 / (drive * pre_filter_gain1);
Expand Down

0 comments on commit 7284e0a

Please sign in to comment.