Skip to main content

sva_core/
encode.rs

1// Concern: refuses a sample past what 32-bit floats or integer PCM hold | Non-concern: the file's byte layout (sva-cli wav.rs) | IO: (node, samples) -> f32 samples or CliError
2
3use sva_engine::{Diagnostic, EngineError, Located};
4
5use crate::CliError;
6
7pub fn float32(node: &str, plane: &[f64]) -> Result<Vec<f32>, CliError> {
8    plane.iter().map(|&v| float32_sample(node, v)).collect()
9}
10
11/// One sample, for a caller filling a buffer it already holds.
12pub fn float32_sample(node: &str, v: f64) -> Result<f32, CliError> {
13    match v as f32 {
14        held if held.is_finite() => Ok(held),
15        _ => Err(unrepresentable(
16            node,
17            v,
18            "a 32-bit float",
19            "scale the output down",
20        )),
21    }
22}
23
24/// Integer PCM holds full scale and nothing past it.
25pub fn full_scale(node: &str, plane: &[f32]) -> Result<(), CliError> {
26    match plane.iter().find(|v| v.abs() > 1.0) {
27        Some(v) => Err(unrepresentable(
28            node,
29            f64::from(*v),
30            "integer PCM",
31            "scale the output into full scale, or write 32-bit floats with --bits 32",
32        )),
33        None => Ok(()),
34    }
35}
36
37fn unrepresentable(node: &str, value: f64, format: &str, help: &str) -> CliError {
38    CliError::Engine(EngineError::refused(Diagnostic {
39        code: "render.unrepresentable_sample".to_string(),
40        message: format!("a sample of {value:e} is past what {format} holds"),
41        location: Located::at(node, None),
42        help: help.to_string(),
43    }))
44}