From 4744ee327acffc6e3ecbaa7f35b0520c5037e3e2 Mon Sep 17 00:00:00 2001
From: thereallaxity <thomas.egeskov.petersen@gmail.com>
Date: Fri, 20 Jan 2023 23:52:49 +0100
Subject: [PATCH 01/13] [major] Implemented real time SID registers
 visualization (pulse and filter values).

Additionally:

* Made it possible for components to not receive focus
* Added user colors for visualization bars
* Updated default color scheme
---
 SIDFactoryII/SIDFactoryII.vcxproj             |   6 +
 SIDFactoryII/color_schemes/default.ini        |   8 ++
 .../editor/components/component_base.cpp      |   5 +
 .../editor/components/component_base.h        |   1 +
 .../components/component_list_selector.cpp    |  34 +++--
 .../components/component_list_selector.h      |   2 +
 .../component_pulse_filter_visualizer.cpp     |  89 ++++++++++++
 .../component_pulse_filter_visualizer.h       |  66 +++++++++
 .../runtime/editor/components_manager.cpp     |   8 +-
 .../datasources/datasource_flightrecorder.cpp |   8 ++
 .../datasources/datasource_flightrecorder.h   |   1 +
 .../datasource_sidregistersbuffer.cpp         |  40 ++++++
 .../datasource_sidregistersbuffer.h           |  25 ++++
 .../runtime/editor/screens/screen_edit.cpp    |  24 +++-
 .../runtime/editor/screens/screen_edit.h      |   5 +-
 ...isualizer_component_pulse_filter_state.cpp | 130 ++++++++++++++++++
 .../visualizer_component_pulse_filter_state.h |  35 +++++
 .../source/runtime/emulation/sid/sidproxy.cpp |  21 ---
 .../runtime/execution/executionhandler.cpp    |   7 +
 .../runtime/execution/executionhandler.h      |  12 ++
 .../runtime/execution/flightrecorder.cpp      |  17 ++-
 .../source/runtime/execution/flightrecorder.h |   8 +-
 .../source/utils/config/configcolors.cpp      |   7 +
 SIDFactoryII/source/utils/usercolors.h        |   5 +
 24 files changed, 512 insertions(+), 52 deletions(-)
 create mode 100644 SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
 create mode 100644 SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h
 create mode 100644 SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.cpp
 create mode 100644 SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.h
 create mode 100644 SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
 create mode 100644 SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h

diff --git a/SIDFactoryII/SIDFactoryII.vcxproj b/SIDFactoryII/SIDFactoryII.vcxproj
index cd94eb77..36e1ddc3 100644
--- a/SIDFactoryII/SIDFactoryII.vcxproj
+++ b/SIDFactoryII/SIDFactoryII.vcxproj
@@ -195,6 +195,7 @@
     <ClCompile Include="source\runtime\editor\components\component_list_selector.cpp" />
     <ClCompile Include="source\runtime\editor\components\component_memory_view.cpp" />
     <ClCompile Include="source\runtime\editor\components\component_orderlistoverview.cpp" />
+    <ClCompile Include="source\runtime\editor\components\component_pulse_filter_visualizer.cpp" />
     <ClCompile Include="source\runtime\editor\components\component_string_list_selector.cpp" />
     <ClCompile Include="source\runtime\editor\components\component_table_row_elements_with_text.cpp" />
     <ClCompile Include="source\runtime\editor\components\component_console.cpp" />
@@ -232,6 +233,7 @@
     <ClCompile Include="source\runtime\editor\datasources\datasource_orderlist.cpp" />
     <ClCompile Include="source\runtime\editor\datasources\datasource_play_markers.cpp" />
     <ClCompile Include="source\runtime\editor\datasources\datasource_sequence.cpp" />
+    <ClCompile Include="source\runtime\editor\datasources\datasource_sidregistersbuffer.cpp" />
     <ClCompile Include="source\runtime\editor\datasources\datasource_table.cpp" />
     <ClCompile Include="source\runtime\editor\datasources\datasource_table_column_major.cpp" />
     <ClCompile Include="source\runtime\editor\datasources\datasource_table_memory_view.cpp" />
@@ -283,6 +285,7 @@
     <ClCompile Include="source\runtime\editor\utilities\editor_utils.cpp" />
     <ClCompile Include="source\runtime\editor\utilities\import_utils.cpp" />
     <ClCompile Include="source\runtime\editor\visualizer_components\visualizer_component_base.cpp" />
+    <ClCompile Include="source\runtime\editor\visualizer_components\visualizer_component_pulse_filter_state.cpp" />
     <ClCompile Include="source\runtime\editor\visualizer_components\vizualizer_component_emulation_state.cpp" />
     <ClCompile Include="source\runtime\emulation\cpuframecapture.cpp" />
     <ClCompile Include="source\runtime\emulation\cpumemory.cpp" />
@@ -373,6 +376,7 @@
     <ClInclude Include="source\runtime\editor\components\component_list_selector.h" />
     <ClInclude Include="source\runtime\editor\components\component_memory_view.h" />
     <ClInclude Include="source\runtime\editor\components\component_orderlistoverview.h" />
+    <ClInclude Include="source\runtime\editor\components\component_pulse_filter_visualizer.h" />
     <ClInclude Include="source\runtime\editor\components\component_string_list_selector.h" />
     <ClInclude Include="source\runtime\editor\components\component_table_row_elements_with_text.h" />
     <ClInclude Include="source\runtime\editor\components\component_console.h" />
@@ -410,6 +414,7 @@
     <ClInclude Include="source\runtime\editor\datasources\datasource_orderlist.h" />
     <ClInclude Include="source\runtime\editor\datasources\datasource_play_markers.h" />
     <ClInclude Include="source\runtime\editor\datasources\datasource_sequence.h" />
+    <ClInclude Include="source\runtime\editor\datasources\datasource_sidregistersbuffer.h" />
     <ClInclude Include="source\runtime\editor\datasources\datasource_table_column_major.h" />
     <ClInclude Include="source\runtime\editor\datasources\datasource_table_memory_view.h" />
     <ClInclude Include="source\runtime\editor\datasources\datasource_table_row_major.h" />
@@ -471,6 +476,7 @@
     <ClInclude Include="source\runtime\editor\utilities\editor_utils.h" />
     <ClInclude Include="source\runtime\editor\utilities\import_utils.h" />
     <ClInclude Include="source\runtime\editor\visualizer_components\visualizer_component_base.h" />
+    <ClInclude Include="source\runtime\editor\visualizer_components\visualizer_component_pulse_filter_state.h" />
     <ClInclude Include="source\runtime\editor\visualizer_components\vizualizer_component_emulation_state.h" />
     <ClInclude Include="source\runtime\emulation\cpuframecapture.h" />
     <ClInclude Include="source\runtime\emulation\cpumemory.h" />
diff --git a/SIDFactoryII/color_schemes/default.ini b/SIDFactoryII/color_schemes/default.ini
index fa41133e..e6d19d4d 100644
--- a/SIDFactoryII/color_schemes/default.ini
+++ b/SIDFactoryII/color_schemes/default.ini
@@ -25,6 +25,7 @@ DarkerGreen 	= 0x004800
 DarkerBlue 		= 0x000060		
 DarkerYellow 	= 0x4c4c00
 DarkestBlue		= 0x000038
+DarkestGrey		= 0x101010
 
 
 Color.Table.Default 											= :LightGrey
@@ -108,6 +109,13 @@ Color.Orderlist.End.Stop										= :White
 Color.Orderlist.Value											= :LightGrey
 Color.Orderlist.Value.Loop.Marker								= :LightGreen
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :DarkestGrey
+Color.StateBar.Bar.Background									= :DarkerGrey
+Color.StateBar.Bar.BackgroundFilteredChannel					= :DarkGrey
+Color.StateBar.Bar.FillColorPulse								= :White
+Color.StateBar.Bar.FillColorFilter								= :LightGrey
+
 Color.Dialog.Background                 						= :DarkRed
 Color.Dialog.Header                     						= :Red
 Color.Dialog.Header.Text										= :White		
diff --git a/SIDFactoryII/source/runtime/editor/components/component_base.cpp b/SIDFactoryII/source/runtime/editor/components/component_base.cpp
index 110a4bd3..5655d823 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_base.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_base.cpp
@@ -90,6 +90,11 @@ namespace Editor
 
 	//----------------------------------------------------------------------------------------------------------------------------------------
 
+	bool ComponentBase::CanReceiveFocus() const
+	{
+		return true;
+	}
+
 	bool ComponentBase::MayTabOutOfFocus(bool inForward) const
 	{
 		return true;
diff --git a/SIDFactoryII/source/runtime/editor/components/component_base.h b/SIDFactoryII/source/runtime/editor/components/component_base.h
index 4f598eb3..9eaf863f 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_base.h
+++ b/SIDFactoryII/source/runtime/editor/components/component_base.h
@@ -52,6 +52,7 @@ namespace Editor
 
 		virtual bool HasDataChange() const;
 
+		virtual bool CanReceiveFocus() const;
 		virtual bool MayTabOutOfFocus(bool inForward) const;
 		virtual bool IsNoteInputSilenced() const;
 		virtual bool IsFastForwardAllowed() const;
diff --git a/SIDFactoryII/source/runtime/editor/components/component_list_selector.cpp b/SIDFactoryII/source/runtime/editor/components/component_list_selector.cpp
index 08708697..4719c820 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_list_selector.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_list_selector.cpp
@@ -213,6 +213,7 @@ namespace Editor
 	void ComponentListSelector::SetSelectionIndex(int inSelectionIndex)
 	{
 		m_CursorPos = inSelectionIndex;
+		AdjustTopVisibleToSelected();
 		m_RequireRefresh = true;
 	}
 
@@ -285,9 +286,7 @@ namespace Editor
 		if (m_CursorPos < m_DataSource->GetSize() - 1)
 		{
 			++m_CursorPos;
-
-			if (m_CursorPos >= m_TopVisibleIndex + m_ContentHeight)
-				m_TopVisibleIndex = m_CursorPos - m_ContentHeight + 1;
+			AdjustTopVisibleToSelected();
 		}
 	}
 
@@ -297,9 +296,7 @@ namespace Editor
 		if (m_CursorPos > 0)
 		{
 			--m_CursorPos;
-
-			if (m_TopVisibleIndex > m_CursorPos)
-				m_TopVisibleIndex = m_CursorPos;
+			AdjustTopVisibleToSelected();
 		}
 	}
 
@@ -314,9 +311,7 @@ namespace Editor
 		if (m_CursorPos != new_cursor_pos)
 		{
 			m_CursorPos = new_cursor_pos;
-
-			if (m_CursorPos >= m_TopVisibleIndex + m_ContentHeight)
-				m_TopVisibleIndex = m_CursorPos - m_ContentHeight + 1;
+			AdjustTopVisibleToSelected();
 		}
 	}
 
@@ -331,9 +326,7 @@ namespace Editor
 		if (m_CursorPos != new_cursor_pos)
 		{
 			m_CursorPos = new_cursor_pos;
-
-			if (m_TopVisibleIndex > m_CursorPos)
-				m_TopVisibleIndex = m_CursorPos;
+			AdjustTopVisibleToSelected();
 		}
 	}
 
@@ -343,9 +336,7 @@ namespace Editor
 		if (m_CursorPos != 0)
 		{
 			m_CursorPos = 0;
-
-			if (m_TopVisibleIndex > m_CursorPos)
-				m_TopVisibleIndex = m_CursorPos;
+			AdjustTopVisibleToSelected();
 		}
 	}
 
@@ -357,13 +348,20 @@ namespace Editor
 		if (m_CursorPos != new_cursor_pos)
 		{
 			m_CursorPos = new_cursor_pos;
-
-			if (m_CursorPos >= m_TopVisibleIndex + m_ContentHeight)
-				m_TopVisibleIndex = m_CursorPos - m_ContentHeight + 1;
+			AdjustTopVisibleToSelected();
 		}
 	}
 
 
+	void ComponentListSelector::AdjustTopVisibleToSelected()
+	{
+		if (m_CursorPos >= m_TopVisibleIndex + m_ContentHeight)
+			m_TopVisibleIndex = m_CursorPos - m_ContentHeight + 1;
+		if (m_TopVisibleIndex > m_CursorPos)
+			m_TopVisibleIndex = m_CursorPos;
+	}
+
+
 
 	std::string ComponentListSelector::CondenseString(const std::string& inString, const char* inPostFix, int inMaxLength) const
 	{
diff --git a/SIDFactoryII/source/runtime/editor/components/component_list_selector.h b/SIDFactoryII/source/runtime/editor/components/component_list_selector.h
index 6e66b750..9145227c 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_list_selector.h
+++ b/SIDFactoryII/source/runtime/editor/components/component_list_selector.h
@@ -51,6 +51,8 @@ namespace Editor
 		void DoPageHome();
 		void DoPageEnd();
 
+		void AdjustTopVisibleToSelected();
+
 		std::string CondenseString(const std::string& inString, const char* inPostFix, int inMaxLength) const;
 
 		Foundation::Color m_TextColor;
diff --git a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
new file mode 100644
index 00000000..25b7c4cf
--- /dev/null
+++ b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
@@ -0,0 +1,89 @@
+#include "runtime/editor/components/component_pulse_filter_visualizer.h"
+
+#include "foundation/graphics/drawfield.h"
+#include "foundation/graphics/textfield.h"
+#include "foundation/graphics/viewport.h"
+#include "runtime/editor/components_manager.h"
+#include "runtime/editor/datasources/datasource_sidregistersbuffer.h"
+#include "runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h"
+#include "runtime/execution/executionhandler.h"
+
+namespace Editor
+{
+	ComponentPulseFilterVisualizer::ComponentPulseFilterVisualizer(
+		int inID, 
+		int inGroupID, 
+		Undo* inUndo,
+		Emulation::ExecutionHandler* inExecutionHandler, 
+		Foundation::TextField* inTextField,
+		Foundation::Viewport* inViewport,
+		ComponentsManager* inComponentsManager,
+		int inX, 
+		int inY, 
+		int inWidth,
+		int inHeight
+	)
+		: ComponentBase(inID, inGroupID, inUndo, inTextField, inX, inY, inWidth, inHeight)
+		, m_Viewport(inViewport)
+		, m_ComponentsManager(inComponentsManager)
+	{
+		unsigned int viewport_width = inWidth * Foundation::TextField::font_width;
+		unsigned int viewport_height = inHeight * Foundation::TextField::font_height;
+		
+		m_DrawField = m_Viewport->CreateDrawField(viewport_width, viewport_height, inX * Foundation::TextField::font_width, inY * Foundation::TextField::font_height);
+		m_DrawField->SetEnable(true);
+
+		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> data_source_sid_registers_buffer = std::make_shared<DataSourceSIDRegistersBufferAfLastDriverUpdate>(inExecutionHandler);
+		
+		m_VisualizerComponent = std::make_shared<VisualizerComponentPulseFilterState>(1, m_DrawField, 0, 0, viewport_width, viewport_height, data_source_sid_registers_buffer);
+		m_VisualizerComponent->SetEnabled(true);
+		m_ComponentsManager->AddVisualizerComponent(m_VisualizerComponent);
+	}
+
+	ComponentPulseFilterVisualizer::~ComponentPulseFilterVisualizer()
+	{
+		m_Viewport->Destroy(m_DrawField);
+	}
+
+
+	bool ComponentPulseFilterVisualizer::ConsumeInput(const Foundation::Keyboard& inKeyboard, CursorControl& inCursorControl, ComponentsManager& inComponentsManager)
+	{
+		return false;
+	}
+
+	bool ComponentPulseFilterVisualizer::ConsumeInput(const Foundation::Mouse& inMouse, bool inModifierKeyMask, CursorControl& inCursorControl, ComponentsManager& inComponentsManager)
+	{
+		return false;
+	}
+
+	bool ComponentPulseFilterVisualizer::ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse)
+	{
+		return false;
+	}
+
+	void ComponentPulseFilterVisualizer::Refresh(const DisplayState& inDisplayState)
+	{
+		
+	}
+
+	void ComponentPulseFilterVisualizer::HandleDataChange()
+	{
+		
+	}
+
+	void ComponentPulseFilterVisualizer::PullDataFromSource(const bool inFromUndo)
+	{
+		
+	}
+
+	void ComponentPulseFilterVisualizer::ExecuteInsertDeleteRule(const DriverInfo::TableInsertDeleteRule& inRule, int inSourceTableID, int inIndexPre, int inIndexPost)
+	{
+		
+	}
+
+	void ComponentPulseFilterVisualizer::ExecuteAction(int inActionInput)
+	{
+		
+	}
+
+}
diff --git a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h
new file mode 100644
index 00000000..32ee3c8c
--- /dev/null
+++ b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h
@@ -0,0 +1,66 @@
+#pragma once
+#include "component_base.h"
+
+namespace Emulation {
+	class ExecutionHandler;
+}
+
+namespace Editor
+{
+	class DataSourceFlightRecorder;
+	class VisualizerComponentPulseFilterState;
+}
+
+namespace Foundation {
+	class DrawField;
+}
+
+namespace Foundation
+{
+	class Viewport;
+}
+
+namespace Editor
+{
+	class ComponentPulseFilterVisualizer : public ComponentBase
+	{
+	public:
+		ComponentPulseFilterVisualizer(
+			int inID, 
+			int inGroupID, 
+			Undo* inUndo,
+			Emulation::ExecutionHandler* inExecutionHandler, 
+			Foundation::TextField* inTextField,
+			Foundation::Viewport* inViewport,
+			ComponentsManager* inComponentsManager,
+			int inX, 
+			int inY, 
+			int inWidth,
+			int inHeight
+		);
+		virtual ~ComponentPulseFilterVisualizer();
+
+		bool CanReceiveFocus() const override { return false; }
+		
+		bool ConsumeInput(const Foundation::Keyboard& inKeyboard, CursorControl& inCursorControl, ComponentsManager& inComponentsManager) override;
+		bool ConsumeInput(const Foundation::Mouse& inMouse, bool inModifierKeyMask, CursorControl& inCursorControl, ComponentsManager& inComponentsManager) override;
+		bool ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse) override;
+
+		void Refresh(const DisplayState& inDisplayState) override;
+		void HandleDataChange() override;
+		void PullDataFromSource(const bool inFromUndo) override;
+
+		void ExecuteInsertDeleteRule(const DriverInfo::TableInsertDeleteRule& inRule, int inSourceTableID, int inIndexPre, int inIndexPost) override;
+		void ExecuteAction(int inActionInput) override;
+
+	private:
+		Foundation::Viewport* m_Viewport;
+		Foundation::DrawField* m_DrawField;
+		
+		ComponentsManager* m_ComponentsManager;
+
+		Emulation::ExecutionHandler* m_ExecutionHandler;
+
+		std::shared_ptr<VisualizerComponentPulseFilterState> m_VisualizerComponent;
+	};
+}
diff --git a/SIDFactoryII/source/runtime/editor/components_manager.cpp b/SIDFactoryII/source/runtime/editor/components_manager.cpp
index d0bef19a..b74a99d3 100644
--- a/SIDFactoryII/source/runtime/editor/components_manager.cpp
+++ b/SIDFactoryII/source/runtime/editor/components_manager.cpp
@@ -369,7 +369,7 @@ namespace Editor
 			{
 				ComponentBase* component = GetComponentAt(inMouse.GetPosition());
 
-				if (component != nullptr)
+				if (component != nullptr && component->CanReceiveFocus())
 				{
 					if (component != m_FocusComponent)
 						SetComponentInFocus(component);
@@ -464,7 +464,7 @@ namespace Editor
 
 	void ComponentsManager::SetComponentInFocus(ComponentBase* inFocusComponent)
 	{
-		if (m_FocusComponent != inFocusComponent)
+		if (m_FocusComponent != inFocusComponent && (inFocusComponent == nullptr || inFocusComponent->CanReceiveFocus()))
 		{
 			if (m_FocusComponent != nullptr)
 				m_FocusComponent->ClearHasControl(*m_CursorControl);
@@ -532,7 +532,7 @@ namespace Editor
 
 		while (next_candidate != nullptr && next_candidate != m_FocusComponent)
 		{
-			if (IsTabGroupEnabled(next_candidate->GetComponentGroupID()))
+			if (IsTabGroupEnabled(next_candidate->GetComponentGroupID()) && next_candidate->CanReceiveFocus())
 			{
 				SetComponentInFocusByTabbing(next_candidate, true);
 				return;
@@ -549,7 +549,7 @@ namespace Editor
 
 		while (next_candidate != nullptr && next_candidate != m_FocusComponent)
 		{
-			if (IsTabGroupEnabled(next_candidate->GetComponentGroupID()))
+			if (IsTabGroupEnabled(next_candidate->GetComponentGroupID())  && next_candidate->CanReceiveFocus())
 			{
 				SetComponentInFocusByTabbing(next_candidate, false);
 				return;
diff --git a/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.cpp b/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.cpp
index 6d31bf80..dc733020 100644
--- a/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.cpp
+++ b/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.cpp
@@ -38,6 +38,14 @@ namespace Editor
 		return m_FlightRecorder->GetFrame(inIndex);
 	}
 
+	const Emulation::FlightRecorder::Frame& DataSourceFlightRecorder::GetMostRecentFrame() const
+	{
+		FOUNDATION_ASSERT(m_FlightRecorder != nullptr);
+		FOUNDATION_ASSERT(m_FlightRecorder->GetCapacity() > 0);
+
+		return m_FlightRecorder->GetNewestFrame();
+	}
+
 
 	const bool DataSourceFlightRecorder::IsRecording() const
 	{
diff --git a/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.h b/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.h
index 346dc2c2..7d6268ea 100644
--- a/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.h
+++ b/SIDFactoryII/source/runtime/editor/datasources/datasource_flightrecorder.h
@@ -15,6 +15,7 @@ namespace Editor
 		void Unlock();
 
 		const Emulation::FlightRecorder::Frame& operator [](unsigned int inIndex) const;
+		const Emulation::FlightRecorder::Frame& GetMostRecentFrame() const;
 		const int GetSize() const override;
 		const bool IsRecording() const;
 		const unsigned int GetNewestRecordingIndex() const;
diff --git a/SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.cpp b/SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.cpp
new file mode 100644
index 00000000..91397064
--- /dev/null
+++ b/SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.cpp
@@ -0,0 +1,40 @@
+#include "datasource_sidregistersbuffer.h"
+#include "foundation/base/assert.h"
+
+namespace Editor
+{
+	DataSourceSIDRegistersBufferAfLastDriverUpdate::DataSourceSIDRegistersBufferAfLastDriverUpdate(Emulation::ExecutionHandler* inExecutionHandler)
+		: m_ExecutionHandler(inExecutionHandler)
+	{
+
+	}
+
+
+	DataSourceSIDRegistersBufferAfLastDriverUpdate::~DataSourceSIDRegistersBufferAfLastDriverUpdate()
+	{
+
+	}
+
+
+	const unsigned char DataSourceSIDRegistersBufferAfLastDriverUpdate::operator [](unsigned int inIndex) const
+	{
+		FOUNDATION_ASSERT(inIndex < sizeof(m_SIDRegistersBuffer.m_Buffer));
+
+		return m_SIDRegistersBuffer.m_Buffer[inIndex];
+	}
+
+	const int DataSourceSIDRegistersBufferAfLastDriverUpdate::GetSize() const
+	{
+		return static_cast<int>(sizeof(m_SIDRegistersBuffer.m_Buffer));
+	}
+
+	void DataSourceSIDRegistersBufferAfLastDriverUpdate::PullDataFromSource()
+	{
+		FOUNDATION_ASSERT(m_ExecutionHandler != nullptr);
+		
+		m_ExecutionHandler->Lock();
+		m_SIDRegistersBuffer = m_ExecutionHandler->GetSIDRegistersBufferAfterLastDriverUpdate();
+		m_ExecutionHandler->Unlock();
+	}
+}
+
diff --git a/SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.h b/SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.h
new file mode 100644
index 00000000..6b4e37f8
--- /dev/null
+++ b/SIDFactoryII/source/runtime/editor/datasources/datasource_sidregistersbuffer.h
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "idatasource.h"
+#include "runtime/execution/executionhandler.h"
+#include "runtime/execution/flightrecorder.h"
+
+namespace Editor
+{
+	class DataSourceSIDRegistersBufferAfLastDriverUpdate : public IDataSource
+	{
+	public:
+		DataSourceSIDRegistersBufferAfLastDriverUpdate(Emulation::ExecutionHandler* inExecutionHandler);
+		virtual ~DataSourceSIDRegistersBufferAfLastDriverUpdate();
+		
+		const unsigned char operator [](unsigned int inIndex) const;
+		const int GetSize() const override;
+
+		bool PushDataToSource() override { return true; }
+		void PullDataFromSource();
+
+	protected:
+		Emulation::ExecutionHandler* m_ExecutionHandler;
+		Emulation::ExecutionHandler::SIDRegistersBuffer m_SIDRegistersBuffer;
+	};
+}
diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
index b2af035a..67153f2a 100644
--- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
+++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
@@ -59,6 +59,8 @@
 #include "SDL.h"
 #include <cctype>
 #include "foundation/base/assert.h"
+#include "runtime/editor/components/component_pulse_filter_visualizer.h"
+
 #include <algorithm>
 
 
@@ -71,6 +73,7 @@ namespace Editor
 	const unsigned char ScreenEdit::OrderListOverviewID = 0x40;
 	const unsigned char ScreenEdit::PlayMarkerListID = 41;
 	const unsigned char ScreenEdit::TracksTableID = 0x42;
+	const unsigned char ScreenEdit::PulseFilterVisualizerID = 0x43;
 
 	ScreenEdit::ScreenEdit(
 		Foundation::Viewport* inViewport,
@@ -1157,7 +1160,7 @@ namespace Editor
 
 		const int top = 2;
 		const int bottom = text_field_dimensions.m_Height - 1;
-		const int order_list_overview_bottom = bottom - (1 + AuxilaryDataPlayMarkers::MaxPlayMarkers);
+		const int order_list_overview_bottom = bottom - (2 + AuxilaryDataPlayMarkers::MaxPlayMarkers);
 		const int player_markers_list_top = order_list_overview_bottom + 1;
 
 		// Create orderlist overview component
@@ -1193,6 +1196,7 @@ namespace Editor
 
 		// Play markers component
 		const int play_markers_width = orderlist_overview_rect.m_Dimensions.m_Width;
+		const int play_markers_height = 4;
 		auto play_markers_data_source = std::make_shared<DataSourcePlayMarkers>(m_DriverInfo->GetAuxilaryDataCollection().GetPlayMarkers(), m_DriverInfo->GetAuxilaryDataCollection().GetSongs(), m_DisplayState);
 
 		m_PlayMarkerListComponent = std::make_shared<ComponentStringListSelector>(
@@ -1203,7 +1207,7 @@ namespace Editor
 			1, 
 			player_markers_list_top, 
 			play_markers_width, 
-			bottom - player_markers_list_top, 
+			play_markers_height, 
 			1, 
 			0
 		);
@@ -1218,6 +1222,22 @@ namespace Editor
 		});
 		m_ComponentsManager->AddComponent(m_PlayMarkerListComponent);
 
+		// Create pulse/filter visualizer component
+		const int pulse_filter_visualzer_top = player_markers_list_top + play_markers_height + 1;
+		auto pulse_filter_visualizer = std::make_shared<ComponentPulseFilterVisualizer>(
+			PulseFilterVisualizerID, 0,
+			undo,
+			m_ExecutionHandler,
+			m_MainTextField,
+			m_Viewport,
+			m_ComponentsManager.get(),
+			1,
+			pulse_filter_visualzer_top,
+			play_markers_width,
+			4);
+
+		m_ComponentsManager->AddComponent(pulse_filter_visualizer);
+
 		// Create the tracks component for editing orderlist and sequence data
 		m_TracksComponent = std::make_shared<ComponentTracks>(
 			TracksTableID, 0, 
diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.h b/SIDFactoryII/source/runtime/editor/screens/screen_edit.h
index 972081cd..316b7986 100644
--- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.h
+++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.h
@@ -63,9 +63,10 @@ namespace Editor
 		};
 
 	public:
-        static const unsigned char OrderListOverviewID;
+		static const unsigned char OrderListOverviewID;
 		static const unsigned char PlayMarkerListID;
-        static const unsigned char TracksTableID;
+		static const unsigned char TracksTableID;
+		static const unsigned char PulseFilterVisualizerID;
 
 		ScreenEdit(
 			Foundation::Viewport* inViewport, 
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
new file mode 100644
index 00000000..96d7b469
--- /dev/null
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -0,0 +1,130 @@
+#include "visualizer_component_pulse_filter_state.h"
+
+#include "foundation/graphics/drawfield.h"
+#include "runtime/editor/components/component_file_selector.h"
+#include "runtime/editor/datasources/datasource_sidregistersbuffer.h"
+#include "runtime/execution/executionhandler.h"
+#include "runtime/execution/flightrecorder.h"
+#include "utils/usercolors.h"
+
+using namespace Foundation;
+using namespace Utility;
+
+namespace Editor
+{
+	VisualizerComponentPulseFilterState::VisualizerComponentPulseFilterState
+	(
+		int inID,
+		Foundation::DrawField* inDrawField,
+		int inX,
+		int inY,
+		int inWidth,
+		int inHeight,
+		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource
+	)
+		: VisualizerComponentBase(inID, inDrawField, inX, inY, inWidth, inHeight)
+		, m_DataSource(inDataSource)
+	{
+	}
+
+
+	VisualizerComponentPulseFilterState::~VisualizerComponentPulseFilterState()
+	{
+	}
+
+
+	bool VisualizerComponentPulseFilterState::ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse)
+	{
+		return false;
+	}
+
+
+	void VisualizerComponentPulseFilterState::Refresh(const DisplayState& inDisplayState)
+	{
+		if (m_Enabled)
+		{
+			const Color color_background = ToColor(UserColor::StateBarArea);
+			const Color color_bar = ToColor(UserColor::StateBarBackground);
+			const Color color_bar_filtered_channel = ToColor(UserColor::StateBarBackgroundFilteredChannel);
+			const Color color_bar_fill = ToColor(UserColor::StateBarFillColorPulse);
+			const Color color_bar_fill_filter = ToColor(UserColor::StateBarFillColorFilter);
+
+			m_DataSource->PullDataFromSource();
+			
+			m_DrawField->DrawBox(color_background, 0, 0, m_Dimensions.m_Width, m_Dimensions.m_Height);
+
+			const int bar_width = m_Dimensions.m_Width - 4;
+			const int bar_height = 12;
+			const int bar_spacing = 16;
+
+			int bar_x = 2;
+			int bar_y = 2;
+
+			const auto& data_source = *m_DataSource;
+				
+			const auto get_pulse_value = [&data_source](unsigned int inChannel) -> unsigned short
+			{
+				if(inChannel > 2)
+					return 0;
+				
+				const unsigned int offset = inChannel * 7;
+				
+				const unsigned short pulse_high = data_source[offset + 3] & 0x0f;
+				const unsigned short pulse_low = data_source[offset + 2];
+
+				const unsigned short value = (pulse_high << 8) | pulse_low; 
+				
+				return value;
+			};
+
+			const auto is_channel_filtered = [&data_source](unsigned int inChannel) -> bool
+			{
+				if(inChannel > 2)
+					return false;
+
+				return (data_source[0x17] & (1 << inChannel)) != 0;
+			};
+
+			for(unsigned int i = 0; i < 3; ++i)
+			{
+				DrawBar(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill);
+				bar_y += bar_spacing;
+			}
+
+			const auto get_filter_value = [&data_source]() -> unsigned short
+			{
+				const unsigned short filter_high = data_source[0x16];
+				const unsigned short filter_low = data_source[0x15] & 7;
+
+				const unsigned short value = (filter_high << 3) | filter_low;
+				
+				return value;
+			};
+
+			DrawBar(bar_x, bar_y, bar_width, bar_height, get_filter_value(), 0x07ff, color_bar, color_bar_fill_filter);
+		}
+	}
+
+
+	void VisualizerComponentPulseFilterState::DrawBar(
+		int inX,
+		int inY,
+		int inWidth,
+		int inHeight,
+		int inValue,
+		int inMaxValue,
+		const Foundation::Color& inBarColor,
+		const Foundation::Color& inBarColorFill)
+	{
+		m_DrawField->DrawBox(inBarColor, inX, inY, inWidth, inHeight);
+
+		if(inValue > 0)
+		{
+			float width_fraction = static_cast<float>(inValue) / static_cast<float>(inMaxValue);
+			int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
+
+			m_DrawField->DrawBox(inBarColorFill, inX, inY + 1, width, inHeight - 2);
+		}
+	}
+
+}
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
new file mode 100644
index 00000000..1357ab16
--- /dev/null
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "visualizer_component_base.h"
+
+namespace Foundation
+{
+	enum class Color : unsigned short;
+}
+
+namespace Editor
+{
+	class DataSourceSIDRegistersBufferAfLastDriverUpdate;
+
+	class VisualizerComponentPulseFilterState : public VisualizerComponentBase
+	{
+	public:
+		VisualizerComponentPulseFilterState(
+			int inID, 
+			Foundation::DrawField* inDrawField, 
+			int inX, 
+			int inY, 
+			int inWidth, 
+			int inHeight,
+			std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource
+		);
+		virtual ~VisualizerComponentPulseFilterState();
+
+		bool ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse) override;
+		void Refresh(const DisplayState& inDisplayState) override;
+
+	private:
+		void DrawBar(int inX, int inY, int inWidth, int inHeight, int inValue, int inMaxValue, const Foundation::Color& inBarColor, const Foundation::Color& inBarColorFill);
+		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> m_DataSource;
+	};
+}
\ No newline at end of file
diff --git a/SIDFactoryII/source/runtime/emulation/sid/sidproxy.cpp b/SIDFactoryII/source/runtime/emulation/sid/sidproxy.cpp
index bcb885da..655104fc 100644
--- a/SIDFactoryII/source/runtime/emulation/sid/sidproxy.cpp
+++ b/SIDFactoryII/source/runtime/emulation/sid/sidproxy.cpp
@@ -225,27 +225,6 @@ namespace Emulation
 		// Clock
 		int nSamplesWritten = m_pSID->clock(nInternalDeltaCycles, pBuffer/*nBufferSize*/);
 
-		// Overwrite with sine wave to test output consistency
-//		for (int i = 0; i < nSamplesWritten; ++i)
-//		{
-//			float r = (static_cast<float>(m_SampleCounter) * 2.0f * 3.1416f) / 25.0f;
-//			short v = static_cast<short>(std::sinf(r) * 65535.0f / 4.0f);
-		//
-//
-		//
-//
-		//
-//
-		//
-//
-		//
-//			pBuffer[i] = v;
-		//
-//
-		//
-		//			m_SampleCounter++;
-		//		}
-
 		if (IsRecordingToFile())
 		{
 			m_FileOutput.push_back(0);
diff --git a/SIDFactoryII/source/runtime/execution/executionhandler.cpp b/SIDFactoryII/source/runtime/execution/executionhandler.cpp
index 7b87022c..b71dbd1d 100644
--- a/SIDFactoryII/source/runtime/execution/executionhandler.cpp
+++ b/SIDFactoryII/source/runtime/execution/executionhandler.cpp
@@ -56,10 +56,14 @@ namespace Emulation
 		m_OutputGain = GetSingleConfigurationValue<Utility::Config::ConfigValueFloat>(Global::instance().GetConfig(), "Sound.Output.Gain", -1.0f);
 
 		Logging::instance().Info("Sound.Output.Gain = %f", m_OutputGain);
+
 		// Set default action vector
 		m_InitVector = 0x1000;
 		m_StopVector = 0x1003;
 		m_UpdateVector = 0x1006;
+
+		// Clear SID registers after last driver update
+		memset(m_SIDRegisterLastDriverUpdate.m_Buffer, 0, sizeof(m_SIDRegisterLastDriverUpdate.m_Buffer));
 	}
 
 	ExecutionHandler::~ExecutionHandler()
@@ -487,6 +491,9 @@ namespace Emulation
 			m_SIDRegisterFlightRecorder->Unlock();
 		}
 
+		// Copy sid registers after driver update
+		m_Memory->GetData(0xd400, m_SIDRegisterLastDriverUpdate.m_Buffer, sizeof(m_SIDRegisterLastDriverUpdate.m_Buffer));
+
 		// Unlock memory access
 		m_Memory->Unlock();
 
diff --git a/SIDFactoryII/source/runtime/execution/executionhandler.h b/SIDFactoryII/source/runtime/execution/executionhandler.h
index 1eeb5b81..bcf26e78 100644
--- a/SIDFactoryII/source/runtime/execution/executionhandler.h
+++ b/SIDFactoryII/source/runtime/execution/executionhandler.h
@@ -28,6 +28,11 @@ namespace Emulation
 	class ExecutionHandler : public Foundation::IAudioStreamFeeder
 	{
 	public:
+		struct SIDRegistersBuffer
+		{
+			unsigned char m_Buffer[0x200];
+		};
+		
 		ExecutionHandler(
 			CPUmos6510* pCPU,
 			CPUMemory* pMemory,
@@ -82,8 +87,12 @@ namespace Emulation
 		// Frame
 		unsigned int GetFrameCounter() const { return m_CPUFrameCounter; }
 
+		// Flight recorder
 		FlightRecorder* GetFlightRecorder() const { return m_SIDRegisterFlightRecorder; }
 
+		// SID registers buffer
+		SIDRegistersBuffer GetSIDRegistersBufferAfterLastDriverUpdate() const { return m_SIDRegisterLastDriverUpdate; }
+
 		// Write output to file
 		void StartWriteOutputToFile(const std::string& inFilename);
 		void StopWriteOutputToFile();
@@ -154,6 +163,9 @@ namespace Emulation
 		// Flight recorder
 		FlightRecorder* m_SIDRegisterFlightRecorder;
 
+		// SID Registers last update
+		SIDRegistersBuffer m_SIDRegisterLastDriverUpdate;
+
 		// Audio output
 		unsigned int m_SampleBufferSize;
 		short* m_SampleBuffer;
diff --git a/SIDFactoryII/source/runtime/execution/flightrecorder.cpp b/SIDFactoryII/source/runtime/execution/flightrecorder.cpp
index e663aae6..4cfa9d16 100644
--- a/SIDFactoryII/source/runtime/execution/flightrecorder.cpp
+++ b/SIDFactoryII/source/runtime/execution/flightrecorder.cpp
@@ -93,7 +93,11 @@ namespace Emulation
 			{
 				FOUNDATION_ASSERT(m_TopIndex == 0);
 
-				RecordFrame(inFrame, inMemory, inCyclesSpend, m_Frames[m_RecordedFrameCount]);
+				Frame& frame = m_Frames[m_RecordedFrameCount];
+				RecordFrame(inFrame, inMemory, inCyclesSpend, frame);
+
+				m_LastRecordedFrame = frame;
+
 				m_RecordedFrameCount++;
 			}
 			else
@@ -101,7 +105,11 @@ namespace Emulation
 				FOUNDATION_ASSERT(m_RecordedFrameCount == m_FrameCapacity);
 				FOUNDATION_ASSERT(m_TopIndex < m_FrameCapacity);
 
-				RecordFrame(inFrame, inMemory, inCyclesSpend, m_Frames[m_TopIndex]);
+				Frame& frame = m_Frames[m_TopIndex];
+				RecordFrame(inFrame, inMemory, inCyclesSpend, frame);
+
+				m_LastRecordedFrame = frame;
+				
 				m_TopIndex++;
 
 				if (m_TopIndex >= m_FrameCapacity)
@@ -132,6 +140,11 @@ namespace Emulation
 		return m_Frames[inIndex];
 	}
 
+	const FlightRecorder::Frame& FlightRecorder::GetNewestFrame() const
+	{
+		return m_LastRecordedFrame;	
+	}
+
 	//------------------------------------------------------------------------------------------------
 
 	void FlightRecorder::RecordFrame(unsigned int inFrame, CPUMemory* inMemory, unsigned int inCyclesSpend, Frame& inFrameData)
diff --git a/SIDFactoryII/source/runtime/execution/flightrecorder.h b/SIDFactoryII/source/runtime/execution/flightrecorder.h
index 44da1373..a26c687a 100644
--- a/SIDFactoryII/source/runtime/execution/flightrecorder.h
+++ b/SIDFactoryII/source/runtime/execution/flightrecorder.h
@@ -17,9 +17,9 @@ namespace Emulation
 	public:
 		struct Frame
 		{
-			unsigned int m_nFrameNumber;
-			unsigned int m_nCyclesSpend;
-			unsigned char m_TempoCounter;
+			unsigned int m_nFrameNumber = 0;
+			unsigned int m_nCyclesSpend = 0;
+			unsigned char m_TempoCounter = 0;
 			unsigned char m_DriverSync[3];
 			unsigned char m_SIDData[0x19];
 
@@ -53,6 +53,7 @@ namespace Emulation
 
 		unsigned int RecordedFrameCount() const;
 		const Frame& GetFrame(unsigned int inIndex) const;
+		const Frame& GetNewestFrame() const;
 
 		const unsigned int GetCapacity() const { return m_FrameCapacity; }
 
@@ -73,6 +74,7 @@ namespace Emulation
 
 		bool m_Locked;
 
+		Frame m_LastRecordedFrame;
 		Frame* m_Frames;
 	};
 }
diff --git a/SIDFactoryII/source/utils/config/configcolors.cpp b/SIDFactoryII/source/utils/config/configcolors.cpp
index f8d8e13c..986cfc1c 100644
--- a/SIDFactoryII/source/utils/config/configcolors.cpp
+++ b/SIDFactoryII/source/utils/config/configcolors.cpp
@@ -102,6 +102,13 @@ namespace Utility
 			Details::SetUserColor(inConfigFile, "Color.Orderlist.Value", UserColor::OrderlistValue, ioViewport, Color::LightGrey);
 			Details::SetUserColor(inConfigFile, "Color.Orderlist.Value.Loop.Marker", UserColor::OrderlistValueLoopMarker, ioViewport, Color::LightGreen);
 			Details::SetUserColor(inConfigFile, "Color.Orderlist.Value.Input", UserColor::OrderlistValueInput, ioViewport, Color::White);
+
+			Details::SetUserColor(inConfigFile, "Color.StateBar.Area", UserColor::StateBarArea, ioViewport, Color::DarkerGrey);
+			Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.Background", UserColor::StateBarBackground, ioViewport, Color::DarkGrey);
+      Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.BackgroundFilteredChannel", UserColor::StateBarBackgroundFilteredChannel, ioViewport, Color::Grey);
+      Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.FillColorPulse", UserColor::StateBarFillColorPulse, ioViewport, Color::White);
+      Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.FillColorFilter", UserColor::StateBarFillColorFilter, ioViewport, Color::LightGrey);
+
 			Details::SetUserColor(inConfigFile, "Color.Dialog.Background", UserColor::DialogBackground, ioViewport, Color::DarkRed);
 			Details::SetUserColor(inConfigFile, "Color.Dialog.Header", UserColor::DialogHeader, ioViewport, Color::Red);
 			Details::SetUserColor(inConfigFile, "Color.Dialog.Header.Text", UserColor::DialogHeaderText, ioViewport, Color::White);
diff --git a/SIDFactoryII/source/utils/usercolors.h b/SIDFactoryII/source/utils/usercolors.h
index 95bcab7e..2419cc4e 100644
--- a/SIDFactoryII/source/utils/usercolors.h
+++ b/SIDFactoryII/source/utils/usercolors.h
@@ -93,6 +93,11 @@ namespace Utility
 		OrderlistValue,
 		OrderlistValueLoopMarker,
 		OrderlistValueInput,
+		StateBarArea,
+		StateBarBackground,
+		StateBarBackgroundFilteredChannel,
+		StateBarFillColorPulse,
+		StateBarFillColorFilter,
 		DialogBackground,
 		DialogHeader,
 		DialogHeaderText,

From 592d0559b799dd145be4edef730441cb8cbe5373 Mon Sep 17 00:00:00 2001
From: rawpowerlaxity <thomas@rawpowergames.com>
Date: Wed, 7 Jun 2023 14:49:21 +0200
Subject: [PATCH 02/13] [minor] Adding visualization of pulse and filter
 [minor] Adding first iteration of highlighting the sequence index being
 selected in the song overview

---
 .../component_orderlistoverview.cpp           | 54 ++++++++++++++++---
 .../components/component_orderlistoverview.h  | 50 ++++++++++++++++-
 .../runtime/editor/driver/driver_utils.cpp    | 15 +++---
 .../runtime/editor/screens/screen_edit.cpp    |  8 +--
 .../runtime/editor/utilities/editor_utils.cpp |  4 +-
 .../runtime/editor/utilities/editor_utils.h   | 11 +++-
 .../visualizer_component_pulse_filter_state.h |  1 +
 7 files changed, 122 insertions(+), 21 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp b/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp
index 37d7f13a..ec424f9c 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp
@@ -45,6 +45,7 @@ namespace Editor
 		int inGroupID, 
 		Undo* inUndo,
 		TextField* inTextField,
+		const EditState& inEditState,
 		const Utility::KeyHookStore& inKeyHookStore,
 		std::shared_ptr<DataSourceTableText> inDataSourceTableText,
 		std::vector<std::shared_ptr<DataSourceOrderList>>& inOrderLists,
@@ -55,6 +56,7 @@ namespace Editor
 		std::function<void(int, bool)> inSetTrackEventPosFunction
 	)
 		: ComponentBase(inID, inGroupID, inUndo, inTextField, inX, inY, ComponentOrderListOverview::GetWidthFromChannelCount(static_cast<int>(inOrderLists.size())), inHeight)
+		, m_EditState(inEditState)
 		, m_TableText(inDataSourceTableText)
 		, m_OrderLists(inOrderLists)
 		, m_SequenceList(inSequenceList)
@@ -313,6 +315,12 @@ namespace Editor
 			}
 		}
 
+		if(consume)
+		{
+			if(UpdateHoveredSequence())
+				m_RequireRefresh = true;
+		}
+
 		if (m_TextEditingDataSourceTableText->RequireRefresh())
 		{
 			m_RequireRefresh = true;
@@ -340,6 +348,7 @@ namespace Editor
 				m_RequireRefresh = true;
 
 				consume = true;
+				UpdateHoveredSequence();
 			}
 			else if (inMouse.IsButtonPressed(Mouse::Left))
 			{
@@ -390,6 +399,8 @@ namespace Editor
 				}
 
 				consume = true;
+				UpdateHoveredSequence();
+
 			}
 		}
 		
@@ -477,10 +488,11 @@ namespace Editor
 			}
 
 			int local_y = 0;
-			int overview_list_size = static_cast<int>(m_Overview.size());
-
-			Color event_pos_values = ToColor(UserColor::SongListEventPos);
-
+			
+			const int overview_list_size = static_cast<int>(m_Overview.size());
+			const Color event_pos_values = ToColor(UserColor::SongListEventPos);
+			const int cursor_screen_y = cursor_position + m_Position.m_Y;
+			
 			for (int i = m_TopPosition; i < overview_list_size && local_y < m_Dimensions.m_Height; ++i)
 			{
 				OverviewEntry& entry = m_Overview[i];
@@ -504,8 +516,17 @@ namespace Editor
 					int sequence_index = sequence_entry.m_Index;
 					if (sequence_index >= 0)
 					{
-						const Color color = sequence_index < 0x100 ? ToColor(UserColor::SongListValues) : ToColor(UserColor::SongListLoopMarker);
-						m_TextField->PrintHexValue(x, y, color, is_uppercase, static_cast<unsigned char>(sequence_index & 0x0ff));
+						const unsigned char sequence_value = static_cast<unsigned char>(sequence_index & 0x0ff);
+
+						if(m_EditState.IsSequenceHighlightingEnabled() && m_HasControl && y != cursor_screen_y && m_HoveredSequenceValue.HasValue() && m_HoveredSequenceValue.GetValue() == sequence_value)
+						{
+							m_TextField->PrintHexValue(x, y, Color::Yellow, is_uppercase, sequence_value);
+						}
+						else
+						{
+							const Color color = sequence_index < 0x100 ? ToColor(UserColor::SongListValues) : ToColor(UserColor::SongListLoopMarker);
+							m_TextField->PrintHexValue(x, y, color, is_uppercase, sequence_value);
+						}
 					}
 
 					x += 3;
@@ -1172,6 +1193,27 @@ namespace Editor
 			m_CursorY = m_MaxCursorY;
 	}
 
+	bool ComponentOrderListOverview::UpdateHoveredSequence()
+	{
+		HoveredSequenceValue NewValue;
+
+		if(m_CursorY < static_cast<int>(m_Overview.size()))
+		{
+			const auto& Row = m_Overview[m_CursorY];
+			if(m_CursorX < static_cast<int>(Row.m_SequenceEntries.size()))
+				NewValue.SetValue(Row.m_SequenceEntries[m_CursorX].m_Index);
+		}
+
+		if(m_HoveredSequenceValue != NewValue)
+		{
+			m_HoveredSequenceValue = NewValue;
+			return true;
+		}
+
+		return false;
+	}
+	
+
 	void ComponentOrderListOverview::ConfigureKeyHooks(const Utility::KeyHookStore& inKeyHookStore)
 	{
 		using namespace Utility;
diff --git a/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.h b/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.h
index b0572b41..7de9448a 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.h
+++ b/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "component_base.h"
+#include "runtime/editor/edit_state.h"
 #include "utils/event.h"
 
 #include <memory>
@@ -36,6 +37,46 @@ namespace Editor
 			ComponentsManager& m_ComponentsManager;
 		};
 
+		struct HoveredSequenceValue
+		{
+			bool operator == (const HoveredSequenceValue& InRhs) const
+			{
+				return m_Value == InRhs.m_Value;
+			}
+
+			bool operator != (const HoveredSequenceValue& InRhs) const
+			{
+				return m_Value != InRhs.m_Value;
+			}
+			
+			void Reset()
+			{
+				m_Value = 0x80;
+			}
+			
+			bool HasValue() const
+			{
+				return (m_Value & 0x80) == 0;
+			}
+			
+			void SetValue(int inValue)
+			{
+				if(inValue >= 0 && inValue < 0x7f)
+					m_Value = inValue;
+				else
+					m_Value = 0x80;
+			}
+			
+			unsigned char GetValue() const
+			{
+				FOUNDATION_ASSERT(HasValue());
+				return m_Value;
+			}
+		
+		private:
+			unsigned char m_Value = 0x80;
+		};
+
 	public:
 		using OrderListChangedEvent = Utility::TEvent<void(int)>;
 
@@ -43,7 +84,8 @@ namespace Editor
 			int inID, 
 			int inGroupID, 
 			Undo* inUndo,
-			Foundation::TextField* inTextField, 
+			Foundation::TextField* inTextField,
+			const EditState& inEditState,
 			const Utility::KeyHookStore& inKeyHookStore,
 			std::shared_ptr<DataSourceTableText> inDataSourceTableText,
 			std::vector<std::shared_ptr<DataSourceOrderList>>& inOrderLists,
@@ -110,6 +152,9 @@ namespace Editor
 
 		void RebuildOverview();
 
+		// Update hovered sequence
+		bool UpdateHoveredSequence();
+		
 		// Key hooks
 		void ConfigureKeyHooks(const Utility::KeyHookStore& inKeyHookStore);
 
@@ -145,6 +190,9 @@ namespace Editor
 
 		OrderListChangedEvent m_OrderListChangedEvent;
 
+		const EditState& m_EditState;
+		HoveredSequenceValue m_HoveredSequenceValue;
+
 		int m_CursorY;
 		int m_CursorX;
 		int m_MaxCursorY;
diff --git a/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp b/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp
index 0fca6812..97293092 100644
--- a/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp
+++ b/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp
@@ -65,11 +65,9 @@ namespace Editor
 		{
 			if (inDriverInfo.HasParsedHeaderBlock(DriverInfo::HeaderBlockID::ID_MusicData))
 			{
-				// Get song count
-				const unsigned char song_count = inDriverInfo.GetAuxilaryDataCollection().GetSongs().GetSongCount();
-
-
-				std::vector<int> usage_count(inDriverInfo.GetMusicData().m_SequenceCount, 0);
+				// Output collection
+				const int SequenceCount = static_cast<int>(inDriverInfo.GetMusicData().m_SequenceCount);
+				std::vector<int> usage_count(SequenceCount, 0);
 
 				// Get Music data descriptor
 				const DriverInfo::MusicData& music_data = inDriverInfo.GetMusicData();
@@ -77,15 +75,18 @@ namespace Editor
 				// Find highest used sequence index
 				unsigned short order_list_1 = music_data.m_OrderListTrack1Address;
 
+				// Get song count
+				const unsigned char song_count = inDriverInfo.GetAuxilaryDataCollection().GetSongs().GetSongCount();
+
 				for (unsigned char i = 0; i < music_data.m_TrackCount * song_count; ++i)
 				{
 					unsigned short order_list_address = order_list_1 + static_cast<unsigned short>(i) * music_data.m_OrderListSize;
 					for (unsigned short j = 0; j < music_data.m_OrderListSize; ++j)
 					{
 						unsigned char value = inMemoryReader[order_list_address + j];
-						if (value < 0x80)
+						if (value < SequenceCount)
 						{
-							if (value == 0x7f)
+							if (value == 0x7e)
 								break;
 
 							usage_count[value]++;
diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
index 67153f2a..206f219d 100644
--- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
+++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
@@ -712,7 +712,7 @@ namespace Editor
 
 		if (inUp)
 		{
-			const unsigned int max_octave = EditorUtils::Has2ndInputOctave() ? 6 : 7;
+			const unsigned int max_octave = EditorUtils::Has2ndNoteInputOctave() ? 6 : 7;
 
 			if (octave < max_octave)
 				m_EditState.SetOctave(octave + 1);
@@ -764,6 +764,7 @@ namespace Editor
 	{
 		m_EditState.SetSequenceHighlighting(!m_EditState.IsSequenceHighlightingEnabled());
 		m_TracksComponent->ForceRefresh();
+		m_OrderListOverviewComponent->ForceRefresh();
 	}
 
 
@@ -1174,7 +1175,8 @@ namespace Editor
 		m_OrderListOverviewComponent = std::make_shared<ComponentOrderListOverview>(
 			OrderListOverviewID, 0, 
 			undo,
-			m_MainTextField, 
+			m_MainTextField,
+			m_EditState,
 			m_KeyHookStore,
 			song_view_text_buffer,
 			m_OrderListDataSources, 
@@ -1740,7 +1742,7 @@ namespace Editor
 			std::string note_keys_octave1 = GetSingleConfigurationValue<ConfigValueString>(config, "Key.Input.Notes.Octave1", std::string(""));
 			std::string note_keys_octave2 = GetSingleConfigurationValue<ConfigValueString>(config, "Key.Input.Notes.Octave2", std::string(""));
 
-			EditorUtils::SetNoteValueKeys(note_keys_octave1, note_keys_octave2);
+			EditorUtils::SetNoteInputValueKeys(note_keys_octave1, note_keys_octave2);
 		}
 
 	}
diff --git a/SIDFactoryII/source/runtime/editor/utilities/editor_utils.cpp b/SIDFactoryII/source/runtime/editor/utilities/editor_utils.cpp
index e256ad0a..7d809510 100644
--- a/SIDFactoryII/source/runtime/editor/utilities/editor_utils.cpp
+++ b/SIDFactoryII/source/runtime/editor/utilities/editor_utils.cpp
@@ -18,13 +18,13 @@ namespace Editor
 		static std::string g_noteKeyListOctave1 = "zsxdcvgbhnjm,l.";
 		static std::string g_noteKeyListOctave2 = "q2w3er5t6y7ui9o0p";
 
-		void SetNoteValueKeys(const std::string& inNoteKeyListOctave1, const std::string& inNoteKeyListOctave2)
+		void SetNoteInputValueKeys(const std::string& inNoteKeyListOctave1, const std::string& inNoteKeyListOctave2)
 		{
 			g_noteKeyListOctave1 = inNoteKeyListOctave1;
 			g_noteKeyListOctave2 = inNoteKeyListOctave2;
 		}
 
-		bool Has2ndInputOctave()
+		bool Has2ndNoteInputOctave()
 		{
 			return !g_noteKeyListOctave2.empty();
 		}
diff --git a/SIDFactoryII/source/runtime/editor/utilities/editor_utils.h b/SIDFactoryII/source/runtime/editor/utilities/editor_utils.h
index 17bb8c1b..c85b297d 100644
--- a/SIDFactoryII/source/runtime/editor/utilities/editor_utils.h
+++ b/SIDFactoryII/source/runtime/editor/utilities/editor_utils.h
@@ -17,20 +17,27 @@ namespace Editor
 	{
 		static constexpr int MAX_SONG_COUNT = 0x10;
 
-		void SetNoteValueKeys(const std::string& inNoteKeyListOctave1, const std::string& inNoteKeyListOctave2);
-		bool Has2ndInputOctave();
+		// Function for note inputs
+		void SetNoteInputValueKeys(const std::string& inNoteKeyListOctave1, const std::string& inNoteKeyListOctave2);
+		bool Has2ndNoteInputOctave();
+		
 		int GetNoteValue(SDL_Keycode inKeyCode, int inOctave);
 		int GetNoteValue(char inKeyCharacter, int inOctave);
+
+		// Hex conversion functions
 		unsigned char ConvertSingleCharHexValueToValue(char inKeyCharacter);
 		char ConvertValueToSingleCharHexValue(unsigned char inValue, bool inUppercase);
 		std::string ConvertToHexValue(unsigned char inValue, bool inUppercase);
 		std::string ConvertToHexValue(unsigned short inValue, bool inUppercase);
 
+		// Table ID query functions
 		unsigned char GetTableIDFromNameInTableDefinition(const DriverInfo& inDriverinfo, const std::string& inTableName);
 
+		// Utility methods for upgrading to multi song packages
 		void UpdateSongNameOfSingleSongPackages(DriverInfo& inDriverInfo);
 		void AddMissingPlayerMarkerLayers(DriverInfo& inDriverInfo);
 
+		// Multi song utility functions
 		void SelectSong(unsigned int inIndex, DriverInfo& inDriverInfo, Emulation::CPUMemory& inCPUMemory);
 		void AddSong(const std::string& inName, DriverInfo& inDriverInfo, Emulation::CPUMemory& inCPUMemory, ComponentsManager* inComponentsManager, unsigned char inSongOverviewTableID);
 		void RemoveSong(unsigned int inIndex, DriverInfo& inDriverInfo, Emulation::CPUMemory& inCPUMemory, ComponentsManager* inComponentsManager, unsigned char inSongOverviewTableID);
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
index 1357ab16..e54098a3 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -1,6 +1,7 @@
 #pragma once
 
 #include "visualizer_component_base.h"
+#include <memory>
 
 namespace Foundation
 {

From 75b09fddcac3770add201cf76ef38c7883ed7c98 Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Tue, 12 Sep 2023 18:00:01 +0200
Subject: [PATCH 03/13] Adapted colorschemes to new visualizers (#102)

---
 SIDFactoryII/color_schemes/ash.ini       |   7 ++
 SIDFactoryII/color_schemes/classic.ini   |   7 ++
 SIDFactoryII/color_schemes/default.ini   |  60 +++++-----
 SIDFactoryII/color_schemes/earth.ini     |   7 ++
 SIDFactoryII/color_schemes/isildur.ini   |  55 +++++----
 SIDFactoryII/color_schemes/navy.ini      |   7 ++
 SIDFactoryII/color_schemes/ocean.ini     |  11 +-
 SIDFactoryII/color_schemes/toilet.ini    | 138 -----------------------
 SIDFactoryII/color_schemes/uglygreen.ini |   9 +-
 SIDFactoryII/color_schemes/wisdom.ini    |  14 ++-
 10 files changed, 116 insertions(+), 199 deletions(-)
 delete mode 100644 SIDFactoryII/color_schemes/toilet.ini

diff --git a/SIDFactoryII/color_schemes/ash.ini b/SIDFactoryII/color_schemes/ash.ini
index ce928fd4..3879f837 100644
--- a/SIDFactoryII/color_schemes/ash.ini
+++ b/SIDFactoryII/color_schemes/ash.ini
@@ -103,6 +103,13 @@ Color.Orderlist.End.Stop										= :LightGray
 Color.Orderlist.Value											= :Gray
 Color.Orderlist.Value.Loop.Marker								= :LightGreen
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :LowerGray
+Color.StateBar.Bar.Background									= :Green-1
+Color.StateBar.Bar.BackgroundFilteredChannel					= :Green
+Color.StateBar.Bar.FillColorPulse								= :White
+Color.StateBar.Bar.FillColorFilter								= :Green
+
 Color.Dialog.Background                 						= :DarkerGray
 Color.Dialog.Header                     						= :DarkGray
 Color.Dialog.Header.Text										= :White
diff --git a/SIDFactoryII/color_schemes/classic.ini b/SIDFactoryII/color_schemes/classic.ini
index 3411ec5e..a79bd0d1 100644
--- a/SIDFactoryII/color_schemes/classic.ini
+++ b/SIDFactoryII/color_schemes/classic.ini
@@ -100,6 +100,13 @@ Color.Orderlist.End.Stop										= :LightGray
 Color.Orderlist.Value											= :Gray
 Color.Orderlist.Value.Loop.Marker								= :LightGreen
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :LowerGray
+Color.StateBar.Bar.Background									= :LowGray
+Color.StateBar.Bar.BackgroundFilteredChannel					= :Green
+Color.StateBar.Bar.FillColorPulse								= :LightGreen
+Color.StateBar.Bar.FillColorFilter								= :Green
+
 Color.Dialog.Background                 						= :DarkerGray
 Color.Dialog.Header                     						= :Green
 Color.Dialog.Header.Text										= :Black
diff --git a/SIDFactoryII/color_schemes/default.ini b/SIDFactoryII/color_schemes/default.ini
index e6d19d4d..09938bcc 100644
--- a/SIDFactoryII/color_schemes/default.ini
+++ b/SIDFactoryII/color_schemes/default.ini
@@ -1,28 +1,28 @@
 // Default color scheme.
 
-Black 			= 0x000000			
-White 			= 0xffffff			
-Red 			= 0xff0000				
-Green 			= 0x00c000			
-Blue 			= 0x0000ff			
-Yellow 			= 0xbfbf00			
-LightRed 		= 0xff8080		
-LightGreen 		= 0x40ff40		
-LightBlue 		= 0x8080ff		
-LightYellow 	= 0xffff60		
-DarkRed 		= 0x800000			
-DarkGreen 		= 0x006000		
-DarkBlue 		= 0x000080		
-DarkYellow 		= 0x707000		
-LighterGreen 	= 0x80ff80		
+Black 			= 0x000000
+White 			= 0xffffff
+Red 			= 0xff0000
+Green 			= 0x00c000
+Blue 			= 0x0000ff
+Yellow 			= 0xbfbf00
+LightRed 		= 0xff8080
+LightGreen 		= 0x40ff40
+LightBlue 		= 0x8080ff
+LightYellow 	= 0xffff60
+DarkRed 		= 0x800000
+DarkGreen 		= 0x006000
+DarkBlue 		= 0x000080
+DarkYellow 		= 0x707000
+LighterGreen 	= 0x80ff80
 LighterGrey 	= 0xc0c0c0
-LightGrey 		= 0x888888	
-Grey 			= 0x707070			
-DarkGrey 		= 0x404040		
-DarkerGrey 		= 0x202020		
-DarkerRed 		= 0x600000		
-DarkerGreen 	= 0x004800		
-DarkerBlue 		= 0x000060		
+LightGrey 		= 0x888888
+Grey 			= 0x707070
+DarkGrey 		= 0x404040
+DarkerGrey 		= 0x202020
+DarkerRed 		= 0x600000
+DarkerGreen 	= 0x004800
+DarkerBlue 		= 0x000060
 DarkerYellow 	= 0x4c4c00
 DarkestBlue		= 0x000038
 DarkestGrey		= 0x101010
@@ -33,13 +33,13 @@ Color.Table.Highlight											= :White
 Color.Table.Text.Background 									= :DarkGrey
 Color.Table.Text 												= :White
 Color.Table.Text.Editing 										= :LightYellow
-Color.Button.Text												= :White		
+Color.Button.Text												= :White
 Color.Button.Default 											= :Black
 Color.Button.Default.MouseOver 									= :DarkGrey
 Color.Button.Highlight 											= :Red
 Color.Button.Highlight.MouseOver 								= :LightRed
 Color.FileSelector.Background 									= :DarkBlue
-Color.FileSelector.List.Text									= :White		
+Color.FileSelector.List.Text									= :White
 Color.FileSelector.Text.Input									= :White
 Color.FileSelector.Cursor.Default 								= :DarkGrey
 Color.FileSelector.Cursor.Focus.Default 						= :LightRed
@@ -48,14 +48,14 @@ Color.FileSelector.Cursor.Focus.Import.Song 					= :DarkYellow
 Color.FileSelector.Cursor.Focus.Save.Song 						= :Red
 Color.FileSelector.Cursor.Focus.Save.Packed 					= :Blue
 Color.MarkerList.Background 									= :DarkBlue
-Color.MarkerList.Text											= :White		
+Color.MarkerList.Text											= :White
 Color.MarkerList.Cursor.Default 								= :DarkGrey
 Color.MarkerList.Cursor.Focus.Default 							= :LightBlue
 Color.SongList.Background 										= :DarkGrey
 Color.SongList.BackgroundText									= :DarkerGrey
 Color.SongList.Text 											= :White
 Color.SongList.Text.Editing 									= :LightYellow
-Color.SongList.EventPos											= :White		
+Color.SongList.EventPos											= :White
 Color.SongList.Values											= :White
 Color.SongList.Cursor 											= :DarkBlue
 Color.SongList.Cursor.Focus 									= :Blue
@@ -112,19 +112,19 @@ Color.Orderlist.Value.Input										= :White
 
 Color.StateBar.Area												= :DarkestGrey
 Color.StateBar.Bar.Background									= :DarkerGrey
-Color.StateBar.Bar.BackgroundFilteredChannel					= :DarkGrey
+Color.StateBar.Bar.BackgroundFilteredChannel					= :LightGrey
 Color.StateBar.Bar.FillColorPulse								= :White
 Color.StateBar.Bar.FillColorFilter								= :LightGrey
 
 Color.Dialog.Background                 						= :DarkRed
 Color.Dialog.Header                     						= :Red
-Color.Dialog.Header.Text										= :White		
+Color.Dialog.Header.Text										= :White
 Color.Dialog.Text												= :White
 Color.Dialog.ListSelector.Cursor								= :DarkGrey
 Color.Dialog.ListSelector.Cursor.Focus							= :DarkBlue
 Color.Dialog.Optimizer.Used										= :White
 Color.Dialog.Optimizer.Unused									= :LighterGrey
-Color.StatusBar.Text											= :White		
+Color.StatusBar.Text											= :White
 Color.StatusBar.Background.Stopped								= :Blue
 Color.StatusBar.Background.Stopped.MouseOver					= :LightBlue
 Color.StatusBar.Background.Playing								= :DarkGreen
@@ -156,5 +156,5 @@ Color.FlightRecorder.Visualizer.CPUUsageHigh					= :LightRed
 Color.FlightRecorder.Visualizer.HorizontalLine1					= :White
 Color.FlightRecorder.Visualizer.HorizontalLine2					= :Grey
 
-Color.DriverTableColor.Set										= :LightGreen 
+Color.DriverTableColor.Set										= :LightGreen
 Color.DriverTableColor.Jump										= :LightYellow
\ No newline at end of file
diff --git a/SIDFactoryII/color_schemes/earth.ini b/SIDFactoryII/color_schemes/earth.ini
index 711388d9..04414098 100644
--- a/SIDFactoryII/color_schemes/earth.ini
+++ b/SIDFactoryII/color_schemes/earth.ini
@@ -113,6 +113,13 @@ Color.Orderlist.End.Stop										= :BgBright
 Color.Orderlist.Value											= :BgLightWeak
 Color.Orderlist.Value.Loop.Marker								= :DgLight
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :BgDarker
+Color.StateBar.Bar.Background									= :BgDark
+Color.StateBar.Bar.BackgroundFilteredChannel					= :BgLightWeak
+Color.StateBar.Bar.FillColorPulse								= :White
+Color.StateBar.Bar.FillColorFilter								= :BgLightWeak
+
 Color.Dialog.Background                 						= :DgDark
 Color.Dialog.Header                     						= :DgDefault
 Color.Dialog.Header.Text										= :White
diff --git a/SIDFactoryII/color_schemes/isildur.ini b/SIDFactoryII/color_schemes/isildur.ini
index 2587906c..7c1656ad 100644
--- a/SIDFactoryII/color_schemes/isildur.ini
+++ b/SIDFactoryII/color_schemes/isildur.ini
@@ -1,29 +1,29 @@
 // Isildur's color scheme.
 
-Black 			= 0x000000			
-White 			= 0xbdbdbd			
-Red 			= 0x844b40				
-Green 			= 0x2f504a			
-Blue 			= 0x364469			
-Yellow 			= 0xbd9441			
-LightRed 		= 0xff8080		
-LightGreen 		= 0x69c68b		
-LightBlue 		= 0x6b72a5		
-LightYellow 	= 0xe7be8e		
-DarkRed 		= 0x800000			
-DarkGreen 		= 0x006000		
-DarkBlue 		= 0x1e222f		
-DarkYellow 		= 0x707000		
-LighterGrey 	= 0xc0c0c0		
-LightGrey 		= 0x888888	
+Black 			= 0x000000
+White 			= 0xbdbdbd
+Red 			= 0x844b40
+Green 			= 0x2f504a
+Blue 			= 0x364469
+Yellow 			= 0xbd9441
+LightRed 		= 0xff8080
+LightGreen 		= 0x69c68b
+LightBlue 		= 0x6b72a5
+LightYellow 	= 0xe7be8e
+DarkRed 		= 0x800000
+DarkGreen 		= 0x006000
+DarkBlue 		= 0x1e222f
+DarkYellow 		= 0x707000
+LighterGrey 	= 0xc0c0c0
+LightGrey 		= 0x888888
 Grey 			= 0x707070
-MidGrey			= 0x505050		
-DarkGrey 		= 0x25282d		
-DarkerGrey 		= 0x202020		
-DarkerRed 		= 0x5d2323		
-DarkerGreen 	= 0x004800		
-DarkerBlue 		= 0x000060		
-DarkerYellow 	= 0x4c4c00	
+MidGrey			= 0x505050
+DarkGrey 		= 0x25282d
+DarkerGrey 		= 0x202020
+DarkerRed 		= 0x5d2323
+DarkerGreen 	= 0x004800
+DarkerBlue 		= 0x000060
+DarkerYellow 	= 0x4c4c00
 
 
 Color.Table.Default 											= :LightGrey
@@ -103,6 +103,13 @@ Color.Orderlist.End.Stop										= :White
 Color.Orderlist.Value											= :LightGrey
 Color.Orderlist.Value.Loop.Marker								= :LightGreen
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :DarkerGrey
+Color.StateBar.Bar.Background									= :DarkBlue
+Color.StateBar.Bar.BackgroundFilteredChannel					= :Yellow
+Color.StateBar.Bar.FillColorPulse								= :LightYellow
+Color.StateBar.Bar.FillColorFilter								= :Yellow
+
 Color.Dialog.Background                 						= :DarkRed
 Color.Dialog.Header                     						= :Red
 Color.Dialog.Text												= :White
@@ -141,5 +148,5 @@ Color.FlightRecorder.Visualizer.CPUUsageHigh					= :LightRed
 Color.FlightRecorder.Visualizer.HorizontalLine1					= 0xffffff
 Color.FlightRecorder.Visualizer.HorizontalLine2					= 0x707070
 
-Color.DriverTableColor.Set										= :LightGreen 
+Color.DriverTableColor.Set										= :LightGreen
 Color.DriverTableColor.Jump										= :LightYellow
\ No newline at end of file
diff --git a/SIDFactoryII/color_schemes/navy.ini b/SIDFactoryII/color_schemes/navy.ini
index 6a24511f..a8526afb 100644
--- a/SIDFactoryII/color_schemes/navy.ini
+++ b/SIDFactoryII/color_schemes/navy.ini
@@ -105,6 +105,13 @@ Color.Orderlist.End.Stop										= :BgBright
 Color.Orderlist.Value											= :BgLightWeak
 Color.Orderlist.Value.Loop.Marker								= :DgLight
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :BgDarker
+Color.StateBar.Bar.Background									= :BgDark
+Color.StateBar.Bar.BackgroundFilteredChannel					= :DgLight
+Color.StateBar.Bar.FillColorPulse								= :BgLightWeak
+Color.StateBar.Bar.FillColorFilter								= :DgLight
+
 Color.Dialog.Background                 						= :DgDark
 Color.Dialog.Header                     						= :DgDefault
 Color.Dialog.Header.Text										= :White
diff --git a/SIDFactoryII/color_schemes/ocean.ini b/SIDFactoryII/color_schemes/ocean.ini
index d1c9ea9d..b30012f9 100644
--- a/SIDFactoryII/color_schemes/ocean.ini
+++ b/SIDFactoryII/color_schemes/ocean.ini
@@ -1,4 +1,4 @@
-// Color scheme "Ocean" by JCH - based on a 5-color palette from Coolors. 
+// Color scheme "Ocean" by JCH - based on a 5-color palette from Coolors.
 
 CoolorsWhite 			= 0xffffff
 
@@ -105,6 +105,13 @@ Color.Orderlist.End.Stop										= :CoolorsNovaOcean
 Color.Orderlist.Value											= :CoolorsLightWeakOcean
 Color.Orderlist.Value.Loop.Marker								= :CoolorsLightGreen
 Color.Orderlist.Value.Input										= :CoolorsWhite
+
+Color.StateBar.Area												= :CoolorsDarkerOcean
+Color.StateBar.Bar.Background									= :CoolorsDarkerOcean
+Color.StateBar.Bar.BackgroundFilteredChannel					= :CoolorsLightWeakOcean
+Color.StateBar.Bar.FillColorPulse								= :CoolorsWhite
+Color.StateBar.Bar.FillColorFilter								= :CoolorsLightWeakOcean
+
 Color.Dialog.Background                 						= :CoolorsDarkGreen
 Color.Dialog.Header                     						= :CoolorsGreen
 Color.Dialog.Header.Text										= :CoolorsWhite
@@ -145,5 +152,5 @@ Color.FlightRecorder.Visualizer.CPUUsageHigh					= 0xff8080
 Color.FlightRecorder.Visualizer.HorizontalLine1					= 0xffffff
 Color.FlightRecorder.Visualizer.HorizontalLine2					= 0x707070
 
-Color.DriverTableColor.Set										= :CoolorsLightGreen 
+Color.DriverTableColor.Set										= :CoolorsLightGreen
 Color.DriverTableColor.Jump										= :CoolorsLightYellow
\ No newline at end of file
diff --git a/SIDFactoryII/color_schemes/toilet.ini b/SIDFactoryII/color_schemes/toilet.ini
deleted file mode 100644
index 4742376d..00000000
--- a/SIDFactoryII/color_schemes/toilet.ini
+++ /dev/null
@@ -1,138 +0,0 @@
-// Toilet color scheme.
-
-Brown-2 = 0x201102
-Brown-1 = 0x402304
-Brown 	= 0x542f07
-Brown+1 = 0xc26b0e
-Brown+2 = 0xe37d10
-Brown+3 = 0xe89f51
-Brown+4 = 0xe3b584
-Brown+5 = 0xedd0b2
-Brown+6 = 0xedddcc
-White 	= 0xffffff
-Grey	= 0xa0a0a0
-Grey+1	= 0xc0c0c0
-
-Color.Table.Default 											= 0xaaaaaa
-Color.Table.Highlight											= :White
-Color.Table.Text.Background 									= 0x404040
-Color.Table.Text 												= :Brown+2
-Color.Table.Text.Editing 										= :White
-Color.Button.Text												= :White		// NEWNEWNEW
-Color.Button.Default 											= 0x000000
-Color.Button.Default.MouseOver 									= 0x404040
-Color.Button.Highlight 											= 0xff0000
-Color.Button.Highlight.MouseOver 								= 0xff8080
-Color.FileSelector.Background 									= :Brown
-Color.FileSelector.List.Text									= :White		// NEW
-Color.FileSelector.Text.Input									= :White
-Color.FileSelector.Cursor.Default 								= 0x404040
-Color.FileSelector.Cursor.Focus.Default 						= 0xff8080
-Color.FileSelector.Cursor.Focus.Load.Song 						= 0x006000
-Color.FileSelector.Cursor.Focus.Import.Song 					= 0x707000
-Color.FileSelector.Cursor.Focus.Save.Song 						= 0xff0000
-Color.FileSelector.Cursor.Focus.Save.Packed 					= 0x0000ff
-Color.MarkerList.Background 									= :Brown
-Color.MarkerList.Text											= :White		// NEWNEW
-Color.MarkerList.Cursor.Default 								= 0x404040
-Color.MarkerList.Cursor.Focus.Default 							= :Brown+1
-Color.SongList.Background 										= :Brown-1
-Color.SongList.BackgroundText									= :Brown-2
-Color.SongList.Text 											= :Brown+6
-Color.SongList.Text.Editing 									= :White
-Color.SongList.EventPos											= :White		// NEW
-Color.SongList.Values											= :White
-Color.SongList.Cursor 											= :Brown
-Color.SongList.Cursor.Focus 									= :Brown+1
-Color.SongList.AreaMarking										= :Brown
-Color.SongList.AreaMarking.Focus								= :Brown+1
-Color.SongList.Playback.Marker 									= 0xff0000
-Color.SongList.Loop.Marker 										= :Brown+4
-Color.Track.Background											= :Brown
-Color.Track.Background.FocusLine								= :Brown-1
-Color.Track.BackgroundMuted										= 0x404040
-Color.Track.BackgroundMuted.FocusLine							= 0x202020
-Color.Track.MarkingArea											= :Brown-1
-Color.Track.MarkingAreaMuted									= 0x202020
-Color.Track.Name												= :Brown+1
-Color.Track.Name.Selected										= :Brown+3
-Color.Track.Name.Focus											= :Brown+2
-Color.Track.Name.Selected.Focus									= :White
-Color.Tracks.EventNumbers.Background							= 0x202020
-Color.Tracks.EventNumbers.Default								= 0x888888
-Color.Tracks.EventNumbers.FocusLine								= 0xbfbf00
-Color.Tracks.EventNumbers.Highlight								= :White
-Color.Tracks.EventNumbers.Highlight.FocusLine					= 0xffff60
-Color.Tracks.EventNumbers.Playback.Marker						= 0xff0000
-Color.Sequence.Error											= 0xff8080
-Color.Sequence.Instrument.Empty									= 0x888888
-Color.Sequence.Instrument.Empty.FocusLine						= 0xc0c0c0
-Color.Sequence.Instrument.Tie									= 0x888888
-Color.Sequence.Instrument.Tie.FocusLine							= 0xc0c0c0
-Color.Sequence.Instrument.Value									= :Brown+4
-Color.Sequence.Instrument.Value.FocusLine						= :White
-Color.Sequence.Instrument.Value.Selected.Highlight				= :Brown+5
-Color.Sequence.Instrument.Value.Selected.Highlight.FocusLine	= :Brown+6
-Color.Sequence.Command.Empty									= 0x888888
-Color.Sequence.Command.Empty.FocusLine							= 0xc0c0c0
-Color.Sequence.Command.Value									= :Brown+3
-Color.Sequence.Command.Value.FocusLine							= :White
-Color.Sequence.Command.Value.Selected.Highlight					= :Brown+5
-Color.Sequence.Command.Value.Selected.Highlight.FocusLine		= :Brown+6
-Color.Sequence.Note.Empty										= 0x888888
-Color.Sequence.Note.Empty.FocusLine								= 0xc0c0c0
-Color.Sequence.Note.Gate.On										= :Brown+2
-Color.Sequence.Note.Gate.On.FocusLine							= :Brown+3
-Color.Sequence.Note.Value										= :Brown+3
-Color.Sequence.Note.Value.FocusLine								= :Brown+4
-Color.Sequence.Note.Value.Tied									= :Grey
-Color.Sequence.Note.Value.Tied.FocusLine						= :Grey+1
-Color.Sequence.Note.Value.Selected.Highlight					= :Brown+5
-Color.Sequence.Note.Value.Selected.Highlight.FocusLine			= :Brown+6
-Color.Orderlist.End.Loop										= :White
-Color.Orderlist.End.Stop										= :White
-Color.Orderlist.Value											= 0x888888
-Color.Orderlist.Value.Loop.Marker								= :Brown+3
-Color.Orderlist.Value.Input										= :White
-Color.Dialog.Background                 						= 0x800000
-Color.Dialog.Header                     						= 0xff0000
-Color.Dialog.Header.Text										= :White		// NEW
-Color.Dialog.Text												= :White
-Color.Dialog.ListSelector.Cursor								= 0x404040
-Color.Dialog.ListSelector.Cursor.Focus							= :Brown
-Color.Dialog.Optimizer.Used										= :White
-Color.Dialog.Optimizer.Unused									= 0xc0c0c0
-Color.StatusBar.Text											= :White		// NEWNEW
-Color.StatusBar.Background.Stopped								= :Brown+1
-Color.StatusBar.Background.Stopped.MouseOver					= :Brown+2
-Color.StatusBar.Background.Playing								= 0x006000
-Color.StatusBar.Background.Playing.MouseOver					= 0x00c000
-Color.StatusBar.Background.PlayingInput							= 0x707000
-Color.StatusBar.Background.PlayingInput.MouseOver				= 0xbfbf00
-Color.ScreenEdit.InfoRect.Background							= 0x202020
-Color.ScreenEdit.InfoRect.Text									= 0x808080
-Color.ScreenEdit.InfoRect.Text.Time.PlaybackState				= :White
-Color.ScreenEdit.Table.Headline									= :Brown+1
-Color.ScreenEdit.Table.Headline.HotkeyLetter					= :Brown+3
-
-Color.Converters.Background										= 0x202020
-Color.Console.Background										= 0x000000
-Color.Console.Text												= :Brown+3
-
-Color.FlightRecorder.Background									= 0x202020
-Color.FlightRecorder.Description								= 0xffffff
-Color.FlightRecorder.GateOn										= 0xffffff
-Color.FlightRecorder.GateOff									= 0xc0c0c0
-Color.FlightRecorder.FilterAndVolume							= 0x8080ff
-Color.FlightRecorder.CPUUsageLow								= 0x40ff40
-Color.FlightRecorder.CPUUsageMedium								= 0xffff60
-Color.FlightRecorder.CPUUsageHigh								= 0xff8080
-Color.FlightRecorder.Visualizer.Background						= 0x404040
-Color.FlightRecorder.Visualizer.CPUUsageLow						= 0x40ff40
-Color.FlightRecorder.Visualizer.CPUUsageMedium					= 0xffff60
-Color.FlightRecorder.Visualizer.CPUUsageHigh					= 0xff8080
-Color.FlightRecorder.Visualizer.HorizontalLine1					= 0xffffff
-Color.FlightRecorder.Visualizer.HorizontalLine2					= 0x707070
-
-Color.DriverTableColor.Set										= :Brown+3 
-Color.DriverTableColor.Jump										= :Brown+2
\ No newline at end of file
diff --git a/SIDFactoryII/color_schemes/uglygreen.ini b/SIDFactoryII/color_schemes/uglygreen.ini
index b94987a5..abede7df 100644
--- a/SIDFactoryII/color_schemes/uglygreen.ini
+++ b/SIDFactoryII/color_schemes/uglygreen.ini
@@ -102,6 +102,13 @@ Color.Orderlist.End.Stop										= :White
 Color.Orderlist.Value											= 0x888888
 Color.Orderlist.Value.Loop.Marker								= :Green+5
 Color.Orderlist.Value.Input										= :White
+
+Color.StateBar.Area												= :Green-3
+Color.StateBar.Bar.Background									= :Green-1
+Color.StateBar.Bar.BackgroundFilteredChannel					= :Green
+Color.StateBar.Bar.FillColorPulse								= :White
+Color.StateBar.Bar.FillColorFilter								= :Green
+
 Color.Dialog.Background                 						= :Grey-1
 Color.Dialog.Header                     						= :Grey
 Color.Dialog.Header.Text										= :White		// NEW
@@ -142,5 +149,5 @@ Color.FlightRecorder.Visualizer.CPUUsageHigh					= 0xff8080
 Color.FlightRecorder.Visualizer.HorizontalLine1					= 0xffffff
 Color.FlightRecorder.Visualizer.HorizontalLine2					= 0x707070
 
-Color.DriverTableColor.Set										= :Blue+4 
+Color.DriverTableColor.Set										= :Blue+4
 Color.DriverTableColor.Jump										= :Blue+2
\ No newline at end of file
diff --git a/SIDFactoryII/color_schemes/wisdom.ini b/SIDFactoryII/color_schemes/wisdom.ini
index 64bd5137..986bd112 100644
--- a/SIDFactoryII/color_schemes/wisdom.ini
+++ b/SIDFactoryII/color_schemes/wisdom.ini
@@ -24,13 +24,13 @@ Color.Table.Text.Background                                     = :Black
 Color.Table.Text                                                = :MediumGrey
 Color.Table.Text.Editing                                        = :MediumGrey
 
-Color.Button.Text                                               = :White        
+Color.Button.Text                                               = :White
 Color.Button.Default                                            = :Black
 Color.Button.Default.MouseOver                                  = :MediumGrey
 Color.Button.Highlight                                          = :Black
 Color.Button.Highlight.MouseOver                                = :MediumGrey
 Color.FileSelector.Background                                   = :Blue
-Color.FileSelector.List.Text                                    = :White        
+Color.FileSelector.List.Text                                    = :White
 Color.FileSelector.Text.Input                                   = :White
 Color.FileSelector.Cursor.Default                               = :LightBlue
 Color.FileSelector.Cursor.Focus.Default                         = :LightBlue
@@ -104,15 +104,21 @@ Color.Orderlist.Value                                           = :White
 Color.Orderlist.Value.Loop.Marker                               = :Purple
 Color.Orderlist.Value.Input                                     = :Purple
 
+Color.StateBar.Area												= :Black
+Color.StateBar.Bar.Background									= :Blue
+Color.StateBar.Bar.BackgroundFilteredChannel					= :LightBlue
+Color.StateBar.Bar.FillColorPulse								= :White
+Color.StateBar.Bar.FillColorFilter								= :LightBlue
+
 Color.Dialog.Background                                         = :Purple
 Color.Dialog.Header                                             = :LightRed
-Color.Dialog.Header.Text                                        = :White        
+Color.Dialog.Header.Text                                        = :White
 Color.Dialog.Text                                               = :White
 Color.Dialog.ListSelector.Cursor                                = :DarkGrey
 Color.Dialog.ListSelector.Cursor.Focus                          = :DarkBlue
 Color.Dialog.Optimizer.Used                                     = :White
 Color.Dialog.Optimizer.Unused                                   = :LightGrey
-Color.StatusBar.Text                                            = :White        
+Color.StatusBar.Text                                            = :White
 Color.StatusBar.Background.Stopped                              = :Blue
 Color.StatusBar.Background.Stopped.MouseOver                    = :LightBlue
 Color.StatusBar.Background.Playing                              = :Green

From 7a92c551a243eabfb02cf31d49c28802a3095900 Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Tue, 12 Sep 2023 18:08:10 +0200
Subject: [PATCH 04/13] Updated README (#102)

---
 README.md | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index 2ef28e55..543a063e 100644
--- a/README.md
+++ b/README.md
@@ -45,11 +45,14 @@ Please report issues in our [issue tracker](https://github.com/issues).
 
 ### Next release
 
-![Commits since last release](https://img.shields.io/github/commits-since/chordian/sidfactory2/release-20221007)
-
+![Commits since last
+release](https://img.shields.io/github/commits-since/chordian/sidfactory2/release-20221007)
 
+- Added: [#102](https://github.com/Chordian/sidfactory2/issues/102) Visualizers for pulse width (per channel), filter cutoff and an
+  indication per channel if it is being filtered.
 - Changed: Configuration parameter `Window.Scale` now has a range from 1.0 to 10.0, so users can blow up the screen even bigger.
   Values below 1.0 were not working correctly.
+
 ### Build 20221007
 
 - Fixed: [#162](https://github.com/Chordian/sidfactory2/issues/162) Crash when

From 455d0599e0f180d0fee1fcc7bf8393c53a15bbdf Mon Sep 17 00:00:00 2001
From: rawpowerlaxity <thomas@rawpowergames.com>
Date: Thu, 14 Sep 2023 09:16:01 +0200
Subject: [PATCH 05/13] [minor] Adding a vertical line over the 3 bars that
 indicate the pulse state output to SID. The vertical line indicates the 50%
 pulse width mark.

---
 ...isualizer_component_pulse_filter_state.cpp | 26 ++++++++++++++++++-
 .../visualizer_component_pulse_filter_state.h | 22 +++++++++++++++-
 2 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index 96d7b469..75e9b0b7 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -87,7 +87,7 @@ namespace Editor
 
 			for(unsigned int i = 0; i < 3; ++i)
 			{
-				DrawBar(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill);
+				DrawBarWithCenterDivider(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
 				bar_y += bar_spacing;
 			}
 
@@ -127,4 +127,28 @@ namespace Editor
 		}
 	}
 
+
+	void VisualizerComponentPulseFilterState::DrawBarWithCenterDivider(
+		int inX,
+		int inY,
+		int inWidth,
+		int inHeight,
+		int inValue,
+		int inMaxValue,
+		const Foundation::Color& inBarColor,
+		const Foundation::Color& inBarColorFill,
+		const Foundation::Color& inDividerColor)
+	{
+		m_DrawField->DrawBox(inBarColor, inX, inY, inWidth, inHeight);
+
+		if(inValue > 0)
+		{
+			float width_fraction = static_cast<float>(inValue) / static_cast<float>(inMaxValue);
+			int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
+
+			m_DrawField->DrawBox(inBarColorFill, inX, inY + 1, width, inHeight - 2);
+		}
+
+		m_DrawField->DrawVerticalLine(inDividerColor, inX + inWidth / 2, inY, inY + inHeight);
+	}
 }
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
index e54098a3..6595c7ff 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -30,7 +30,27 @@ namespace Editor
 		void Refresh(const DisplayState& inDisplayState) override;
 
 	private:
-		void DrawBar(int inX, int inY, int inWidth, int inHeight, int inValue, int inMaxValue, const Foundation::Color& inBarColor, const Foundation::Color& inBarColorFill);
+		void DrawBar(
+			int inX,
+			int inY,
+			int inWidth,
+			int inHeight,
+			 int inValue,
+			 int inMaxValue,
+			 const Foundation::Color& inBarColor,
+			 const Foundation::Color& inBarColorFill);
+
+		void DrawBarWithCenterDivider(
+			int inX,
+			int inY,
+			int inWidth,
+			int inHeight,
+			int inValue,
+			int inMaxValue,
+			const Foundation::Color& inBarColor,
+			const Foundation::Color& inBarColorFill,
+			const Foundation::Color& inDividerColor);
+		
 		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> m_DataSource;
 	};
 }
\ No newline at end of file

From aa2072702237c72c716f63570a897df9a774410d Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Fri, 15 Sep 2023 10:03:10 +0200
Subject: [PATCH 06/13] Alternative visualization for pulse (#169)

* Alternative visualization for pulse

* Made visualization style for pulse configurable (#102)

* Formatting

* Formatting

* Formatting

* Formatting

* Added config option to README

* [minor] Pulse filter visualizer extensions:

* Added functionality for visualizer component to receive non exclusive mouse input (only a few things were missing in the component manager)
* Implemented switching of visualization mode when clicked (left mouse button)

---------

Co-authored-by: rawpowerlaxity <thomas@rawpowergames.com>
---
 .clang-format                                 |  6 +--
 README.md                                     | 12 +++--
 SIDFactoryII/config.ini                       | 16 ++++--
 .../runtime/editor/components_manager.cpp     | 19 +++++++
 .../runtime/editor/components_manager.h       |  1 +
 .../visualizer_component_base.cpp             |  3 +-
 ...isualizer_component_pulse_filter_state.cpp | 54 +++++++++++++------
 .../visualizer_component_pulse_filter_state.h | 13 ++---
 dist/documentation/user.default.ini           |  7 +++
 9 files changed, 96 insertions(+), 35 deletions(-)

diff --git a/.clang-format b/.clang-format
index 798dad4c..2dcae007 100644
--- a/.clang-format
+++ b/.clang-format
@@ -38,7 +38,7 @@ BraceWrapping:
   AfterExternBlock: true
   BeforeCatch:     false
   BeforeElse:      true
-  # BeforeLambdaBody: true
+  BeforeLambdaBody: true
   IndentBraces:    false
   SplitEmptyFunction: true
   SplitEmptyRecord: true
@@ -56,8 +56,8 @@ ColumnLimit:     0
 CommentPragmas:  '^ IWYU pragma:'
 CompactNamespaces: false
 ConstructorInitializerAllOnOneLineOrOnePerLine: false
-ConstructorInitializerIndentWidth: 2
-ContinuationIndentWidth: 2
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
 Cpp11BracedListStyle: false
 DeriveLineEnding: true
 DerivePointerAlignment: false
diff --git a/README.md b/README.md
index 543a063e..09b4a04d 100644
--- a/README.md
+++ b/README.md
@@ -48,10 +48,14 @@ Please report issues in our [issue tracker](https://github.com/issues).
 ![Commits since last
 release](https://img.shields.io/github/commits-since/chordian/sidfactory2/release-20221007)
 
-- Added: [#102](https://github.com/Chordian/sidfactory2/issues/102) Visualizers for pulse width (per channel), filter cutoff and an
-  indication per channel if it is being filtered.
-- Changed: Configuration parameter `Window.Scale` now has a range from 1.0 to 10.0, so users can blow up the screen even bigger.
-  Values below 1.0 were not working correctly.
+- Added: [#102](https://github.com/Chordian/sidfactory2/issues/102) Visualizers
+  for pulse width (per channel), filter cutoff and an indication per channel if
+  it is being filtered.
+- Added: Config option `Visualizer.PulseWidth.Style` to set the default style
+  for the pulse width visualizer.
+- Changed: Configuration parameter `Window.Scale` now has a range from 1.0 to
+  10.0, so users can blow up the screen even bigger. Values below 1.0 were not
+  working correctly.
 
 ### Build 20221007
 
diff --git a/SIDFactoryII/config.ini b/SIDFactoryII/config.ini
index 1ebe8175..53ab996a 100644
--- a/SIDFactoryII/config.ini
+++ b/SIDFactoryII/config.ini
@@ -6,7 +6,7 @@
 // The config.ini file contains the factory default settings. You can change these if you want, but it may be overwritten
 // when you download and paste the next release. This is where the user.ini file comes in handy. If you want to make sure
 // that your personal settings remain sticky, copy the changed entries to the user.ini file (you may have to create the
-// file first). All entries in user.ini will always override the corresponding entries in the config.ini file. 
+// file first). All entries in user.ini will always override the corresponding entries in the config.ini file.
 //
 // A genuine settings dialog box is planned for a future release of SID Factory II.
 //
@@ -48,18 +48,18 @@ Editor.Driver.Default               = "sf2driver11_04_01.prg"  	// This determin
 
 Editor.Skip.Intro                   = 0         // If you set this to 1, the black intro screen with logo and credits will never be shown.
 
-Editor.Follow.Play                  = 0         // If you set this to 1, follow play is on by default. 
+Editor.Follow.Play                  = 0         // If you set this to 1, follow play is on by default.
 
-Editor.Sequence.Highlights          = 0         // If you set this to 1, sequence highlights are on by default. 
+Editor.Sequence.Highlights          = 0         // If you set this to 1, sequence highlights are on by default.
 
 Editor.Confirm.QuickSave            = 1         // If you set this to 1, a confirmation dialog pops up when quick saving
                                                 // If set to 0, the quick save is performed without asking for confirmation
-												
+
 //
 // PLAYBACK OPTIONS
 //
 
-Playback.StopEmulationIfDriverStops = 1			// If the driver stops (at the end of a jingle, for instance), setting this value to non-zero 
+Playback.StopEmulationIfDriverStops = 1			// If the driver stops (at the end of a jingle, for instance), setting this value to non-zero
 												// will stop the emulation and follow play also.
 
 // Virtual piano keyboard layout
@@ -82,6 +82,12 @@ Window.Scaling                      = 1.0       // Scale window contents. Pixels
 Window.Scaling.Smooth               = 1         // If you set this to 1, scaling will smooth pixels.
                                                 // Set to 0 will use "nearest neighbour" scaling.
 
+//
+// Visualizers
+//
+Visualizer.PulseWidth.Style         = 0         // The way pulse width is visualized
+                                                // 0 = absolute value, 1 = alternative style
+
 //
 // OVERLAY
 //
diff --git a/SIDFactoryII/source/runtime/editor/components_manager.cpp b/SIDFactoryII/source/runtime/editor/components_manager.cpp
index 774badf7..f1bdb712 100644
--- a/SIDFactoryII/source/runtime/editor/components_manager.cpp
+++ b/SIDFactoryII/source/runtime/editor/components_manager.cpp
@@ -402,6 +402,12 @@ namespace Editor
 					}
 				}
 			}
+
+			// Let visualizer components consume non exclusive mouse input (if the mouse is over them)
+			auto* VisualComponent = GetVisualizerComponentAt(inMouse.GetPosition());
+
+			if(VisualComponent != nullptr)
+				VisualComponent->ConsumeNonExclusiveInput(inMouse);
 		}
 
 		return false;
@@ -635,4 +641,17 @@ namespace Editor
 
 		return nullptr;
 	}
+
+
+	VisualizerComponentBase* ComponentsManager::GetVisualizerComponentAt(const Foundation::Point& inPosition) const
+	{
+		for (auto visualizerComponent : m_VisualizerComponents)
+		{
+			if (visualizerComponent->ContainsPosition(inPosition))
+				return &*visualizerComponent;
+		}
+
+		return nullptr;
+	}
+
 }
\ No newline at end of file
diff --git a/SIDFactoryII/source/runtime/editor/components_manager.h b/SIDFactoryII/source/runtime/editor/components_manager.h
index 78530dac..1bff13d7 100644
--- a/SIDFactoryII/source/runtime/editor/components_manager.h
+++ b/SIDFactoryII/source/runtime/editor/components_manager.h
@@ -84,6 +84,7 @@ namespace Editor
 		ComponentBase* GetComponentAfter(ComponentBase* inComponent) const;
 		ComponentBase* GetComponentBefore(ComponentBase* inComponent) const;
 		ComponentBase* GetComponentAt(const Foundation::Point& inPosition) const;
+		VisualizerComponentBase* GetVisualizerComponentAt(const Foundation::Point& inPosition) const;
 
 		bool m_Suspended;
 
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_base.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_base.cpp
index 6c60d9c9..c546cc44 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_base.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_base.cpp
@@ -62,7 +62,8 @@ namespace Editor
 
 	bool VisualizerComponentBase::ContainsPosition(const Foundation::Point& inPixelPosition) const
 	{
-		return m_Rect.Contains(inPixelPosition);
+		Foundation::Rect Rect = { m_DrawField->GetPosition(), m_Rect.m_Dimensions };
+		return Rect.Contains(inPixelPosition);
 	}
 
 
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index 75e9b0b7..dcfe2de6 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -1,14 +1,18 @@
 #include "visualizer_component_pulse_filter_state.h"
 
 #include "foundation/graphics/drawfield.h"
+#include "foundation/input/mouse.h"
 #include "runtime/editor/components/component_file_selector.h"
 #include "runtime/editor/datasources/datasource_sidregistersbuffer.h"
 #include "runtime/execution/executionhandler.h"
 #include "runtime/execution/flightrecorder.h"
+#include "utils/configfile.h"
+#include "utils/global.h"
 #include "utils/usercolors.h"
 
 using namespace Foundation;
 using namespace Utility;
+using namespace Utility::Config;
 
 namespace Editor
 {
@@ -25,6 +29,8 @@ namespace Editor
 		: VisualizerComponentBase(inID, inDrawField, inX, inY, inWidth, inHeight)
 		, m_DataSource(inDataSource)
 	{
+		ConfigFile& config_file = Global::instance().GetConfig();
+		m_PulseWidthStyle = GetSingleConfigurationValue<ConfigValueInt>(config_file, "Visualizer.PulseWidth.Style", 0);
 	}
 
 
@@ -35,6 +41,12 @@ namespace Editor
 
 	bool VisualizerComponentPulseFilterState::ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse)
 	{
+		if(inMouse.IsButtonPressed(Mouse::Button::Left))
+		{
+			m_PulseWidthStyle = (m_PulseWidthStyle + 1) & 1;
+			return true;
+		}
+		
 		return false;
 	}
 
@@ -50,7 +62,7 @@ namespace Editor
 			const Color color_bar_fill_filter = ToColor(UserColor::StateBarFillColorFilter);
 
 			m_DataSource->PullDataFromSource();
-			
+
 			m_DrawField->DrawBox(color_background, 0, 0, m_Dimensions.m_Width, m_Dimensions.m_Height);
 
 			const int bar_width = m_Dimensions.m_Width - 4;
@@ -61,31 +73,31 @@ namespace Editor
 			int bar_y = 2;
 
 			const auto& data_source = *m_DataSource;
-				
+
 			const auto get_pulse_value = [&data_source](unsigned int inChannel) -> unsigned short
 			{
-				if(inChannel > 2)
+				if (inChannel > 2)
 					return 0;
-				
+
 				const unsigned int offset = inChannel * 7;
-				
+
 				const unsigned short pulse_high = data_source[offset + 3] & 0x0f;
 				const unsigned short pulse_low = data_source[offset + 2];
 
-				const unsigned short value = (pulse_high << 8) | pulse_low; 
-				
+				const unsigned short value = (pulse_high << 8) | pulse_low;
+
 				return value;
 			};
 
 			const auto is_channel_filtered = [&data_source](unsigned int inChannel) -> bool
 			{
-				if(inChannel > 2)
+				if (inChannel > 2)
 					return false;
 
 				return (data_source[0x17] & (1 << inChannel)) != 0;
 			};
 
-			for(unsigned int i = 0; i < 3; ++i)
+			for (unsigned int i = 0; i < 3; ++i)
 			{
 				DrawBarWithCenterDivider(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
 				bar_y += bar_spacing;
@@ -97,7 +109,7 @@ namespace Editor
 				const unsigned short filter_low = data_source[0x15] & 7;
 
 				const unsigned short value = (filter_high << 3) | filter_low;
-				
+
 				return value;
 			};
 
@@ -118,7 +130,7 @@ namespace Editor
 	{
 		m_DrawField->DrawBox(inBarColor, inX, inY, inWidth, inHeight);
 
-		if(inValue > 0)
+		if (inValue > 0)
 		{
 			float width_fraction = static_cast<float>(inValue) / static_cast<float>(inMaxValue);
 			int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
@@ -141,12 +153,22 @@ namespace Editor
 	{
 		m_DrawField->DrawBox(inBarColor, inX, inY, inWidth, inHeight);
 
-		if(inValue > 0)
+		if (inValue > 0)
 		{
-			float width_fraction = static_cast<float>(inValue) / static_cast<float>(inMaxValue);
-			int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
-
-			m_DrawField->DrawBox(inBarColorFill, inX, inY + 1, width, inHeight - 2);
+			if (m_PulseWidthStyle == 1)
+			{
+				int abs_value = inValue > 0x800 ? 0x1000 - inValue : inValue;
+				float width_fraction = static_cast<float>(abs_value) / static_cast<float>(inMaxValue);
+				int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
+				int x = inValue > 0x800 ? inX + (inWidth - width) : inX;
+				m_DrawField->DrawBox(inBarColorFill, x, inY + 1, width, inHeight - 2);
+			}
+			else
+			{
+				float width_fraction = static_cast<float>(inValue) / static_cast<float>(inMaxValue);
+				int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
+				m_DrawField->DrawBox(inBarColorFill, inX, inY + 1, width, inHeight - 2);
+			}
 		}
 
 		m_DrawField->DrawVerticalLine(inDividerColor, inX + inWidth / 2, inY, inY + inHeight);
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
index 6595c7ff..94b5ff88 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -16,11 +16,11 @@ namespace Editor
 	{
 	public:
 		VisualizerComponentPulseFilterState(
-			int inID, 
-			Foundation::DrawField* inDrawField, 
-			int inX, 
-			int inY, 
-			int inWidth, 
+			int inID,
+			Foundation::DrawField* inDrawField,
+			int inX,
+			int inY,
+			int inWidth,
 			int inHeight,
 			std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource
 		);
@@ -50,7 +50,8 @@ namespace Editor
 			const Foundation::Color& inBarColor,
 			const Foundation::Color& inBarColorFill,
 			const Foundation::Color& inDividerColor);
-		
+
 		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> m_DataSource;
+		int m_PulseWidthStyle;
 	};
 }
\ No newline at end of file
diff --git a/dist/documentation/user.default.ini b/dist/documentation/user.default.ini
index 5f42f228..a7f4966b 100644
--- a/dist/documentation/user.default.ini
+++ b/dist/documentation/user.default.ini
@@ -61,6 +61,13 @@ Window.Scaling                      = 1.0       // Scale window contents. Pixels
                                                 // (or accept the glitch).
 Window.Scaling.Smooth               = 1         // If you set this to 1, scaling will smooth pixels.
                                                 // Set to 0 will use "nearest neighbour" scaling.
+
+//
+// Visualizers
+//
+Visualizer.PulseWidth.Style         = 0         // The way pulse width is visualized
+                                                // 0 = absolute value, 1 = alternative style
+
 //
 // OVERLAY
 //

From 7b101b64c586e42e8047e22fac0439d9f561e4bf Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Fri, 15 Sep 2023 15:01:06 +0200
Subject: [PATCH 07/13] Mute pulse visualizer when track is muted

---
 .../component_pulse_filter_visualizer.cpp     |  26 ++--
 .../component_pulse_filter_visualizer.h       |  29 +++--
 .../runtime/editor/screens/screen_edit.cpp    | 115 +++++++++---------
 ...isualizer_component_pulse_filter_state.cpp |  17 +--
 .../visualizer_component_pulse_filter_state.h |   6 +-
 5 files changed, 100 insertions(+), 93 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
index 25b7c4cf..e27b627f 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
@@ -7,35 +7,36 @@
 #include "runtime/editor/datasources/datasource_sidregistersbuffer.h"
 #include "runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h"
 #include "runtime/execution/executionhandler.h"
+#include "runtime/editor/datasources/datasource_track_components.h"
 
 namespace Editor
 {
 	ComponentPulseFilterVisualizer::ComponentPulseFilterVisualizer(
-		int inID, 
-		int inGroupID, 
+		int inID,
+		int inGroupID,
 		Undo* inUndo,
-		Emulation::ExecutionHandler* inExecutionHandler, 
+		Emulation::ExecutionHandler* inExecutionHandler,
 		Foundation::TextField* inTextField,
 		Foundation::Viewport* inViewport,
 		ComponentsManager* inComponentsManager,
-		int inX, 
-		int inY, 
+		std::shared_ptr<DataSourceTrackComponents> inTracks,
+		int inX,
+		int inY,
 		int inWidth,
-		int inHeight
-	)
+		int inHeight)
 		: ComponentBase(inID, inGroupID, inUndo, inTextField, inX, inY, inWidth, inHeight)
 		, m_Viewport(inViewport)
 		, m_ComponentsManager(inComponentsManager)
 	{
 		unsigned int viewport_width = inWidth * Foundation::TextField::font_width;
 		unsigned int viewport_height = inHeight * Foundation::TextField::font_height;
-		
+
 		m_DrawField = m_Viewport->CreateDrawField(viewport_width, viewport_height, inX * Foundation::TextField::font_width, inY * Foundation::TextField::font_height);
 		m_DrawField->SetEnable(true);
 
 		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> data_source_sid_registers_buffer = std::make_shared<DataSourceSIDRegistersBufferAfLastDriverUpdate>(inExecutionHandler);
-		
-		m_VisualizerComponent = std::make_shared<VisualizerComponentPulseFilterState>(1, m_DrawField, 0, 0, viewport_width, viewport_height, data_source_sid_registers_buffer);
+
+		m_VisualizerComponent = std::make_shared<VisualizerComponentPulseFilterState>(1, m_DrawField, 0, 0, viewport_width, viewport_height, data_source_sid_registers_buffer, inTracks);
 		m_VisualizerComponent->SetEnabled(true);
 		m_ComponentsManager->AddVisualizerComponent(m_VisualizerComponent);
 	}
@@ -63,27 +64,22 @@ namespace Editor
 
 	void ComponentPulseFilterVisualizer::Refresh(const DisplayState& inDisplayState)
 	{
-		
 	}
 
 	void ComponentPulseFilterVisualizer::HandleDataChange()
 	{
-		
 	}
 
 	void ComponentPulseFilterVisualizer::PullDataFromSource(const bool inFromUndo)
 	{
-		
 	}
 
 	void ComponentPulseFilterVisualizer::ExecuteInsertDeleteRule(const DriverInfo::TableInsertDeleteRule& inRule, int inSourceTableID, int inIndexPre, int inIndexPost)
 	{
-		
 	}
 
 	void ComponentPulseFilterVisualizer::ExecuteAction(int inActionInput)
 	{
-		
 	}
 
 }
diff --git a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h
index 32ee3c8c..59ba25b2 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h
+++ b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.h
@@ -1,7 +1,9 @@
 #pragma once
 #include "component_base.h"
+#include "runtime/editor/datasources/datasource_track_components.h"
 
-namespace Emulation {
+namespace Emulation
+{
 	class ExecutionHandler;
 }
 
@@ -11,7 +13,8 @@ namespace Editor
 	class VisualizerComponentPulseFilterState;
 }
 
-namespace Foundation {
+namespace Foundation
+{
 	class DrawField;
 }
 
@@ -24,24 +27,24 @@ namespace Editor
 {
 	class ComponentPulseFilterVisualizer : public ComponentBase
 	{
-	public:
+	  public:
 		ComponentPulseFilterVisualizer(
-			int inID, 
-			int inGroupID, 
+			int inID,
+			int inGroupID,
 			Undo* inUndo,
-			Emulation::ExecutionHandler* inExecutionHandler, 
+			Emulation::ExecutionHandler* inExecutionHandler,
 			Foundation::TextField* inTextField,
 			Foundation::Viewport* inViewport,
 			ComponentsManager* inComponentsManager,
-			int inX, 
-			int inY, 
+			std::shared_ptr<DataSourceTrackComponents> inTracks,
+			int inX,
+			int inY,
 			int inWidth,
-			int inHeight
-		);
+			int inHeight);
 		virtual ~ComponentPulseFilterVisualizer();
 
 		bool CanReceiveFocus() const override { return false; }
-		
+
 		bool ConsumeInput(const Foundation::Keyboard& inKeyboard, CursorControl& inCursorControl, ComponentsManager& inComponentsManager) override;
 		bool ConsumeInput(const Foundation::Mouse& inMouse, bool inModifierKeyMask, CursorControl& inCursorControl, ComponentsManager& inComponentsManager) override;
 		bool ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse) override;
@@ -53,10 +56,10 @@ namespace Editor
 		void ExecuteInsertDeleteRule(const DriverInfo::TableInsertDeleteRule& inRule, int inSourceTableID, int inIndexPre, int inIndexPost) override;
 		void ExecuteAction(int inActionInput) override;
 
-	private:
+	  private:
 		Foundation::Viewport* m_Viewport;
 		Foundation::DrawField* m_DrawField;
-		
+
 		ComponentsManager* m_ComponentsManager;
 
 		Emulation::ExecutionHandler* m_ExecutionHandler;
diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
index 257c2ec9..539308b0 100644
--- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
+++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
@@ -700,7 +700,7 @@ namespace Editor
 
 		AuxilaryDataEditingPreferences::NotationMode notation_mode = editing_preferences.GetNotationMode();
 		editing_preferences.SetNotationMode(notation_mode == AuxilaryDataEditingPreferences::NotationMode::Sharp
-			? AuxilaryDataEditingPreferences::NotationMode::Flat 
+			? AuxilaryDataEditingPreferences::NotationMode::Flat
 			: AuxilaryDataEditingPreferences::NotationMode::Sharp);
 
 		m_TracksComponent->ForceRefresh();
@@ -730,8 +730,8 @@ namespace Editor
 
 		if (!inToggleRegion)
 		{
-			const AuxilaryDataHardwarePreferences::SIDModel sid_model = hardware_preferences.GetSIDModel() == AuxilaryDataHardwarePreferences::SIDModel::MOS6581 
-				? AuxilaryDataHardwarePreferences::SIDModel::MOS8580 
+			const AuxilaryDataHardwarePreferences::SIDModel sid_model = hardware_preferences.GetSIDModel() == AuxilaryDataHardwarePreferences::SIDModel::MOS6581
+				? AuxilaryDataHardwarePreferences::SIDModel::MOS8580
 				: AuxilaryDataHardwarePreferences::SIDModel::MOS6581;
 
 			hardware_preferences.SetSIDModel(sid_model);
@@ -745,8 +745,8 @@ namespace Editor
 		}
 		else
 		{
-			const AuxilaryDataHardwarePreferences::Region hardware_region = hardware_preferences.GetRegion() == AuxilaryDataHardwarePreferences::Region::PAL 
-				? AuxilaryDataHardwarePreferences::Region::NTSC 
+			const AuxilaryDataHardwarePreferences::Region hardware_region = hardware_preferences.GetRegion() == AuxilaryDataHardwarePreferences::Region::PAL
+				? AuxilaryDataHardwarePreferences::Region::NTSC
 				: AuxilaryDataHardwarePreferences::Region::PAL;
 
 			hardware_preferences.SetRegion(hardware_region);
@@ -842,7 +842,7 @@ namespace Editor
 
 						m_CPUMemory->Unlock();
 
-						m_ComponentsManager->StartDialog(std::make_shared<DialogMessage>("Statistics", text, 60, false, []() {}));						
+						m_ComponentsManager->StartDialog(std::make_shared<DialogMessage>("Statistics", text, 60, false, []() {}));
 					}
 					break;
 				case DialogUtilities::Selection::Optimize:
@@ -893,10 +893,10 @@ namespace Editor
 						{
 							const unsigned short default_destination_address = 0x1000;
 							m_ComponentsManager->StartDialog(std::make_shared<DialogPackingOptions>(
-								default_destination_address, 
-								zp_range.m_LowestZeroPage, 
-								zp_range, 
-								dialog_ok, 
+								default_destination_address,
+								zp_range.m_LowestZeroPage,
+								zp_range,
+								dialog_ok,
 								dialog_cancel
 							));
 						}
@@ -929,7 +929,7 @@ namespace Editor
 							m_CPUMemory->Lock();
 
 							DataSourceUtils::ExpandSequences(m_SequenceDataSources);
-		
+
 							m_CPUMemory->Unlock();
 
 							m_ComponentsManager->ForceRefresh();
@@ -1118,7 +1118,7 @@ namespace Editor
 
 			return first_free_sequence_index;
 		};
-		
+
 		auto get_first_empty_sequence_index = [&]() -> unsigned char
 		{
 			m_CPUMemory->Lock();
@@ -1173,20 +1173,20 @@ namespace Editor
 		);
 
 		m_OrderListOverviewComponent = std::make_shared<ComponentOrderListOverview>(
-			OrderListOverviewID, 0, 
+			OrderListOverviewID, 0,
 			undo,
 			m_MainTextField,
 			m_EditState,
 			m_KeyHookStore,
 			song_view_text_buffer,
-			m_OrderListDataSources, 
-			m_SequenceDataSources, 
-			1, 
-			top, 
-			order_list_overview_bottom - top, 
+			m_OrderListDataSources,
+			m_SequenceDataSources,
+			1,
+			top,
+			order_list_overview_bottom - top,
 			[&](int inEventPosition, bool inStartPlayingFromPosition)
 			{
-				m_TracksComponent->SetEventPosition(inEventPosition, false); 
+				m_TracksComponent->SetEventPosition(inEventPosition, false);
 				if(inStartPlayingFromPosition)
 					DoPlay(inEventPosition);
 			}
@@ -1203,14 +1203,14 @@ namespace Editor
 
 		m_PlayMarkerListComponent = std::make_shared<ComponentStringListSelector>(
 			PlayMarkerListID, 0,
-			undo, 
-			play_markers_data_source, 
-			m_MainTextField, 
-			1, 
-			player_markers_list_top, 
-			play_markers_width, 
-			play_markers_height, 
-			1, 
+			undo,
+			play_markers_data_source,
+			m_MainTextField,
+			1,
+			player_markers_list_top,
+			play_markers_width,
+			play_markers_height,
+			1,
 			0
 		);
 		m_PlayMarkerListComponent->SetColors(ToColor(UserColor::MarkerListBackground), ToColor(UserColor::MarkerListCursorFocus), ToColor(UserColor::MarkerListCursorNoFocus));
@@ -1233,6 +1233,7 @@ namespace Editor
 			m_MainTextField,
 			m_Viewport,
 			m_ComponentsManager.get(),
+			m_TracksDataSource,
 			1,
 			pulse_filter_visualzer_top,
 			play_markers_width,
@@ -1242,15 +1243,15 @@ namespace Editor
 
 		// Create the tracks component for editing orderlist and sequence data
 		m_TracksComponent = std::make_shared<ComponentTracks>(
-			TracksTableID, 0, 
-			undo, 
-			m_TracksDataSource, 
+			TracksTableID, 0,
+			undo,
+			m_TracksDataSource,
 			m_NotSelectedSongOrderListDataSources,
-			m_MainTextField, 
-			m_DriverInfo->GetAuxilaryDataCollection(), 
+			m_MainTextField,
+			m_DriverInfo->GetAuxilaryDataCollection(),
 			m_EditState,
-			tracks_table_x, 
-			top, 
+			tracks_table_x,
+			top,
 			bottom - top);
 		m_ComponentsManager->AddComponent(m_TracksComponent);
 
@@ -1263,7 +1264,7 @@ namespace Editor
 
 		// Create tables as configured by the driver
 		const std::vector<DriverInfo::TableDefinition>& table_definitions = m_DriverInfo->GetTableDefinitions();
-		
+
 		int highest_table = 0;
 		int widest_table = 0;
 
@@ -1403,9 +1404,9 @@ namespace Editor
 
 				table->GetSelectedRowChangedEvent().Add(
 					nullptr,
-					Utility::TDelegate<void(int)>([&](int inSelectedRow) 
-					{ 
-						m_EditState.SetSelectedInstrument(static_cast<unsigned char>(inSelectedRow)); 
+					Utility::TDelegate<void(int)>([&](int inSelectedRow)
+					{
+						m_EditState.SetSelectedInstrument(static_cast<unsigned char>(inSelectedRow));
 						m_TracksComponent->ForceRefresh();
 					})
 				);
@@ -1417,9 +1418,9 @@ namespace Editor
 
 				table->GetSelectedRowChangedEvent().Add(
 					nullptr,
-					Utility::TDelegate<void(int)>([&](int inSelectedRow) 
-					{ 
-						m_EditState.SetSelectedCommand(static_cast<unsigned char>(inSelectedRow)); 
+					Utility::TDelegate<void(int)>([&](int inSelectedRow)
+					{
+						m_EditState.SetSelectedCommand(static_cast<unsigned char>(inSelectedRow));
 						m_TracksComponent->ForceRefresh();
 					})
 				);
@@ -1774,7 +1775,7 @@ namespace Editor
 
 			return true;
 		} });
- 
+
 		m_KeyHooks.push_back({ "Key.ScreenEdit.PlayFromMarker", m_KeyHookStore, [&]()
 		{
 			if (IsPlaying())
@@ -1843,31 +1844,31 @@ namespace Editor
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.OctaveDown", m_KeyHookStore, [&]()
-		{ 
-			DoOctaveChange(false); 
+		{
+			DoOctaveChange(false);
 			return true;
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.OctaveUp", m_KeyHookStore, [&]()
-		{ 
-			DoOctaveChange(true); 
+		{
+			DoOctaveChange(true);
 			return true;
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.ToggleSIDModel", m_KeyHookStore, [&]()
-		{ 
-			DoToggleSIDModelAndRegion(false); 
+		{
+			DoToggleSIDModelAndRegion(false);
 			return true;
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.ToggleRegion", m_KeyHookStore, [&]()
-		{ 
-			DoToggleSIDModelAndRegion(true); 
+		{
+			DoToggleSIDModelAndRegion(true);
 			return true;
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.LoadSong", m_KeyHookStore, [&]()
-		{ 
+		{
 			DoStop();
 			DoLoadSong();
 
@@ -1875,7 +1876,7 @@ namespace Editor
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.LoadInstrument", m_KeyHookStore, [&]()
-		{ 
+		{
 			DoStop();
 			DoLoadInstrument();
 
@@ -1883,7 +1884,7 @@ namespace Editor
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.ImportSong", m_KeyHookStore, [&]()
-		{ 
+		{
 			DoStop();
 			DoLoadImportSong();
 
@@ -1891,7 +1892,7 @@ namespace Editor
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.SaveSong", m_KeyHookStore, [&]()
-		{ 
+		{
 			DoStop();
 			DoSaveSong();
 
@@ -1899,7 +1900,7 @@ namespace Editor
 		} });
 
 		m_KeyHooks.push_back({ "Key.ScreenEdit.SaveInstrument", m_KeyHookStore, [&]()
-		{ 
+		{
 			DoStop();
 			DoSaveInstrument();
 
@@ -1989,7 +1990,7 @@ namespace Editor
 		{
 			if (m_Undo->HasRedoStep())
 			{
-				m_Undo->DoRedo(*m_CursorControl);			
+				m_Undo->DoRedo(*m_CursorControl);
 				m_ComponentsManager->PullDataFromAllSources(true);
 			}
 
@@ -2135,7 +2136,7 @@ namespace Editor
 					if (it == m_KeyTableIDPairs.end())
 						return static_cast<int>(i);
 				}
-				
+
 				return -1;
 			}(table_definition.m_Name);
 
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index dcfe2de6..ccc33c9a 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -16,18 +16,18 @@ using namespace Utility::Config;
 
 namespace Editor
 {
-	VisualizerComponentPulseFilterState::VisualizerComponentPulseFilterState
-	(
+	VisualizerComponentPulseFilterState::VisualizerComponentPulseFilterState(
 		int inID,
 		Foundation::DrawField* inDrawField,
 		int inX,
 		int inY,
 		int inWidth,
 		int inHeight,
-		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource
-	)
+		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource,
+		std::shared_ptr<DataSourceTrackComponents> inTracks)
 		: VisualizerComponentBase(inID, inDrawField, inX, inY, inWidth, inHeight)
 		, m_DataSource(inDataSource)
+		, m_Tracks(inTracks)
 	{
 		ConfigFile& config_file = Global::instance().GetConfig();
 		m_PulseWidthStyle = GetSingleConfigurationValue<ConfigValueInt>(config_file, "Visualizer.PulseWidth.Style", 0);
@@ -41,12 +41,12 @@ namespace Editor
 
 	bool VisualizerComponentPulseFilterState::ConsumeNonExclusiveInput(const Foundation::Mouse& inMouse)
 	{
-		if(inMouse.IsButtonPressed(Mouse::Button::Left))
+		if (inMouse.IsButtonPressed(Mouse::Button::Left))
 		{
 			m_PulseWidthStyle = (m_PulseWidthStyle + 1) & 1;
 			return true;
 		}
-		
+
 		return false;
 	}
 
@@ -99,7 +99,10 @@ namespace Editor
 
 			for (unsigned int i = 0; i < 3; ++i)
 			{
-				DrawBarWithCenterDivider(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
+				if (!(*m_Tracks)[i]->IsMuted())
+				{
+					DrawBarWithCenterDivider(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
+				}
 				bar_y += bar_spacing;
 			}
 
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
index 94b5ff88..4c33c7ed 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -2,6 +2,7 @@
 
 #include "visualizer_component_base.h"
 #include <memory>
+#include "runtime/editor/datasources/datasource_track_components.h"
 
 namespace Foundation
 {
@@ -22,7 +23,8 @@ namespace Editor
 			int inY,
 			int inWidth,
 			int inHeight,
-			std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource
+			std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> inDataSource,
+			std::shared_ptr<DataSourceTrackComponents> inTracks
 		);
 		virtual ~VisualizerComponentPulseFilterState();
 
@@ -52,6 +54,8 @@ namespace Editor
 			const Foundation::Color& inDividerColor);
 
 		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> m_DataSource;
+		std::shared_ptr<DataSourceTrackComponents> m_Tracks;
+
 		int m_PulseWidthStyle;
 	};
 }
\ No newline at end of file

From 23b2afe18b7dcc375b18de68cc36e8e2f4d5fd52 Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Fri, 15 Sep 2023 15:33:25 +0200
Subject: [PATCH 08/13] Used same enabled/muted colors as the track

---
 .../components/component_pulse_filter_visualizer.cpp     | 2 +-
 .../visualizer_component_pulse_filter_state.cpp          | 9 +++++++--
 2 files changed, 8 insertions(+), 3 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
index e27b627f..e1244add 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_pulse_filter_visualizer.cpp
@@ -5,9 +5,9 @@
 #include "foundation/graphics/viewport.h"
 #include "runtime/editor/components_manager.h"
 #include "runtime/editor/datasources/datasource_sidregistersbuffer.h"
+#include "runtime/editor/datasources/datasource_track_components.h"
 #include "runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h"
 #include "runtime/execution/executionhandler.h"
-#include "runtime/editor/datasources/datasource_track_components.h"
 
 namespace Editor
 {
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index ccc33c9a..45148c20 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -56,10 +56,11 @@ namespace Editor
 		if (m_Enabled)
 		{
 			const Color color_background = ToColor(UserColor::StateBarArea);
-			const Color color_bar = ToColor(UserColor::StateBarBackground);
+			const Color color_bar = ToColor(UserColor::TrackBackground);
 			const Color color_bar_filtered_channel = ToColor(UserColor::StateBarBackgroundFilteredChannel);
 			const Color color_bar_fill = ToColor(UserColor::StateBarFillColorPulse);
 			const Color color_bar_fill_filter = ToColor(UserColor::StateBarFillColorFilter);
+			const Color color_muted = ToColor(UserColor::TrackBackgroundMuted);
 
 			m_DataSource->PullDataFromSource();
 
@@ -99,7 +100,11 @@ namespace Editor
 
 			for (unsigned int i = 0; i < 3; ++i)
 			{
-				if (!(*m_Tracks)[i]->IsMuted())
+				if ((*m_Tracks)[i]->IsMuted())
+				{
+					m_DrawField->DrawBox(color_muted, bar_x, bar_y, bar_width, bar_height);
+				}
+				else
 				{
 					DrawBarWithCenterDivider(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
 				}

From 86b13225c576462ff615247a5654919cc155c713 Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Fri, 15 Sep 2023 16:10:12 +0200
Subject: [PATCH 09/13] If no enabled channels use filter, mute filter meter

---
 .../visualizer_component_pulse_filter_state.cpp    | 14 ++++++++++++--
 1 file changed, 12 insertions(+), 2 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index 45148c20..37bf63dd 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -98,9 +98,12 @@ namespace Editor
 				return (data_source[0x17] & (1 << inChannel)) != 0;
 			};
 
+			bool any_enabled_channel_filtered = false;
 			for (unsigned int i = 0; i < 3; ++i)
 			{
-				if ((*m_Tracks)[i]->IsMuted())
+				bool is_muted = (*m_Tracks)[i]->IsMuted();
+				any_enabled_channel_filtered = any_enabled_channel_filtered | (is_channel_filtered(i) & !is_muted);
+				if (is_muted)
 				{
 					m_DrawField->DrawBox(color_muted, bar_x, bar_y, bar_width, bar_height);
 				}
@@ -121,7 +124,14 @@ namespace Editor
 				return value;
 			};
 
-			DrawBar(bar_x, bar_y, bar_width, bar_height, get_filter_value(), 0x07ff, color_bar, color_bar_fill_filter);
+			if (any_enabled_channel_filtered)
+			{
+				DrawBar(bar_x, bar_y, bar_width, bar_height, get_filter_value(), 0x07ff, color_bar, color_bar_fill_filter);
+			}
+			else
+			{
+				m_DrawField->DrawBox(color_muted, bar_x, bar_y, bar_width, bar_height);
+			}
 		}
 	}
 

From 65839dd9bdc74e5a0b8fb2ef9b078c62e2df4535 Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Fri, 15 Sep 2023 16:17:45 +0200
Subject: [PATCH 10/13] Revert "If no enabled channels use filter, mute filter
 meter"

This reverts commit 86b13225c576462ff615247a5654919cc155c713.
---
 .../visualizer_component_pulse_filter_state.cpp    | 14 ++------------
 1 file changed, 2 insertions(+), 12 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index 37bf63dd..45148c20 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -98,12 +98,9 @@ namespace Editor
 				return (data_source[0x17] & (1 << inChannel)) != 0;
 			};
 
-			bool any_enabled_channel_filtered = false;
 			for (unsigned int i = 0; i < 3; ++i)
 			{
-				bool is_muted = (*m_Tracks)[i]->IsMuted();
-				any_enabled_channel_filtered = any_enabled_channel_filtered | (is_channel_filtered(i) & !is_muted);
-				if (is_muted)
+				if ((*m_Tracks)[i]->IsMuted())
 				{
 					m_DrawField->DrawBox(color_muted, bar_x, bar_y, bar_width, bar_height);
 				}
@@ -124,14 +121,7 @@ namespace Editor
 				return value;
 			};
 
-			if (any_enabled_channel_filtered)
-			{
-				DrawBar(bar_x, bar_y, bar_width, bar_height, get_filter_value(), 0x07ff, color_bar, color_bar_fill_filter);
-			}
-			else
-			{
-				m_DrawField->DrawBox(color_muted, bar_x, bar_y, bar_width, bar_height);
-			}
+			DrawBar(bar_x, bar_y, bar_width, bar_height, get_filter_value(), 0x07ff, color_bar, color_bar_fill_filter);
 		}
 	}
 

From 79f70b85c9fef26e296bc3675962e391035bd16e Mon Sep 17 00:00:00 2001
From: Michel de Bree <michel@micheldebree.nl>
Date: Sat, 16 Sep 2023 08:50:21 +0200
Subject: [PATCH 11/13] Made bar with divider pulse width bar

It already had pulse width specifics in the implementation, so
I made that clearer
---
 .../visualizer_component_pulse_filter_state.cpp | 17 ++++++++++-------
 .../visualizer_component_pulse_filter_state.h   |  5 ++---
 2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index 45148c20..a062d64a 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -106,7 +106,7 @@ namespace Editor
 				}
 				else
 				{
-					DrawBarWithCenterDivider(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), 0x0fff, is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
+					DrawPulseWidthBar(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
 				}
 				bar_y += bar_spacing;
 			}
@@ -148,32 +148,35 @@ namespace Editor
 	}
 
 
-	void VisualizerComponentPulseFilterState::DrawBarWithCenterDivider(
+	// Draw a bar for pulse width
+	void VisualizerComponentPulseFilterState::DrawPulseWidthBar(
 		int inX,
 		int inY,
 		int inWidth,
 		int inHeight,
 		int inValue,
-		int inMaxValue,
 		const Foundation::Color& inBarColor,
 		const Foundation::Color& inBarColorFill,
 		const Foundation::Color& inDividerColor)
 	{
 		m_DrawField->DrawBox(inBarColor, inX, inY, inWidth, inHeight);
 
+		int maxValue = 0xfff;
+		int middleValue = (maxValue / 2);
+
 		if (inValue > 0)
 		{
 			if (m_PulseWidthStyle == 1)
 			{
-				int abs_value = inValue > 0x800 ? 0x1000 - inValue : inValue;
-				float width_fraction = static_cast<float>(abs_value) / static_cast<float>(inMaxValue);
+				int abs_value = inValue > middleValue ? maxValue - inValue : inValue;
+				float width_fraction = static_cast<float>(abs_value) / static_cast<float>(maxValue);
 				int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
-				int x = inValue > 0x800 ? inX + (inWidth - width) : inX;
+				int x = inValue > middleValue ? inX + (inWidth - width) : inX;
 				m_DrawField->DrawBox(inBarColorFill, x, inY + 1, width, inHeight - 2);
 			}
 			else
 			{
-				float width_fraction = static_cast<float>(inValue) / static_cast<float>(inMaxValue);
+				float width_fraction = static_cast<float>(inValue) / static_cast<float>(maxValue);
 				int width = static_cast<int>(static_cast<float>(inWidth) * (width_fraction < 0 ? 0 : (width_fraction > 1.0f ? 1.0f : width_fraction)));
 				m_DrawField->DrawBox(inBarColorFill, inX, inY + 1, width, inHeight - 2);
 			}
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
index 4c33c7ed..55fa2695 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -42,13 +42,12 @@ namespace Editor
 			 const Foundation::Color& inBarColor,
 			 const Foundation::Color& inBarColorFill);
 
-		void DrawBarWithCenterDivider(
+		void DrawPulseWidthBar(
 			int inX,
 			int inY,
 			int inWidth,
 			int inHeight,
 			int inValue,
-			int inMaxValue,
 			const Foundation::Color& inBarColor,
 			const Foundation::Color& inBarColorFill,
 			const Foundation::Color& inDividerColor);
@@ -58,4 +57,4 @@ namespace Editor
 
 		int m_PulseWidthStyle;
 	};
-}
\ No newline at end of file
+}

From 6ab500b9a684d088dbef50325f05a1091065c355 Mon Sep 17 00:00:00 2001
From: rawpowerlaxity <thomas@rawpowergames.com>
Date: Sat, 16 Sep 2023 10:24:30 +0200
Subject: [PATCH 12/13] [minor] Changed color settings propery names for the
 pulse and filter visualization from Color.StateBar.xxx to
 Color.Visualizer.xxx

Also added specific color for the pulse bar separator line

NOTE: Added a default DarkestGrey color the fall back color definitions
---
 SIDFactoryII/color_schemes/default.ini        | 12 +++++----
 .../source/foundation/graphics/color.cpp      |  1 +
 .../source/foundation/graphics/color.h        |  1 +
 ...isualizer_component_pulse_filter_state.cpp | 26 ++++++++++++-------
 .../visualizer_component_pulse_filter_state.h |  2 +-
 .../source/utils/config/configcolors.cpp      | 12 +++++----
 SIDFactoryII/source/utils/usercolors.h        | 12 +++++----
 7 files changed, 41 insertions(+), 25 deletions(-)

diff --git a/SIDFactoryII/color_schemes/default.ini b/SIDFactoryII/color_schemes/default.ini
index 09938bcc..85f1bed7 100644
--- a/SIDFactoryII/color_schemes/default.ini
+++ b/SIDFactoryII/color_schemes/default.ini
@@ -110,11 +110,13 @@ Color.Orderlist.Value											= :LightGrey
 Color.Orderlist.Value.Loop.Marker								= :LightGreen
 Color.Orderlist.Value.Input										= :White
 
-Color.StateBar.Area												= :DarkestGrey
-Color.StateBar.Bar.Background									= :DarkerGrey
-Color.StateBar.Bar.BackgroundFilteredChannel					= :LightGrey
-Color.StateBar.Bar.FillColorPulse								= :White
-Color.StateBar.Bar.FillColorFilter								= :LightGrey
+Color.Visualizer.Area											= :DarkestGrey
+Color.Visualizer.Bar.Background									= :DarkGrey
+Color.Visualizer.Bar.BackgroundMuted							= :DarkerGrey
+Color.Visualizer.Bar.BackgroundFilteredChannel					= :Grey
+Color.Visualizer.Bar.Separator									= :DarkestGrey
+Color.Visualizer.Bar.FillColorPulse								= :White
+Color.Visualizer.Bar.FillColorFilter							= :LightGrey
 
 Color.Dialog.Background                 						= :DarkRed
 Color.Dialog.Header                     						= :Red
diff --git a/SIDFactoryII/source/foundation/graphics/color.cpp b/SIDFactoryII/source/foundation/graphics/color.cpp
index e2853175..942e5fef 100644
--- a/SIDFactoryII/source/foundation/graphics/color.cpp
+++ b/SIDFactoryII/source/foundation/graphics/color.cpp
@@ -33,6 +33,7 @@ namespace Foundation
 		m_Colors[0x14] = 0xff004800;		// Darker Green
 		m_Colors[0x15] = 0xff000060;		// Darker Blue
 		m_Colors[0x16] = 0xff4c4c00;		// Darker Yellow
+		m_Colors[0x17] = 0xff101010;		// Darkest Grey
 	}
 
 
diff --git a/SIDFactoryII/source/foundation/graphics/color.h b/SIDFactoryII/source/foundation/graphics/color.h
index 30ee15de..50a25f17 100644
--- a/SIDFactoryII/source/foundation/graphics/color.h
+++ b/SIDFactoryII/source/foundation/graphics/color.h
@@ -29,6 +29,7 @@ namespace Foundation
 		DarkerGreen,		// 20
 		DarkerBlue,			// 21
 		DarkerYellow,		// 22
+		DarkestGrey,		// 23
 
 		UserColor00 = 0x40,
 	};
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
index a062d64a..1ad95945 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.cpp
@@ -55,12 +55,13 @@ namespace Editor
 	{
 		if (m_Enabled)
 		{
-			const Color color_background = ToColor(UserColor::StateBarArea);
-			const Color color_bar = ToColor(UserColor::TrackBackground);
-			const Color color_bar_filtered_channel = ToColor(UserColor::StateBarBackgroundFilteredChannel);
-			const Color color_bar_fill = ToColor(UserColor::StateBarFillColorPulse);
-			const Color color_bar_fill_filter = ToColor(UserColor::StateBarFillColorFilter);
-			const Color color_muted = ToColor(UserColor::TrackBackgroundMuted);
+			const Color color_background = ToColor(UserColor::VisualizerArea);
+			const Color color_bar = ToColor(UserColor::VisualizerBarBackground);
+			const Color color_bar_filtered_channel = ToColor(UserColor::VisualizerBarBackgroundFilteredChannel);
+			const Color color_bar_fill = ToColor(UserColor::VisualizerBarFillColorPulse);
+			const Color color_bar_fill_filter = ToColor(UserColor::VisualizerBarFillColorFilter);
+			const Color color_muted = ToColor(UserColor::VisualizerBarBackgroundMuted);
+			const Color color_separator = ToColor(UserColor::VisualizerBarSeparator);
 
 			m_DataSource->PullDataFromSource();
 
@@ -106,7 +107,14 @@ namespace Editor
 				}
 				else
 				{
-					DrawPulseWidthBar(bar_x, bar_y, bar_width, bar_height, get_pulse_value(i), is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill, color_background);
+					DrawPulseWidthBar(
+						bar_x,
+						bar_y,
+						bar_width,
+						bar_height,
+						get_pulse_value(i),
+						is_channel_filtered(i) ? color_bar_filtered_channel : color_bar, color_bar_fill,
+						color_separator);
 				}
 				bar_y += bar_spacing;
 			}
@@ -157,7 +165,7 @@ namespace Editor
 		int inValue,
 		const Foundation::Color& inBarColor,
 		const Foundation::Color& inBarColorFill,
-		const Foundation::Color& inDividerColor)
+		const Foundation::Color& inSeparatorColor)
 	{
 		m_DrawField->DrawBox(inBarColor, inX, inY, inWidth, inHeight);
 
@@ -182,6 +190,6 @@ namespace Editor
 			}
 		}
 
-		m_DrawField->DrawVerticalLine(inDividerColor, inX + inWidth / 2, inY, inY + inHeight);
+		m_DrawField->DrawVerticalLine(inSeparatorColor, inX + inWidth / 2, inY, inY + inHeight);
 	}
 }
diff --git a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
index 55fa2695..e11d5b61 100644
--- a/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
+++ b/SIDFactoryII/source/runtime/editor/visualizer_components/visualizer_component_pulse_filter_state.h
@@ -50,7 +50,7 @@ namespace Editor
 			int inValue,
 			const Foundation::Color& inBarColor,
 			const Foundation::Color& inBarColorFill,
-			const Foundation::Color& inDividerColor);
+			const Foundation::Color& inSeparatorColor);
 
 		std::shared_ptr<DataSourceSIDRegistersBufferAfLastDriverUpdate> m_DataSource;
 		std::shared_ptr<DataSourceTrackComponents> m_Tracks;
diff --git a/SIDFactoryII/source/utils/config/configcolors.cpp b/SIDFactoryII/source/utils/config/configcolors.cpp
index 3c6aebe5..543b293e 100644
--- a/SIDFactoryII/source/utils/config/configcolors.cpp
+++ b/SIDFactoryII/source/utils/config/configcolors.cpp
@@ -103,11 +103,13 @@ namespace Utility
 			Details::SetUserColor(inConfigFile, "Color.Orderlist.Value.Loop.Marker", UserColor::OrderlistValueLoopMarker, ioViewport, Color::LightGreen);
 			Details::SetUserColor(inConfigFile, "Color.Orderlist.Value.Input", UserColor::OrderlistValueInput, ioViewport, Color::White);
 
-			Details::SetUserColor(inConfigFile, "Color.StateBar.Area", UserColor::StateBarArea, ioViewport, Color::DarkerGrey);
-			Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.Background", UserColor::StateBarBackground, ioViewport, Color::DarkGrey);
-      Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.BackgroundFilteredChannel", UserColor::StateBarBackgroundFilteredChannel, ioViewport, Color::Grey);
-      Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.FillColorPulse", UserColor::StateBarFillColorPulse, ioViewport, Color::White);
-      Details::SetUserColor(inConfigFile, "Color.StateBar.Bar.FillColorFilter", UserColor::StateBarFillColorFilter, ioViewport, Color::LightGrey);
+			Details::SetUserColor(inConfigFile, "Color.Visualizer.Area", UserColor::VisualizerArea, ioViewport, Color::DarkestGrey);
+			Details::SetUserColor(inConfigFile, "Color.Visualizer.Bar.Background", UserColor::VisualizerBarBackground, ioViewport, Color::DarkGrey);
+			Details::SetUserColor(inConfigFile, "Color.Visualizer.Bar.BackgroundMuted", UserColor::VisualizerBarBackgroundMuted, ioViewport, Color::DarkerGrey);
+      		Details::SetUserColor(inConfigFile, "Color.Visualizer.Bar.BackgroundFilteredChannel", UserColor::VisualizerBarBackgroundFilteredChannel, ioViewport, Color::Grey);
+      		Details::SetUserColor(inConfigFile, "Color.Visualizer.Bar.Separator", UserColor::VisualizerBarSeparator, ioViewport, Color::DarkestGrey);
+      		Details::SetUserColor(inConfigFile, "Color.Visualizer.Bar.FillColorPulse", UserColor::VisualizerBarFillColorPulse, ioViewport, Color::White);
+      		Details::SetUserColor(inConfigFile, "Color.Visualizer.Bar.FillColorFilter", UserColor::VisualizerBarFillColorFilter, ioViewport, Color::LightGrey);
 
 			Details::SetUserColor(inConfigFile, "Color.Dialog.Background", UserColor::DialogBackground, ioViewport, Color::DarkRed);
 			Details::SetUserColor(inConfigFile, "Color.Dialog.Header", UserColor::DialogHeader, ioViewport, Color::Red);
diff --git a/SIDFactoryII/source/utils/usercolors.h b/SIDFactoryII/source/utils/usercolors.h
index 2419cc4e..e9e94254 100644
--- a/SIDFactoryII/source/utils/usercolors.h
+++ b/SIDFactoryII/source/utils/usercolors.h
@@ -93,11 +93,13 @@ namespace Utility
 		OrderlistValue,
 		OrderlistValueLoopMarker,
 		OrderlistValueInput,
-		StateBarArea,
-		StateBarBackground,
-		StateBarBackgroundFilteredChannel,
-		StateBarFillColorPulse,
-		StateBarFillColorFilter,
+		VisualizerArea,
+		VisualizerBarBackground,
+		VisualizerBarBackgroundMuted,
+		VisualizerBarBackgroundFilteredChannel,
+		VisualizerBarSeparator,
+		VisualizerBarFillColorPulse,
+		VisualizerBarFillColorFilter,
 		DialogBackground,
 		DialogHeader,
 		DialogHeaderText,

From 876107d947d7c602750f265a93cc69cf2c0c3513 Mon Sep 17 00:00:00 2001
From: rawpowerlaxity <thomas@rawpowergames.com>
Date: Tue, 5 Dec 2023 23:17:23 +0100
Subject: [PATCH 13/13] [minor] Adding support for showing the use count of a
 sequence in the message bar, when ever the current sequence index changes for
 editing, or the orderlist is altered.

---
 SIDFactoryII/SIDFactoryII.vcxproj             |  4 +--
 .../component_orderlistoverview.cpp           |  1 +
 .../editor/components/component_track.cpp     | 28 ++++++++--------
 .../editor/components/component_track.h       |  4 +--
 .../editor/components/component_tracks.cpp    | 14 ++++++++
 .../editor/components/component_tracks.h      |  4 +++
 .../runtime/editor/driver/driver_utils.cpp    |  8 ++---
 .../runtime/editor/screens/screen_edit.cpp    | 32 +++++++++++++++++--
 .../runtime/editor/screens/screen_edit.h      |  4 ++-
 .../editor/screens/statusbar/status_bar.cpp   | 16 +++++++---
 .../editor/screens/statusbar/status_bar.h     |  3 +-
 .../source/runtime/emulation/cpumemory.cpp    | 28 ++++++++--------
 .../source/runtime/emulation/cpumemory.h      |  8 ++---
 13 files changed, 104 insertions(+), 50 deletions(-)

diff --git a/SIDFactoryII/SIDFactoryII.vcxproj b/SIDFactoryII/SIDFactoryII.vcxproj
index 36e1ddc3..8032479f 100644
--- a/SIDFactoryII/SIDFactoryII.vcxproj
+++ b/SIDFactoryII/SIDFactoryII.vcxproj
@@ -29,13 +29,13 @@
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>true</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
   <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
     <ConfigurationType>Application</ConfigurationType>
     <UseDebugLibraries>false</UseDebugLibraries>
-    <PlatformToolset>v142</PlatformToolset>
+    <PlatformToolset>v143</PlatformToolset>
     <WholeProgramOptimization>true</WholeProgramOptimization>
     <CharacterSet>MultiByte</CharacterSet>
   </PropertyGroup>
diff --git a/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp b/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp
index ec424f9c..43575d30 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_orderlistoverview.cpp
@@ -575,6 +575,7 @@ namespace Editor
 	void ComponentOrderListOverview::PullDataFromSource(const bool inFromUndo)
 	{
 		m_TableText->PullDataFromSource();
+		m_RequireRefresh |= inFromUndo;
 	}
 
 
diff --git a/SIDFactoryII/source/runtime/editor/components/component_track.cpp b/SIDFactoryII/source/runtime/editor/components/component_track.cpp
index ce44e0a1..eec5f910 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_track.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_track.cpp
@@ -187,14 +187,12 @@ namespace Editor
 			UpdateSequenceStatusReport();
 		}
 
-		{
-			const unsigned int order_list_index = m_EventPosDetails.OrderListIndex();
-			const auto& order_list_entry = (*m_DataSourceOrderList)[order_list_index];
-			if (order_list_entry.m_Transposition >= 0xfe)
-				m_OrderListIndexChangedEvent.Execute(m_HasControl, order_list_index, 0xff);
-			else
-				m_OrderListIndexChangedEvent.Execute(m_HasControl, order_list_index, order_list_entry.m_SequenceIndex);
-		}
+		const unsigned int order_list_index = m_EventPosDetails.OrderListIndex();
+		const auto& order_list_entry = (*m_DataSourceOrderList)[order_list_index];
+		if (order_list_entry.m_Transposition >= 0xfe)
+			m_OrderListIndexChangedEvent.Execute(m_HasControl, order_list_index, 0xff);
+		else
+			m_OrderListIndexChangedEvent.Execute(m_HasControl, order_list_index, order_list_entry.m_SequenceIndex);
 	}
 
 
@@ -572,6 +570,8 @@ namespace Editor
 			{
 				if (m_DataSourceOrderList->PushDataToSource())
 					m_HasDataChangeOrderList = false;
+
+				SetEventPosDetails(m_EventPosDetails.OrderListIndex(), m_EventPosDetails.SequenceIndex(), true);
 			}
 
 			if (!m_DataChangeSequenceIndexList.empty())
@@ -657,7 +657,7 @@ namespace Editor
 	}
 
 
-	void ComponentTrack::SetEventPosition(int inEventPos)
+	void ComponentTrack::SetEventPosition(int inEventPos, bool inForceOrderListIndexChangeEvent)
 	{
 		FOUNDATION_ASSERT(inEventPos >= 0);
 
@@ -702,7 +702,7 @@ namespace Editor
 				if (!found_event_pos && m_EventPos >= event_pos && m_EventPos < next_event_pos)
 				{
 					found_event_pos = true;
-					SetEventPosDetails(i, m_EventPos - event_pos);
+					SetEventPosDetails(i, m_EventPos - event_pos, inForceOrderListIndexChangeEvent);
 
 					break;
 				}
@@ -772,7 +772,7 @@ namespace Editor
 		if (m_HasControl && m_FocusModeOrderList)
 		{
 			int event_pos = GetEventPositionAtTopOfCurrentSequence();
-			SetEventPosition(event_pos);
+			SetEventPosition(event_pos, true);
 		}
 
 		UpdateOrderListStatusReport();
@@ -1842,13 +1842,13 @@ namespace Editor
 	}
 
 
-	void ComponentTrack::SetEventPosDetails(unsigned int inOrderListIndex, unsigned int inSequenceIndex)
+	void ComponentTrack::SetEventPosDetails(unsigned int inOrderListIndex, unsigned int inSequenceIndex, bool inForceOrderListIndexChangeEvent)
 	{
 		unsigned int previous_order_list_index = m_EventPosDetails.OrderListIndex();
 
 		m_EventPosDetails.Set(inOrderListIndex, inSequenceIndex);
 
-		if (inOrderListIndex != previous_order_list_index)
+		if (inOrderListIndex != previous_order_list_index || inForceOrderListIndexChangeEvent)
 		{
 			const auto& order_list_entry = (*m_DataSourceOrderList)[inOrderListIndex];
 			if (order_list_entry.m_Transposition >= 0xfe)
@@ -2209,7 +2209,7 @@ namespace Editor
 				}
 
 				int event_pos = DoKeyUp();
-				SetEventPosDetails(m_EventPosDetails.OrderListIndex(), m_EventPosDetails.SequenceIndex() - 1);
+				SetEventPosDetails(m_EventPosDetails.OrderListIndex(), m_EventPosDetails.SequenceIndex() - 1, true);
 				DoDelete(inIsControlDown);
 
 				return event_pos;
diff --git a/SIDFactoryII/source/runtime/editor/components/component_track.h b/SIDFactoryII/source/runtime/editor/components/component_track.h
index 26932b7d..fdb478f5 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_track.h
+++ b/SIDFactoryII/source/runtime/editor/components/component_track.h
@@ -146,7 +146,7 @@ namespace Editor
 		void SetCursorPosition(int inCursorPosition);
 
 		int GetMaxEventPosition() const;
-		void SetEventPosition(int inEventPos);
+		void SetEventPosition(int inEventPos, bool inForceOrderListIndexChangeEvent = false);
 		int GetEventPosition() const;
 		int GetEventPositionAtTopOfCurrentSequence() const;
 
@@ -218,7 +218,7 @@ namespace Editor
 		void UpdateMaxEventPos();
 
 	private:
-		void SetEventPosDetails(unsigned int inOrderListIndex, unsigned int inSequenceIndex);
+		void SetEventPosDetails(unsigned int inOrderListIndex, unsigned int inSequenceIndex, bool inForceOrderListIndexChangeEvent = false);
 
 		// Status report
 		void UpdateSequenceStatusReport();
diff --git a/SIDFactoryII/source/runtime/editor/components/component_tracks.cpp b/SIDFactoryII/source/runtime/editor/components/component_tracks.cpp
index 08c03f8a..0300f6c1 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_tracks.cpp
+++ b/SIDFactoryII/source/runtime/editor/components/component_tracks.cpp
@@ -94,6 +94,14 @@ namespace Editor
 					(*m_DataSource)[i]->UpdateMaxEventPos();
 				}
 			}));
+
+			// Set orderlist index changed event
+			(*m_DataSource)[i]->GetOrderListIndexChangedEvent().Add(
+				this,
+				Utility::TDelegate<void(bool, unsigned int, unsigned char)>([this](bool inHasControl, unsigned int inIndex, unsigned char inValue)
+			{
+				this->m_OrderListIndexChangedEvent.Execute(inHasControl, inIndex, inValue);
+			}));
 		}
 
 		// Set the event position on each track
@@ -600,6 +608,12 @@ namespace Editor
 	}
 
 
+	ComponentTrack::OrderListIndexChangedEvent& ComponentTracks::GetOrderListIndexChangedEvent()
+	{
+		return m_OrderListIndexChangedEvent;
+	}
+
+
 	void ComponentTracks::AlignTracks()
 	{
 		m_RequireRefresh = true;
diff --git a/SIDFactoryII/source/runtime/editor/components/component_tracks.h b/SIDFactoryII/source/runtime/editor/components/component_tracks.h
index 76e8d0f1..e9b0f43e 100644
--- a/SIDFactoryII/source/runtime/editor/components/component_tracks.h
+++ b/SIDFactoryII/source/runtime/editor/components/component_tracks.h
@@ -80,6 +80,8 @@ namespace Editor
 
 		void OnOrderListChanged(int inChannel);
 
+		ComponentTrack::OrderListIndexChangedEvent& GetOrderListIndexChangedEvent();
+
 	private:
 		void AlignTracks();
 		void HandleSequenceSplit(unsigned char inSequence, unsigned char inSequenceToAdd);
@@ -107,6 +109,8 @@ namespace Editor
 		const AuxilaryDataCollection& m_AuxilaryData;
 		ComponentTrackUtils::FocusRow m_FocusRow;
 
+		ComponentTrack::OrderListIndexChangedEvent m_OrderListIndexChangedEvent;
+
 		std::shared_ptr<DataSourceTrackComponents> m_DataSource;
 		std::vector<std::shared_ptr<DataSourceOrderList>> m_OtherOrderListDataSources;
 	};
diff --git a/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp b/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp
index 97293092..1d595dfd 100644
--- a/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp
+++ b/SIDFactoryII/source/runtime/editor/driver/driver_utils.cpp
@@ -84,13 +84,11 @@ namespace Editor
 					for (unsigned short j = 0; j < music_data.m_OrderListSize; ++j)
 					{
 						unsigned char value = inMemoryReader[order_list_address + j];
-						if (value < SequenceCount)
-						{
-							if (value == 0x7e)
-								break;
 
+						if (value < SequenceCount)
 							usage_count[value]++;
-						}
+						else if (value >= 0xfe)
+							break;
 					}
 				}
 
diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
index 539308b0..5c71e483 100644
--- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
+++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.cpp
@@ -223,7 +223,7 @@ namespace Editor
 			: song_name;
 
 		m_StatusBar = std::make_unique<StatusBarEdit>(m_MainTextField, m_EditState, m_DriverState, m_DriverInfo->GetAuxilaryDataCollection(), mouse_button_octave, mouse_button_flat_sharp, mouse_button_sid_model, mouse_button_context_highlight, mouse_button_follow_play);
-		m_StatusBar->SetText(m_ActivationMessage.length() > 0 ? m_ActivationMessage : " SID Factory II [Selected song: " + song_selection_text + "]", 2500);
+		m_StatusBar->SetText(m_ActivationMessage.length() > 0 ? m_ActivationMessage : " SID Factory II [Selected song: " + song_selection_text + "]", 2500, false);
 		m_ActivationMessage = "";
 
 		// Create flight recorder overlay
@@ -1460,8 +1460,22 @@ namespace Editor
 			Utility::TDelegate<void(int)>([&](int inChannel) { m_TracksComponent->OnOrderListChanged(inChannel); })
 		);
 
+		// Hook up tracks for when order list index changes
+		m_TracksComponent->GetOrderListIndexChangedEvent().Add(
+			nullptr,
+			Utility::TDelegate<void(bool, unsigned int, unsigned char)>([this](bool InHasFocus, unsigned int InOrderlistIndex, unsigned char InSequenceIndex)
+			{
+				const bool is_playing = m_DriverState.GetPlayState() == Editor::DriverState::PlayState::Playing;
+
+				if(m_EditState.IsFollowPlayMode() && is_playing)
+					return;
+				
+				if(InHasFocus)
+					this->ShowSequenceUsageCount(InSequenceIndex);
+			})
+		);
+
 		// Enable groups
-		//m_ComponentsManager->SetGroupEnabledForTabbing(0);
 		m_ComponentsManager->SetGroupEnabledForInput(0, true);
 
 		if (m_ActivationFocusOnComponent)
@@ -1745,7 +1759,6 @@ namespace Editor
 
 			EditorUtils::SetNoteInputValueKeys(note_keys_octave1, note_keys_octave2);
 		}
-
 	}
 
 
@@ -2150,5 +2163,18 @@ namespace Editor
 			}
 		}
 	}
+
+	void ScreenEdit::ShowSequenceUsageCount(unsigned char inSequenceIndex)
+	{
+		if(inSequenceIndex < 0x80)
+		{
+			m_CPUMemory->Lock();
+			std::vector<int> sequence_index_use_count = DriverUtils::GetSequenceUsageCount(*m_DriverInfo, *m_CPUMemory);
+			m_CPUMemory->Unlock();
+			std::string text = " Sequence index: " + EditorUtils::ConvertToHexValue(inSequenceIndex, m_DisplayState.IsHexUppercase()) + " use count: " + std::to_string(sequence_index_use_count[inSequenceIndex]);
+				
+			SetStatusBarMessage(text, 5000);
+		}
+	}
 }
 
diff --git a/SIDFactoryII/source/runtime/editor/screens/screen_edit.h b/SIDFactoryII/source/runtime/editor/screens/screen_edit.h
index 316b7986..14782c58 100644
--- a/SIDFactoryII/source/runtime/editor/screens/screen_edit.h
+++ b/SIDFactoryII/source/runtime/editor/screens/screen_edit.h
@@ -171,11 +171,13 @@ namespace Editor
 		void ConfigureNoteKeys();
 		void ConfigurePlaybackOptions();
 
+		void ShowSequenceUsageCount(unsigned char inSequenceIndex);
+
 		template<typename EXECUTION_CALLBACK>
 		void StartSongsDialogWithSelectionExecution(const std::string& headline, EXECUTION_CALLBACK&& inExecutionCallback);
 		template<typename EXECUTION_CALLBACK>
 		void StartMoveSongDialogWithSelectionExecution(const std::string& inCaption, EXECUTION_CALLBACK&& inExecutionCallback);
-
+		
 		// Load/save requests
 		std::function<void(void)> m_LoadRequestCallback;
 		std::function<void(void)> m_SaveRequestCallback;
diff --git a/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.cpp b/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.cpp
index f1c097cc..0a358d34 100644
--- a/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.cpp
+++ b/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.cpp
@@ -13,6 +13,7 @@ namespace Editor
 {
 	StatusBar::StatusBar(Foundation::TextField* inTextField) 
 		: m_TextField(inTextField)
+		, m_CanBeOverwritten(true)
 		, m_NeedRefresh(true)
 		, m_TextColor(ToColor(UserColor::StatusBarText))
 		, m_BackgroundColor(ToColor(UserColor::StatusBarBackgroundStopped))
@@ -55,15 +56,19 @@ namespace Editor
 
 	void StatusBar::SetText(const std::string& inText)
 	{
-		SetText(inText, 0);
+		SetText(inText, 0, true);
 	}
 
 
-	void StatusBar::SetText(const std::string& inText, int inDuration)
+	void StatusBar::SetText(const std::string& inText, int inDuration, bool inCanBeOverwritten)
 	{
-		m_Text = inText;
-		m_TextClearTimer = inDuration;
-		m_NeedRefresh = true;
+		if(!inCanBeOverwritten || m_CanBeOverwritten)
+		{
+			m_Text = inText;
+			m_TextClearTimer = inDuration;
+			m_NeedRefresh = true;
+			m_CanBeOverwritten = inCanBeOverwritten;
+		}
 	}
 
 	bool StatusBar::IsDisplayingTimedText() const
@@ -149,6 +154,7 @@ namespace Editor
 			{
 				m_Text = "";
 				m_NeedRefresh = true;
+				m_CanBeOverwritten = true;
 			}
 		}
 
diff --git a/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.h b/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.h
index ab8424e2..802f03bb 100644
--- a/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.h
+++ b/SIDFactoryII/source/runtime/editor/screens/statusbar/status_bar.h
@@ -25,7 +25,7 @@ namespace Editor
 
 		void SetColors(const Foundation::Color& inTextColor, const Foundation::Color& inBackgroundColor, const Foundation::Color& inBackgroundMouseOverColor);
 		void SetText(const std::string& inText);
-		void SetText(const std::string& inText, int inDuration);
+		void SetText(const std::string& inText, int inDuration, bool inCanBeOverwritten = true);
 		bool IsDisplayingTimedText() const;
 		void Refresh();
 
@@ -60,6 +60,7 @@ namespace Editor
 			std::function<void(Foundation::Mouse::Button, int)> m_MouseButtonCallback;
 		};
 
+		bool m_CanBeOverwritten;
 		bool m_NeedRefresh;
 		bool m_NeedUpdate;
 
diff --git a/SIDFactoryII/source/runtime/emulation/cpumemory.cpp b/SIDFactoryII/source/runtime/emulation/cpumemory.cpp
index 26165910..a46b9be1 100644
--- a/SIDFactoryII/source/runtime/emulation/cpumemory.cpp
+++ b/SIDFactoryII/source/runtime/emulation/cpumemory.cpp
@@ -7,7 +7,7 @@ namespace Emulation
 {
 	CPUMemory::CPUMemory(unsigned int nSize, Foundation::IPlatform* inPlatform)
 		: m_nSize(nSize)
-		, m_IsLocked(false)
+		, m_LockRefCount(0)
 		, m_MemorySnapshot(nullptr)
 	{
 		FOUNDATION_ASSERT(inPlatform != nullptr);
@@ -31,18 +31,20 @@ namespace Emulation
 	void CPUMemory::Lock()
 	{
 		m_Mutex->Lock();
-		m_IsLocked = true;
+		m_LockRefCount++;
 	}
 
 	void CPUMemory::Unlock()
 	{
-		m_IsLocked = false;
+		m_LockRefCount--;
+		FOUNDATION_ASSERT(m_LockRefCount >= 0);
+		
 		m_Mutex->Unlock();
 	}
 
 	bool CPUMemory::IsLocked() const
 	{
-		return m_IsLocked;
+		return m_LockRefCount > 0;
 	}
 
 	//------------------------------------------------------------------------------------------------------------------------------
@@ -59,7 +61,7 @@ namespace Emulation
 	{
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(m_MemorySnapshot == nullptr);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		m_MemorySnapshot = new unsigned char[m_nSize];
 		memcpy(m_MemorySnapshot, m_Memory, m_nSize);
@@ -69,7 +71,7 @@ namespace Emulation
 	{
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(m_MemorySnapshot != nullptr);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		memcpy(m_Memory, m_MemorySnapshot, m_nSize);
 	}
@@ -77,7 +79,7 @@ namespace Emulation
 	void CPUMemory::FlushSnapshot()
 	{
 		FOUNDATION_ASSERT(m_MemorySnapshot != nullptr);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		delete[] m_MemorySnapshot;
 		m_MemorySnapshot = nullptr;
@@ -89,7 +91,7 @@ namespace Emulation
 	{
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(nAddress < m_nSize);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		return m_Memory[nAddress];
 	}
@@ -98,7 +100,7 @@ namespace Emulation
 	{
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(nAddress < m_nSize - 1);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		return (unsigned short)m_Memory[nAddress] | (((unsigned short)m_Memory[nAddress + 1]) << 8);
 	}
@@ -108,7 +110,7 @@ namespace Emulation
 		FOUNDATION_ASSERT(inDestinationBuffer != nullptr);
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(inAddress < m_nSize + inDestinationBufferByteCount);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		unsigned char* pDest = (unsigned char*)inDestinationBuffer;
 
@@ -122,7 +124,7 @@ namespace Emulation
 	{
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(nAddress < m_nSize);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		m_Memory[nAddress] = ucByte;
 	}
@@ -131,7 +133,7 @@ namespace Emulation
 	{
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(nAddress < m_nSize - 1);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		m_Memory[nAddress] = (unsigned char)(usWord & 0x00ff);
 		m_Memory[nAddress + 1] = (unsigned char)((usWord & 0xff00) >> 8);
@@ -142,7 +144,7 @@ namespace Emulation
 		FOUNDATION_ASSERT(pSourceBuffer != nullptr);
 		FOUNDATION_ASSERT(m_Memory != nullptr);
 		FOUNDATION_ASSERT(nAddress + nSourceBufferByteCount <= m_nSize);
-		FOUNDATION_ASSERT(m_IsLocked);
+		FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 		unsigned char* pSrc = (unsigned char*)pSourceBuffer;
 
diff --git a/SIDFactoryII/source/runtime/emulation/cpumemory.h b/SIDFactoryII/source/runtime/emulation/cpumemory.h
index 3b889fc5..072fa30c 100644
--- a/SIDFactoryII/source/runtime/emulation/cpumemory.h
+++ b/SIDFactoryII/source/runtime/emulation/cpumemory.h
@@ -20,7 +20,7 @@ namespace Emulation
 		{
 			FOUNDATION_ASSERT(inAddress >= 0);
 			FOUNDATION_ASSERT(inAddress < (int)m_nSize);
-			FOUNDATION_ASSERT(m_IsLocked);
+			FOUNDATION_ASSERT(m_LockRefCount);
 
 			return m_Memory[inAddress];
 		}
@@ -29,7 +29,7 @@ namespace Emulation
 		{
 			FOUNDATION_ASSERT(inAddress >= 0);
 			FOUNDATION_ASSERT(inAddress < (int)m_nSize);
-			FOUNDATION_ASSERT(m_IsLocked);
+			FOUNDATION_ASSERT(m_LockRefCount);
 
 			return m_Memory[inAddress];
 		}
@@ -62,7 +62,7 @@ namespace Emulation
 			unsigned int iAddress = static_cast<unsigned int>(static_cast<const unsigned char*>(inMemoryOffsetPointer) - m_Memory);
 
 			FOUNDATION_ASSERT(iAddress < m_nSize);
-			FOUNDATION_ASSERT(m_IsLocked);
+			FOUNDATION_ASSERT(m_LockRefCount > 0);
 
 			return iAddress;
 		};
@@ -70,7 +70,7 @@ namespace Emulation
 	private:
 		std::shared_ptr<Foundation::IMutex> m_Mutex;
 
-		bool m_IsLocked;
+		int m_LockRefCount;
 
 		unsigned int m_nSize;
 		unsigned char* m_Memory;