1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-22 12:33:29 +00:00

Attempts to obey accumulator size in determining sample end.

This commit is contained in:
Thomas Harte 2020-11-26 15:07:29 -05:00
parent b0efc647f1
commit 8edb3fcd5f
2 changed files with 16 additions and 6 deletions

View File

@ -78,6 +78,9 @@ void GLU::EnsoniqState::set_register(uint16_t address, uint8_t value) {
} break;
case 0xc0:
oscillators[address & 0x1f].table_size = value;
// The most-significant bit that should be used is 16 + (value & 7).
oscillators[address & 0x1f].overflow_mask = ~(0xffffff >> (7 - (value & 7)));
break;
default:
@ -194,13 +197,13 @@ void GLU::generate_audio(size_t number_of_samples, std::int16_t *target, int16_t
// Test for a new halting event.
switch(remote_.oscillators[c].control & 6) {
case 0: // Free-run mode; just keep the counter to its genuine 24 bits and always update sample.
remote_.oscillators[c].position &= 0x00ffffff;
case 0: // Free-run mode; don't truncate the position at all, in case the
// accumulator bits in use changes.
output += remote_.oscillators[c].output(remote_.ram_);
break;
case 2: // One-shot mode; check for end of run. Otherwise update sample.
if(remote_.oscillators[c].position & 0xff000000) {
if(remote_.oscillators[c].position & remote_.oscillators[c].overflow_mask) {
remote_.oscillators[c].position = 0;
remote_.oscillators[c].control |= 1;
} else {
@ -213,9 +216,10 @@ void GLU::generate_audio(size_t number_of_samples, std::int16_t *target, int16_t
break;
case 6: // Swap mode; possibly trigger partner, and update sample.
// TODO: possibly this function argues in favour of summing the output
// in a separate loop?
if(remote_.oscillators[c].position & 0xff000000) {
// Per tech note #11: "Whenever a swap occurs from a higher-numbered
// oscillator to a lower-numbered one, the output signal from the corresponding
// generator temporarily falls to the zero-crossing level (silence)"
if(remote_.oscillators[c].position & remote_.oscillators[c].overflow_mask) {
remote_.oscillators[c].control |= 1;
remote_.oscillators[c].position = 0;
remote_.oscillators[c^1].control &= ~1;
@ -227,6 +231,7 @@ void GLU::generate_audio(size_t number_of_samples, std::int16_t *target, int16_t
}
// Maximum total output was 32 channels times a 16-bit range. Map that down.
// TODO: dynamic total volume?
target[sample] = (output * output_range_) >> 20;
// Apply any RAM writes that interleave here.
@ -266,6 +271,7 @@ int16_t GLU::EnsoniqState::Oscillator::output(uint8_t *ram) {
const auto level = sample(ram);
// "An oscillator will halt when a zero is encountered in its waveform table."
// TODO: only if in free-run mode, I think? Or?
if(!level) {
control |= 1;
return 0;

View File

@ -76,6 +76,10 @@ class GLU: public Outputs::Speaker::SampleSource {
uint8_t control;
uint8_t table_size;
// Derived state.
uint32_t overflow_mask; // If a non-zero bit gets anywhere into the overflow mask, this channel
// has wrapped around. It's a function of table_size.
uint8_t sample(uint8_t *ram);
int16_t output(uint8_t *ram);
} oscillators[32];