From 761a3172bf4c15aed3836e4d1cd6f815b651b0e0 Mon Sep 17 00:00:00 2001 From: LLLL Colonq Date: Sat, 29 Aug 2026 04:06:51 -0400 Subject: Fix --- 2026/games_submissions/asrael_io/source/src/sfx.rs | 302 --------------------- 1 file changed, 302 deletions(-) delete mode 100644 2026/games_submissions/asrael_io/source/src/sfx.rs (limited to '2026/games_submissions/asrael_io/source/src/sfx.rs') diff --git a/2026/games_submissions/asrael_io/source/src/sfx.rs b/2026/games_submissions/asrael_io/source/src/sfx.rs deleted file mode 100644 index a1367df..0000000 --- a/2026/games_submissions/asrael_io/source/src/sfx.rs +++ /dev/null @@ -1,302 +0,0 @@ -use std::sync::mpsc::{Receiver, Sender, channel}; - -use cpal::traits::{DeviceTrait, HostTrait, StreamTrait}; -use cpal::{Device, OutputCallbackInfo, Stream, SupportedStreamConfig}; -use resid::{ChipModel, PAL_CLOCK, SamplingMethod, Sid}; - -const GATE: u8 = 0x01; -const TRIANGLE: u8 = 0x10; -const SAWTOOTH: u8 = 0x20; -const PULSE: u8 = 0x40; -const NOISE: u8 = 0x80; - -enum Sound { - EnemyShoot, - Explosion, - Hit, - Lose, - Shoot, - Win, -} - -struct Pending { - config: SupportedStreamConfig, - device: Device, - rx: Receiver, - sid: Sid, -} - -pub struct Sfx { - pending: Option, - stream: Option, - tx: Sender, -} - -impl Sfx { - pub fn new() -> Self { - let device = cpal::default_host() - .default_output_device() - .expect("no audio output device"); - - let config = device - .default_output_config() - .expect("no default audio config"); - - let mut sid = Sid::new(ChipModel::Mos6581); - let (tx, rx) = channel::(); - - sid.set_sampling_parameters(SamplingMethod::ResampleFast, PAL_CLOCK, config.sample_rate()); - Self::set_volume(&mut sid, 0x0F); - Self::set_envelope(&mut sid, 0, 0x06, 0x00); - Self::set_envelope(&mut sid, 1, 0x06, 0x00); - Self::set_envelope(&mut sid, 2, 0x08, 0xA9); - - Self { - pending: Some(Pending { - config, - device, - rx, - sid, - }), - stream: None, - tx, - } - } - - pub fn resume(&mut self) { - if let Some(stream) = &self.stream { - let _ = stream.play(); - return; - } - - let Some(Pending { - config, - device, - rx, - mut sid, - }) = self.pending.take() - else { - return; - }; - - let channels = config.channels() as usize; - let sample_rate = config.sample_rate(); - let mut scratch: Vec = Vec::new(); - - let mut enemy_shoot_hz: f32 = 0.0; - let mut explosion_hz: f32 = 0.0; - let mut hit_t: u32 = 0; - let mut lose_hz: f32 = 0.0; - let mut lose_t: u32 = 0; - let mut lose_wob: f32 = 0.0; - let mut shoot_hz: f32 = 0.0; - let mut win_t: u32 = 0; - - let stream = device - .build_output_stream( - config.into(), - move |data: &mut [f32], _: &OutputCallbackInfo| { - while let Ok(sound) = rx.try_recv() { - match sound { - Sound::EnemyShoot => { - enemy_shoot_hz = 520.0; - Self::set_freq(&mut sid, 1, enemy_shoot_hz); - Self::gate_on(&mut sid, 1, TRIANGLE); - } - - Sound::Explosion => { - hit_t = 0; - Self::set_envelope(&mut sid, 2, 0x08, 0xA9); - - explosion_hz = 2500.0; - Self::set_freq(&mut sid, 2, explosion_hz); - Self::gate_on(&mut sid, 2, NOISE); - } - - Sound::Hit => { - Self::set_envelope(&mut sid, 2, 0x05, 0x00); - - hit_t = 45; - Self::set_freq(&mut sid, 2, 2500.0); - Self::gate_on(&mut sid, 2, NOISE); - } - - Sound::Lose => { - enemy_shoot_hz = 0.0; - Self::set_envelope(&mut sid, 1, 0x00, 0xC6); - Self::set_pulse_width(&mut sid, 1, 0x0800); - - lose_hz = 392.0; - lose_t = 300; - lose_wob = 0.0; - Self::set_freq(&mut sid, 1, lose_hz); - Self::gate_on(&mut sid, 1, PULSE); - } - - Sound::Shoot => { - shoot_hz = 1760.0; - Self::set_freq(&mut sid, 0, shoot_hz); - Self::gate_on(&mut sid, 0, SAWTOOTH); - } - - Sound::Win => { - shoot_hz = 0.0; - Self::set_envelope(&mut sid, 0, 0x00, 0xA9); - Self::set_pulse_width(&mut sid, 0, 0x0800); - - win_t = 300; - Self::set_freq(&mut sid, 0, 987.77); - Self::gate_on(&mut sid, 0, PULSE); - } - } - } - - let frames = data.len() / channels; - if scratch.len() < frames { - scratch.resize(frames, 0); - } - let out = &mut scratch[..frames]; - - for block in out.chunks_mut(64) { - Self::sweep(&mut sid, &mut shoot_hz, 0.975, 220.0, 0, SAWTOOTH); - Self::sweep(&mut sid, &mut enemy_shoot_hz, 0.97, 200.0, 1, TRIANGLE); - Self::sweep(&mut sid, &mut explosion_hz, 0.985, 150.0, 2, NOISE); - - if hit_t > 0 { - hit_t -= 1; - if hit_t == 0 { - Self::gate_off(&mut sid, 2, NOISE); - } - } - - if win_t > 0 { - win_t -= 1; - - if win_t == 245 || win_t == 190 { - let hz = if win_t == 245 { 1318.5 } else { 1661.2 }; - Self::set_freq(&mut sid, 0, hz); - Self::gate_on(&mut sid, 0, PULSE); - } - - if win_t == 0 { - Self::gate_off(&mut sid, 0, PULSE); - } - } - - if lose_t > 0 { - lose_t -= 1; - lose_hz *= 0.995; - lose_wob += 0.35; - - let hz = lose_hz * (1.0 + 0.05 * lose_wob.sin()); - Self::set_freq(&mut sid, 1, hz); - - if lose_t == 0 { - Self::gate_off(&mut sid, 1, PULSE); - } - } - - Self::fill(&mut sid, block, sample_rate); - } - - for (frame, &s) in data.chunks_mut(channels).zip(out.iter()) { - frame.fill(s as f32 / 32768.0); - } - }, - move |err| log::error!("audio stream error: {err}"), - None, - ) - .expect("failed to build audio stream"); - - stream.play().expect("failed to start audio stream"); - self.stream = Some(stream); - } - - pub fn enemy_shoot(&self) { - let _ = self.tx.send(Sound::EnemyShoot); - } - - pub fn explode(&self) { - let _ = self.tx.send(Sound::Explosion); - } - - pub fn hit(&self) { - let _ = self.tx.send(Sound::Hit); - } - - pub fn lose(&self) { - let _ = self.tx.send(Sound::Lose); - } - - pub fn shoot(&self) { - let _ = self.tx.send(Sound::Shoot); - } - - pub fn win(&self) { - let _ = self.tx.send(Sound::Win); - } - - fn fill(sid: &mut Sid, out: &mut [i16], sample_rate: u32) { - let budget = PAL_CLOCK / sample_rate + 1; - let mut i = 0; - - while i < out.len() { - let target = (out.len() - i) as u32; - let (n, _) = sid.sample(target * budget, &mut out[i..], 1); - - if n == 0 { - break; - } - - i += n; - } - } - - fn gate_off(sid: &mut Sid, voice: u8, wave: u8) { - sid.write(voice * 7 + 4, wave); - } - - fn gate_on(sid: &mut Sid, voice: u8, wave: u8) { - sid.write(voice * 7 + 4, wave); - sid.write(voice * 7 + 4, wave | GATE); - } - - fn set_envelope(sid: &mut Sid, voice: u8, attack_decay: u8, sustain_release: u8) { - let base = voice * 7; - - sid.write(base + 5, attack_decay); - sid.write(base + 6, sustain_release); - } - - fn set_freq(sid: &mut Sid, voice: u8, hz: f32) { - let base = voice * 7; - let freq = (hz * 16_777_216.0 / PAL_CLOCK as f32) as u16; - - sid.write(base, freq as u8); - sid.write(base + 1, (freq >> 8) as u8); - } - - fn set_pulse_width(sid: &mut Sid, voice: u8, width: u16) { - let base = voice * 7; - - sid.write(base + 2, width as u8); - sid.write(base + 3, (width >> 8) as u8); - } - - fn set_volume(sid: &mut Sid, volume: u8) { - sid.write(0x18, volume); - } - - fn sweep(sid: &mut Sid, hz: &mut f32, rate: f32, floor: f32, voice: u8, wave: u8) { - if *hz > 0.0 { - *hz *= rate; - - if *hz < floor { - *hz = 0.0; - Self::gate_off(sid, voice, wave); - } else { - Self::set_freq(sid, voice, *hz); - } - } - } -} -- cgit v1.3.1