From f8bb66d2a0c22a363aa233f3ea819b6c492768b7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 26 Jun 2021 23:39:59 -0400 Subject: [PATCH] Attempts an essentially-complete implementation of tone channels. --- Machines/Enterprise/Dave.cpp | 48 +++++++++++++++++++++--------- Machines/Enterprise/Dave.hpp | 17 +++++++---- Machines/Enterprise/Enterprise.cpp | 6 ++-- 3 files changed, 49 insertions(+), 22 deletions(-) diff --git a/Machines/Enterprise/Dave.cpp b/Machines/Enterprise/Dave.cpp index 8d5ef6593..224764c5b 100644 --- a/Machines/Enterprise/Dave.cpp +++ b/Machines/Enterprise/Dave.cpp @@ -50,15 +50,35 @@ void Dave::set_sample_volume_range(int16_t range) { } void Dave::get_samples(std::size_t number_of_samples, int16_t *target) { - // Step 1: divide input clock to 125,000 Hz (?) for(size_t c = 0; c < number_of_samples; c++) { -#define update_channel(x) \ - if(!channels_[x].count) { \ - channels_[x].output ^= true; \ - channels_[x].count = channels_[x].reload; \ - } else { \ - --channels_[x].count; \ - } + poly_state_[int(Channel::Distortion::FourBit)] = poly4_.next(); + poly_state_[int(Channel::Distortion::FiveBit)] = poly5_.next(); + poly_state_[int(Channel::Distortion::SevenBit)] = poly7_.next(); + + // TODO: substitute poly_state_[2] if polynomial substitution is in play. + +#define update_channel(x) { \ + auto output = channels_[x].output & 1; \ + channels_[x].output <<= 1; \ + if(!channels_[x].count) { \ + channels_[x].count = channels_[x].reload; \ + \ + if(channels_[x].distortion == Channel::Distortion::None) \ + output ^= 1; \ + else \ + output = poly_state_[int(channels_[x].distortion)]; \ + \ + if(channels_[x].high_pass && (channels_[(x+1)%3].output&3) == 2) { \ + output = 0; \ + } \ + if(channels_[x].ring_modulate) { \ + output = ~(output ^ channels_[(x+2)%3].output) & 1; \ + } \ + } else { \ + --channels_[x].count; \ + } \ + channels_[x].output |= output; \ + } update_channel(0); update_channel(1); @@ -69,16 +89,16 @@ void Dave::get_samples(std::size_t number_of_samples, int16_t *target) { // Dumbest ever first attempt: sum channels. target[(c << 1) + 0] = volume_ * ( - channels_[0].amplitude[0] * channels_[0].output + - channels_[1].amplitude[0] * channels_[1].output + - channels_[2].amplitude[0] * channels_[2].output + channels_[0].amplitude[0] * (channels_[0].output & 1) + + channels_[1].amplitude[0] * (channels_[1].output & 1) + + channels_[2].amplitude[0] * (channels_[2].output & 1) ); target[(c << 1) + 1] = volume_ * ( - channels_[0].amplitude[1] * channels_[0].output + - channels_[1].amplitude[1] * channels_[1].output + - channels_[2].amplitude[1] * channels_[2].output + channels_[0].amplitude[1] * (channels_[0].output & 1) + + channels_[1].amplitude[1] * (channels_[1].output & 1) + + channels_[2].amplitude[1] * (channels_[2].output & 1) ); } } diff --git a/Machines/Enterprise/Dave.hpp b/Machines/Enterprise/Dave.hpp index 911707431..3d7c3619b 100644 --- a/Machines/Enterprise/Dave.hpp +++ b/Machines/Enterprise/Dave.hpp @@ -41,27 +41,32 @@ class Dave: public Outputs::Speaker::SampleSource { bool high_pass = false; bool ring_modulate = false; enum class Distortion { - None, - FourBit, - FiveBit, - SevenBit, + None = 0, + FourBit = 1, + FiveBit = 2, + SevenBit = 3, } distortion = Distortion::None; uint8_t amplitude[2]{}; // Current state. uint16_t count = 0; - bool output = true; + int output = 0; } channels_[3]; int16_t volume_ = 0; - // Various polynomials that contribute to audio generation. + // Polynomials that are always running. Numeric::LFSRv<0xc> poly4_; Numeric::LFSRv<0x14> poly5_; Numeric::LFSRv<0x60> poly7_; + + // The selectable, noise-related polynomial. Numeric::LFSRv<0x110> poly9_; Numeric::LFSRv<0x500> poly11_; Numeric::LFSRv<0x6000> poly15_; Numeric::LFSRv<0x12000> poly17_; + + // Current state of the active polynomials. + uint8_t poly_state_[4]; }; } diff --git a/Machines/Enterprise/Enterprise.cpp b/Machines/Enterprise/Enterprise.cpp index bda4eec55..34ff7fcb5 100644 --- a/Machines/Enterprise/Enterprise.cpp +++ b/Machines/Enterprise/Enterprise.cpp @@ -210,7 +210,7 @@ template class ConcreteMachine: page<3>(0x00); // Set up audio. - speaker_.set_input_rate(125000.0f); // TODO: a bigger number, and respect the programmable divider. + speaker_.set_input_rate(250000.0f); // TODO: a bigger number, and respect the programmable divider. // Pass on any media. insert_media(target.media); @@ -368,7 +368,9 @@ template class ConcreteMachine: } inline void update_audio() { - speaker_.run_for(audio_queue_, time_since_audio_update_.divide_cycles(Cycles(32))); + // TODO: divide by only 8, letting Dave divide itself by a further 2 or 3 + // as per its own register. + speaker_.run_for(audio_queue_, time_since_audio_update_.divide_cycles(Cycles(16))); } private: