Skip to content

Commit

Permalink
draw panning center in delay graph
Browse files Browse the repository at this point in the history
  • Loading branch information
magnetophon committed Nov 15, 2024
1 parent dc67eef commit 837a9bf
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 24 deletions.
55 changes: 49 additions & 6 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -688,16 +688,24 @@ impl DelayGraph {
zoomed: bool,
) {
let mut diamond_path = vg::Path::new();
let mut center_path = vg::Path::new();
let mut pan_path = vg::Path::new();
let first_note = params.first_note.load(std::sync::atomic::Ordering::SeqCst);

let panning_center = if params.taps.panning_center.value() < 0 {
first_note
} else {
params.taps.panning_center.value() as u8
};
// Determine min and max note values if zoomed
let (min_note_value, max_note_value) = if zoomed {
let mut used_notes: Vec<u8> =
(0..params.current_tap.load(std::sync::atomic::Ordering::SeqCst))
.map(|i| params.notes[i].load(Ordering::SeqCst))
.collect();
if params.first_note.load(std::sync::atomic::Ordering::SeqCst) != NO_LEARNED_NOTE {
used_notes.push(params.first_note.load(std::sync::atomic::Ordering::SeqCst));
if first_note != NO_LEARNED_NOTE {
used_notes.push(first_note);
used_notes.push(panning_center);
}
let min = used_notes.iter().copied().min().unwrap_or(0);
let max = used_notes.iter().copied().max().unwrap_or(127);
Expand All @@ -711,10 +719,40 @@ impl DelayGraph {
// Calculate available height with margins
let margin = 3.0 * line_width;
let available_height = 2.0f32.mul_add(-(margin + diamond_size + border_width), bounds.h);

// Draw half a diamond for the first note at time 0
let first_note = params.first_note.load(std::sync::atomic::Ordering::SeqCst);
// Draw half a diamond for the panning center
if first_note != NO_LEARNED_NOTE {
let normalized_panning_center = if max_note_value == min_note_value {
panning_center as f32 / 127.0
} else {
(panning_center as f32 - min_note_value) / (max_note_value - min_note_value)
};

let target_panning_center_height =
(1.0 - normalized_panning_center).mul_add(available_height, margin + diamond_size);

if params.previous_panning_center_height.load(Ordering::SeqCst) == 0.0 {
params
.previous_panning_center_height
.store(target_panning_center_height, Ordering::SeqCst);
}
let panning_center_height =
(params.previous_panning_center_height.load(Ordering::SeqCst) * ZOOM_SMOOTH_POLE)
+ (target_panning_center_height * (1.0 - ZOOM_SMOOTH_POLE));
params
.previous_panning_center_height
.store(panning_center_height, Ordering::SeqCst);

let diamond_half_size = line_width;

let panning_center_x = bounds.x;
let panning_center_y = bounds.y + panning_center_height;

center_path.move_to(panning_center_x, panning_center_y + diamond_half_size);
center_path.line_to(panning_center_x + diamond_half_size, panning_center_y);
center_path.line_to(panning_center_x, panning_center_y - diamond_half_size);
center_path.close();

// Draw half a diamond for the first note at time 0
let normalized_first_note = if max_note_value == min_note_value {
f32::from(first_note) / 127.0
} else {
Expand Down Expand Up @@ -802,6 +840,12 @@ impl DelayGraph {
&vg::Paint::color(border_color).with_line_width(line_width),
);

// Draw the diamond for panning center before the first note
canvas.stroke_path(
&center_path,
&vg::Paint::color(border_color).with_line_width(line_width),
);

canvas.stroke_path(
&diamond_path,
&vg::Paint::color(color).with_line_width(line_width),
Expand All @@ -818,7 +862,6 @@ impl DelayGraph {

canvas.stroke_path(
&cover_line_path,
// &vg::Paint::color(Color::red().into()).with_line_width(line_width),
&vg::Paint::color(background_color).with_line_width(line_width),
);
}
Expand Down
38 changes: 20 additions & 18 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ pub struct Del2Params {
previous_time_scaling_factor: Arc<AtomicF32>,
previous_note_heights: AtomicF32Array,
previous_first_note_height: Arc<AtomicF32>,
previous_panning_center_height: Arc<AtomicF32>,

/// A voice's gain. This can be polyphonically modulated.
#[id = "gain"]
Expand Down Expand Up @@ -278,7 +279,7 @@ impl GlobalParams {
#[derive(Params)]
pub struct TapsParams {
#[id = "panning_center"]
pub panning_center: FloatParam,
pub panning_center: IntParam,
#[id = "panning_amount"]
pub panning_amount: FloatParam,
#[id = "note_to_cutoff_amount"]
Expand All @@ -295,16 +296,13 @@ pub struct TapsParams {
impl TapsParams {
pub fn new(should_update_filter: Arc<AtomicBool>) -> Self {
Self {
panning_center: FloatParam::new(
panning_center: IntParam::new(
"panning center",
-1.0,
FloatRange::Linear {
min: -1.0,
max: 127.0,
},
-1,
IntRange::Linear { min: -1, max: 127 },
)
.with_value_to_string(Del2::v2s_f32_note())
.with_string_to_value(Del2::s2v_f32_note()),
.with_value_to_string(Del2::v2s_i32_note())
.with_string_to_value(Del2::s2v_i32_note()),
panning_amount: FloatParam::new(
"panning_amount",
0.0,
Expand Down Expand Up @@ -538,6 +536,7 @@ impl Del2Params {
Arc::new(AtomicF32::new(0.0))
})),
previous_first_note_height: Arc::new(AtomicF32::new(0.0)),
previous_panning_center_height: Arc::new(AtomicF32::new(0.0)),

gain: FloatParam::new(
"Gain",
Expand Down Expand Up @@ -911,14 +910,14 @@ impl Plugin for Del2 {
.smoothed
.next_block(&mut self.global_drive, block_len);

let panning_center = if self.params.taps.panning_center.value() < 0.0 {
let panning_center = if self.params.taps.panning_center.value() < 0 {
f32::from(
self.params
.first_note
.load(std::sync::atomic::Ordering::SeqCst),
)
} else {
self.params.taps.panning_center.value()
self.params.taps.panning_center.value() as f32
};
let panning_amount = self.params.taps.panning_amount.value();

Expand Down Expand Up @@ -1257,6 +1256,9 @@ impl Del2 {
self.params
.previous_first_note_height
.store(0.0, Ordering::SeqCst);
self.params
.previous_panning_center_height
.store(0.0, Ordering::SeqCst);
for i in 0..NUM_TAPS {
self.params.previous_note_heights[i].store(0.0, Ordering::SeqCst);
}
Expand Down Expand Up @@ -1533,10 +1535,10 @@ impl Del2 {
string.parse::<f32>().ok()
})
}
fn v2s_f32_note() -> Arc<dyn Fn(f32) -> String + Send + Sync> {
fn v2s_i32_note() -> Arc<dyn Fn(i32) -> String + Send + Sync> {
Arc::new(move |value| {
let note_nr = value.round() as u8; // Convert the floating-point value to the nearest u8
if value < 0.0 {
let note_nr = value as u8; // Convert the floating-point value to the nearest u8
if value < 0 {
"first note of pattern".to_string()
} else {
let note_name = util::NOTES[(note_nr % 12) as usize];
Expand All @@ -1545,7 +1547,7 @@ impl Del2 {
}
})
}
fn s2v_f32_note() -> Arc<dyn Fn(&str) -> Option<f32> + Send + Sync> {
fn s2v_i32_note() -> Arc<dyn Fn(&str) -> Option<i32> + Send + Sync> {
Arc::new(move |string| {
let trimmed_string = string.trim().to_lowercase();

Expand All @@ -1555,12 +1557,12 @@ impl Del2 {
.iter()
.any(|&keyword| trimmed_string.contains(keyword))
{
return Some(-1.0);
return Some(-1);
}
let len = trimmed_string.len();
if len < 2 {
// if it's short, return to default: "first note of pattern"
return Some(-1.0);
return Some(-1);
}

// The note part could be one or two characters, based on whether it includes a sharp or flat (e.g., "C", "C#", "D")
Expand All @@ -1578,7 +1580,7 @@ impl Del2 {
.iter()
.position(|&n| n.eq_ignore_ascii_case(note_name))
{
return Some((note_index as i32 + (octave + 1) * 12) as f32);
return Some(note_index as i32 + (octave + 1) * 12);
}
}

Expand Down

0 comments on commit 837a9bf

Please sign in to comment.