1use crate::{
3 AppliedParameters, Backend, PreparedSession, ProcessStatus, SessionConfig, SessionCounters,
4 SessionError, SessionResult, SourceAccess, TimingInfo,
5};
6
7#[derive(Clone, Debug)]
8pub struct RenderReport {
9 pub source_frames: u64,
10 pub output_frames: u64,
11 pub source_sample_rate: u32,
12 pub output_sample_rate: u32,
13 pub channels: usize,
14 pub backend: Backend,
15 pub parameters: AppliedParameters,
16 pub timing: TimingInfo,
17 pub counters: SessionCounters,
18 pub memory: crate::OwnedMemory,
19}
20#[derive(Clone, Debug)]
21pub struct RenderedAudio {
22 pub samples: Vec<f32>,
23 pub report: RenderReport,
24}
25
26pub fn render(input: &[f32], mut config: SessionConfig) -> SessionResult<RenderedAudio> {
28 if !(1..=2).contains(&config.channels) || input.len() % config.channels != 0 {
29 return Err(SessionError::InvalidFormat);
30 }
31 if input.iter().any(|v| !v.is_finite()) {
32 return Err(SessionError::NonFiniteInput);
33 }
34 let frames = (input.len() / config.channels) as u64;
35 if config.source_frames.is_some_and(|length| length != frames) {
36 return Err(SessionError::InvalidFormat);
37 }
38 config.source_frames = Some(frames);
39 config.source_access = SourceAccess::Seekable;
40 let mut session = PreparedSession::new(config)?.activate();
41 let channels = session.config().channels;
42 let parameters = session.applied_parameters();
43 let expected =
44 (frames as f64 * parameters.achieved_stretch * session.config().output_sample_rate as f64
45 / session.config().source_sample_rate as f64)
46 .round() as usize;
47 let mut samples = Vec::with_capacity(expected.saturating_mul(channels));
48 let mut block = vec![0.0; 1024 * channels];
49 while !session.finished() {
50 let progress = session.advance(32);
51 match progress.status {
52 ProcessStatus::Fault => {
53 return Err(session.fault().unwrap_or(SessionError::InvalidState));
54 }
55 ProcessStatus::NeedSource => {
56 let request = session.source_request().ok_or(SessionError::InvalidState)?;
57 let start = request.start_frame as usize * channels;
58 let end = (start + request.frames * channels).min(input.len());
59 if start == end {
60 session.finish_input()?;
61 } else {
62 session.supply(request, &input[start..end])?;
63 }
64 }
65 _ => {}
66 }
67 let stamp = session.read_output(&mut block)?;
68 samples.extend_from_slice(&block[..stamp.frames * channels]);
69 session.acknowledge(stamp.consumed(stamp.frames)?)?;
70 }
71 Ok(RenderedAudio {
72 report: RenderReport {
73 source_frames: frames,
74 output_frames: (samples.len() / channels) as u64,
75 source_sample_rate: session.config().source_sample_rate,
76 output_sample_rate: session.config().output_sample_rate,
77 channels,
78 backend: session.config().backend,
79 parameters,
80 timing: session.timing(),
81 counters: session.counters(),
82 memory: session.owned_memory(),
83 },
84 samples,
85 })
86}