From 066e4421e89415bf250dca505059281aed5fbc1e Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Mon, 6 Dec 2021 06:35:08 -0500 Subject: [PATCH] Attempt volcntrld. --- Machines/Amiga/Audio.cpp | 36 ++++++++++++++++++++++++++++-------- Machines/Amiga/Audio.hpp | 12 +++++++++--- 2 files changed, 37 insertions(+), 11 deletions(-) diff --git a/Machines/Amiga/Audio.cpp b/Machines/Amiga/Audio.cpp index 22541cc58..9e5000222 100644 --- a/Machines/Amiga/Audio.cpp +++ b/Machines/Amiga/Audio.cpp @@ -47,12 +47,22 @@ void Audio::set_volume(int channel, uint16_t volume) { channels_[channel].volume = (volume & 0x40) ? 64 : (volume & 0x3f); } -void Audio::set_data(int channel, uint16_t data) { +template void Audio::set_data(int channel, uint16_t data) { assert(channel >= 0 && channel < 4); channels_[channel].wants_data = false; channels_[channel].data = data; + + // TODO: "the [PWM] counter is reset when ... AUDxDAT is written", but + // does that just mean written by the CPU, or does it include DMA? + // My guess is the former. But TODO. + if constexpr (is_external) { + channels_[channel].reset_output_phase(); + } } +template void Audio::set_data(int, uint16_t); +template void Audio::set_data(int, uint16_t); + void Audio::set_channel_enables(uint16_t enables) { channels_[0].dma_enabled = enables & 1; channels_[1].dma_enabled = enables & 2; @@ -86,7 +96,7 @@ bool Audio::advance_dma(int channel) { return false; } - set_data(channel, ram_[channels_[channel].data_address & ram_mask_]); + set_data(channel, ram_[channels_[channel].data_address & ram_mask_]); ++channels_[channel].data_address; if(channels_[channel].should_reload_address) { @@ -354,7 +364,9 @@ template <> bool Audio::Channel::transit< // [AUDxIR]: see return result. - // TODO: volcntrld (?) + // volcntrld + volume_latch = volume; + reset_output_phase(); // pbufld1 data_latch = data; @@ -442,7 +454,9 @@ template <> bool Audio::Channel::transit< Audio::Channel::State::PlayingHigh>(Channel *moduland) { begin_state(moduland); - // TODO: volcntrld (?) + // volcntrld + volume_latch = volume; + reset_output_phase(); // percntrld period_counter = period; @@ -572,7 +586,10 @@ template <> bool Audio::Channel::transit< begin_state(moduland); bool wants_interrupt = false; - // TODO: volcntrld? + + // volcntrld + volume_latch = volume; + reset_output_phase(); // Is this correct? // percntrld period_counter = period; @@ -631,9 +648,12 @@ template <> bool Audio::Channel::output(Chann bool Audio::Channel::output(Channel *moduland) { // Update pulse-width modulation. - output_phase = (output_phase + 1) & 63; - output_enabled |= !output_phase; - output_enabled &= output_phase != volume; + output_phase = output_phase + 1; + if(output_phase == 64) { + reset_output_phase(); + } else { + output_enabled &= output_phase != volume_latch; + } switch(state) { case State::Disabled: return output(moduland); diff --git a/Machines/Amiga/Audio.hpp b/Machines/Amiga/Audio.hpp index 626f67e6e..ae63339fb 100644 --- a/Machines/Amiga/Audio.hpp +++ b/Machines/Amiga/Audio.hpp @@ -44,7 +44,7 @@ class Audio: public DMADevice<4> { void set_volume(int channel, uint16_t); /// Sets the next two samples of audio to output. - void set_data(int channel, uint16_t); + template void set_data(int channel, uint16_t); /// Provides a copy of the DMA enable flags, for the purpose of /// determining which channels are enabled for DMA. @@ -90,7 +90,8 @@ class Audio: public DMADevice<4> { bool attach_volume = false; // Output volume, [0, 64]. - uint8_t volume; + uint8_t volume = 0; + uint8_t volume_latch = 0; // Indicates whether DMA is enabled for this channel. bool dma_enabled = false; @@ -137,8 +138,13 @@ class Audio: public DMADevice<4> { // Output state. int8_t output_level = 0; - uint8_t output_phase = 0; // TODO: this should count down, not up. + uint8_t output_phase = 0; bool output_enabled = false; + + void reset_output_phase() { + output_phase = 0; + output_enabled = (volume_latch > 0) && !attach_period && !attach_volume; + } } channels_[4]; // Transient output state, and its destination.