use crate::YM_SAMPLE_RATE_F32;
use crate::metadata::YmMetadata;
use ym2149::Ym2149Backend;
use ym2149_arkos_replayer::ArkosPlayer;
use ym2149_common::{ChiptunePlayerBase, PlaybackState};
pub struct ArkosWasmPlayer {
player: ArkosPlayer,
estimated_frames: usize,
duration_secs: f32,
}
impl ArkosWasmPlayer {
pub fn new(player: ArkosPlayer) -> (Self, YmMetadata) {
let samples_per_frame = (YM_SAMPLE_RATE_F32 / player.replay_frequency_hz())
.round()
.max(1.0) as u32;
let estimated_frames = player.estimated_total_ticks().max(1);
let duration_seconds =
(estimated_frames as f32 * samples_per_frame as f32) / YM_SAMPLE_RATE_F32;
let info = player.metadata().clone();
let frame_rate = player.replay_frequency_hz().round().max(1.0) as u32;
let metadata = YmMetadata {
title: info.title,
author: if info.author.is_empty() {
info.composer
} else {
info.author
},
comments: info.comments,
format: "AKS".to_string(),
frame_count: estimated_frames as u32,
frame_rate,
duration_seconds,
};
(
Self {
player,
estimated_frames,
duration_secs: duration_seconds,
},
metadata,
)
}
pub fn duration_seconds(&self) -> f32 {
self.duration_secs
}
pub fn play(&mut self) {
ChiptunePlayerBase::play(&mut self.player);
}
pub fn pause(&mut self) {
ChiptunePlayerBase::pause(&mut self.player);
}
pub fn stop(&mut self) {
ChiptunePlayerBase::stop(&mut self.player);
}
pub fn state(&self) -> PlaybackState {
ChiptunePlayerBase::state(&self.player)
}
pub fn frame_position(&self) -> usize {
self.player.current_tick_index()
}
pub fn frame_count(&self) -> usize {
self.estimated_frames
}
pub fn playback_position(&self) -> f32 {
ChiptunePlayerBase::playback_position(&self.player)
}
pub fn generate_samples(&mut self, count: usize) -> Vec<f32> {
ChiptunePlayerBase::generate_samples(&mut self.player, count)
}
pub fn generate_samples_into(&mut self, buffer: &mut [f32]) {
ChiptunePlayerBase::generate_samples_into(&mut self.player, buffer);
}
pub fn set_channel_mute(&mut self, channel: usize, mute: bool) {
ChiptunePlayerBase::set_channel_mute(&mut self.player, channel, mute);
}
pub fn is_channel_muted(&self, channel: usize) -> bool {
ChiptunePlayerBase::is_channel_muted(&self.player, channel)
}
pub fn dump_registers(&self) -> [u8; 16] {
self.player
.chip(0)
.map(|chip| chip.dump_registers())
.unwrap_or([0; 16])
}
pub fn set_color_filter(&mut self, enabled: bool) {
if let Some(chip) = self.player.chip_mut(0) {
chip.set_color_filter(enabled);
}
}
pub fn channel_count(&self) -> usize {
self.player.channel_count()
}
pub fn dump_all_registers(&self) -> Vec<[u8; 16]> {
(0..self.player.psg_count())
.filter_map(|i| self.player.chip(i).map(|c| c.dump_registers()))
.collect()
}
pub fn get_channel_outputs(&self) -> Vec<[f32; 3]> {
(0..self.player.psg_count())
.filter_map(|i| {
self.player.chip(i).map(|c| {
let (a, b, c) = c.get_channel_outputs();
[a, b, c]
})
})
.collect()
}
pub fn generate_samples_with_channels_into(&mut self, mono: &mut [f32], channels: &mut [f32]) {
let channel_count = self.player.channel_count();
let psg_count = self.player.psg_count();
let mut sample_buf = [0.0f32; 1];
for (i, mono_sample) in mono.iter_mut().enumerate() {
ChiptunePlayerBase::generate_samples_into(&mut self.player, &mut sample_buf);
*mono_sample = sample_buf[0];
let base = i * channel_count;
for psg_idx in 0..psg_count {
if let Some(chip) = self.player.chip(psg_idx) {
let (a, b, c) = chip.get_channel_outputs();
let offset = base + psg_idx * 3;
channels[offset] = a;
channels[offset + 1] = b;
channels[offset + 2] = c;
}
}
}
}
}