Skip to content

Commit

Permalink
wip ActionTrigger
Browse files Browse the repository at this point in the history
  • Loading branch information
magnetophon committed Oct 21, 2024
1 parent a3b8686 commit 53fa9b1
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 40 deletions.
159 changes: 125 additions & 34 deletions src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,33 @@ use nih_plug_vizia::vizia::prelude::*;
use nih_plug_vizia::vizia::vg;
use nih_plug_vizia::widgets::*;
use nih_plug_vizia::{assets, create_vizia_editor, ViziaState, ViziaTheming};
use std::sync::atomic::Ordering;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};

use crate::AtomicByteArray;
use crate::Del2Params;
use crate::DelayData;
use crate::DelayDataOutput;

#[derive(Lens, Clone)]
pub(crate) struct Data {
pub(crate) params: Arc<Del2Params>,
pub(crate) delay_data: Arc<Mutex<DelayDataOutput>>,
pub params: Arc<Del2Params>,
pub delay_data: Arc<Mutex<DelayDataOutput>>,
pub input_meter: Arc<AtomicF32>,
pub output_meter: Arc<AtomicF32>,
pub is_learning: Arc<AtomicBool>,
pub learning_index: Arc<AtomicUsize>,
pub learned_notes: Arc<AtomicByteArray>,
}

impl Model for Data {}

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

pub(crate) fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dyn Editor>> {
pub fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option<Box<dyn Editor>> {
create_vizia_editor(editor_state, ViziaTheming::Custom, move |cx, _| {
assets::register_noto_sans_light(cx);
assets::register_noto_sans_thin(cx);
Expand Down Expand Up @@ -79,6 +83,13 @@ pub(crate) fn create(editor_data: Data, editor_state: Arc<ViziaState>) -> Option
});
});
});
ActionTrigger::new(
cx,
Data::is_learning,
Data::learning_index,
0,
Data::learned_notes,
);

HStack::new(cx, |cx| {
HStack::new(cx, |cx| {
Expand Down Expand Up @@ -215,20 +226,6 @@ pub struct DelayGraph {
delay_data: Arc<Mutex<DelayDataOutput>>,
}

impl DelayGraph {
pub fn new<DelayDataL>(cx: &mut Context, delay_data: DelayDataL) -> Handle<Self>
where
DelayDataL: Lens<Target = Arc<Mutex<DelayDataOutput>>>,
{
Self {
delay_data: delay_data.get(cx),
}
.build(cx, |_cx| {
// put other widgets here
})
}
}

// TODO: add grid to show bars & beats
impl View for DelayGraph {
// For CSS:
Expand All @@ -240,7 +237,7 @@ impl View for DelayGraph {
let mut locked_delay_data = self.delay_data.lock().unwrap();
let delay_data = locked_delay_data.read();

let bounding_box = draw_context.bounds();
let bounds = draw_context.bounds();

let background_color: vg::Color = draw_context.background_color().into();
let border_color: vg::Color = draw_context.border_color().into();
Expand All @@ -250,27 +247,23 @@ impl View for DelayGraph {
let path_line_width = draw_context.outline_width();

// Compute the time scaling factor
let time_scaling_factor = self.compute_time_scaling_factor(
&delay_data,
bounding_box.w,
border_width,
path_line_width,
);
let time_scaling_factor =
self.compute_time_scaling_factor(&delay_data, bounds.w, border_width, path_line_width);

// Draw components
self.draw_background(canvas, bounding_box, background_color, border_width);
self.draw_background(canvas, bounds, background_color, border_width);
self.draw_delay_times_as_lines(
canvas,
&delay_data,
bounding_box,
bounds,
border_color,
1.0,
time_scaling_factor,
);
self.draw_time_line(
canvas,
&delay_data,
bounding_box,
bounds,
selection_color,
path_line_width,
time_scaling_factor,
Expand All @@ -279,7 +272,7 @@ impl View for DelayGraph {
self.draw_tap_velocities(
canvas,
&delay_data,
bounding_box,
bounds,
outline_color,
path_line_width,
time_scaling_factor,
Expand All @@ -288,19 +281,30 @@ impl View for DelayGraph {
self.draw_tap_notes_as_diamonds(
canvas,
&delay_data,
bounding_box,
bounds,
selection_color,
path_line_width,
time_scaling_factor,
border_width,
true,
);
self.draw_bounding_outline(canvas, bounding_box, border_color, border_width);
self.draw_bounding_outline(canvas, bounds, border_color, border_width);
}
}

// Functional Breakdown
impl DelayGraph {
pub fn new<DelayDataL>(cx: &mut Context, delay_data: DelayDataL) -> Handle<Self>
where
DelayDataL: Lens<Target = Arc<Mutex<DelayDataOutput>>>,
{
Self {
delay_data: delay_data.get(cx),
}
.build(cx, |_cx| {
// put other widgets here
})
}

fn compute_time_scaling_factor(
&self,
delay_data: &DelayData,
Expand Down Expand Up @@ -516,3 +520,90 @@ fn make_column(cx: &mut Context, title: &str, contents: impl FnOnce(&mut Context
})
.class("column");
}

///////////////////////////////////////////////////////////////////////////////
// ActionTrigger //
///////////////////////////////////////////////////////////////////////////////

pub struct ActionTrigger {
is_learning: Arc<AtomicBool>,
learning_index: Arc<AtomicUsize>,
own_index: usize,
learned_notes: Arc<AtomicByteArray>,
}
impl ActionTrigger {
pub fn new<IsLearningL, LearningIndexL, LearnedNoteL>(
cx: &mut Context,

is_learning: IsLearningL,
learning_index: LearningIndexL,
own_index: usize,
learned_notes: LearnedNoteL,
) -> Handle<Self>
where
IsLearningL: Lens<Target = Arc<AtomicBool>>,
LearningIndexL: Lens<Target = Arc<AtomicUsize>>,
LearnedNoteL: Lens<Target = Arc<AtomicByteArray>>,
{
Self {
is_learning: is_learning.get(cx),
learning_index: learning_index.get(cx),
own_index,
learned_notes: learned_notes.get(cx),
// delay_data: delay_data.get(cx),
}
.build(cx, |_cx| {
// put other widgets here
})
}

pub fn start_learning(&self) {
self.is_learning.store(true, Ordering::SeqCst);
self.learning_index.store(self.own_index, Ordering::SeqCst);
}

pub fn stop_learning(&self) {
self.is_learning.store(false, Ordering::SeqCst);
}

pub fn set_learning_index(&self, index: usize) {
self.learning_index.store(index, Ordering::SeqCst);
}

pub fn get_learning_index(&self) -> usize {
self.learning_index.load(Ordering::SeqCst)
}

// Checks if learning is active for this trigger
pub fn is_learning(&self) -> bool {
self.is_learning.load(Ordering::SeqCst) && self.get_learning_index() == self.own_index
}

/////////////////////////////////////////////////////////////////////////////////////////////////////////////
// for drawing
/////////////////////////////////////////////////////////////////////////////////////////////////////////////
fn draw_background(&self, canvas: &mut Canvas, bounds: BoundingBox, color: vg::Color) {
let mut path = vg::Path::new();
path.rect(bounds.x, bounds.y, bounds.w, bounds.h);
path.close();

let paint = vg::Paint::color(color);
canvas.fill_path(&path, &paint);
}
}

impl View for ActionTrigger {
// For CSS:
fn element(&self) -> Option<&'static str> {
Some("action-trigger")
}

fn draw(&self, draw_context: &mut DrawContext, canvas: &mut Canvas) {
let bounds = draw_context.bounds();
let background_color: vg::Color = draw_context.background_color().into();

self.draw_background(canvas, bounds, background_color);
// Example of using internal state in a simplistic way
if self.is_learning() {}
}
}
43 changes: 37 additions & 6 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ use nih_plug::prelude::*;
use nih_plug_vizia::vizia::prelude::*;
use nih_plug_vizia::ViziaState;
use std::simd::f32x4;
use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
use std::sync::atomic::{AtomicBool, AtomicU64, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
use synfx_dsp::fh_va::{FilterParams, LadderFilter, LadderMode};
use triple_buffer::TripleBuffer;
Expand All @@ -47,8 +47,6 @@ const VELOCITY_HIGH_NAME_PREFIX: &str = "high velocity";
const MAX_BLOCK_LEN: usize = 32768;

const PEAK_METER_DECAY_MS: f64 = 150.0;
// TODO: make an enum of which controls we have
const MAX_NR_LEARNED_NOTES: usize = 4;

struct Del2 {
params: Arc<Del2Params>,
Expand All @@ -69,7 +67,6 @@ struct Del2 {
amp_envelopes: [Smoother<f32>; MAX_NR_TAPS],
envelope_block: Vec<f32>,
releasings: [bool; MAX_NR_TAPS],
learned_notes: [u8; MAX_NR_LEARNED_NOTES],
sample_rate: f32,
peak_meter_decay_weight: f32,
input_meter: Arc<AtomicF32>,
Expand All @@ -78,6 +75,7 @@ struct Del2 {
// for which control are we learning?
is_learning: Arc<AtomicBool>,
learning_index: Arc<AtomicUsize>,
learned_notes: Arc<AtomicByteArray>,
samples_since_last_event: u32,
timing_last_event: u32,
min_tap_samples: u32,
Expand Down Expand Up @@ -428,6 +426,7 @@ impl Default for Del2 {
let amp_envelopes = array_init::array_init(|_| Smoother::none());
let is_learning = Arc::new(AtomicBool::new(false));
let learning_index = Arc::new(AtomicUsize::new(0));
let learned_notes = Arc::new(AtomicByteArray::new());
Self {
params: Arc::new(Del2Params::new(
should_update_filter.clone(),
Expand All @@ -450,14 +449,14 @@ impl Default for Del2 {
envelope_block: vec![0.0; MAX_BLOCK_LEN],
releasings: [false; MAX_NR_TAPS],
//TODO: make Option<u8>
learned_notes: [0; MAX_NR_LEARNED_NOTES],
sample_rate: 1.0,
peak_meter_decay_weight: 1.0,
input_meter: Arc::new(AtomicF32::new(util::MINUS_INFINITY_DB)),
output_meter: Arc::new(AtomicF32::new(util::MINUS_INFINITY_DB)),
delay_write_index: 0,
is_learning,
learning_index,
learned_notes,
samples_since_last_event: 0,
timing_last_event: 0,
min_tap_samples: 0,
Expand Down Expand Up @@ -543,6 +542,9 @@ impl Plugin for Del2 {
input_meter: self.input_meter.clone(),
output_meter: self.output_meter.clone(),
delay_data: self.delay_data_output.clone(),
is_learning: self.is_learning.clone(),
learning_index: self.learning_index.clone(),
learned_notes: self.learned_notes.clone(),
},
self.params.editor_state.clone(),
)
Expand Down Expand Up @@ -679,7 +681,11 @@ impl Del2 {
CountingState::MidiLearn => {
let is_learning = self.is_learning.clone();
is_learning.store(false, Ordering::Release);
self.learned_notes[self.learning_index.load(Ordering::SeqCst)] = note;
self.learned_notes.store(
self.learning_index.load(Ordering::SeqCst),
note,
Ordering::Release,
);
self.counting_state = CountingState::TimeOut;
self.timing_last_event = 0;
self.samples_since_last_event = 0;
Expand Down Expand Up @@ -1112,6 +1118,31 @@ impl Enum for MyLadderMode {
})
}
}
// #[derive(Debug)]
struct AtomicByteArray {
data: AtomicU64,
}

impl AtomicByteArray {
fn new() -> Self {
Self {
data: AtomicU64::new(0), // Initialize with zero
}
}

fn load(&self, index: usize, ordering: Ordering) -> u8 {
assert!(index < 8, "Index out of bounds");
let value = self.data.load(ordering);
((value >> (index * 8)) & 0xFF) as u8
}

fn store(&self, index: usize, byte: u8, ordering: Ordering) {
assert!(index < 8, "Index out of bounds");
let mask = !(0xFFu64 << (index * 8));
let new_value = (self.data.load(ordering) & mask) | ((byte as u64) << (index * 8));
self.data.store(new_value, ordering);
}
}

nih_export_clap!(Del2);
nih_export_vst3!(Del2);
5 changes: 5 additions & 0 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,11 @@ delay-graph {
selection-color: #fabdf0;
}

action-trigger {
top: 100px;
background-color: #4e4e4e;
}

generic-ui .row {
col-between: 6px;
height: auto;
Expand Down

0 comments on commit 53fa9b1

Please sign in to comment.