Check and Windows preview / check (anvil) (push) Canceled after 0s
Check and Windows preview / check (braze) (push) Canceled after 0s
Check and Windows preview / check (crucible) (push) Canceled after 0s
Check and Windows preview / check (knurl) (push) Canceled after 0s
Check and Windows preview / check (lathe) (push) Canceled after 0s
Check and Windows preview / check (patina) (push) Canceled after 0s
Check and Windows preview / check (planish) (push) Canceled after 0s
Check and Windows preview / check (rivet) (push) Canceled after 0s
Check and Windows preview / check (temper) (push) Canceled after 0s
Check and Windows preview / check (weld) (push) Canceled after 0s
Check and Windows preview / previews (push) Canceled after 0s
Check and Windows preview / windows (push) Canceled after 0s
Anvil gets a sidechain input named Kick. With Kick lock on, kicks are found on the undelayed sidechain, so with the lookahead each hit ducks the sub (Duck, Release) when the delayed kick plays and restarts the sub at Phase, shifted by Offset (-30 to +30 ms, also before the kick). The Audition steps the offset from -30 to +30 ms, 4 kicks each, and measures how kick and sub sum below 150 Hz after each hit; Keep takes the offset heard. On a 55 Hz kick burst against a 55 Hz sub the sum peaks at 0 ms (+2.4 dB) and nearly again one period away (+/-20 ms), so the bars check the choice by ear rather than make it.
84 lines
2.5 KiB
Rust
84 lines
2.5 KiB
Rust
use anvil_core::{Engine, Monitor, Settings, Source};
|
|
use std::{
|
|
alloc::{GlobalAlloc, Layout, System},
|
|
cell::Cell,
|
|
};
|
|
|
|
struct CheckedAllocator;
|
|
thread_local! {
|
|
static CHECK:Cell<bool>=const {Cell::new(false)};
|
|
static OPERATIONS:Cell<usize>=const {Cell::new(0)};
|
|
}
|
|
fn record() {
|
|
if CHECK.try_with(Cell::get).unwrap_or(false) {
|
|
let _ = OPERATIONS.try_with(|n| n.set(n.get() + 1));
|
|
}
|
|
}
|
|
unsafe impl GlobalAlloc for CheckedAllocator {
|
|
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
|
|
record();
|
|
unsafe { System.alloc(layout) }
|
|
}
|
|
unsafe fn dealloc(&self, pointer: *mut u8, layout: Layout) {
|
|
record();
|
|
unsafe { System.dealloc(pointer, layout) }
|
|
}
|
|
unsafe fn realloc(&self, pointer: *mut u8, layout: Layout, size: usize) -> *mut u8 {
|
|
record();
|
|
unsafe { System.realloc(pointer, layout, size) }
|
|
}
|
|
}
|
|
#[global_allocator]
|
|
static ALLOCATOR: CheckedAllocator = CheckedAllocator;
|
|
|
|
#[test]
|
|
fn processing_notes_settings_and_analysis_do_not_allocate_or_free() {
|
|
let mut engine = Engine::new(48000., 2).unwrap();
|
|
let mut settings = Settings {
|
|
ghost: 80.,
|
|
kick_lock: true,
|
|
kick_offset: -12.,
|
|
..Settings::default()
|
|
};
|
|
engine.set_settings(settings).unwrap();
|
|
CHECK.with(|v| v.set(true));
|
|
for i in 0..96000 {
|
|
if i % 4800 == 0 {
|
|
settings.split = 60. + (i % 100) as f32;
|
|
settings.source = if i > 48000 {
|
|
Source::Midi
|
|
} else {
|
|
Source::Audio
|
|
};
|
|
settings.octave = -((i / 4800) % 2);
|
|
engine.set_settings(settings).unwrap();
|
|
engine.note_on(30 + (i / 4800 % 12) as u8);
|
|
}
|
|
if i % 4800 == 2400 {
|
|
engine.note_off(30 + (i / 4800 % 12) as u8);
|
|
}
|
|
let t = i as f32 / 48000.;
|
|
let x = if (i / 2400) % 2 == 0 {
|
|
(std::f32::consts::TAU * 55. * t).sin() * 0.5
|
|
} else {
|
|
0.
|
|
};
|
|
let kick = if i % 12000 < 400 { 0.8 } else { 0. };
|
|
std::hint::black_box(engine.process_with_kick(
|
|
[x, x],
|
|
kick,
|
|
Monitor {
|
|
solo: i % 3 == 0,
|
|
phone: i % 5 == 0,
|
|
audition: i > 30000,
|
|
},
|
|
));
|
|
if i % 1600 == 0 {
|
|
std::hint::black_box(engine.take_analyzer());
|
|
}
|
|
}
|
|
engine.reset();
|
|
CHECK.with(|v| v.set(false));
|
|
assert_eq!(OPERATIONS.with(Cell::get), 0);
|
|
}
|