mod common;
use rosc::{OscBundle, OscPacket};
use scsynth::{Options, World};
const SAMPLE_RATE: u32 = 44_100;
const FREQ: f32 = 440.0;
#[test]
fn renders_sine_tone() {
let dir = std::env::temp_dir().join(format!("scsynth-nrt-{}", std::process::id()));
std::fs::create_dir_all(&dir).unwrap();
let cmd_path = dir.join("commands.osc");
let wav_path = dir.join("out.wav");
std::fs::write(&cmd_path, nrt_command_file()).unwrap();
let options = Options::new()
.real_time(false)
.input_channels(0)
.output_channels(1)
.sample_rate(SAMPLE_RATE)
.block_size(64)
.load_synthdefs(false)
.verbosity(-1)
.nrt_command_file(&cmd_path)
.unwrap()
.nrt_output_file(&wav_path, "WAV", "int16")
.unwrap();
let world = World::new(options).expect("World_New failed");
world.non_realtime_render();
let mut reader = hound::WavReader::open(&wav_path).expect("output WAV not written");
assert_eq!(reader.spec().channels, 1);
assert_eq!(reader.spec().sample_rate, SAMPLE_RATE);
let samples: Vec<f32> = reader
.samples::<i16>()
.map(|s| s.unwrap() as f32 / i16::MAX as f32)
.collect();
assert!(
samples.len() > (SAMPLE_RATE / 4) as usize,
"too few samples rendered: {}",
samples.len()
);
assert!(common::rms(&samples) > 0.1, "output is ~silent");
let sr = SAMPLE_RATE as f32;
let at_440 = common::goertzel(&samples, sr, FREQ);
let at_1000 = common::goertzel(&samples, sr, 1000.0);
let at_220 = common::goertzel(&samples, sr, 220.0);
assert!(
at_440 > 10.0 * at_1000 && at_440 > 10.0 * at_220,
"expected a dominant 440 Hz tone (440={at_440}, 1000={at_1000}, 220={at_220})"
);
let _ = std::fs::remove_dir_all(&dir);
}
fn nrt_command_file() -> Vec<u8> {
let start = OscPacket::Bundle(OscBundle {
timetag: rosc::OscTime {
seconds: 0,
fractional: 0,
},
content: vec![
OscPacket::Message(common::d_recv(common::synthdef_sine(FREQ, 1))),
OscPacket::Message(common::s_new("sine", 1000, 0, 0)),
],
});
let stop = OscPacket::Bundle(OscBundle {
timetag: rosc::OscTime {
seconds: 0,
fractional: 0x8000_0000,
},
content: vec![OscPacket::Message(common::n_free(1000))],
});
let mut file = Vec::new();
for bundle in [start, stop] {
let bytes = rosc::encoder::encode(&bundle).unwrap();
file.extend_from_slice(&(bytes.len() as u32).to_be_bytes());
file.extend_from_slice(&bytes);
}
file
}