1//! SNES S-DSP, responsible for audio playback 2 3mod interpolate; 4mod tables; 5 6use crate::apu::AudioRam; 7use crate::apu::dsp::interpolate::InterpolateArgs; 8use bincode::{Decode, Encode}; 9use jgenesis_common::num::{GetBit, U16Ext}; 10use snes_config::AudioInterpolationMode; 11use std::array; 12use std::ops::Index; 13 14const BRR_BLOCK_LEN: u16 = 9; 15 16#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 17enum EnvelopeMode { 18 Adsr, 19 #[default] 20 Gain, 21} 22 23impl EnvelopeMode { 24 fn from_bit(bit: bool) -> Self { 25 if bit { Self::Adsr } else { Self::Gain } 26 } 27 28 fn to_bit(self) -> bool { 29 self == Self::Adsr 30 } 31} 32 33#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 34enum GainMode { 35 #[default] 36 Direct, 37 Custom, 38} 39 40impl GainMode { 41 fn from_bit(bit: bool) -> Self { 42 if bit { Self::Custom } else { Self::Direct } 43 } 44 45 fn to_bit(self) -> bool { 46 self == Self::Custom 47 } 48} 49 50#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Encode, Decode)] 51enum EnvelopePhase { 52 Attack, 53 Decay, 54 Sustain, 55 #[default] 56 Release, 57} 58 59const BRR_BUFFER_LEN: usize = 12; 60 61#[derive(Debug, Clone, Default, Encode, Decode)] 62struct BrrRingBuffer { 63 buffer: [i16; BRR_BUFFER_LEN], 64 fill_idx: usize, 65 sample_idx: usize, 66} 67 68impl BrrRingBuffer { 69 fn reset(&mut self) { 70 self.fill_idx = 0; 71 self.sample_idx = 0; 72 } 73 74 fn write(&mut self, sample: i16) { 75 self.buffer[self.fill_idx] = sample; 76 self.fill_idx = (self.fill_idx + 1) % BRR_BUFFER_LEN; 77 } 78 79 fn shift_sample_idx(&mut self) { 80 self.sample_idx = (self.sample_idx + 4) % BRR_BUFFER_LEN; 81 } 82 83 fn last_two_written_samples(&self) -> (i16, i16) { 84 if self.fill_idx == 0 { 85 (self.buffer[BRR_BUFFER_LEN - 2], self.buffer[BRR_BUFFER_LEN - 1]) 86 } else if self.fill_idx == 1 { 87 (self.buffer[BRR_BUFFER_LEN - 1], self.buffer[0]) 88 } else { 89 (self.buffer[self.fill_idx - 2], self.buffer[self.fill_idx - 1]) 90 } 91 } 92} 93 94impl Index<u16> for BrrRingBuffer { 95 type Output = i16; 96 97 fn index(&self, index: u16) -> &Self::Output { 98 let buffer_idx = (self.sample_idx + index as usize) % BRR_BUFFER_LEN; 99 &self.buffer[buffer_idx] 100 } 101} 102 103#[derive(Debug, Clone, Encode, Decode)] 104struct Voice { 105 audio_interpolation: AudioInterpolationMode, 106 // Registers 107 instrument_number: u8, 108 sample_rate: u16, 109 pitch_modulation_enabled: bool, 110 envelope_mode: EnvelopeMode, 111 attack_rate: u8, 112 decay_rate: u8, 113 sustain_rate: u8, 114 sustain_level: u8, 115 gain_mode: GainMode, 116 // Meaning of gain value varies based on gain mode 117 gain_value: u8, 118 volume_l: i8, 119 volume_r: i8, 120 keyed_on: bool, 121 keyed_off: bool, 122 output_noise: bool, 123 // Stored in full here to preserve the highest 2 bits which are R/W 124 last_pitch_h_write: u8, 125 // State 126 brr_block_address: u16, 127 brr_buffer: BrrRingBuffer, 128 brr_decoder_idx: u16, 129 pitch_counter: u16, 130 envelope_level: u16, 131 clipped_envelope_value: u16, 132 envelope_phase: EnvelopePhase, 133 current_sample: i16, 134 restart_pending: bool, 135 restart_delay_remaining: u8, 136 end_flag_seen: bool, 137} 138 139impl Voice { 140 fn new(audio_interpolation: AudioInterpolationMode) -> Self { 141 Self { 142 audio_interpolation, 143 instrument_number: 0, 144 sample_rate: 0, 145 pitch_modulation_enabled: false, 146 envelope_mode: EnvelopeMode::default(), 147 attack_rate: 0, 148 decay_rate: 0, 149 sustain_rate: 0, 150 sustain_level: 0, 151 gain_mode: GainMode::default(), 152 gain_value: 0, 153 volume_l: 0, 154 volume_r: 0, 155 keyed_on: false, 156 keyed_off: false, 157 output_noise: false, 158 last_pitch_h_write: 0, 159 brr_block_address: 0, 160 brr_buffer: BrrRingBuffer::default(), 161 brr_decoder_idx: 0, 162 pitch_counter: 0, 163 envelope_level: 0, 164 clipped_envelope_value: 0, 165 envelope_phase: EnvelopePhase::default(), 166 current_sample: 0, 167 restart_pending: false, 168 restart_delay_remaining: 0, 169 end_flag_seen: false, 170 } 171 } 172 173 fn write_pitch_low(&mut self, value: u8) { 174 self.sample_rate.set_lsb(value); 175 } 176 177 fn write_pitch_high(&mut self, value: u8) { 178 // Sample rate is 14 bits; drop the highest 2 179 self.sample_rate.set_msb(value & 0x3F); 180 181 // Preserve original value for register reads 182 self.last_pitch_h_write = value; 183 } 184 185 fn write_adsr_low(&mut self, value: u8) { 186 // 4-bit attack rate, 3-bit decay rate, and ADSR/Gain select bit 187 self.attack_rate = value & 0x0F; 188 self.decay_rate = (value >> 4) & 0x07; 189 self.envelope_mode = EnvelopeMode::from_bit(value.bit(7)); 190 191 log::trace!( 192 " Attack rate: {:02X}, Decay rate: {:02X}, Envelope Mode: {:?}", 193 self.attack_rate, 194 self.decay_rate, 195 self.envelope_mode 196 ); 197 } 198 199 fn read_adsr_low(&self) -> u8 { 200 self.attack_rate | (self.decay_rate << 4) | (u8::from(self.envelope_mode.to_bit()) << 7) 201 } 202 203 fn write_adsr_high(&mut self, value: u8) { 204 // 5-bit sustain rate, 3-bit sustain level 205 self.sustain_rate = value & 0x1F; 206 self.sustain_level = value >> 5; 207 208 log::trace!( 209 " Sustain rate: {:02X}, Sustain level: {:02X}", 210 self.sustain_rate, 211 self.sustain_level 212 ); 213 } 214 215 fn read_adsr_high(&self) -> u8 { 216 self.sustain_rate | (self.sustain_level << 5) 217 } 218 219 fn write_gain(&mut self, value: u8) { 220 self.gain_mode = GainMode::from_bit(value.bit(7)); 221 self.gain_value = value & 0x7F; 222 223 log::trace!(" Gain mode: {:?}, Gain value: {:02X}", self.gain_mode, self.gain_value); 224 } 225 226 fn read_gain(&self) -> u8 { 227 self.gain_value | (u8::from(self.gain_mode.to_bit()) << 7) 228 } 229 230 fn read_envelope(&self) -> u8 { 231 // VxENVX reads return the highest 7 bits of the 11-bit envelope value 232 (self.envelope_level >> 4) as u8 233 } 234 235 fn read_output(&self) -> u8 { 236 // VxOUTX reads return the highest 8 bits of the 15-bit sample value (pre-volume) 237 (self.current_sample >> 7) as u8 238 } 239 240 fn write_key_on(&mut self, key_on: bool) { 241 self.keyed_on = key_on; 242 243 // Keying on immediately moves envelope to attack, resets envelope value, and restarts the channel 244 if key_on { 245 self.envelope_phase = EnvelopePhase::Attack; 246 self.envelope_level = 0; 247 self.restart_pending = true; 248 } 249 } 250 251 fn write_key_off(&mut self, key_off: bool) { 252 self.keyed_off = key_off; 253 254 // Keying off immediately moves envelope to release (but does not modify envelope value or other state) 255 if key_off { 256 self.envelope_phase = EnvelopePhase::Release; 257 } 258 } 259 260 fn soft_reset(&mut self) { 261 // Soft reset keys off the voice and immediately sets envelope to 0 262 self.write_key_off(true); 263 self.envelope_level = 0; 264 } 265 266 fn clock( 267 &mut self, 268 registers: &DspRegisters, 269 audio_ram: &AudioRam, 270 prev_voice_sample: i16, 271 noise_generator_output: i16, 272 ) { 273 if self.restart_pending { 274 self.restart_pending = false; 275 self.restart(registers, audio_ram); 276 } 277 278 if self.restart_delay_remaining != 0 { 279 // Output empty sample 280 self.current_sample = 0; 281 282 // After 2 clocks, prevent the channel from starting if key off or soft reset is set 283 if self.restart_delay_remaining <= 3 && (self.keyed_off || registers.soft_reset) { 284 self.envelope_phase = EnvelopePhase::Release; 285 } 286 287 self.restart_delay_remaining -= 1; 288 if self.restart_delay_remaining == 0 { 289 // Reset BRR decoder state and decode the first 2 groups 290 // Actual hardware decodes 3 groups here, but decoding 2 simplifies the ring buffer handling 291 self.brr_buffer.reset(); 292 self.brr_decoder_idx = 0; 293 294 for _ in 0..2 { 295 self.decode_brr_group(registers.sample_table_address, audio_ram); 296 } 297 } 298 299 return; 300 } 301 302 let interpolated_sample = if self.output_noise { 303 // Turning on noise for a voice replaces the output with the noise generator output, 304 // but envelope is still used and all of the BRR decoding continues to run in the 305 // background 306 noise_generator_output 307 } else { 308 // Bits 12-15 of pitch counter are used as the sample index 309 let sample_idx = self.pitch_counter >> 12; 310 let args = InterpolateArgs { 311 pitch_counter: self.pitch_counter, 312 oldest: self.brr_buffer[sample_idx], 313 older: self.brr_buffer[sample_idx + 1], 314 old: self.brr_buffer[sample_idx + 2], 315 sample: self.brr_buffer[sample_idx + 3], 316 }; 317 318 match self.audio_interpolation { 319 AudioInterpolationMode::Gaussian => interpolate::gaussian(args), 320 AudioInterpolationMode::Hermite => interpolate::hermite(args), 321 } 322 }; 323 324 // TODO do this after multiplying by sample? 325 self.clock_envelope(registers.global_counter); 326 327 // Apply 11-bit envelope; still a signed 15-bit sample 328 let sample = 329 ((i32::from(interpolated_sample) * i32::from(self.envelope_level)) >> 11) as i16; 330 self.current_sample = sample; 331 332 self.pitch_counter += self.sample_rate; 333 if self.pitch_modulation_enabled && !self.output_noise { 334 // Adjust pitch based on previous voice's output 335 let modulation_rate = 336 ((i32::from(prev_voice_sample) >> 5) * i32::from(self.sample_rate)) >> 10; 337 self.pitch_counter = 338 self.pitch_counter.wrapping_add_signed(modulation_rate as i16).clamp(0, 0x7FFF); 339 } 340 341 if self.pitch_counter >= 0x4000 { 342 self.pitch_counter -= 0x4000; 343 self.decode_brr_group(registers.sample_table_address, audio_ram); 344 self.brr_buffer.shift_sample_idx(); 345 } 346 } 347 348 fn restart(&mut self, registers: &DspRegisters, audio_ram: &AudioRam) { 349 // Table address is located at DIR + 4*instrument 350 let table_addr = registers 351 .sample_table_address 352 .wrapping_add(u16::from(self.instrument_number) << 2) as usize; 353 354 // First 2 bytes of table entry hold start address 355 let start_addr = u16::from_le_bytes([audio_ram[table_addr], audio_ram[table_addr + 1]]); 356 self.brr_block_address = start_addr; 357 self.pitch_counter = 0; 358 359 // Each voice outputs 5 empty samples after a restart 360 self.restart_delay_remaining = 5; 361 362 self.end_flag_seen = false; 363 } 364 365 // Decode a group of 4 BRR samples, advancing to the next BRR block or looping if necessary 366 fn decode_brr_group(&mut self, sample_table_address: u16, audio_ram: &AudioRam) { 367 if self.brr_decoder_idx == 16 { 368 // Advance to next block 369 let prev_block_header = audio_ram[self.brr_block_address as usize]; 370 let prev_block_end_flag = prev_block_header.bit(0); 371 if prev_block_end_flag { 372 self.end_flag_seen = true; 373 374 // Jump to loop address 375 let table_addr = sample_table_address 376 .wrapping_add(u16::from(self.instrument_number) << 2) 377 as usize; 378 let loop_addr = 379 u16::from_le_bytes([audio_ram[table_addr + 2], audio_ram[table_addr + 3]]); 380 self.brr_block_address = loop_addr; 381 } else { 382 self.brr_block_address = self.brr_block_address.wrapping_add(BRR_BLOCK_LEN); 383 } 384 385 self.brr_decoder_idx = 0; 386 } 387 388 let header = audio_ram[self.brr_block_address as usize]; 389 let shift = header >> 4; 390 let filter = (header >> 2) & 0x03; 391 let loop_flag = header.bit(1); 392 let end_flag = header.bit(0); 393 394 // Immediately mute channel after decoding a header with end set and loop clear 395 if end_flag && !loop_flag { 396 self.envelope_phase = EnvelopePhase::Release; 397 self.envelope_level = 0; 398 } 399 400 let mut brr_nibbles = [0_i8; 4]; 401 let decoder_idx = self.brr_decoder_idx; 402 for i in 0..2 { 403 let sample_addr = self.brr_block_address.wrapping_add(1 + (decoder_idx >> 1) + i); 404 let sample_pair = audio_ram[sample_addr as usize]; 405 406 // High nibble stores the first sample, low nibble stores the second sample 407 // Treat both as signed 4-bit integers 408 let first_sample = (sample_pair as i8) >> 4; 409 let second_sample = ((sample_pair as i8) << 4) >> 4; 410 brr_nibbles[(2 * i) as usize] = first_sample; 411 brr_nibbles[(2 * i + 1) as usize] = second_sample; 412 } 413 self.brr_decoder_idx += 4; 414 415 let (mut older_sample, mut old_sample) = self.brr_buffer.last_two_written_samples(); 416 for brr_nibble in brr_nibbles { 417 let shifted = apply_brr_shift(brr_nibble, shift); 418 let brr_sample = apply_brr_filter(shifted, filter, old_sample, older_sample); 419 self.brr_buffer.write(brr_sample); 420 421 older_sample = old_sample; 422 old_sample = brr_sample; 423 } 424 } 425 426 fn clock_envelope(&mut self, global_counter: u16) { 427 if self.envelope_phase == EnvelopePhase::Release { 428 // Release ignores other settings and decrements envelope value by 8 every sample 429 self.envelope_level = self.envelope_level.saturating_sub(8); 430 self.clipped_envelope_value = self.envelope_level.wrapping_sub(8) & 0x7FF; 431 return; 432 } 433 434 // ADSR transitions are checked every sample, even if envelope is in Gain mode 435 if self.envelope_phase == EnvelopePhase::Attack && self.envelope_level >= 0x7E0 { 436 self.envelope_phase = EnvelopePhase::Decay; 437 } 438 439 if self.envelope_phase == EnvelopePhase::Decay { 440 let sustain_level = u16::from(self.sustain_level + 1) << 8; 441 if self.envelope_level <= sustain_level { 442 self.envelope_phase = EnvelopePhase::Sustain; 443 } 444 } 445 446 let current_value: i32 = self.envelope_level.into(); 447 let (rate, step) = match (self.envelope_mode, self.gain_mode) { 448 (EnvelopeMode::Gain, GainMode::Direct) => { 449 // Force envelope level to 16*N 450 let target_value = i32::from(self.gain_value) << 4; 451 if current_value == target_value { 452 (0, 0) 453 } else { 454 (31, target_value - current_value) 455 } 456 } 457 (EnvelopeMode::Gain, GainMode::Custom) => { 458 let rate = self.gain_value & 0x1F; 459 let step = match self.gain_value & 0x60 { 460 0x00 => { 461 // Linear decrease (fixed decrement by 32) 462 -32 463 } 464 0x20 => { 465 // Exponential decrease 466 compute_exp_decay(current_value) 467 } 468 0x40 => { 469 // Linear increase (fixed increment by 32) 470 32 471 } 472 0x60 => { 473 // Bent increase (uses clipped value rather than clamped value) 474 if self.clipped_envelope_value < 0x600 { 32 } else { 8 } 475 } 476 _ => unreachable!("value & 0x60 is always one of the above values"), 477 }; 478 479 (rate, step) 480 } 481 (EnvelopeMode::Adsr, _) => match self.envelope_phase { 482 EnvelopePhase::Attack => { 483 let rate = (self.attack_rate << 1) | 0x01; 484 let step = if rate == 31 { 1024 } else { 32 }; 485 (rate, step) 486 } 487 EnvelopePhase::Decay => { 488 let rate = 0x10 | (self.decay_rate << 1); 489 let step = compute_exp_decay(current_value); 490 (rate, step) 491 } 492 EnvelopePhase::Sustain => { 493 let step = compute_exp_decay(current_value); 494 (self.sustain_rate, step) 495 } 496 EnvelopePhase::Release => (31, -8), 497 }, 498 }; 499 500 if rate != 0 501 && (global_counter + tables::ENVELOPE_OFFSET[rate as usize]) 502 .is_multiple_of(tables::ENVELOPE_RATE[rate as usize]) 503 { 504 let new_value = current_value + step; 505 self.envelope_level = new_value.clamp(0, 0x7FF) as u16; 506 self.clipped_envelope_value = (new_value as u16) & 0x7FF; 507 } 508 } 509} 510 511fn apply_brr_shift(nibble: i8, shift: u8) -> i16 { 512 match shift { 513 0 => (nibble >> 1).into(), 514 1..=12 => i16::from(nibble) << (shift - 1), 515 13..=15 => { 516 // "Invalid" shift values; resulting sample will always be either 0 or -2048 ($F800) 517 if nibble < 0 { -2048 } else { 0 } 518 } 519 _ => panic!("invalid BRR shift value: {shift}"), 520 } 521} 522 523fn apply_brr_filter(sample: i16, filter: u8, old: i16, older: i16) -> i16 { 524 // Do math in 32 bits to avoid overflows 525 let sample: i32 = sample.into(); 526 let old: i32 = old.into(); 527 let older: i32 = older.into(); 528 529 let filtered = match filter { 530 // no filter 531 0 => sample, 532 // sample + 0.9375 * old 533 1 => sample + old + (-old >> 4), 534 // sample + 1.90625 * old - 0.9375 * older 535 2 => sample + (old << 1) + (-(3 * old) >> 5) - older + (older >> 4), 536 // sample + 1.796875 * old - 0.8125 * older 537 3 => sample + (old << 1) + (-(13 * old) >> 6) - older + ((3 * older) >> 4), 538 _ => panic!("invalid BRR filter value: {filter}"), 539 }; 540 541 // Clamp to 16 bits 542 let clamped = filtered.clamp(i16::MIN.into(), i16::MAX.into()) as i16; 543 544 // Clip to 15 bits 545 (clamped << 1) >> 1 546} 547 548fn compute_exp_decay(current_value: i32) -> i32 { 549 -(((current_value - 1) >> 8) + 1) 550} 551 552#[derive(Debug, Clone, Encode, Decode)] 553struct NoiseGenerator { 554 output: i16, 555} 556 557impl NoiseGenerator { 558 fn new() -> Self { 559 Self { output: i16::MIN >> 1 } 560 } 561 562 fn clock(&mut self, noise_frequency: u8, global_counter: u16) { 563 // Noise generator uses the same rate/offset tables as the envelopes 564 let rate = noise_frequency as usize; 565 if rate != 0 566 && (global_counter + tables::ENVELOPE_OFFSET[rate]) 567 .is_multiple_of(tables::ENVELOPE_RATE[rate]) 568 { 569 let new_bit = self.output.bit(0) ^ self.output.bit(1); 570 self.output = ((self.output >> 1) & 0x3FFF) | (i16::from(new_bit) << 14); 571 572 // Clip to 15 bits 573 self.output = (self.output << 1) >> 1; 574 } 575 } 576} 577 578#[derive(Debug, Clone, Encode, Decode)] 579struct EchoFilter { 580 echo_enabled: [bool; 8], 581 buffer_start_address: u16, 582 buffer_current_offset: u16, 583 buffer_samples_remaining: u16, 584 buffer_size_samples: u16, 585 volume_l: i8, 586 volume_r: i8, 587 feedback_volume: i8, 588 fir_coefficients: [i8; 8], 589 sample_buffer_l: [i16; 8], 590 sample_buffer_r: [i16; 8], 591 sample_buffer_idx: usize, 592 // Stored because the highest 4 bits are unused R/W 593 last_edl_write: u8, 594} 595 596impl EchoFilter { 597 fn new() -> Self { 598 Self { 599 echo_enabled: [false; 8], 600 buffer_start_address: 0, 601 buffer_current_offset: 0, 602 buffer_samples_remaining: 1, 603 buffer_size_samples: 1, 604 volume_l: 0, 605 volume_r: 0, 606 feedback_volume: 0, 607 fir_coefficients: [0; 8], 608 sample_buffer_l: [0; 8], 609 sample_buffer_r: [0; 8], 610 sample_buffer_idx: 0, 611 last_edl_write: 0, 612 } 613 } 614 615 fn write_echo_enabled(&mut self, eon: u8) { 616 for i in 0..8 { 617 self.echo_enabled[i] = eon.bit(i as u8); 618 } 619 } 620 621 fn read_echo_enabled(&self) -> u8 { 622 (0..8).map(|i| u8::from(self.echo_enabled[i]) << i).reduce(|a, b| a | b).unwrap() 623 } 624 625 fn write_echo_buffer_size(&mut self, edl: u8) { 626 self.buffer_size_samples = match edl & 0x0F { 627 0 => 1, 628 edl => u16::from(edl) << 9, 629 }; 630 631 self.last_edl_write = edl; 632 } 633 634 fn do_filter( 635 &mut self, 636 echo_buffer_writes_enabled: bool, 637 audio_ram: &mut AudioRam, 638 voice_samples_l: &[i32; 8], 639 voice_samples_r: &[i32; 8], 640 ) -> (i32, i32) { 641 let current_buffer_addr = 642 self.buffer_start_address.wrapping_add(self.buffer_current_offset); 643 self.sample_buffer_l[self.sample_buffer_idx] = 644 read_echo_sample(audio_ram, current_buffer_addr); 645 self.sample_buffer_r[self.sample_buffer_idx] = 646 read_echo_sample(audio_ram, current_buffer_addr.wrapping_add(2)); 647 648 // Add the 7 older samples with 16-bit wrapping behavior 649 let mut fir_sample_l: i32 = 0; 650 let mut fir_sample_r: i32 = 0; 651 for i in 0..7 { 652 let coefficient: i32 = self.fir_coefficients[i].into(); 653 654 let buffer_idx = self.sample_buffer_idx.wrapping_add(i + 1) & 0x07; 655 let sample_l: i32 = self.sample_buffer_l[buffer_idx].into(); 656 let sample_r: i32 = self.sample_buffer_r[buffer_idx].into(); 657 658 fir_sample_l += (coefficient * sample_l) >> 6; 659 fir_sample_r += (coefficient * sample_r) >> 6; 660 } 661 662 // Clip to 16 bits before adding the newest sample 663 fir_sample_l = (fir_sample_l as i16).into(); 664 fir_sample_r = (fir_sample_r as i16).into(); 665 666 // Add in the newest sample and clamp to 16 bits 667 fir_sample_l += (i32::from(self.fir_coefficients[7]) 668 * i32::from(self.sample_buffer_l[self.sample_buffer_idx])) 669 >> 6; 670 fir_sample_r += (i32::from(self.fir_coefficients[7]) 671 * i32::from(self.sample_buffer_r[self.sample_buffer_idx])) 672 >> 6; 673 674 let mut fir_sample_l = fir_sample_l.clamp(i16::MIN.into(), i16::MAX.into()); 675 let mut fir_sample_r = fir_sample_r.clamp(i16::MIN.into(), i16::MAX.into()); 676 677 // Force the lowest bit clear in FIR sample 678 fir_sample_l &= !1; 679 fir_sample_r &= !1; 680 681 if echo_buffer_writes_enabled { 682 self.write_to_echo_buffer( 683 audio_ram, 684 voice_samples_l, 685 voice_samples_r, 686 fir_sample_l, 687 fir_sample_r, 688 ); 689 } 690 691 self.sample_buffer_idx = (self.sample_buffer_idx + 1) & 0x07; 692 693 self.buffer_samples_remaining -= 1; 694 if self.buffer_samples_remaining == 0 { 695 self.buffer_current_offset = 0; 696 self.buffer_samples_remaining = self.buffer_size_samples; 697 } else { 698 self.buffer_current_offset = self.buffer_current_offset.wrapping_add(4); 699 } 700 701 let echo_out_l = (fir_sample_l * i32::from(self.volume_l)) >> 7; 702 let echo_out_r = (fir_sample_r * i32::from(self.volume_r)) >> 7; 703 704 (echo_out_l, echo_out_r) 705 } 706 707 fn write_to_echo_buffer( 708 &self, 709 audio_ram: &mut AudioRam, 710 voice_samples_l: &[i32; 8], 711 voice_samples_r: &[i32; 8], 712 fir_sample_l: i32, 713 fir_sample_r: i32, 714 ) { 715 let mut echo_voice_sum_l: i32 = 0; 716 let mut echo_voice_sum_r: i32 = 0; 717 for i in (0..8).filter(|&i| self.echo_enabled[i]) { 718 echo_voice_sum_l += voice_samples_l[i]; 719 echo_voice_sum_r += voice_samples_r[i]; 720 721 echo_voice_sum_l = echo_voice_sum_l.clamp(i16::MIN.into(), i16::MAX.into()); 722 echo_voice_sum_r = echo_voice_sum_r.clamp(i16::MIN.into(), i16::MAX.into()); 723 } 724 725 let echo_feedback_l = (fir_sample_l * i32::from(self.feedback_volume)) >> 7; 726 let echo_feedback_r = (fir_sample_r * i32::from(self.feedback_volume)) >> 7; 727 728 // Force the lowest bit clear before writing back to echo buffer 729 let echo_sample_l = 730 (echo_voice_sum_l + echo_feedback_l).clamp(i16::MIN.into(), i16::MAX.into()) & !1; 731 let echo_sample_r = 732 (echo_voice_sum_r + echo_feedback_r).clamp(i16::MIN.into(), i16::MAX.into()) & !1; 733 734 let current_buffer_addr = 735 self.buffer_start_address.wrapping_add(self.buffer_current_offset); 736 write_echo_sample(audio_ram, current_buffer_addr, echo_sample_l as i16); 737 write_echo_sample(audio_ram, current_buffer_addr.wrapping_add(2), echo_sample_r as i16); 738 } 739} 740 741fn read_echo_sample(audio_ram: &AudioRam, address: u16) -> i16 { 742 let lsb = audio_ram[address as usize]; 743 let msb = audio_ram[address.wrapping_add(1) as usize]; 744 i16::from_le_bytes([lsb, msb]) >> 1 745} 746 747fn write_echo_sample(audio_ram: &mut AudioRam, address: u16, value: i16) { 748 let [value_lsb, value_msb] = value.to_le_bytes(); 749 audio_ram[address as usize] = value_lsb; 750 audio_ram[address.wrapping_add(1) as usize] = value_msb; 751} 752 753#[derive(Debug, Clone, Encode, Decode)] 754struct DspRegisters { 755 sample_table_address: u16, 756 master_volume_l: i8, 757 master_volume_r: i8, 758 noise_frequency: u8, 759 echo_buffer_writes_enabled: bool, 760 mute_amplifier: bool, 761 soft_reset: bool, 762 global_counter: u16, 763 // Unused R/W registers 764 unused_xa_registers: [u8; 8], 765 unused_xb_registers: [u8; 8], 766 unused_xe_registers: [u8; 8], 767 unused_1d_register: u8, 768} 769 770impl DspRegisters { 771 fn new() -> Self { 772 Self { 773 sample_table_address: 0, 774 master_volume_l: 0, 775 master_volume_r: 0, 776 noise_frequency: 0, 777 echo_buffer_writes_enabled: false, 778 mute_amplifier: true, 779 soft_reset: true, 780 global_counter: 0, 781 unused_xa_registers: [0; 8], 782 unused_xb_registers: [0; 8], 783 unused_xe_registers: [0; 8], 784 unused_1d_register: 0, 785 } 786 } 787 788 fn write_flg(&mut self, value: u8) { 789 self.noise_frequency = value & 0x1F; 790 self.echo_buffer_writes_enabled = !value.bit(5); 791 self.mute_amplifier = value.bit(6); 792 self.soft_reset = value.bit(7); 793 794 log::trace!(" Noise frequency: {:02X}", self.noise_frequency); 795 log::trace!(" Echo buffer writes enabled: {}", self.echo_buffer_writes_enabled); 796 log::trace!(" Mute amplifier: {}", self.mute_amplifier); 797 log::trace!(" Soft reset: {}", self.soft_reset); 798 } 799 800 fn read_flg(&self) -> u8 { 801 self.noise_frequency 802 | (u8::from(!self.echo_buffer_writes_enabled) << 5) 803 | (u8::from(self.mute_amplifier) << 6) 804 | (u8::from(self.soft_reset) << 7) 805 } 806} 807 808#[derive(Debug, Clone, Encode, Decode)] 809pub struct AudioDsp { 810 voices: [Voice; 8], 811 registers: DspRegisters, 812 noise_generator: NoiseGenerator, 813 echo_filter: EchoFilter, 814 register_address: u8, 815} 816 817impl AudioDsp { 818 pub fn new(audio_interpolation: AudioInterpolationMode) -> Self { 819 Self { 820 voices: array::from_fn(|_| Voice::new(audio_interpolation)), 821 registers: DspRegisters::new(), 822 noise_generator: NoiseGenerator::new(), 823 echo_filter: EchoFilter::new(), 824 register_address: 0, 825 } 826 } 827 828 pub fn read_address(&self) -> u8 { 829 self.register_address 830 } 831 832 pub fn write_address(&mut self, address: u8) { 833 self.register_address = address; 834 } 835 836 pub fn read_register(&self) -> u8 { 837 log::trace!("DSP register read: {:02X}", self.register_address); 838 839 // Addresses $80-$FF mirror $00-$7F 840 let address = self.register_address & 0x7F; 841 842 // High nibble of register address encodes the voice 843 let voice = (address >> 4) as usize; 844 845 match address & 0x0F { 846 0x00 => self.voices[voice].volume_l as u8, 847 0x01 => self.voices[voice].volume_r as u8, 848 0x02 => self.voices[voice].sample_rate.lsb(), 849 0x03 => self.voices[voice].last_pitch_h_write, 850 0x04 => self.voices[voice].instrument_number, 851 0x05 => self.voices[voice].read_adsr_low(), 852 0x06 => self.voices[voice].read_adsr_high(), 853 0x07 => self.voices[voice].read_gain(), 854 0x08 => self.voices[voice].read_envelope(), 855 0x09 => self.voices[voice].read_output(), 856 0x0A => self.registers.unused_xa_registers[voice], 857 0x0B => self.registers.unused_xb_registers[voice], 858 0x0E => self.registers.unused_xe_registers[voice], 859 0x0F => self.echo_filter.fir_coefficients[voice] as u8, 860 // $xC and $xD registers are not voice-specific 861 0x0C | 0x0D => match address { 862 0x0C => self.registers.master_volume_l as u8, 863 0x1C => self.registers.master_volume_r as u8, 864 0x2C => self.echo_filter.volume_l as u8, 865 0x3C => self.echo_filter.volume_r as u8, 866 0x4C => { 867 // Key on flags 868 (0..8) 869 .map(|voice| u8::from(self.voices[voice].keyed_on) << voice) 870 .reduce(|a, b| a | b) 871 .unwrap() 872 } 873 0x5C => { 874 // Key off flags 875 (0..8) 876 .map(|voice| u8::from(self.voices[voice].keyed_off) << voice) 877 .reduce(|a, b| a | b) 878 .unwrap() 879 } 880 0x6C => self.registers.read_flg(), 881 0x7C => { 882 // ENDX (end flags) 883 (0..8) 884 .map(|voice| u8::from(self.voices[voice].end_flag_seen) << voice) 885 .reduce(|a, b| a | b) 886 .unwrap() 887 } 888 0x0D => self.echo_filter.feedback_volume as u8, 889 0x1D => self.registers.unused_1d_register, 890 0x2D => { 891 // Pitch modulation enable flags (voices 1-7 only) 892 (1..8) 893 .map(|voice| u8::from(self.voices[voice].pitch_modulation_enabled) << voice) 894 .reduce(|a, b| a | b) 895 .unwrap() 896 } 897 0x3D => { 898 // Output noise flags 899 (0..8) 900 .map(|voice| u8::from(self.voices[voice].output_noise) << voice) 901 .reduce(|a, b| a | b) 902 .unwrap() 903 } 904 0x4D => self.echo_filter.read_echo_enabled(), 905 0x5D => (self.registers.sample_table_address >> 8) as u8, 906 0x6D => (self.echo_filter.buffer_start_address >> 8) as u8, 907 0x7D => self.echo_filter.last_edl_write, 908 _ => unreachable!("all $xC and $xD addresses covered"), 909 }, 910 _ => unreachable!("all addresses <= $7F covered"), 911 } 912 } 913 914 pub fn write_register(&mut self, value: u8) { 915 // Addresses $80-$FF are not writable 916 if self.register_address >= 0x80 { 917 return; 918 } 919 920 log::trace!("DSP register write: {:02X}: {value:02X}", self.register_address); 921 922 // High nibble of register address encodes the voice 923 let voice = (self.register_address >> 4) as usize; 924 925 match self.register_address & 0x0F { 926 0x00 => { 927 self.voices[voice].volume_l = value as i8; 928 log::trace!(" Voice {voice} volume L: {value:02X}"); 929 } 930 0x01 => { 931 self.voices[voice].volume_r = value as i8; 932 log::trace!(" Voice {voice} volume R: {value:02X}"); 933 } 934 0x02 => { 935 self.voices[voice].write_pitch_low(value); 936 log::trace!(" Voice {voice} sample rate: {:04X}", self.voices[voice].sample_rate); 937 } 938 0x03 => { 939 self.voices[voice].write_pitch_high(value); 940 log::trace!(" Voice {voice} sample rate: {:04X}", self.voices[voice].sample_rate); 941 } 942 0x04 => { 943 self.voices[voice].instrument_number = value; 944 log::trace!(" Voice {voice} instrument number: {value:02X}"); 945 } 946 0x05 => { 947 log::trace!(" Voice {voice} ADSR low write: {value:02X}"); 948 self.voices[voice].write_adsr_low(value); 949 } 950 0x06 => { 951 log::trace!(" Voice {voice} ADSR high write: {value:02X}"); 952 self.voices[voice].write_adsr_high(value); 953 } 954 0x07 => { 955 log::trace!(" Voice {voice} gain write: {value:02X}"); 956 self.voices[voice].write_gain(value); 957 } 958 0x08 | 0x09 => { 959 // Current envelope value and current output value 960 // These are technically writable, although the DSP overwrites them at 32000 Hz 961 // TODO implement these 962 } 963 0x0A => { 964 self.registers.unused_xa_registers[voice] = value; 965 } 966 0x0B => { 967 self.registers.unused_xb_registers[voice] = value; 968 } 969 0x0E => { 970 self.registers.unused_xe_registers[voice] = value; 971 } 972 0x0F => { 973 self.echo_filter.fir_coefficients[voice] = value as i8; 974 } 975 // $xC and $xD registers are not voice-specific 976 0x0C | 0x0D => match self.register_address { 977 0x0C => { 978 self.registers.master_volume_l = value as i8; 979 log::trace!(" Master volume L: {value:02X}"); 980 } 981 0x1C => { 982 self.registers.master_volume_r = value as i8; 983 log::trace!(" Master volume R: {value:02X}"); 984 } 985 0x2C => { 986 self.echo_filter.volume_l = value as i8; 987 log::trace!(" Echo volume L: {}", self.echo_filter.volume_l); 988 } 989 0x3C => { 990 self.echo_filter.volume_r = value as i8; 991 log::trace!(" Echo volume R: {}", self.echo_filter.volume_r); 992 } 993 0x4C => { 994 // Key on flags 995 for voice in 0..8 { 996 self.voices[voice].write_key_on(value.bit(voice as u8)); 997 } 998 log::trace!(" Key on: {value:02X}"); 999 } 1000 0x5C => { 1001 // Key off flags 1002 for voice in 0..8 { 1003 self.voices[voice].write_key_off(value.bit(voice as u8)); 1004 } 1005 log::trace!(" Key off: {value:02X}"); 1006 } 1007 0x6C => { 1008 self.registers.write_flg(value); 1009 1010 // Apply soft reset immediately if set 1011 if self.registers.soft_reset { 1012 for voice in &mut self.voices { 1013 voice.soft_reset(); 1014 } 1015 } 1016 } 1017 0x7C => { 1018 // ENDX; writing any value clears all of the flags 1019 for voice in &mut self.voices { 1020 voice.end_flag_seen = false; 1021 } 1022 } 1023 0x0D => { 1024 self.echo_filter.feedback_volume = value as i8; 1025 1026 log::trace!(" Echo feedback volume: {}", self.echo_filter.feedback_volume); 1027 } 1028 0x1D => { 1029 self.registers.unused_1d_register = value; 1030 } 1031 0x2D => { 1032 // Pitch modulation enable flags (voices 1-7 only) 1033 for voice in 1..8 { 1034 self.voices[voice].pitch_modulation_enabled = value.bit(voice as u8); 1035 } 1036 log::trace!(" Pitch modulation enabled: {value:02X}"); 1037 } 1038 0x3D => { 1039 // Output noise flags 1040 for voice in 0..8 { 1041 self.voices[voice].output_noise = value.bit(voice as u8); 1042 } 1043 log::trace!(" Output noise: {value:02X}"); 1044 } 1045 0x4D => { 1046 self.echo_filter.write_echo_enabled(value); 1047 1048 log::trace!(" Echo enabled: {value:02X}"); 1049 } 1050 0x5D => { 1051 // Sample table address is in 256-byte steps 1052 self.registers.sample_table_address = u16::from_le_bytes([0x00, value]); 1053 log::trace!( 1054 " Sample table address: {:04X}", 1055 self.registers.sample_table_address 1056 ); 1057 } 1058 0x6D => { 1059 // Echo ring buffer address is in 256-byte steps 1060 self.echo_filter.buffer_start_address = u16::from_le_bytes([0x00, value]); 1061 log::trace!( 1062 "Echo buffer start address: {:04X}", 1063 self.echo_filter.buffer_start_address 1064 ); 1065 } 1066 0x7D => { 1067 self.echo_filter.write_echo_buffer_size(value); 1068 log::trace!(" Echo buffer size: {value:02X}"); 1069 } 1070 _ => unreachable!("all $xC and $xD addresses covered"), 1071 }, 1072 _ => unreachable!("all addresses <= $7F covered"), 1073 } 1074 } 1075 1076 #[must_use] 1077 pub fn clock(&mut self, audio_ram: &mut AudioRam) -> (i16, i16) { 1078 if self.registers.global_counter == 0 { 1079 self.registers.global_counter = 0x77FF; 1080 } else { 1081 self.registers.global_counter -= 1; 1082 } 1083 1084 self.noise_generator.clock(self.registers.noise_frequency, self.registers.global_counter); 1085 1086 for i in 0..8 { 1087 let prev_voice_output = if i != 0 { self.voices[i - 1].current_sample } else { 0 }; 1088 self.voices[i].clock( 1089 &self.registers, 1090 audio_ram, 1091 prev_voice_output, 1092 self.noise_generator.output, 1093 ); 1094 } 1095 1096 self.sample(audio_ram) 1097 } 1098 1099 fn sample(&mut self, audio_ram: &mut AudioRam) -> (i16, i16) { 1100 let mut voice_samples_l = [0; 8]; 1101 let mut voice_samples_r = [0; 8]; 1102 let mut voice_sum_l = 0_i32; 1103 let mut voice_sum_r = 0_i32; 1104 for (i, voice) in self.voices.iter().enumerate() { 1105 let voice_sample_l = (i32::from(voice.current_sample) * i32::from(voice.volume_l)) >> 6; 1106 let voice_sample_r = (i32::from(voice.current_sample) * i32::from(voice.volume_r)) >> 6; 1107 1108 voice_samples_l[i] = voice_sample_l; 1109 voice_samples_r[i] = voice_sample_r; 1110 1111 voice_sum_l += voice_sample_l; 1112 voice_sum_r += voice_sample_r; 1113 1114 voice_sum_l = voice_sum_l.clamp(i16::MIN.into(), i16::MAX.into()); 1115 voice_sum_r = voice_sum_r.clamp(i16::MIN.into(), i16::MAX.into()); 1116 } 1117 1118 voice_sum_l = (voice_sum_l * i32::from(self.registers.master_volume_l)) >> 7; 1119 voice_sum_l = voice_sum_l.clamp(i16::MIN.into(), i16::MAX.into()); 1120 1121 voice_sum_r = (voice_sum_r * i32::from(self.registers.master_volume_r)) >> 7; 1122 voice_sum_r = voice_sum_r.clamp(i16::MIN.into(), i16::MAX.into()); 1123 1124 let (echo_l, echo_r) = self.echo_filter.do_filter( 1125 self.registers.echo_buffer_writes_enabled, 1126 audio_ram, 1127 &voice_samples_l, 1128 &voice_samples_r, 1129 ); 1130 1131 let (out_l, out_r) = if !self.registers.mute_amplifier { 1132 let out_l = (voice_sum_l + echo_l).clamp(i16::MIN.into(), i16::MAX.into()); 1133 let out_r = (voice_sum_r + echo_r).clamp(i16::MIN.into(), i16::MAX.into()); 1134 (out_l, out_r) 1135 } else { 1136 // All processing continues while muted, but the DSP outputs silence 1137 (0, 0) 1138 }; 1139 1140 ((out_l as i16) ^ !0, (out_r as i16) ^ !0) 1141 } 1142 1143 pub fn reset(&mut self) { 1144 // Set soft reset flag, mute amplifier, and block echo buffer writes 1145 self.registers.write_flg(0xE0); 1146 1147 for voice in &mut self.voices { 1148 voice.soft_reset(); 1149 } 1150 } 1151 1152 pub fn update_audio_interpolation(&mut self, audio_interpolation: AudioInterpolationMode) { 1153 for voice in &mut self.voices { 1154 voice.audio_interpolation = audio_interpolation; 1155 } 1156 } 1157}