///|
pub(all) struct Source {
samples : Array[Double]
keyframes : Array[Keyframe]
start : Int32
gain : Double
}
///|
let offline_frame_limit : Int32 = 1440000
///|
let offline_work_limit : Int64 = 384000000L
// Bounded offline mixing. Each source has an independent convolution history.
// Summation is unclipped; clipping is measured before optional PCM quantization.
///|
pub fn render_mix(
sources : Array[Source],
measurements : Array[Measurement],
sample_rate : Int32,
hrir_rate : Int32,
fade_samples : Int32,
) -> SceneResult raise AudioError {
if sources.is_empty() || sources.length() > 16 || measurements.is_empty() {
raise InvalidAudio
}
let taps = measurements[0].hrir.left.length()
let mut work = 0L
let mut length = 0
for s in sources {
if s.start < 0 ||
s.start >= offline_frame_limit ||
!finite(s.gain) ||
s.gain.abs() > 16.0 {
raise InvalidAudio
}
work += s.samples.length().to_int64() * taps.to_int64()
if work > offline_work_limit || s.samples.length() > offline_frame_limit {
raise InvalidAudio
}
let end = s.start + s.samples.length() + taps - 1
if end > length {
length = end
}
}
if length > offline_frame_limit {
raise InvalidAudio
}
let result : Stereo = {
left: Array::make(length, 0.0),
right: Array::make(length, 0.0),
}
for s in sources {
let audio = render_scene(
s.samples,
measurements,
s.keyframes,
sample_rate,
hrir_rate,
fade_samples,
).audio
for i in 0.. peak {
peak = x.abs()
}
if x.abs() > 1.0 {
clipped += 1
}
}
}
{ audio: result, peak, clipped_samples: clipped, }
}