fmod_utils/
info.rs

1//! Write system information
2
3use std;
4use fmod::{self, ChannelControl};
5
6static INDENT : std::sync::atomic::AtomicU32 = std::sync::atomic::AtomicU32::new (0);
7
8//
9//  fn write_info_system
10//
11#[expect(clippy::missing_panics_doc)]
12pub fn write_info_system <W : std::io::Write>
13  (writer : &mut W, system : &fmod::System) -> Result <(), std::io::Error>
14{
15  let indent = indent_string();
16  writeln!(writer, "{indent}# fmod system info #")?;
17  writeln!(writer, "{}{:<36} {}",   indent, "fmod system: version:",
18    system.get_version_string().unwrap())?;
19  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: output:",
20    system.get_output().unwrap())?;
21  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: num drivers:",
22    system.get_num_drivers().unwrap())?;
23  for i in 0..system.get_num_drivers().unwrap() {
24    let driver_info = system.get_driver_info (i).unwrap();
25    writeln!(writer, "{indent}fmod system: driver info[{i}]:")?;
26    writeln!(writer, "{indent}    {driver_info:?}")?;
27  }
28  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: record num drivers:",
29    system.get_record_num_drivers().unwrap())?;
30  for i in 0..system.get_record_num_drivers().unwrap().0 {
31    let (info, state) = system.get_record_driver_info (i).unwrap();
32    writeln!(writer, "{indent}fmod system: record driver info[{i}]:")?;
33    writeln!(writer, "{indent}    {info:?}")?;
34    writeln!(writer, "{indent}    {state:?}")?;
35  }
36  writeln!(writer, "{}{:<36} {}", indent, "fmod system: driver:",
37    system.get_driver().unwrap())?;
38  writeln!(writer, "{}{:<36} {}", indent, "fmod system: software channels:",
39    system.get_software_channels().unwrap())?;
40  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: channels playing:",
41    system.get_channels_playing().unwrap())?;
42  let (samplerate, speakermode, numrawspeakers) =
43    system.get_software_format().unwrap();
44  writeln!(writer, "{indent}fmod system: software format:")?;
45  writeln!(writer, "{indent}    sample rate:      {samplerate}")?;
46  writeln!(writer, "{indent}    speaker mode:     {speakermode:?}")?;
47  writeln!(writer, "{indent}    num raw speakers: {numrawspeakers}")?;
48  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: dsp buffer size:",
49    system.get_dsp_buffer_size().unwrap())?;
50  // TODO: get_advanced_settings
51  writeln!(writer, "{indent}fmod system: speaker mode channels:")?;
52  for i in 0..fmod::Speakermode::MAX as u32 {
53    use fmod::FromPrimitive;
54    let mode = fmod::Speakermode::from_u32 (i).unwrap();
55    writeln!(writer, "{}    {:?}: {}",
56      indent, mode, system.get_speaker_mode_channels (mode).unwrap())?;
57  }
58  writeln!(writer, "{indent}fmod system: num plugins:")?;
59  writeln!(writer, "{}    Plugintype::Output: {:?}", indent,
60    system.get_num_plugins (fmod::Plugintype::Output).unwrap())?;
61  writeln!(writer, "{}    Plugintype::Codec:  {:?}", indent,
62    system.get_num_plugins (fmod::Plugintype::Codec).unwrap())?;
63  writeln!(writer, "{}    Plugintype::DSP:    {:?}", indent,
64    system.get_num_plugins (fmod::Plugintype::Dsp).unwrap())?;
65  // TODO: get_plugin_handle, get_plugin_info
66  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: output by plugin:",
67    system.get_output_by_plugin().unwrap())?;
68  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: 3d num listeners:",
69    system.get_3d_num_listeners().unwrap())?;
70  for i in 0..system.get_3d_num_listeners().unwrap() {
71    let attributes = system.get_3d_listener_attributes (i).unwrap();
72    writeln!(writer, "{indent}fmod system: 3d listener attributes[{i}]:")?;
73    writeln!(writer, "{}    pos:      {:?}", indent, attributes.pos)?;
74    writeln!(writer, "{}    vel:      {:?}", indent, attributes.vel)?;
75    writeln!(writer, "{}    forward:  {:?}", indent, attributes.forward)?;
76    writeln!(writer, "{}    up:       {:?}", indent, attributes.up)?;
77  }
78  writeln!(writer, "{indent}fmod system: 3d speaker position:")?;
79  let driver_id     = system.get_driver().unwrap();
80  let driver_info   = system.get_driver_info (driver_id).unwrap();
81  #[expect(clippy::cast_sign_loss)]
82  for i in 0..driver_info.speakermodechannels as u32 {
83    use fmod::FromPrimitive;
84    let speaker = fmod::Speaker::from_u32 (i).unwrap();
85    writeln!(writer, "{}    {:?}:          {:?}",
86      indent, speaker, system.get_speaker_position (speaker).unwrap())?;
87  }
88  let (doppler_scale, distance_factor, roll_off_scale) =
89    system.get_3d_settings().unwrap();
90  writeln!(writer, "{indent}fmod system: 3d settings:")?;
91  writeln!(writer, "{indent}    doppler scale:   {doppler_scale}")?;
92  writeln!(writer, "{indent}    distance factor: {distance_factor}")?;
93  writeln!(writer, "{indent}    roll off scale:  {roll_off_scale}")?;
94  let (buffer_size, time_unit) = system.get_stream_buffer_size().unwrap();
95  writeln!(writer, "{}{:<36} ({}, {:?})", indent,
96    "fmod system: stream buffer size:", buffer_size, time_unit)?;
97  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: cpu usage:",
98    system.get_cpu_usage().unwrap())?;
99  writeln!(writer, "{}{:<36} {:?}", indent, "fmod system: sound ram:",
100    system.get_sound_ram().unwrap())?;
101  // TODO: get_master_channel_group
102  // TODO: get_master_sound_group
103  writeln!(writer, "{indent}fmod system: reverb properties:")?;
104  #[expect(clippy::cast_possible_wrap)]
105  for i in 0..fmod::dsp::REVERB_MAXINSTANCES as i32 {
106    writeln!(writer, "{indent}    instance[{i}]:")?;
107    indent_bump (4);
108    let properties = show_reverb_properties (&system.get_reverb_properties (i)
109      .unwrap());
110    indent_unbump (4);
111    write!(writer, "{properties}")?;
112  }
113  // TODO: get_reverb_ambient_properties
114  writeln!(writer, "{}{:<36} {}", indent, "fmod system: geometry settings:",
115    system.get_geometry_settings().unwrap())?;
116  Ok(())
117} // end fn write_info_system
118
119//
120//  fn write_info_reverb3d
121//
122#[expect(clippy::missing_panics_doc)]
123pub fn write_info_reverb3d <W : std::io::Write>
124  (writer : &mut W, reverb : &fmod::Reverb3d) -> Result <(), std::io::Error>
125{
126  let indent = indent_string();
127  writeln!(writer, "{indent}# fmod reverb info #")?;
128  writeln!(writer, "{}fmod reverb: active:   {}", indent,
129    reverb.get_active().unwrap())?;
130  let attributes = reverb.get_3d_attributes().unwrap();
131  writeln!(writer, "{indent}fmod reverb: 3d attributes:")?;
132  writeln!(writer, "{}    position:     {:?}", indent, attributes.position)?;
133  writeln!(writer, "{}    min distance: {:?}", indent, attributes.mindistance)?;
134  writeln!(writer, "{}    max distance: {:?}", indent, attributes.maxdistance)?;
135  write!(writer, "{}fmod reverb: properties: {}", indent,
136    show_reverb_properties (&reverb.get_properties().unwrap()))?;
137  Ok(())
138} // end fn write_info_reverb
139
140//
141//  fn write_info_dsp
142//
143#[expect(clippy::missing_panics_doc)]
144pub fn write_info_dsp <W : std::io::Write>
145  (writer : &mut W, dsp : &fmod::Dsp) -> Result <(), std::io::Error>
146{
147  let indent = indent_string();
148  writeln!(writer, "{indent}# fmod dsp info #")?;
149  writeln!(writer, "{}{:<24} {:?}", indent, "fmod dsp: type:",
150    dsp.get_type().unwrap())?;
151  writeln!(writer, "{}{:<24} {}",   indent, "fmod dsp: active:",
152    dsp.get_active().unwrap())?;
153  // TODO: active speakers ?
154  writeln!(writer, "{}{:<24} {}",   indent, "fmod dsp: bypass:",
155    dsp.get_bypass().unwrap())?;
156  writeln!(writer, "{}{:<24} {}",   indent, "fmod dsp: num inputs:",
157    dsp.get_num_inputs().unwrap())?;
158  writeln!(writer, "{}{:<24} {}",   indent, "fmod dsp: num outputs:",
159    dsp.get_num_outputs().unwrap())?;
160  // TODO: show inputs/outputs ?
161  // TODO: parameters ?
162  // TODO: memory info ?
163  Ok(())
164} // end fn write_info_dsp
165
166//
167//  fn write_info_channel
168//
169#[expect(clippy::missing_panics_doc)]
170pub fn write_info_channel <W : std::io::Write> (
171  writer  : &mut W,
172  channel : &fmod::Channel
173) -> Result <(), std::io::Error> {
174  let indent = indent_string();
175  writeln!(writer, "{indent}# fmod channel info #")?;
176  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: index:",
177    channel.get_index().unwrap())?;
178  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: channel group:",
179    channel.get_channel_group().unwrap().get_name().unwrap())?;
180  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: priority:",
181    channel.get_priority().unwrap())?;
182  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: is virtual:",
183    channel.is_virtual().unwrap())?;
184  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: position (ms):",
185    channel.get_position (fmod::Timeunit::MS).unwrap())?;
186  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: loop count:",
187    channel.get_loop_count().unwrap())?;
188  let (loop_start, loop_end) =
189    channel.get_loop_points (fmod::Timeunit::MS, fmod::Timeunit::MS).unwrap();
190  writeln!(writer, "{}{:<36} (start: {}, end: {})", indent,
191    "fmod channel: loop points (ms):", loop_start, loop_end)?;
192  writeln!(writer, "{}{:<36} {}", indent, "fmod channel: frequency:",
193    channel.get_frequency().unwrap())?;
194  // TODO: speaker levels ?
195  // TODO: input channel mixes ?
196  // TODO: dsp head ?
197  // TODO: memory info ?
198  writeln!(writer, "{indent}fmod channel: channel control:")?;
199  write_info_channel_control (writer, channel)?;
200  Ok(())
201} // end fn write_info_channel
202
203//
204//  fn write_info_channel_control
205//
206#[expect(clippy::missing_panics_doc)]
207pub fn write_info_channel_control <W : std::io::Write, C : ChannelControl> (
208  writer  : &mut W,
209  control : &C
210) -> Result <(), std::io::Error> {
211  let indent = indent_string();
212  writeln!(writer, "{indent}# fmod channel control info #")?;
213  // TODO: the following fails for a newly created channel, how to check that
214  // these will not fail?
215  writeln!(writer, "{}{:<36} Mode({:b})", indent, "fmod channel control: mode:",
216    control.get_mode().unwrap())?;
217  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: is playing:",
218    control.is_playing().unwrap())?;
219  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: paused:",
220    control.get_paused().unwrap())?;
221  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: volume:",
222    control.get_volume().unwrap())?;
223  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: mute:",
224    control.get_mute().unwrap())?;
225  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: audibility:",
226    control.get_audibility().unwrap())?;
227  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: low pass gain:",
228    control.get_low_pass_gain().unwrap())?;
229  let delay = control.get_delay().unwrap();
230  writeln!(writer, "{}{:<36} {:?}", indent, "fmod channel control: delay:",
231    delay)?;
232  writeln!(writer, "{indent}fmod channel control: reverb properties (wet level):")?;
233  #[expect(clippy::cast_possible_wrap)]
234  for i in 0..fmod::dsp::REVERB_MAXINSTANCES as i32 {
235    writeln!(writer, "{}    instance[{}]: {}",
236      indent, i, control.get_reverb_properties (i).unwrap())?;
237  }
238  let num_dsps = control.get_num_dsps().unwrap();
239  writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: num dsps:",
240    num_dsps)?;
241  for i in 0..num_dsps {
242    writeln!(writer, "{indent}fmod channel control: dsp[{i}]:")?;
243    #[expect(clippy::cast_possible_wrap)]
244    let dsp = control.get_dsp (i as i32).unwrap();
245    indent_bump (4);
246    write_info_dsp (writer, &dsp)?;
247    indent_unbump (4);
248  }
249  match control.get_3d_attributes() {
250    Ok ((position, velocity)) => {
251      writeln!(writer, "{indent}fmod channel control: 3d attributes:")?;
252      writeln!(writer, "{indent}    position: {position:?}")?;
253      writeln!(writer, "{indent}    velocity: {velocity:?}")?;
254      writeln!(writer, "{}{:<36} {:?}", indent,
255        "fmod channel control: 3d min max distance:",
256        control.get_3d_min_max_distance().unwrap())?;
257      writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: 3d spread:",
258        control.get_3d_spread().unwrap())?;
259      writeln!(writer, "{}{:<36} {}", indent, "fmod channel control: 3d doppler level:",
260        control.get_3d_doppler_level().unwrap())?;
261      writeln!(writer, "{}{:<36} {:?}", indent,
262        "fmod channel control: 3d custom rolloff:",
263        control.get_3d_custom_rolloff().unwrap())?;
264      writeln!(writer, "{}{:<36} {:?}", indent,
265        "fmod channel control: 3d distance filter:",
266        control.get_3d_distance_filter().unwrap())?;
267      writeln!(writer, "{}{:<36} {:?}", indent,
268        "fmod channel control: 3d occlusion:",
269        control.get_3d_occlusion().unwrap())?;
270      writeln!(writer, "{}{:<36} {:?}", indent,
271        "fmod channel control: 3d cone orientation:",
272        control.get_3d_cone_orientation().unwrap())?;
273      let (inside_cone_angle, outside_cone_angle, outside_volume) =
274        control.get_3d_cone_settings().unwrap();
275      writeln!(writer, "{indent}fmod channel control: 3d cone settings:")?;
276      writeln!(writer, "{indent}    inside cone angle:  {inside_cone_angle}")?;
277      writeln!(writer, "{indent}    outside cone angle: {outside_cone_angle}")?;
278      writeln!(writer, "{indent}    outside volume:     {outside_volume}")?;
279    }
280    Err (fmod::Error::Needs3d) => {}
281    err => {
282      writeln!(writer, "channel control 3d attributes error: {err:?}")?;
283      unreachable!()
284    }
285  }
286  Ok (())
287}
288
289//
290//  fn write_info_channel_group
291//
292#[expect(clippy::missing_panics_doc)]
293pub fn write_info_channel_group <W : std::io::Write> (
294  writer : &mut W,
295  group  : &fmod::ChannelGroup
296) -> Result <(), std::io::Error> {
297  let indent = indent_string();
298  writeln!(writer, "{indent}# fmod channel group info #")?;
299  writeln!(writer, "{}{:<40} {}", indent, "fmod channel group: name:",
300    group.get_name().unwrap())?;
301  writeln!(writer, "{}{:<40} {}", indent, "fmod channel group: is master:",
302    group.is_master().unwrap())?;
303  if let Ok (Some (parent_group)) = group.get_parent_group() {
304    writeln!(writer, "{}{:<40} {}", indent, "fmod channel group: parent group:",
305      parent_group.get_name().unwrap())?;
306  }
307  let num_groups = group.get_num_groups().unwrap();
308  writeln!(writer, "{}{:<40} {}", indent, "fmod channel group: num groups:",
309    num_groups)?;
310  /*
311  for i in 0..num_groups {
312    writeln!(writer, "{}fmod channel group: subgroup[{}]:", indent, i)?;
313    indent_bump (4);
314    write_info_channel_group (writer, &group.get_group (i).unwrap())?;
315    indent_unbump (4);
316  }
317  */
318  let num_channels = group.get_num_channels().unwrap();
319  writeln!(writer, "{}{:<40} {}", indent, "fmod channel group: num channels:",
320    num_channels)?;
321  for i in 0..num_channels {
322    writeln!(writer, "{indent}fmod channel group: channel[{i}]:")?;
323    indent_bump (4);
324    write_info_channel (writer, &group.get_channel (i).unwrap())?;
325    indent_unbump (4);
326  }
327  writeln!(writer, "{indent}fmod channelgroup: channel control:")?;
328  write_info_channel_control (writer, group)?;
329  Ok(())
330} // end fn write_info_channel_group
331
332//
333//  fn write_info_sound
334//
335#[expect(clippy::missing_panics_doc)]
336pub fn write_info_sound <W : std::io::Write> (
337  writer  : &mut W,
338  sound   : &fmod::Sound
339) -> Result <(), std::io::Error> {
340  let indent = indent_string();
341  writeln!(writer, "{indent}# fmod sound info #")?;
342  writeln!(writer, "{}{:<32} {}",   indent, "fmod sound: name:",
343    sound.get_name().unwrap())?;
344  writeln!(writer, "{}{:<32} {}",   indent, "fmod sound: length (ms):",
345    sound.get_length (fmod::Timeunit::MS).unwrap())?;
346  writeln!(writer, "{}{:<32} {:?}", indent, "fmod sound: format:",
347    sound.get_format().unwrap())?;
348  writeln!(writer, "{}{:<32} {}",   indent, "fmod sound: num sub sounds:",
349    sound.get_num_sub_sounds().unwrap())?;
350  // TODO: sub sounds
351  writeln!(writer, "{}{:<32} {:?}", indent, "fmod sound: num tags:",
352    sound.get_num_tags().unwrap())?;
353  // TODO: tags
354  writeln!(writer, "{}{:<32} {:?}", indent, "fmod sound: open state:",
355    sound.get_open_state().unwrap())?;
356  writeln!(writer, "{}{:<32} Mode({:b})", indent, "fmod sound: mode:",
357    sound.get_mode().unwrap())?;
358  writeln!(writer, "{}{:<32} {}",   indent, "fmod sound: loop count:",
359    sound.get_loop_count().unwrap())?;
360  let (loop_start, loop_end) =
361    sound.get_loop_points (fmod::Timeunit::MS, fmod::Timeunit::MS).unwrap();
362  writeln!(writer, "{}{:<32} (start: {}, end: {})", indent,
363    "fmod sound: loop points (ms):",
364    loop_start, loop_end)?;
365  // TODO: the following returns Err (Format):
366  /*
367  writeln!(writer,
368    "fmod sound: music speed:      {}", sound.get_music_speed().unwrap()
369  )?;
370  */
371  let (frequency, priority) = sound.get_defaults().unwrap();
372  writeln!(writer, "{indent}fmod sound: defaults:")?;
373  writeln!(writer, "{indent}    frequency:  {frequency}")?;
374  writeln!(writer, "{indent}    priority:   {priority}")?;
375  writeln!(writer, "{}{:<32} {}", indent, "fmod sound: num sync points:",
376    sound.get_num_sync_points().unwrap())?;
377  // TODO: sync point info
378  writeln!(writer, "{}{:<32} {:?}", indent, "fmod sound: 3d min max distance:",
379    sound.get_3d_min_max_distance().unwrap())?;
380  let (inside_cone_angle, outside_cone_angle, outside_volume)
381    = sound.get_3d_cone_settings().unwrap();
382  writeln!(writer, "{indent}fmod sound: 3d cone settings:")?;
383  writeln!(writer, "{indent}    inside cone angle:   {inside_cone_angle}")?;
384  writeln!(writer, "{indent}    outside cone angle:  {outside_cone_angle}")?;
385  writeln!(writer, "{indent}    outside volume:      {outside_volume}")?;
386  // TODO: 3d custom rolloffs ?
387  // TODO: memory info
388  Ok(())
389} // end fn write_info_sound
390
391//
392//  fn show_reverb_properties
393//
394pub fn show_reverb_properties (reverb_properties : &fmod::reverb3d::Properties)
395  -> String
396{
397  use std::fmt::Write;
398  let indent = indent_string();
399  let mut s = String::new();
400  writeln!(s, "{indent}ReverbProperties {{").unwrap();
401  writeln!(s, "{}    {:<22} {}", indent, "decay time:",
402    reverb_properties.decay_time).unwrap();
403  writeln!(s, "{}    {:<22} {}", indent, "early delay:",
404    reverb_properties.early_delay).unwrap();
405  writeln!(s, "{}    {:<22} {}", indent, "late delay:",
406    reverb_properties.late_delay).unwrap();
407  writeln!(s, "{}    {:<22} {}", indent, "hf reference:",
408    reverb_properties.hf_reference).unwrap();
409  writeln!(s, "{}    {:<22} {}", indent, "hf decay ratio:",
410    reverb_properties.hf_decay_ratio).unwrap();
411  writeln!(s, "{}    {:<22} {}", indent, "diffusion:",
412    reverb_properties.diffusion).unwrap();
413  writeln!(s, "{}    {:<22} {}", indent, "density:",
414    reverb_properties.density).unwrap();
415  writeln!(s, "{}    {:<22} {}", indent, "low shelf frequency:",
416    reverb_properties.low_shelf_frequency).unwrap();
417  writeln!(s, "{}    {:<22} {}", indent, "low shelf gain:",
418    reverb_properties.low_shelf_gain).unwrap();
419  writeln!(s, "{}    {:<22} {}", indent, "high cut:",
420    reverb_properties.high_cut).unwrap();
421  writeln!(s, "{}    {:<22} {}", indent, "early late mix:",
422    reverb_properties.early_late_mix).unwrap();
423  writeln!(s, "{}    {:<22} {}", indent, "wet level:",
424    reverb_properties.wet_level).unwrap();
425  writeln!(s, "{indent}}}").unwrap();
426  s
427} // end fn show_reverb_properties
428
429//
430//  private
431//
432fn indent_bump (spaces : u32) -> String {
433  INDENT.fetch_add (spaces, std::sync::atomic::Ordering::SeqCst);
434  indent_string()
435}
436
437fn indent_unbump (spaces : u32) -> String {
438  INDENT.fetch_sub (spaces, std::sync::atomic::Ordering::SeqCst);
439  indent_string()
440}
441
442fn indent_string () -> String {
443  use std::iter::FromIterator;
444  let indent = INDENT.load (std::sync::atomic::Ordering::SeqCst) as usize;
445  String::from_iter (std::iter::repeat_n (' ', indent))
446}
447
448fn _pretty_indent (d : &dyn std::fmt::Debug) -> String {
449  let indent = indent_string();
450  let s = format!("{d:#?}");
451  let mut lines = s.lines();
452  let first = lines.next().unwrap();
453  #[expect(clippy::format_collect)]
454  let mut rest : String = lines.map (|line| format!("{indent}{line}\n")).collect();
455  rest.pop().unwrap();
456  [first.to_string(), "\n".to_string(), rest].concat()
457}