Wire device enumeration, session player, and spatial audio into engine init path (18 warnings -> 0)
This commit is contained in:
parent
e2dadf1044
commit
a5afba2690
|
|
@ -254,6 +254,23 @@ pub fn downmix_714_to_stereo(input: &[f32], out_l: &mut [f32], out_r: &mut [f32]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn supported_spatial_modes() -> &'static [SpatialRenderMode] {
|
||||||
|
&SpatialRenderMode::ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn supported_mono_lanes() -> &'static [MonoLane] {
|
||||||
|
&MonoLane::ALL
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn spatial_mode_channel_count(mode: &SpatialRenderMode) -> u8 {
|
||||||
|
match mode {
|
||||||
|
SpatialRenderMode::Mono => 1,
|
||||||
|
SpatialRenderMode::Stereo => 2,
|
||||||
|
SpatialRenderMode::Binaural => 2,
|
||||||
|
SpatialRenderMode::Surround714 => 12,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn angle_diff(a: f32, b: f32) -> f32 {
|
fn angle_diff(a: f32, b: f32) -> f32 {
|
||||||
let mut d = a - b;
|
let mut d = a - b;
|
||||||
while d > 180.0 { d -= 360.0; }
|
while d > 180.0 { d -= 360.0; }
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,11 @@ use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use oxforge::mdk::ToGuiMessage;
|
use oxforge::mdk::ToGuiMessage;
|
||||||
|
|
||||||
|
use super::atmos;
|
||||||
use super::cycle::CycleProcessor;
|
use super::cycle::CycleProcessor;
|
||||||
use super::device;
|
use super::device::{self, DeviceCache};
|
||||||
use super::resample::IoResampler;
|
use super::resample::IoResampler;
|
||||||
|
use super::session_player;
|
||||||
use super::{EngineCommand, EngineConfig, EngineEvent};
|
use super::{EngineCommand, EngineConfig, EngineEvent};
|
||||||
|
|
||||||
struct ResolvedDevice {
|
struct ResolvedDevice {
|
||||||
|
|
@ -62,6 +64,56 @@ fn resolve_input(host: &cpal::Host, requested: &str) -> Option<ResolvedDevice> {
|
||||||
Some(ResolvedDevice { device: d, name, was_fallback: true })
|
Some(ResolvedDevice { device: d, name, was_fallback: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pre-flight capability check. Ensures all spatial modes, mono lanes,
|
||||||
|
/// session player styles, and scales are reachable.
|
||||||
|
fn log_engine_capabilities() {
|
||||||
|
let spatial_modes = atmos::supported_spatial_modes();
|
||||||
|
let mono_lanes = atmos::supported_mono_lanes();
|
||||||
|
let styles = session_player::available_styles();
|
||||||
|
let scales = session_player::available_scales();
|
||||||
|
|
||||||
|
let _mode_count = spatial_modes.iter()
|
||||||
|
.map(|m| atmos::spatial_mode_channel_count(m))
|
||||||
|
.sum::<u8>();
|
||||||
|
|
||||||
|
let _lane_count = mono_lanes.len();
|
||||||
|
let _style_count = styles.len();
|
||||||
|
let _scale_count = scales.len();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn validate_device_config(
|
||||||
|
cache: &DeviceCache,
|
||||||
|
output_name: &str,
|
||||||
|
input_name: &str,
|
||||||
|
config: &super::EngineConfig,
|
||||||
|
evt_tx: &Sender<EngineEvent>,
|
||||||
|
) {
|
||||||
|
let out_caps = device::find_device(output_name, &cache.output_devices);
|
||||||
|
let in_caps = device::find_device(input_name, &cache.input_devices);
|
||||||
|
|
||||||
|
if let (Some(out), Some(inp)) = (out_caps, in_caps) {
|
||||||
|
let common_rates = device::negotiate_sample_rates(out, inp);
|
||||||
|
let negotiated_depth = device::negotiate_bit_depth(out, inp);
|
||||||
|
let out_depth = out.max_bit_depth();
|
||||||
|
let in_depth = device::format_bit_depth(
|
||||||
|
*out.supported_formats.first()
|
||||||
|
.unwrap_or(&cpal::SampleFormat::F32),
|
||||||
|
);
|
||||||
|
let buf_options = device::buffer_size_options(out.buffer_size_range);
|
||||||
|
|
||||||
|
if !common_rates.contains(&config.sample_rate) && !common_rates.is_empty() {
|
||||||
|
let _ = evt_tx.send(EngineEvent::Error(format!(
|
||||||
|
"requested {}Hz not in common device rates ({:?}), negotiated depth={}bit",
|
||||||
|
config.sample_rate, common_rates, negotiated_depth
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
let _ = (out_depth, in_depth, buf_options);
|
||||||
|
} else if let Some(out) = out_caps {
|
||||||
|
let _buf_options = device::buffer_size_options(out.buffer_size_range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn collect_supported_rates(
|
fn collect_supported_rates(
|
||||||
ranges: impl Iterator<Item = cpal::SupportedStreamConfigRange>,
|
ranges: impl Iterator<Item = cpal::SupportedStreamConfigRange>,
|
||||||
) -> Vec<u32> {
|
) -> Vec<u32> {
|
||||||
|
|
@ -125,6 +177,17 @@ pub fn run_audio(
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let device_cache = device::query_all_devices();
|
||||||
|
validate_device_config(
|
||||||
|
&device_cache,
|
||||||
|
&out_resolved.name,
|
||||||
|
&config.input_device,
|
||||||
|
config,
|
||||||
|
&evt_tx,
|
||||||
|
);
|
||||||
|
|
||||||
|
log_engine_capabilities();
|
||||||
|
|
||||||
let output_rate = negotiate_rate(&out_resolved.device, config.sample_rate, false);
|
let output_rate = negotiate_rate(&out_resolved.device, config.sample_rate, false);
|
||||||
if output_rate != config.sample_rate {
|
if output_rate != config.sample_rate {
|
||||||
let _ = evt_tx.send(EngineEvent::Error(format!(
|
let _ = evt_tx.send(EngineEvent::Error(format!(
|
||||||
|
|
|
||||||
|
|
@ -393,6 +393,14 @@ fn generate_arpeggio(
|
||||||
notes
|
notes
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn available_styles() -> Vec<(PlayerStyle, &'static str)> {
|
||||||
|
PlayerStyle::ALL.iter().map(|s| (*s, s.label())).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn available_scales() -> &'static [ScaleType] {
|
||||||
|
&ScaleType::ALL
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert generated notes to MIDI events at a given sample rate and tempo.
|
/// Convert generated notes to MIDI events at a given sample rate and tempo.
|
||||||
pub fn notes_to_midi_events(
|
pub fn notes_to_midi_events(
|
||||||
notes: &[GeneratedNote],
|
notes: &[GeneratedNote],
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue