Ghost adds the sub's harmonics 2–10 above Ghost from, so phones hear the note. The band above the split is measured per harmonic and only missing harmonics are filled, so added ones cannot cancel the patch's own. The sub level does not change. Phone monitors the output in mono, 400 Hz–7 kHz.
79 lines
2.3 KiB
Rust
79 lines
2.3 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.,
|
|
..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.
|
|
};
|
|
std::hint::black_box(engine.process_sample(
|
|
[x, x],
|
|
Monitor {
|
|
solo: i % 3 == 0,
|
|
phone: i % 5 == 0,
|
|
},
|
|
));
|
|
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);
|
|
}
|