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:
parent
91b5da06e3
commit
9b80563443
@ -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);
|
||||||
|
@ -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;
|
||||||
|
Loading…
Reference in New Issue
Block a user