add base-pan decoding

left channel is base signal, right channel is stereo balance modulator
main
Charlotte Som 2023-05-28 22:52:02 +01:00
parent a70a47d668
commit 1919b0a166
6 changed files with 2050 additions and 23 deletions

9
.editorconfig Normal file
View File

@ -0,0 +1,9 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = true

1959
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,7 @@ crate-type = ["cdylib"]
[dependencies] [dependencies]
nih_plug = { git = "https://github.com/robbert-vdh/nih-plug.git", features = ["assert_process_allocs"] } nih_plug = { git = "https://github.com/robbert-vdh/nih-plug.git", features = ["assert_process_allocs"] }
nih_plug_vizia = { git = "https://github.com/robbert-vdh/nih-plug.git" }
[profile.release] [profile.release]
lto = "thin" lto = "thin"

View File

@ -1,6 +1,6 @@
# charlotte's mid side # charlotte's mid side
simple mid side decoder. left channel -> mid, right channel -> side (positive values pan right, negative values pan left) multimodal stereo signal decoder
## Building ## Building

41
src/editor.rs Normal file
View File

@ -0,0 +1,41 @@
use std::sync::Arc;
use nih_plug::prelude::*;
use nih_plug_vizia::vizia::prelude::*;
use nih_plug_vizia::widgets::{ParamSlider, ResizeHandle};
use nih_plug_vizia::{create_vizia_editor, ViziaState};
use crate::MidSideParams;
#[derive(Lens)]
struct Data {
params: Arc<MidSideParams>,
}
impl Model for Data {}
pub fn default_state() -> Arc<ViziaState> {
ViziaState::new(|| (320, 100))
}
pub fn create(state: Arc<ViziaState>, params: Arc<MidSideParams>) -> Option<Box<dyn Editor>> {
create_vizia_editor(
state,
nih_plug_vizia::ViziaTheming::Builtin,
move |cx, _| {
nih_plug_vizia::assets::register_noto_sans_light(cx);
nih_plug_vizia::assets::register_noto_sans_thin(cx);
Data {
params: params.clone(),
}
.build(cx);
ResizeHandle::new(cx);
VStack::new(cx, |cx| {
ParamSlider::new(cx, Data::params, |p| &p.mode);
});
},
)
}

View File

@ -1,10 +1,10 @@
use nih_plug::prelude::*; use nih_plug::prelude::*;
use nih_plug_vizia::ViziaState;
use std::sync::Arc; use std::sync::Arc;
fn decode_mid_side(channel_0: &mut [f32], channel_1: &mut [f32]) { mod editor;
// positive sides -> pan right
// negative sides -> pan left
fn decode_mid_side(channel_0: &mut [f32], channel_1: &mut [f32]) {
assert_eq!(channel_0.len(), channel_1.len()); assert_eq!(channel_0.len(), channel_1.len());
for sample_idx in 0..channel_0.len() { for sample_idx in 0..channel_0.len() {
@ -19,10 +19,50 @@ fn decode_mid_side(channel_0: &mut [f32], channel_1: &mut [f32]) {
} }
} }
fn decode_signal_balance(channel_0: &mut [f32], channel_1: &mut [f32]) {
// positive balance -> pan right
// negative balance -> pan left
assert_eq!(channel_0.len(), channel_1.len());
for sample_idx in 0..channel_0.len() {
let sig = channel_0[sample_idx];
let balance = channel_1[sample_idx];
let left = sig * (0.5 * -balance + 1.0);
let right = sig * (0.5 * balance + 1.0);
channel_0[sample_idx] = left;
channel_1[sample_idx] = right;
}
}
// time to wire up nih-plug. all of this is boilerplate // time to wire up nih-plug. all of this is boilerplate
#[derive(Enum, PartialEq, Eq)]
pub enum MidSideMode {
#[id = "conventional"]
Conventional,
#[id = "balance"]
PanAmount,
}
#[derive(Params)] #[derive(Params)]
struct MidSideParams {} pub struct MidSideParams {
#[id = "mode"]
mode: EnumParam<MidSideMode>,
#[persist = "editor-state"]
editor_state: Arc<ViziaState>,
}
impl Default for MidSideParams {
fn default() -> Self {
Self {
mode: EnumParam::new("Mode", MidSideMode::Conventional),
editor_state: editor::default_state(),
}
}
}
struct MidSide { struct MidSide {
params: Arc<MidSideParams>, params: Arc<MidSideParams>,
@ -31,7 +71,7 @@ struct MidSide {
impl Default for MidSide { impl Default for MidSide {
fn default() -> Self { fn default() -> Self {
Self { Self {
params: Arc::new(MidSideParams {}), params: Arc::new(MidSideParams::default()),
} }
} }
} }
@ -79,13 +119,18 @@ impl Plugin for MidSide {
) -> ProcessStatus { ) -> ProcessStatus {
assert_eq!(buffer.channels(), 2); assert_eq!(buffer.channels(), 2);
let mode = self.params.mode.value();
for (_block_idx, block) in buffer.iter_blocks(128) { for (_block_idx, block) in buffer.iter_blocks(128) {
let mut block_channels = block.into_iter(); let mut block_channels = block.into_iter();
let channel_0 = block_channels.next().unwrap(); let channel_0 = block_channels.next().unwrap();
let channel_1 = block_channels.next().unwrap(); let channel_1 = block_channels.next().unwrap();
decode_mid_side(channel_0, channel_1); match mode {
MidSideMode::Conventional => decode_mid_side(channel_0, channel_1),
MidSideMode::PanAmount => decode_signal_balance(channel_0, channel_1),
}
} }
ProcessStatus::Normal ProcessStatus::Normal
@ -94,6 +139,10 @@ impl Plugin for MidSide {
fn params(&self) -> Arc<dyn Params> { fn params(&self) -> Arc<dyn Params> {
self.params.clone() self.params.clone()
} }
fn editor(&mut self, _async_executor: AsyncExecutor<Self>) -> Option<Box<dyn Editor>> {
editor::create(self.params.editor_state.clone(), self.params.clone())
}
} }
impl Vst3Plugin for MidSide { impl Vst3Plugin for MidSide {