From 9b80563443736a5ff401135e713d3f43d7457776 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 5 Dec 2021 06:38:55 -0500 Subject: [PATCH] Exposes targets for modulation. --- Machines/Amiga/Audio.cpp | 86 +++++++++++++++++++++------------------- Machines/Amiga/Audio.hpp | 12 ++++-- 2 files changed, 54 insertions(+), 44 deletions(-) diff --git a/Machines/Amiga/Audio.cpp b/Machines/Amiga/Audio.cpp index 5f48dacca..cf682b5fc 100644 --- a/Machines/Amiga/Audio.cpp +++ b/Machines/Amiga/Audio.cpp @@ -104,9 +104,15 @@ void Audio::output() { InterruptFlag::AudioChannel2, InterruptFlag::AudioChannel3, }; + Channel *const modulands[] = { + &channels_[1], + &channels_[2], + &channels_[3], + nullptr, + }; for(int c = 0; c < 4; c++) { - if(channels_[c].output()) { + if(channels_[c].output(modulands[c])) { posit_interrupt(interrupts[c]); } } @@ -322,16 +328,16 @@ void Audio::output() { // Non-action fallback transition and setter, plus specialised begin_state declarations. // -template void Audio::Channel::begin_state() { +template void Audio::Channel::begin_state(Channel *) { state = end; } -template <> void Audio::Channel::begin_state(); -template <> void Audio::Channel::begin_state(); +template <> void Audio::Channel::begin_state(Channel *); +template <> void Audio::Channel::begin_state(Channel *); template < Audio::Channel::State begin, - Audio::Channel::State end> bool Audio::Channel::transit() { - begin_state(); + Audio::Channel::State end> bool Audio::Channel::transit(Channel *moduland) { + begin_state(moduland); return false; } @@ -341,8 +347,8 @@ template < template <> bool Audio::Channel::transit< Audio::Channel::State::Disabled, - Audio::Channel::State::WaitingForDummyDMA>() { - begin_state(); + Audio::Channel::State::WaitingForDummyDMA>(Channel *moduland) { + begin_state(moduland); period_counter = period; // i.e. percntrld length_counter = length; // i.e. lencntrld @@ -354,8 +360,8 @@ template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit< Audio::Channel::State::Disabled, - Audio::Channel::State::PlayingHigh>() { - begin_state(); + Audio::Channel::State::PlayingHigh>(Channel *moduland) { + begin_state(moduland); data_latch = data; // i.e. pbufld1 period_counter = period; // i.e. percntrld @@ -367,14 +373,14 @@ template <> bool Audio::Channel::transit< return true; } -template <> bool Audio::Channel::output() { +template <> bool Audio::Channel::output(Channel *moduland) { if(!wants_data && !dma_enabled && !interrupt_pending) { - return transit(); + return transit(moduland); } // Test for DMA-style transition. if(dma_enabled) { - return transit(); + return transit(moduland); } return false; @@ -386,8 +392,8 @@ template <> bool Audio::Channel::output() { template <> bool Audio::Channel::transit< Audio::Channel::State::WaitingForDummyDMA, - Audio::Channel::State::WaitingForDMA>() { - begin_state(); + Audio::Channel::State::WaitingForDMA>(Channel *moduland) { + begin_state(moduland); wants_data = true; if(length == 1) { @@ -398,13 +404,13 @@ template <> bool Audio::Channel::transit< return false; } -template <> bool Audio::Channel::output() { +template <> bool Audio::Channel::output(Channel *moduland) { if(!dma_enabled) { - return transit(); + return transit(moduland); } if(dma_enabled && !wants_data) { - return transit(); + return transit(moduland); } return false; @@ -416,8 +422,8 @@ template <> bool Audio::Channel::output bool Audio::Channel::transit< Audio::Channel::State::WaitingForDMA, - Audio::Channel::State::PlayingHigh>() { - begin_state(); + Audio::Channel::State::PlayingHigh>(Channel *moduland) { + begin_state(moduland); data_latch = data; wants_data = true; @@ -426,13 +432,13 @@ template <> bool Audio::Channel::transit< return false; } -template <> bool Audio::Channel::output() { +template <> bool Audio::Channel::output(Channel *moduland) { if(!dma_enabled) { - return transit(); + return transit(moduland); } if(dma_enabled && !wants_data) { - return transit(); + return transit(moduland); } return false; @@ -444,8 +450,8 @@ template <> bool Audio::Channel::output() template <> bool Audio::Channel::transit< Audio::Channel::State::PlayingHigh, - Audio::Channel::State::PlayingLow>() { - begin_state(); + Audio::Channel::State::PlayingLow>(Channel *moduland) { + begin_state(moduland); // TODO: if AUDxAP, then pubfid2 // TODO: if AUDxAP and AUDxON, then AUDxDR @@ -469,20 +475,20 @@ template <> bool Audio::Channel::transit< return false; } -template <> void Audio::Channel::begin_state() { +template <> void Audio::Channel::begin_state(Channel *) { state = Audio::Channel::State::PlayingHigh; // Output high byte. output_level = int8_t(data_latch >> 8); } -template <> bool Audio::Channel::output() { +template <> bool Audio::Channel::output(Channel *moduland) { -- period_counter; // This is a reasonable guess as to the exit condition for this node; // Commodore doesn't document. if(!period_counter) { - return transit(); + return transit(moduland); } return false; @@ -494,8 +500,8 @@ template <> bool Audio::Channel::output() { template <> bool Audio::Channel::transit< Audio::Channel::State::PlayingLow, - Audio::Channel::State::PlayingHigh>() { - begin_state(); + Audio::Channel::State::PlayingHigh>(Channel *moduland) { + begin_state(moduland); // TODO: include napnav in tests @@ -520,22 +526,22 @@ template <> bool Audio::Channel::transit< return false; } -template <> void Audio::Channel::begin_state() { +template <> void Audio::Channel::begin_state(Channel *) { state = Audio::Channel::State::PlayingLow; // Output low byte. output_level = int8_t(data_latch & 0xff); } -template <> bool Audio::Channel::output() { +template <> bool Audio::Channel::output(Channel *moduland) { -- period_counter; if(!period_counter) { const bool dma_or_no_interrupt = dma_enabled || !interrupt_pending; if(dma_or_no_interrupt) { - return transit(); + return transit(moduland); } else { - return transit(); + return transit(moduland); } } @@ -546,18 +552,18 @@ template <> bool Audio::Channel::output() { // Dispatcher // -bool Audio::Channel::output() { +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; switch(state) { - case State::Disabled: return output(); - case State::WaitingForDummyDMA: return output(); - case State::WaitingForDMA: return output(); - case State::PlayingHigh: return output(); - case State::PlayingLow: return output(); + case State::Disabled: return output(moduland); + case State::WaitingForDummyDMA: return output(moduland); + case State::WaitingForDMA: return output(moduland); + case State::PlayingHigh: return output(moduland); + case State::PlayingLow: return output(moduland); default: assert(false); diff --git a/Machines/Amiga/Audio.hpp b/Machines/Amiga/Audio.hpp index e78872178..aa63ff735 100644 --- a/Machines/Amiga/Audio.hpp +++ b/Machines/Amiga/Audio.hpp @@ -111,21 +111,25 @@ class Audio: public DMADevice<4> { } state = State::Disabled; /// Dispatches to the appropriate templatised output for the current state. + /// @param moduland The channel to modulate, if modulation is enabled. /// @returns @c true if an interrupt should be posted; @c false otherwise. - bool output(); + bool output(Channel *moduland); /// Applies dynamic logic for @c state, mostly testing for potential state transitions. + /// @param moduland The channel to modulate, if modulation is enabled. /// @returns @c true if an interrupt should be posted; @c false otherwise. - template bool output(); + template bool output(Channel *moduland); /// Transitions from @c begin to @c end, calling the appropriate @c begin_state /// and taking any steps specific to that particular transition. + /// @param moduland The channel to modulate, if modulation is enabled. /// @returns @c true if an interrupt should be posted; @c false otherwise. - template bool transit(); + template bool transit(Channel *moduland); /// Begins @c state, performing all fixed logic that would otherwise have to be /// repeated endlessly in the relevant @c output. - template void begin_state(); + /// @param moduland The channel to modulate, if modulation is enabled. + template void begin_state(Channel *moduland); // Output state. int8_t output_level = 0;