use ym2149::Ym2149Backend;
use ym2149_common::{ChiptunePlayer, ChiptunePlayerBase, MetadataFields, PlaybackState};
use ym2149_sndh_replayer::{SndhPlayer, load_sndh};
use crate::YM_SAMPLE_RATE_F32;
use crate::metadata::YmMetadata;
pub struct SndhWasmPlayer {
player: SndhPlayer,
}
impl SndhWasmPlayer {
pub fn new(data: &[u8]) -> Result<(Self, YmMetadata), String> {
let sample_rate = YM_SAMPLE_RATE_F32 as u32;
let mut player =
load_sndh(data, sample_rate).map_err(|e| format!("Failed to load SNDH: {e}"))?;
let default_subsong = player.default_subsong();
player
.init_subsong(default_subsong)
.map_err(|e| format!("Failed to init SNDH subsong: {e}"))?;
let metadata = metadata_from_player(&player);
Ok((Self { player }, metadata))
}
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_frame() as usize
}
pub fn frame_count(&self) -> usize {
self.player.total_frames() as usize
}
pub fn playback_position(&self) -> f32 {
self.player.progress()
}
pub fn seek_frame(&mut self, frame: usize) -> bool {
self.player.seek_to_frame(frame as u32).is_ok()
}
pub fn seek_percentage(&mut self, position: f32) -> bool {
ChiptunePlayerBase::seek(&mut self.player, position)
}
pub fn duration_seconds(&self) -> f32 {
ChiptunePlayerBase::duration_seconds(&self.player)
}
pub fn has_duration_info(&self) -> bool {
self.player.has_duration_info()
}
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 generate_samples_stereo(&mut self, frame_count: usize) -> Vec<f32> {
let mut buffer = vec![0.0f32; frame_count * 2];
self.player.render_f32_stereo(&mut buffer);
buffer
}
pub fn generate_samples_into_stereo(&mut self, buffer: &mut [f32]) {
self.player.render_f32_stereo(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.ym2149().dump_registers()
}
pub fn set_color_filter(&mut self, _enabled: bool) {
}
pub fn subsong_count(&self) -> usize {
self.player.subsong_count()
}
pub fn current_subsong(&self) -> usize {
self.player.current_subsong()
}
pub fn set_subsong(&mut self, index: usize) -> bool {
self.player.init_subsong(index).is_ok()
}
}
fn metadata_from_player(player: &SndhPlayer) -> YmMetadata {
let meta = ChiptunePlayer::metadata(player);
let frame_count = player.total_frames();
let frame_rate = meta.frame_rate();
let duration_seconds = if frame_count > 0 && frame_rate > 0 {
frame_count as f32 / frame_rate as f32
} else {
0.0
};
YmMetadata {
title: if meta.title().is_empty() {
"(unknown)".to_string()
} else {
meta.title().to_string()
},
author: if meta.author().is_empty() {
"(unknown)".to_string()
} else {
meta.author().to_string()
},
comments: meta.comments().to_string(),
format: "SNDH".to_string(),
frame_count,
frame_rate,
duration_seconds,
}
}