use ym2149_common::visualization::{
MAX_CHANNEL_COUNT, MAX_PSG_COUNT, SPECTRUM_BINS, SpectrumAnalyzer, WaveformSynthesizer,
};
const VELOCITY_SMOOTHING: f32 = 0.7;
pub struct CaptureBuffer {
waveform: WaveformSynthesizer,
spectrum: SpectrumAnalyzer,
psg_count: usize,
sid_active: [bool; MAX_CHANNEL_COUNT],
drum_active: [bool; MAX_CHANNEL_COUNT],
buzz_active: [bool; MAX_CHANNEL_COUNT],
prev_spectrum: [[f32; SPECTRUM_BINS]; MAX_CHANNEL_COUNT],
spectrum_velocity: [[f32; SPECTRUM_BINS]; MAX_CHANNEL_COUNT],
}
impl CaptureBuffer {
pub fn new() -> Self {
Self {
waveform: WaveformSynthesizer::new(),
spectrum: SpectrumAnalyzer::new(),
psg_count: 1,
sid_active: [false; MAX_CHANNEL_COUNT],
drum_active: [false; MAX_CHANNEL_COUNT],
buzz_active: [false; MAX_CHANNEL_COUNT],
prev_spectrum: [[0.0; SPECTRUM_BINS]; MAX_CHANNEL_COUNT],
spectrum_velocity: [[0.0; SPECTRUM_BINS]; MAX_CHANNEL_COUNT],
}
}
pub fn update_from_registers(
&mut self,
register_banks: &[[u8; 16]],
psg_count: usize,
sid_active: &[bool; MAX_CHANNEL_COUNT],
drum_active: &[bool; MAX_CHANNEL_COUNT],
) {
let count = psg_count.clamp(1, MAX_PSG_COUNT);
self.psg_count = count;
self.sid_active = *sid_active;
self.drum_active = *drum_active;
self.buzz_active = [false; MAX_CHANNEL_COUNT];
for (psg_idx, regs) in register_banks.iter().enumerate().take(count) {
for ch in 0..3 {
let global_ch = psg_idx * 3 + ch;
let amp_reg = regs[8 + ch];
let envelope_enabled = (amp_reg & 0x10) != 0;
self.buzz_active[global_ch] = envelope_enabled;
}
}
self.waveform.update_multi_psg(register_banks, count);
self.spectrum.update_multi_psg(register_banks, count);
let channel_count = count * 3;
for ch in 0..channel_count {
let current = self.spectrum.channel_spectrum(ch);
for (bin, &cur_val) in current.iter().enumerate() {
let delta = (cur_val - self.prev_spectrum[ch][bin]).abs();
self.spectrum_velocity[ch][bin] = VELOCITY_SMOOTHING
* self.spectrum_velocity[ch][bin]
+ (1.0 - VELOCITY_SMOOTHING) * delta * 3.0; self.prev_spectrum[ch][bin] = cur_val;
}
}
}
pub fn waveform(&self, channel: usize) -> &std::collections::VecDeque<f32> {
self.waveform.channel_waveform(channel)
}
pub fn spectrum_channel(&self, channel: usize) -> &[f32; SPECTRUM_BINS] {
self.spectrum.channel_spectrum(channel)
}
pub fn channel_count(&self) -> usize {
self.psg_count * 3
}
pub fn is_sid_active(&self, channel: usize) -> bool {
self.sid_active.get(channel).copied().unwrap_or(false)
}
pub fn is_drum_active(&self, channel: usize) -> bool {
self.drum_active.get(channel).copied().unwrap_or(false)
}
pub fn is_buzz_active(&self, channel: usize) -> bool {
self.buzz_active.get(channel).copied().unwrap_or(false)
}
pub fn spectrum_velocity(&self, channel: usize, bin: usize) -> f32 {
self.spectrum_velocity
.get(channel)
.and_then(|ch| ch.get(bin))
.copied()
.unwrap_or(0.0)
.clamp(0.0, 1.0)
}
pub fn mono_output(&self) -> std::collections::VecDeque<f32> {
let channel_count = self.channel_count();
if channel_count == 0 {
return std::collections::VecDeque::new();
}
let len = (0..channel_count)
.map(|ch| self.waveform.channel_waveform(ch).len())
.min()
.unwrap_or(0);
if len == 0 {
return std::collections::VecDeque::new();
}
let mut mono = std::collections::VecDeque::with_capacity(len);
for i in 0..len {
let sum: f32 = (0..channel_count)
.map(|ch| {
self.waveform
.channel_waveform(ch)
.get(i)
.copied()
.unwrap_or(0.0)
})
.sum();
mono.push_back(sum / channel_count as f32);
}
mono
}
}
impl Default for CaptureBuffer {
fn default() -> Self {
Self::new()
}
}