feat(patina): Tone guard for bass lines
Patina detects the played note (30-500 Hz) and remembers, over about 4 s, how high each spectral bump is at a fixed frequency and relative to the note. Bumps that follow the note (a boosted harmonic the patch is built on) get less cut; bumps fixed in Hz (formants, room modes) are cut as before. On a saw line F1-F2 with harmonic 6 boosted, the cut on that harmonic drops from 5.78 dB to 0.44 dB at 100 %, while a fixed formant at 1.5 kHz stays at 5.78 dB. One held note is cut as normal, since the two cases cannot be told apart. - New parameter tone-guard (0-100 %, default 0), appended at the end; 0 % is the old behaviour and old settings load unchanged. - New Bass line preset. - Editor: Tone guard control, NOTE readout and a strip over the spectrum where cuts are held back. - No added latency, no allocation on the audio thread; patina-core now depends on common-dsp.
This commit is contained in:
1 parent
6d868a63c4
commit
53bc26d14d
15 files changed
+391
-10
No files matched your search
@@ -62,6 +62,8 @@ pub struct PatinaParams {
|
||||
pub mix: FloatParam,
|
||||
#[id = "output"]
|
||||
pub output: FloatParam,
|
||||
#[id = "tone-guard"]
|
||||
pub tone_guard: FloatParam,
|
||||
#[id = "bypass"]
|
||||
pub bypass: BoolParam,
|
||||
#[nested(array, group = "Focus")]
|
||||
@@ -82,6 +84,7 @@ impl Default for PatinaParams {
|
||||
high: log("High frequency", d.high, 21., 20000., " Hz"),
|
||||
mix: linear("Mix", 100., 0., 100., " %"),
|
||||
output: linear("Output", 0., -12., 12., " dB"),
|
||||
tone_guard: linear("Tone guard", d.tone_guard, 0., 100., " %"),
|
||||
bypass: BoolParam::new("Bypass", false).make_bypass(),
|
||||
focus: std::array::from_fn(|_| FocusParams::default()),
|
||||
}
|
||||
@@ -116,6 +119,7 @@ impl PatinaParams {
|
||||
&self.focus[3].frequency,
|
||||
&self.focus[3].width,
|
||||
&self.focus[3].sensitivity,
|
||||
&self.tone_guard,
|
||||
]
|
||||
}
|
||||
pub fn settings(&self) -> Settings {
|
||||
@@ -137,6 +141,7 @@ impl PatinaParams {
|
||||
width: self.focus[i].width.value(),
|
||||
sensitivity: self.focus[i].sensitivity.value(),
|
||||
}),
|
||||
tone_guard: self.tone_guard.value(),
|
||||
};
|
||||
// Independent automation of bounds may cross them; preserve a valid effective range.
|
||||
if s.low >= s.high {
|
||||
@@ -145,8 +150,8 @@ impl PatinaParams {
|
||||
s
|
||||
}
|
||||
}
|
||||
/// Host float parameters: ten main controls, then four per focus point.
|
||||
pub const COUNT: usize = 26;
|
||||
/// Host float parameters: ten main controls, four per focus point, then Tone guard.
|
||||
pub const COUNT: usize = 27;
|
||||
pub fn values(s: &Settings) -> [f32; COUNT] {
|
||||
let mut v = [0.; COUNT];
|
||||
v[..10].copy_from_slice(&[
|
||||
@@ -169,5 +174,6 @@ pub fn values(s: &Settings) -> [f32; COUNT] {
|
||||
s.focus[i].sensitivity,
|
||||
]);
|
||||
}
|
||||
v[26] = s.tone_guard;
|
||||
v
|
||||
}
|
||||
Reference in new issue
Block a user