diff --git a/src/dsp/mod.rs b/src/dsp/mod.rs index 293989e..9d532c0 100644 --- a/src/dsp/mod.rs +++ b/src/dsp/mod.rs @@ -46,6 +46,8 @@ mod node_tslfo; mod node_pverb; #[allow(non_upper_case_globals)] mod node_rndwk; +#[allow(non_upper_case_globals)] +mod node_mux9; pub mod biquad; pub mod tracker; @@ -83,6 +85,7 @@ use crate::fa_biqfilt_ord; use crate::fa_vosc_ovrsmpl; use crate::fa_distort; use crate::fa_comb_mode; +use crate::fa_mux9_in_cnt; use node_amp::Amp; use node_sin::Sin; @@ -107,6 +110,7 @@ use node_comb::Comb; use node_tslfo::TsLFO; use node_pverb::PVerb; use node_rndwk::RndWk; +use node_mux9::Mux9; pub const MIDI_MAX_FREQ : f32 = 13289.75; @@ -694,6 +698,22 @@ macro_rules! node_list { (5 gain3 n_gain d_gain r_id f_def stp_d 0.0, 1.0, 1.0) (6 ogain n_gain d_gain r_id f_def stp_d 0.0, 1.0, 1.0) [0 sig], + mux9 => Mux9 UIType::Generic UICategory::NtoM + ( 0 slct n_id d_id r_id f_def stp_d 0.0, 1.0, 0.0) + ( 1 t_rst n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 2 t_up n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 3 t_down n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 4 in_1 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 5 in_2 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 6 in_3 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 7 in_4 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 8 in_5 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + ( 9 in_6 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + (10 in_7 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + (11 in_8 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + (12 in_9 n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) + {13 0 in_cnt setting(3) fa_mux9_in_cnt 0 8} + [0 sig], smap => SMap UIType::Generic UICategory::CV (0 inp n_id d_id r_id f_def stp_d -1.0, 1.0, 0.0) (1 min n_id d_id r_s f_def stp_d -1.0, 1.0, -1.0) diff --git a/src/dsp/node_mix3.rs b/src/dsp/node_mix3.rs index cd2ddee..9be766f 100644 --- a/src/dsp/node_mix3.rs +++ b/src/dsp/node_mix3.rs @@ -5,7 +5,7 @@ use crate::nodes::{NodeAudioContext, NodeExecContext}; use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; -/// A simple amplifier +/// A 3 channel signal mixer #[derive(Debug, Clone)] pub struct Mix3 { } @@ -16,11 +16,11 @@ impl Mix3 { } } pub const ch1 : &'static str = - "Mix3 inp\nChannel 1 Signal input\nRange: (-1..1)\n"; + "Mix3 ch1\nChannel 1 Signal input\nRange: (-1..1)\n"; pub const ch2 : &'static str = - "Mix3 inp2\nChannel 2 Signal input\nRange: (-1..1)\n"; + "Mix3 ch2\nChannel 2 Signal input\nRange: (-1..1)\n"; pub const ch3 : &'static str = - "Mix3 inp3\nChannel 3 Signal input\nRange: (-1..1)\n"; + "Mix3 ch3\nChannel 3 Signal input\nRange: (-1..1)\n"; pub const gain1 : &'static str = "Mix3 gain1\nChannel 1 gain\nRange: (0..1)"; pub const gain2 : &'static str = diff --git a/src/dsp/node_mux9.rs b/src/dsp/node_mux9.rs new file mode 100644 index 0000000..dd2b8fa --- /dev/null +++ b/src/dsp/node_mux9.rs @@ -0,0 +1,185 @@ +// Copyright (c) 2021 Weird Constructor +// This file is a part of HexoDSP. Released under GPL-3.0-or-later. +// See README.md and COPYING for details. + +use crate::nodes::{NodeAudioContext, NodeExecContext}; +use crate::dsp::{NodeId, SAtom, ProcBuf, DspNode, LedPhaseVals, NodeContext}; +use crate::dsp::helpers::{Trigger}; + +#[macro_export] +macro_rules! fa_mux9_in_cnt { ($formatter: expr, $v: expr, $denorm_v: expr) => { { + let s = + match ($v.round() as usize) { + 0 => "1", + 1 => "2", + 2 => "3", + 3 => "4", + 4 => "5", + 5 => "6", + 6 => "7", + 7 => "8", + 8 => "9", + _ => "?", + }; + write!($formatter, "{}", s) +} } } + +/// A 9 channel signal multiplexer +#[derive(Debug, Clone)] +pub struct Mux9 { + trig_rst: Trigger, + trig_up: Trigger, + trig_down: Trigger, + idx: u8, +} + +impl Mux9 { + pub fn new(_nid: &NodeId) -> Self { + Self { + trig_rst: Trigger::new(), + trig_up: Trigger::new(), + trig_down: Trigger::new(), + idx: 0, + } + } + pub const slct : &'static str = + "Mux9 slct\n\nRange: (0..1)\n"; + pub const t_rst : &'static str = + "Mux9 t_rst\n\nRange: (-1..1)\n"; + pub const t_up : &'static str = + "Mux9 t_up\n\nRange: (-1..1)\n"; + pub const t_down : &'static str = + "Mux9 t_down\n\nRange: (-1..1)\n"; + pub const in_1 : &'static str = + "Mux9 in_1\n\nRange: (-1..1)\n"; + pub const in_2 : &'static str = + "Mux9 in_2\n\nRange: (-1..1)\n"; + pub const in_3 : &'static str = + "Mux9 in_3\n\nRange: (-1..1)\n"; + pub const in_4 : &'static str = + "Mux9 in_4\n\nRange: (-1..1)\n"; + pub const in_5 : &'static str = + "Mux9 in_5\n\nRange: (-1..1)\n"; + pub const in_6 : &'static str = + "Mux9 in_6\n\nRange: (-1..1)\n"; + pub const in_7 : &'static str = + "Mux9 in_7\n\nRange: (-1..1)\n"; + pub const in_8 : &'static str = + "Mux9 in_8\n\nRange: (-1..1)\n"; + pub const in_9 : &'static str = + "Mux9 in_9\n\nRange: (-1..1)\n"; + pub const in_cnt : &'static str = + "Mux9 in_cnt\nThe number of inputs that are routed to the output. \ + This will limit the number of maximally used inputs.\n"; + pub const sig : &'static str = + "Mux9 sig\n\nRange: (-1..1)\n"; + pub const DESC : &'static str = +r#"9 Ch. Multiplexer + +An up to 9 channel multiplexer aka switch or junction. You can route one of the 9 (or fewer) inputs to the output. The opposite of this node is the 'Demux9', which demultiplexes or routes the one input signal to one of the 9 outputs. +"#; + pub const HELP : &'static str = +r#"Mux9 - 9 Channel Multiplexer/Switch + +This is an up to 9 channel multiplexer, also known as switch or junction. +You can route one of the 9 (or fewer) inputs to the one output. +Selection of the input is done either via a control signal to the +'slct' input (range 0..1) (exclusive) or via the 't_rst', 't_up' or +'t_down' triggers. + +If the 'slct' input is not connected, the trigger inputs are active. +If you still prefer a knob for manually selecting the input, consider using +some constant signal source like an 'Amp' node with an unconnected input. + +The 'in_cnt' parameter allows selecting the number of routed input channels. + +The opposite of this node is the 'Demux9', which demultiplexes or routes +the one input signal to one of the 9 outputs. +"#; + +} + +impl DspNode for Mux9 { + fn outputs() -> usize { 1 } + + fn set_sample_rate(&mut self, _srate: f32) { } + fn reset(&mut self) { } + + #[inline] + fn process( + &mut self, ctx: &mut T, _ectx: &mut NodeExecContext, + nctx: &NodeContext, + atoms: &[SAtom], inputs: &[ProcBuf], + outputs: &mut [ProcBuf], ctx_vals: LedPhaseVals) + { + use crate::dsp::{at, out, inp, denorm}; + + let in_1 = inp::Mux9::in_1(inputs); + let in_2 = inp::Mux9::in_2(inputs); + let in_3 = inp::Mux9::in_3(inputs); + let in_4 = inp::Mux9::in_4(inputs); + let in_5 = inp::Mux9::in_5(inputs); + let in_6 = inp::Mux9::in_6(inputs); + let in_7 = inp::Mux9::in_7(inputs); + let in_8 = inp::Mux9::in_8(inputs); + let in_9 = inp::Mux9::in_9(inputs); + let slct = inp::Mux9::slct(inputs); + let t_rst = inp::Mux9::t_rst(inputs); + let t_up = inp::Mux9::t_up(inputs); + let t_down = inp::Mux9::t_down(inputs); + let out = out::Mux9::sig(outputs); + + let max : u8 = at::Mux9::in_cnt(atoms).i() as u8 + 1; + self.idx = self.idx % max; + + if nctx.in_connected & 0x1 == 0x1 { + for frame in 0..ctx.nframes() { + self.idx = + (max as f32 * denorm::Mux9::slct(slct, frame)) + .floor() as u8 + % max; + + out.write(frame, match self.idx { + 0 => denorm::Mux9::in_1(in_1, frame), + 1 => denorm::Mux9::in_2(in_2, frame), + 2 => denorm::Mux9::in_3(in_3, frame), + 3 => denorm::Mux9::in_4(in_4, frame), + 4 => denorm::Mux9::in_5(in_5, frame), + 5 => denorm::Mux9::in_6(in_6, frame), + 6 => denorm::Mux9::in_7(in_7, frame), + 7 => denorm::Mux9::in_8(in_8, frame), + _ => denorm::Mux9::in_9(in_9, frame), + }); + } + + } else { + for frame in 0..ctx.nframes() { + if self.trig_rst.check_trigger( + denorm::Mux9::t_rst(t_rst, frame)) + { self.idx = 0; } + + if self.trig_up.check_trigger( + denorm::Mux9::t_up(t_up, frame)) + { self.idx = (self.idx + 1) % max; } + + if self.trig_down.check_trigger( + denorm::Mux9::t_down(t_down, frame)) + { self.idx = (self.idx + max - 1) % max; } + + out.write(frame, match self.idx { + 0 => denorm::Mux9::in_1(in_1, frame), + 1 => denorm::Mux9::in_2(in_2, frame), + 2 => denorm::Mux9::in_3(in_3, frame), + 3 => denorm::Mux9::in_4(in_4, frame), + 4 => denorm::Mux9::in_5(in_5, frame), + 5 => denorm::Mux9::in_6(in_6, frame), + 6 => denorm::Mux9::in_7(in_7, frame), + 7 => denorm::Mux9::in_8(in_8, frame), + _ => denorm::Mux9::in_9(in_9, frame), + }); + } + } + + ctx_vals[0].set(out.read(ctx.nframes() - 1)); + } +}