feat(knurl): add Knurl cycle texture
Check and Windows preview / check (anvil) (push) Successful in 2m1s
Check and Windows preview / check (crucible) (push) Successful in 1m31s
Check and Windows preview / check (knurl) (push) Successful in 2m4s
Check and Windows preview / check (lathe) (push) Successful in 1m27s
Check and Windows preview / check (patina) (push) Successful in 1m54s
Check and Windows preview / check (rivet) (push) Successful in 1m30s
Check and Windows preview / check (temper) (push) Successful in 1m31s
Check and Windows preview / check (weld) (push) Successful in 2m31s
Check and Windows preview / previews (push) Successful in 1m26s
Independent plugin release / plan (push) Successful in 7s
Check and Windows preview / windows (push) Successful in 2m26s
Independent plugin release / build (push) Successful in 3m0s
Independent plugin release / publish (push) Successful in 8s
Check and Windows preview / check (anvil) (push) Successful in 2m1s
Check and Windows preview / check (crucible) (push) Successful in 1m31s
Check and Windows preview / check (knurl) (push) Successful in 2m4s
Check and Windows preview / check (lathe) (push) Successful in 1m27s
Check and Windows preview / check (patina) (push) Successful in 1m54s
Check and Windows preview / check (rivet) (push) Successful in 1m30s
Check and Windows preview / check (temper) (push) Successful in 1m31s
Check and Windows preview / check (weld) (push) Successful in 2m31s
Check and Windows preview / previews (push) Successful in 1m26s
Independent plugin release / plan (push) Successful in 7s
Check and Windows preview / windows (push) Successful in 2m26s
Independent plugin release / build (push) Successful in 3m0s
Independent plugin release / publish (push) Successful in 8s
Knurl follows the played note and treats every cycle of the wave on its own: a repeating level pattern over 1-16 cycles makes subharmonics in tune with every note, random level and timing per cycle add rattle, and a noise burst per cycle, highpassed at a multiple of f0, adds grit. Amounts are counted in cycles, so the texture is the same on F1 and on C2. - Cycle clock from the shared note tracker, restarted at each note; the audio is delayed by the lookahead plus 4.2 ms of timing-jitter headroom. - Per-cycle randomness from a hash of the cycle number: Same every note or Free. - Patterns Off, Double, Triple, Fry (default), Gallop, Stutter or drawn; grit switchable per step. Pattern persisted as knurl-pattern. - Editor: last eight cycles overlaid, pattern bars with the playing step. - Tests match the prototype: Double gives f0/2 at -8.19 dB, Triple f0/3 at -10.68 dB, equal on F1 and C2, no added clicks, bit-exact when off, no allocation on the audio thread.
This commit is contained in:
1 parent
f4c0a833e6
commit
5cc3770737
27 files changed
+4699
-33
No files matched your search
@@ -11,11 +11,11 @@ fn main() {
|
||||
.map(|a| a[1].as_str())
|
||||
.unwrap_or("rivet");
|
||||
if ![
|
||||
"rivet", "patina", "anvil", "crucible", "lathe", "temper", "weld",
|
||||
"rivet", "patina", "anvil", "crucible", "lathe", "temper", "weld", "knurl",
|
||||
]
|
||||
.contains(&plugin)
|
||||
{
|
||||
eprintln!("Use --plugin rivet, patina, anvil, crucible, lathe, temper or weld");
|
||||
eprintln!("Use --plugin rivet, patina, anvil, crucible, lathe, temper, weld or knurl");
|
||||
std::process::exit(2);
|
||||
}
|
||||
let patina = plugin == "patina" || args.iter().any(|arg| arg == "--resonance");
|
||||
@@ -25,7 +25,10 @@ fn main() {
|
||||
let lathe = plugin == "lathe";
|
||||
let temper = plugin == "temper";
|
||||
let weld = plugin == "weld";
|
||||
let (width, height) = if weld {
|
||||
let knurl = plugin == "knurl";
|
||||
let (width, height) = if knurl {
|
||||
(knurl_ui::WIDTH, knurl_ui::HEIGHT)
|
||||
} else if weld {
|
||||
(weld_ui::WIDTH, weld_ui::HEIGHT)
|
||||
} else if temper {
|
||||
(temper_ui::WIDTH, temper_ui::HEIGHT)
|
||||
@@ -146,6 +149,22 @@ fn main() {
|
||||
}
|
||||
temper_state.accept_frame(engine.take_analyzer());
|
||||
}
|
||||
let mut knurl_settings = knurl_core::Settings::default();
|
||||
let mut knurl_state = knurl_ui::State::default();
|
||||
if knurl {
|
||||
// An F1 saw bass with the default Fry pattern, jitter and grit.
|
||||
let mut engine = knurl_core::Engine::new(48000., 2).unwrap();
|
||||
engine.set_settings(knurl_settings).unwrap();
|
||||
let mut saw = common_dsp::Saw::new(48000., 43.65);
|
||||
for i in 0..36000 {
|
||||
let x = (saw.sample() * 2.2).tanh() * 0.5;
|
||||
engine.process_sample([x, x]);
|
||||
if i % 1600 == 0 {
|
||||
knurl_state.accept_frame(engine.take_analyzer());
|
||||
}
|
||||
}
|
||||
knurl_state.accept_frame(engine.take_analyzer());
|
||||
}
|
||||
let mut weld_settings = weld_core::Settings::default();
|
||||
let mut weld_state = weld_ui::State::default();
|
||||
if weld {
|
||||
@@ -275,7 +294,9 @@ fn main() {
|
||||
let session_motif = session.motifs[0].id;
|
||||
shared.replace(session).unwrap();
|
||||
let ctx = egui::Context::default();
|
||||
if weld {
|
||||
if knurl {
|
||||
knurl_ui::style(&ctx);
|
||||
} else if weld {
|
||||
weld_ui::style(&ctx);
|
||||
} else if temper {
|
||||
temper_ui::style(&ctx);
|
||||
@@ -310,7 +331,9 @@ fn main() {
|
||||
},
|
||||
|ui| {
|
||||
egui::CentralPanel::default().show(ui, |ui| {
|
||||
if weld {
|
||||
if knurl {
|
||||
knurl_ui::show(ui, &mut knurl_settings, &mut knurl_state);
|
||||
} else if weld {
|
||||
weld_ui::show(ui, &mut weld_settings, &mut weld_state);
|
||||
} else if temper {
|
||||
temper_ui::show(ui, &mut temper_settings, &mut temper_state);
|
||||
|
||||
Reference in new issue
Block a user