From a0d14f4030e9082871ef9b077a972e41046e4c7a Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Wed, 8 Apr 2020 23:15:44 -0400 Subject: [PATCH] Starts trying to make sense of the various fields at play. --- Components/OPL2/OPL2.cpp | 8 +++---- Components/OPL2/OPL2.hpp | 45 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/Components/OPL2/OPL2.cpp b/Components/OPL2/OPL2.cpp index 2d03c38d4..4e64f9463 100644 --- a/Components/OPL2/OPL2.cpp +++ b/Components/OPL2/OPL2.cpp @@ -185,7 +185,7 @@ void OPLL::write_register(uint8_t address, uint8_t value) { if(address >= 0x20 && address <= 0x28) { const auto index = address - 0x20; channels_[index].frequency = (channels_[index].frequency & 0xff) | (value & 1); - channels_[index].octave = (value >> 1) & 7; + channels_[index].octave = (value >> 1) & 0x7; channels_[index].key_on = value & 0x10; channels_[index].hold_sustain_level = value & 0x20; return; @@ -198,8 +198,8 @@ void OPLL::setup_fixed_instrument(int number, const uint8_t *data) { auto carrier = &operators_[number * 2 + 1]; // Set waveforms — only sine and halfsine are available. - carrier->waveform = (data[3] & 0x10) ? 1 : 0; - modulator->waveform = (data[3] & 0x08) ? 1 : 0; + carrier->waveform = Operator::Waveform((data[3] & 0x10) ? 1 : 0); + modulator->waveform = Operator::Waveform((data[3] & 0x08) ? 1 : 0); // Set modulator amplitude and key-scale level. modulator->scaling_level = data[2] >> 6; @@ -317,7 +317,7 @@ void OPL2::write_register(uint8_t address, uint8_t value) { const auto index = operator_by_address[address - 0xe0]; if(index == -1) return; - operators_[index].waveform = value & 3; + operators_[index].waveform = Operator::Waveform(value & 3); return; } diff --git a/Components/OPL2/OPL2.hpp b/Components/OPL2/OPL2.hpp index 35f11cf26..80cb6295e 100644 --- a/Components/OPL2/OPL2.hpp +++ b/Components/OPL2/OPL2.hpp @@ -19,18 +19,43 @@ namespace Yamaha { namespace OPL { struct Operator { + /// If true then an amplitude modulation of "3.7Hz" is applied, + /// with a depth "determined by the AM-DEPTH of the BD register"? bool apply_amplitude_modulation = false; + + /// If true then a vibrato of '6.4 Hz' is applied, with a depth + /// "determined by VOB_DEPTH of the BD register"? bool apply_vibrato = false; + + /// Selects between an ADSR envelope that holds at the sustain level + /// for as long as this key is on, releasing afterwards, and one that + /// simply switches straight to the release rate once the sustain + /// level is hit, getting back to 0 regardless of an ongoing key-on. bool hold_sustain_level = false; + + /// Provides a potential faster step through the ADSR envelope. Cf. p12. bool keyboard_scaling_rate = false; + + /// Indexes a lookup table to determine what multiple of the channel's frequency + /// this operator is advancing at. int frequency_multiple = 0; - int scaling_level = 0; + + /// Sets the current output level of this modulator, as an attenuation. int output_level = 0; + + /// Selects attenuation that is applied as a function of interval. Cf. p14. + int scaling_level = 0; + + /// Sets the ADSR rates. int attack_rate = 0; int decay_rate = 0; int sustain_level = 0; int release_rate = 0; - int waveform = 0; + + /// Selects the generated waveform. + enum class Waveform { + Sine, HalfSine, AbsSine, PulseSine + } waveform = Waveform::Sine; }; struct Channel { @@ -39,6 +64,22 @@ struct Channel { bool key_on = false; int feedback_strength = 0; bool use_fm_synthesis = true; + + // This should be called at a rate of around 49,716 Hz. + void update() { + // Per the documentation: + // F-Num = Music Frequency * 2^(20-Block) / 49716 + // + // Given that a 256-entry table is used to store a quarter of a sine wave, + // making 1024 steps per complete wave, add what I've called frequency + // to an accumulator and move on whenever that exceeds 2^(10 - octave). + // + // TODO: but, how does that apply to the two operator multipliers? + // + // Or: 2^19? + } + + // Stateful information. }; template class OPLBase: public ::Outputs::Speaker::SampleSource {