#[cfg(test)]
mod tests {
use crate::clap::test_util::{self, StereoTestBuffers};
use clack_host::prelude::*;
use std::path::PathBuf;
#[test]
fn test_model_gain_calibration() {
let mut model_path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
model_path.push("tests/fixtures/models/BossWN-nano.nam");
let (_entry, _host_info, mut plugin_instance) = test_util::make_test_plugin();
let params = test_util::make_default_params(Some(model_path.clone()));
test_util::load_plugin_state(&mut plugin_instance, ¶ms);
plugin_instance.call_on_main_thread_callback();
let audio_config = PluginAudioConfiguration {
sample_rate: 48000.0,
min_frames_count: 512,
max_frames_count: 512,
};
let stopped_processor = plugin_instance.activate(|_, _| (), audio_config).unwrap();
let mut started_processor = stopped_processor.start_processing().unwrap();
let n = 512;
let mut bufs = StereoTestBuffers::new(n, 0.5, 0.5);
let mut input_channels = [bufs.in_l.as_mut_slice(), bufs.in_r.as_mut_slice()];
let input_audio = bufs.input_ports.with_input_buffers([AudioPortBuffer {
latency: 0,
channels: AudioPortBufferType::f32_input_only(
input_channels.iter_mut().map(InputChannel::constant),
),
}]);
let output_channels = [bufs.out_l.as_mut_slice(), bufs.out_r.as_mut_slice()];
let mut output_audio = bufs.output_ports.with_output_buffers([AudioPortBuffer {
latency: 0,
channels: AudioPortBufferType::f32_output_only(output_channels.into_iter()),
}]);
let input_events = InputEvents::empty();
let mut output_events = OutputEvents::from_buffer(&mut bufs.output_events_buffer);
started_processor
.process(
&input_audio,
&mut output_audio,
&input_events,
&mut output_events,
None,
None,
)
.unwrap();
let clap_rms: f32 = (bufs.out_l.iter().map(|x| x * x).sum::<f32>() / n as f32).sqrt();
assert!(
(0.05..=0.20).contains(&clap_rms),
"CLAP output RMS out of band ({:.6}) — expected [0.05, 0.20] for Nano model",
clap_rms
);
use crate::models::NamModel;
let sys = crate::common::diagnostics::SystemSnapshot::capture();
let model_pair = crate::loader::build::load_and_build_model(
&model_path,
&sys,
true,
crate::loader::LoadOptions::default(),
)
.expect("Failed to load model directly");
let mut direct_model = model_pair.model_l.expect("Failed to build direct model");
let input_mult = model_pair.input_mult_adj;
let output_mult = model_pair.output_mult_adj;
assert!((input_mult - 1.0).abs() < 1e-4);
assert!((output_mult - 1.0).abs() > 1e-4);
use crate::dsp::pipeline::DENORMAL_DITHER_OFFSET;
let mut direct_in = vec![0.5f32; n];
for val in direct_in.iter_mut() {
*val = *val * input_mult + DENORMAL_DITHER_OFFSET;
}
let mut direct_out = vec![0.0f32; n];
direct_model.process(&direct_in, &mut direct_out);
for val in direct_out.iter_mut() {
*val = (*val - DENORMAL_DITHER_OFFSET) * output_mult;
}
let direct_rms: f32 = (direct_out.iter().map(|x| x * x).sum::<f32>() / n as f32).sqrt();
assert!(
direct_rms > 0.001,
"Direct output RMS too low ({:.6})",
direct_rms
);
}
}