use crate::{
context::{self, DistanceModel, SoundContext},
listener::Listener,
renderer::render_source_2d_only,
source::SoundSource,
};
use fyrox_core::{
reflect::prelude::*,
visitor::{Visit, VisitResult, Visitor},
};
use hrtf::HrirSphere;
use std::{fmt::Debug, path::PathBuf};
#[derive(Clone, Debug, Default, Reflect)]
pub struct HrtfRenderer {
hrir_path: PathBuf,
#[reflect(hidden)]
processor: Option<hrtf::HrtfProcessor>,
}
impl Visit for HrtfRenderer {
fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
let mut region = visitor.enter_region(name)?;
self.hrir_path.visit("ResourcePath", &mut region)?;
drop(region);
if visitor.is_reading() {
self.processor = Some(hrtf::HrtfProcessor::new(
HrirSphere::from_file(&self.hrir_path, context::SAMPLE_RATE).unwrap(),
SoundContext::HRTF_INTERPOLATION_STEPS,
SoundContext::HRTF_BLOCK_LEN,
));
}
Ok(())
}
}
impl HrtfRenderer {
pub fn new(hrir_sphere: hrtf::HrirSphere) -> Self {
Self {
hrir_path: hrir_sphere.source().to_path_buf(),
processor: Some(hrtf::HrtfProcessor::new(
hrir_sphere,
SoundContext::HRTF_INTERPOLATION_STEPS,
SoundContext::HRTF_BLOCK_LEN,
)),
}
}
pub(crate) fn render_source(
&mut self,
source: &mut SoundSource,
listener: &Listener,
distance_model: DistanceModel,
out_buf: &mut [(f32, f32)],
) {
render_source_2d_only(source, out_buf);
let new_distance_gain =
source.spatial_blend() * source.calculate_distance_gain(listener, distance_model);
let new_sampling_vector = source.calculate_sampling_vector(listener);
self.processor
.as_mut()
.unwrap()
.process_samples(hrtf::HrtfContext {
source: &source.frame_samples,
output: out_buf,
new_sample_vector: hrtf::Vec3::new(
new_sampling_vector.x,
new_sampling_vector.y,
new_sampling_vector.z,
),
prev_sample_vector: hrtf::Vec3::new(
source.prev_sampling_vector.x,
source.prev_sampling_vector.y,
source.prev_sampling_vector.z,
),
prev_left_samples: &mut source.prev_left_samples,
prev_right_samples: &mut source.prev_right_samples,
prev_distance_gain: source.prev_distance_gain.unwrap_or(new_distance_gain),
new_distance_gain,
});
source.prev_sampling_vector = new_sampling_vector;
source.prev_distance_gain = Some(new_distance_gain);
}
}