use patina_core::{Engine, Monitor, Settings}; use std::{ alloc::{GlobalAlloc, Layout, System}, cell::Cell, }; struct CheckedAllocator; thread_local! { static CHECK:Cell=const {Cell::new(false)}; static OPERATIONS:Cell=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_automation_and_analysis_do_not_allocate_or_free() { let mut engine = Engine::new(48000., 2).unwrap(); let mut settings = Settings::preset(1); settings.tone_guard = 80.; engine.set_settings(settings).unwrap(); CHECK.with(|v| v.set(true)); for i in 0..48000 { if i % 512 == 0 { settings.focus[0].enabled = true; settings.focus[0].frequency = 1000. + (i % 10000) as f32; settings.focus[0].sensitivity = 6.; settings.low = 120. + (i % 100) as f32; engine.set_settings(settings).unwrap(); } // A pitched input, so Tone guard estimates the pitch and updates its maps. let x = 0.3 * (i as f32 * std::f32::consts::TAU * 55. / 48000.) .sin() .signum(); std::hint::black_box(engine.process_sample([x, -x], Monitor { delta: i > 24000 })); std::hint::black_box(engine.take_analyzer()); } engine.reset(); CHECK.with(|v| v.set(false)); assert_eq!(OPERATIONS.with(Cell::get), 0); }