From 335a68396fc2315cc3aa3a0955481f50b5dd3605 Mon Sep 17 00:00:00 2001
From: Thomas Harte <thomas.harte@gmail.com>
Date: Sat, 4 Apr 2020 23:39:09 -0400
Subject: [PATCH] Attempts to complete OPL2 register decoding.

---
 Components/OPL2/OPL2.cpp | 26 ++++++++++++++++++++++++--
 Components/OPL2/OPL2.hpp |  9 +++++++++
 2 files changed, 33 insertions(+), 2 deletions(-)

diff --git a/Components/OPL2/OPL2.cpp b/Components/OPL2/OPL2.cpp
index 3c60d634f..7ed5765c3 100644
--- a/Components/OPL2/OPL2.cpp
+++ b/Components/OPL2/OPL2.cpp
@@ -36,7 +36,7 @@ namespace {
 			Registers 4 and 5, i.e. decay and attack rate, modulator and carrier.
 
 		Bytes 7, 8:
-			Registers 6 and 6, i.e. decay-sustain level and release rate, modulator and carrier.
+			Registers 6 and 7, i.e. decay-sustain level and release rate, modulator and carrier.
 
 */
 
@@ -134,6 +134,16 @@ uint8_t OPL2::read(uint16_t address) {
 void OPL2::set_opl2_register(uint8_t location, uint8_t value) {
 	printf("OPL2 write: %02x to %d\n", value, selected_register_);
 
+	// Deal with timer changes synchronously.
+	switch(location) {
+		case 0x02:	timers_[0] = value; 	return;
+		case 0x03:	timers_[1] = value;		return;
+		case 0x04:	timer_control_ = value;	return;
+
+		default: break;
+	}
+
+	// Enqueue any changes that affect audio output.
 	task_queue_.enqueue([this, location, value] {
 
 		//
@@ -149,7 +159,7 @@ void OPL2::set_opl2_register(uint8_t location, uint8_t value) {
 			return;
 		}
 
-		if(location >= 0x50 && location <= 0x55) {
+		if(location >= 0x40 && location <= 0x55) {
 			operators_[location - 0x40].scaling_level = value >> 6;
 			operators_[location - 0x40].output_level = value & 0x3f;
 			return;
@@ -194,5 +204,17 @@ void OPL2::set_opl2_register(uint8_t location, uint8_t value) {
 			channels_[location - 0xc0].two_operator = value & 1;
 			return;
 		}
+
+
+		//
+		// Modal modifications.
+		//
+		switch(location) {
+			case 0x01:	waveform_enable_ = value & 0x20;	break;
+			case 0x08:	csm_keyboard_split_ = value;		break;
+			case 0xbd:	depth_rhythm_control_ = value;		break;
+
+			default: break;
+		}
 	});
 }
diff --git a/Components/OPL2/OPL2.hpp b/Components/OPL2/OPL2.hpp
index 563a605a5..ced242df6 100644
--- a/Components/OPL2/OPL2.hpp
+++ b/Components/OPL2/OPL2.hpp
@@ -50,6 +50,7 @@ class OPL2: public ::Outputs::Speaker::SampleSource {
 
 		void set_opl2_register(uint8_t location, uint8_t value);
 
+		// Asynchronous properties, valid only on the audio thread.
 		struct Operator {
 			bool apply_amplitude_modulation = false;
 			bool apply_vibrato = false;
@@ -72,6 +73,14 @@ class OPL2: public ::Outputs::Speaker::SampleSource {
 			int feedback_strength;
 			bool two_operator;
 		} channels_[9];
+
+		uint8_t depth_rhythm_control_;
+		uint8_t csm_keyboard_split_;
+		bool waveform_enable_;
+
+		// Synchronous properties, valid only on the emulation thread.
+		uint8_t timers_[2];
+		uint8_t timer_control_;
 };
 
 }