1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-10-04 01:57:54 +00:00

Exposes targets for modulation.

This commit is contained in:
Thomas Harte 2021-12-05 06:38:55 -05:00
parent 91b5da06e3
commit 9b80563443
2 changed files with 54 additions and 44 deletions

View File

@ -104,9 +104,15 @@ void Audio::output() {
InterruptFlag::AudioChannel2, InterruptFlag::AudioChannel2,
InterruptFlag::AudioChannel3, InterruptFlag::AudioChannel3,
}; };
Channel *const modulands[] = {
&channels_[1],
&channels_[2],
&channels_[3],
nullptr,
};
for(int c = 0; c < 4; c++) { for(int c = 0; c < 4; c++) {
if(channels_[c].output()) { if(channels_[c].output(modulands[c])) {
posit_interrupt(interrupts[c]); posit_interrupt(interrupts[c]);
} }
} }
@ -322,16 +328,16 @@ void Audio::output() {
// Non-action fallback transition and setter, plus specialised begin_state declarations. // Non-action fallback transition and setter, plus specialised begin_state declarations.
// //
template <Audio::Channel::State end> void Audio::Channel::begin_state() { template <Audio::Channel::State end> void Audio::Channel::begin_state(Channel *) {
state = end; state = end;
} }
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingHigh>(); template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingHigh>(Channel *);
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingLow>(); template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingLow>(Channel *);
template < template <
Audio::Channel::State begin, Audio::Channel::State begin,
Audio::Channel::State end> bool Audio::Channel::transit() { Audio::Channel::State end> bool Audio::Channel::transit(Channel *moduland) {
begin_state<end>(); begin_state<end>(moduland);
return false; return false;
} }
@ -341,8 +347,8 @@ template <
template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit<
Audio::Channel::State::Disabled, Audio::Channel::State::Disabled,
Audio::Channel::State::WaitingForDummyDMA>() { Audio::Channel::State::WaitingForDummyDMA>(Channel *moduland) {
begin_state<State::WaitingForDummyDMA>(); begin_state<State::WaitingForDummyDMA>(moduland);
period_counter = period; // i.e. percntrld period_counter = period; // i.e. percntrld
length_counter = length; // i.e. lencntrld length_counter = length; // i.e. lencntrld
@ -354,8 +360,8 @@ template <> bool Audio::Channel::transit<
template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit<
Audio::Channel::State::Disabled, Audio::Channel::State::Disabled,
Audio::Channel::State::PlayingHigh>() { Audio::Channel::State::PlayingHigh>(Channel *moduland) {
begin_state<State::PlayingHigh>(); begin_state<State::PlayingHigh>(moduland);
data_latch = data; // i.e. pbufld1 data_latch = data; // i.e. pbufld1
period_counter = period; // i.e. percntrld period_counter = period; // i.e. percntrld
@ -367,14 +373,14 @@ template <> bool Audio::Channel::transit<
return true; return true;
} }
template <> bool Audio::Channel::output<Audio::Channel::State::Disabled>() { template <> bool Audio::Channel::output<Audio::Channel::State::Disabled>(Channel *moduland) {
if(!wants_data && !dma_enabled && !interrupt_pending) { if(!wants_data && !dma_enabled && !interrupt_pending) {
return transit<State::Disabled, State::PlayingHigh>(); return transit<State::Disabled, State::PlayingHigh>(moduland);
} }
// Test for DMA-style transition. // Test for DMA-style transition.
if(dma_enabled) { if(dma_enabled) {
return transit<State::Disabled, State::WaitingForDummyDMA>(); return transit<State::Disabled, State::WaitingForDummyDMA>(moduland);
} }
return false; return false;
@ -386,8 +392,8 @@ template <> bool Audio::Channel::output<Audio::Channel::State::Disabled>() {
template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit<
Audio::Channel::State::WaitingForDummyDMA, Audio::Channel::State::WaitingForDummyDMA,
Audio::Channel::State::WaitingForDMA>() { Audio::Channel::State::WaitingForDMA>(Channel *moduland) {
begin_state<State::WaitingForDMA>(); begin_state<State::WaitingForDMA>(moduland);
wants_data = true; wants_data = true;
if(length == 1) { if(length == 1) {
@ -398,13 +404,13 @@ template <> bool Audio::Channel::transit<
return false; return false;
} }
template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDummyDMA>() { template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDummyDMA>(Channel *moduland) {
if(!dma_enabled) { if(!dma_enabled) {
return transit<State::WaitingForDummyDMA, State::Disabled>(); return transit<State::WaitingForDummyDMA, State::Disabled>(moduland);
} }
if(dma_enabled && !wants_data) { if(dma_enabled && !wants_data) {
return transit<State::WaitingForDummyDMA, State::WaitingForDMA>(); return transit<State::WaitingForDummyDMA, State::WaitingForDMA>(moduland);
} }
return false; return false;
@ -416,8 +422,8 @@ template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDummyDM
template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit<
Audio::Channel::State::WaitingForDMA, Audio::Channel::State::WaitingForDMA,
Audio::Channel::State::PlayingHigh>() { Audio::Channel::State::PlayingHigh>(Channel *moduland) {
begin_state<State::PlayingHigh>(); begin_state<State::PlayingHigh>(moduland);
data_latch = data; data_latch = data;
wants_data = true; wants_data = true;
@ -426,13 +432,13 @@ template <> bool Audio::Channel::transit<
return false; return false;
} }
template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDMA>() { template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDMA>(Channel *moduland) {
if(!dma_enabled) { if(!dma_enabled) {
return transit<State::WaitingForDummyDMA, State::Disabled>(); return transit<State::WaitingForDummyDMA, State::Disabled>(moduland);
} }
if(dma_enabled && !wants_data) { if(dma_enabled && !wants_data) {
return transit<State::WaitingForDummyDMA, State::PlayingHigh>(); return transit<State::WaitingForDummyDMA, State::PlayingHigh>(moduland);
} }
return false; return false;
@ -444,8 +450,8 @@ template <> bool Audio::Channel::output<Audio::Channel::State::WaitingForDMA>()
template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit<
Audio::Channel::State::PlayingHigh, Audio::Channel::State::PlayingHigh,
Audio::Channel::State::PlayingLow>() { Audio::Channel::State::PlayingLow>(Channel *moduland) {
begin_state<State::PlayingLow>(); begin_state<State::PlayingLow>(moduland);
// TODO: if AUDxAP, then pubfid2 // TODO: if AUDxAP, then pubfid2
// TODO: if AUDxAP and AUDxON, then AUDxDR // TODO: if AUDxAP and AUDxON, then AUDxDR
@ -469,20 +475,20 @@ template <> bool Audio::Channel::transit<
return false; return false;
} }
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingHigh>() { template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingHigh>(Channel *) {
state = Audio::Channel::State::PlayingHigh; state = Audio::Channel::State::PlayingHigh;
// Output high byte. // Output high byte.
output_level = int8_t(data_latch >> 8); output_level = int8_t(data_latch >> 8);
} }
template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>() { template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>(Channel *moduland) {
-- period_counter; -- period_counter;
// This is a reasonable guess as to the exit condition for this node; // This is a reasonable guess as to the exit condition for this node;
// Commodore doesn't document. // Commodore doesn't document.
if(!period_counter) { if(!period_counter) {
return transit<State::PlayingHigh, State::PlayingLow>(); return transit<State::PlayingHigh, State::PlayingLow>(moduland);
} }
return false; return false;
@ -494,8 +500,8 @@ template <> bool Audio::Channel::output<Audio::Channel::State::PlayingHigh>() {
template <> bool Audio::Channel::transit< template <> bool Audio::Channel::transit<
Audio::Channel::State::PlayingLow, Audio::Channel::State::PlayingLow,
Audio::Channel::State::PlayingHigh>() { Audio::Channel::State::PlayingHigh>(Channel *moduland) {
begin_state<State::PlayingHigh>(); begin_state<State::PlayingHigh>(moduland);
// TODO: include napnav in tests // TODO: include napnav in tests
@ -520,22 +526,22 @@ template <> bool Audio::Channel::transit<
return false; return false;
} }
template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingLow>() { template <> void Audio::Channel::begin_state<Audio::Channel::State::PlayingLow>(Channel *) {
state = Audio::Channel::State::PlayingLow; state = Audio::Channel::State::PlayingLow;
// Output low byte. // Output low byte.
output_level = int8_t(data_latch & 0xff); output_level = int8_t(data_latch & 0xff);
} }
template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>() { template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>(Channel *moduland) {
-- period_counter; -- period_counter;
if(!period_counter) { if(!period_counter) {
const bool dma_or_no_interrupt = dma_enabled || !interrupt_pending; const bool dma_or_no_interrupt = dma_enabled || !interrupt_pending;
if(dma_or_no_interrupt) { if(dma_or_no_interrupt) {
return transit<State::PlayingLow, State::PlayingHigh>(); return transit<State::PlayingLow, State::PlayingHigh>(moduland);
} else { } else {
return transit<State::PlayingLow, State::Disabled>(); return transit<State::PlayingLow, State::Disabled>(moduland);
} }
} }
@ -546,18 +552,18 @@ template <> bool Audio::Channel::output<Audio::Channel::State::PlayingLow>() {
// Dispatcher // Dispatcher
// //
bool Audio::Channel::output() { bool Audio::Channel::output(Channel *moduland) {
// Update pulse-width modulation. // Update pulse-width modulation.
output_phase = (output_phase + 1) & 63; output_phase = (output_phase + 1) & 63;
output_enabled |= !output_phase; output_enabled |= !output_phase;
output_enabled &= output_phase != volume; output_enabled &= output_phase != volume;
switch(state) { switch(state) {
case State::Disabled: return output<State::Disabled>(); case State::Disabled: return output<State::Disabled>(moduland);
case State::WaitingForDummyDMA: return output<State::WaitingForDummyDMA>(); case State::WaitingForDummyDMA: return output<State::WaitingForDummyDMA>(moduland);
case State::WaitingForDMA: return output<State::WaitingForDMA>(); case State::WaitingForDMA: return output<State::WaitingForDMA>(moduland);
case State::PlayingHigh: return output<State::PlayingHigh>(); case State::PlayingHigh: return output<State::PlayingHigh>(moduland);
case State::PlayingLow: return output<State::PlayingLow>(); case State::PlayingLow: return output<State::PlayingLow>(moduland);
default: default:
assert(false); assert(false);

View File

@ -111,21 +111,25 @@ class Audio: public DMADevice<4> {
} state = State::Disabled; } state = State::Disabled;
/// Dispatches to the appropriate templatised output for the current state. /// 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. /// @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. /// 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. /// @returns @c true if an interrupt should be posted; @c false otherwise.
template <State state> bool output(); template <State state> bool output(Channel *moduland);
/// Transitions from @c begin to @c end, calling the appropriate @c begin_state /// Transitions from @c begin to @c end, calling the appropriate @c begin_state
/// and taking any steps specific to that particular transition. /// 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. /// @returns @c true if an interrupt should be posted; @c false otherwise.
template <State begin, State end> bool transit(); template <State begin, State end> bool transit(Channel *moduland);
/// Begins @c state, performing all fixed logic that would otherwise have to be /// Begins @c state, performing all fixed logic that would otherwise have to be
/// repeated endlessly in the relevant @c output. /// repeated endlessly in the relevant @c output.
template <State state> void begin_state(); /// @param moduland The channel to modulate, if modulation is enabled.
template <State state> void begin_state(Channel *moduland);
// Output state. // Output state.
int8_t output_level = 0; int8_t output_level = 0;