ym2149_common/
util.rs

1//! Shared helper utilities for YM2149 register math.
2//!
3//! These functions are used by downstream crates (CLI, Bevy plugin, visualization)
4//! to derive channel periods and frequencies in a consistent way.
5
6use crate::PSG_MASTER_CLOCK_HZ as PSG_CLOCK_U32;
7
8/// Default YM2149 master clock frequency (as f32 for calculations).
9const PSG_MASTER_CLOCK_F32: f32 = PSG_CLOCK_U32 as f32;
10
11const PERIOD_DENOMINATOR: f32 = 16.0;
12
13/// Compute the 12-bit tone period from register low/high bytes.
14#[inline]
15#[must_use]
16pub fn channel_period(lo: u8, hi: u8) -> Option<u16> {
17    let period = (((hi as u16) & 0x0F) << 8) | (lo as u16);
18    if period == 0 { None } else { Some(period) }
19}
20
21/// Convert a tone period into a frequency using the default 2MHz master clock.
22#[inline]
23#[must_use]
24pub fn period_to_frequency(period: u16) -> f32 {
25    period_to_frequency_with_clock(PSG_MASTER_CLOCK_F32, period)
26}
27
28/// Convert a tone period into a frequency for a specific master clock.
29#[inline]
30#[must_use]
31pub fn period_to_frequency_with_clock(master_clock_hz: f32, period: u16) -> f32 {
32    if period == 0 {
33        0.0
34    } else {
35        master_clock_hz / (PERIOD_DENOMINATOR * period as f32)
36    }
37}
38
39/// Convenience helper returning the three channel frequencies for the default clock.
40#[inline]
41#[must_use]
42pub fn channel_frequencies(registers: &[u8; 16]) -> [Option<f32>; 3] {
43    channel_frequencies_with_clock(registers, PSG_MASTER_CLOCK_F32)
44}
45
46/// Compute the frequency of each channel for a given master clock.
47#[inline]
48#[must_use]
49pub fn channel_frequencies_with_clock(
50    registers: &[u8; 16],
51    master_clock_hz: f32,
52) -> [Option<f32>; 3] {
53    [
54        channel_period(registers[0], registers[1])
55            .map(|period| period_to_frequency_with_clock(master_clock_hz, period)),
56        channel_period(registers[2], registers[3])
57            .map(|period| period_to_frequency_with_clock(master_clock_hz, period)),
58        channel_period(registers[4], registers[5])
59            .map(|period| period_to_frequency_with_clock(master_clock_hz, period)),
60    ]
61}