// SPDX-License-Identifier: Unlicense

#include "settings.h"

#include "base64.h"
#include "collection.h"
#include "file.h"
#include "getopt.h"
#include "global.h"
#include "helper.h"
#include "player.h"
#include "sfx.h"
#include "string_.h"

#include <map>

static constexpr f32 cameraXrParallaxHighwayRotation = 0.0f;
static constexpr f32 cameraXrParallaxHighwayScale = 0.1f;
static constexpr f32 cameraXrParallaxHighwayX = -3.1f;
static constexpr f32 cameraXrParallaxHighwayXFactor = 0.08f;
static constexpr f32 cameraXrParallaxHighwayY = -5.0f;
static constexpr f32 cameraXrParallaxHighwayYFactor = 0.0f;
static constexpr f32 cameraXrParallaxHighwayZ = -7.1f;
static constexpr f32 cameraXrParallaxHighwayZFactor = 0.0f;
static constexpr f32 cameraXrParallaxX = 0.0f;
static constexpr f32 cameraXrParallaxXFactor = 0.0f;
static constexpr f32 cameraXrParallaxXRotation = 0.0f;
static constexpr f32 cameraXrParallaxY = 0.0f;
static constexpr f32 cameraXrParallaxYFactor = 0.0f;
static constexpr f32 cameraXrParallaxYRotation = 0.0f;
static constexpr f32 cameraXrParallaxZ = 0.0f;
static constexpr f32 cameraXrParallaxZFactor = 0.0f;

Instrument Settings::applicationInstrument = Instrument::LeadGuitar;
#ifdef SHR3D_COOP
Instrument Settings::applicationInstrumentCoop = Instrument::BassGuitar;
#endif // SHR3D_COOP
BackupMode Settings::applicationBackupMode =
#ifdef __ANDROID__
BackupMode::off;
#else // __ANDROID__
BackupMode::onceOnStart;
#endif // __ANDROID__
EndOfSong Settings::applicationEndOfSong = EndOfSong::loopSong;
bool Settings::applicationToneSwitch = true;
AudioSystem Settings::audioSystem =
#ifdef PLATFORM_WINDOWS
#ifdef SHR3D_AUDIO_SDL
AudioSystem::SDL;
#elif defined(SHR3D_AUDIO_WASAPI)
AudioSystem::WASAPI;
#elif defined(SHR3D_AUDIO_ASIO)
AudioSystem::ASIO;
#endif
#endif // PLATFORM_WINDOWS
#ifdef PLATFORM_LINUX
AudioSystem::SDL;
#endif // PLATFORM_LINUX
#ifdef PLATFORM_ANDROID_SDL
#ifdef SHR3D_AUDIO_SDL
AudioSystem::SDL;
#elif defined(SHR3D_AUDIO_AAUDIO)
AudioSystem::AAudio;
#elif defined(SHR3D_AUDIO_SUPERPOWERED)
AudioSystem::Superpowered;
#endif
#endif // PLATFORM_ANDROID_SDL
#ifdef PLATFORM_OPENXR_ANDROID
#ifdef SHR3D_AUDIO_SDL
AudioSystem::SDL;
#elif defined(SHR3D_AUDIO_AAUDIO)
AudioSystem::AAudio;
#endif
#endif // PLATFORM_OPENXR_ANDROID
#ifdef PLATFORM_EMSCRIPTEN
AudioSystem::WebAudio;
#endif // PLATFORM_EMSCRIPTEN
f32 Settings::audioEffectVolume = 0.6f;
f32 Settings::audioEffectVolumeCoop = 0.6f;
f32 Settings::audioMusicVolume = 0.3f;
#ifdef SHR3D_AUDIO_AAUDIO
i32 Settings::audioAAudioBlockSize = 128;
i32 Settings::audioAAudioChannelInput;
#ifdef SHR3D_COOP
i32 Settings::audioAAudioChannelInputCoop;
#endif // SHR3D_COOP
std::string Settings::audioAAudioDeviceInput = "Default";
std::string Settings::audioAAudioDeviceOutput = "Default";
i32 Settings::audioAAudioSampleRate = 48000;
bool Settings::audioAAudioExclusiveMode = false;
AAudioPerformanceMode Settings::audioAAudioPerformanceMode = AAudioPerformanceMode::None;
#endif // SHR3D_AUDIO_AAUDIO
#ifdef SHR3D_AUDIO_ASIO
std::string Settings::audioAsioDevice;
i32 Settings::audioAsioChannelInput0;
i32 Settings::audioAsioChannelInput1;
#ifdef SHR3D_COOP
i32 Settings::audioAsioChannelInputCoop0;
i32 Settings::audioAsioChannelInputCoop1;
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
#ifdef SHR3D_AUDIO_ASIO_SECOND_DEVICE_FOR_TUNER_DIVIDED
std::string Settings::audioAsioSecondDeviceForTunerDivided;
#endif // SHR3D_AUDIO_ASIO_SECOND_DEVICE_FOR_TUNER_DIVIDED
bool Settings::audioAsioDividedPickup = false;
bool Settings::audioAsioDividedPickupAsMainInput = false;
i32 Settings::audioAsioDividedPickupChannelString0;
i32 Settings::audioAsioDividedPickupChannelString1;
i32 Settings::audioAsioDividedPickupChannelString2;
i32 Settings::audioAsioDividedPickupChannelString3;
i32 Settings::audioAsioDividedPickupChannelString4;
i32 Settings::audioAsioDividedPickupChannelString5;
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
i32 Settings::audioAsioChannelOutput;
i32 Settings::audioAsioBlockSize = 0;
i32 Settings::audioAsioSampleRate = 0;
#endif // SHR3D_AUDIO_ASIO
#ifdef SHR3D_AUDIO_JACK
std::string Settings::audioJackInputDevice0;
std::string Settings::audioJackInputDevice1;
std::string Settings::audioJackOutputDevice0;
std::string Settings::audioJackOutputDevice1;
#ifdef SHR3D_COOP
std::string Settings::audioJackInputDeviceCoop0;
std::string Settings::audioJackInputDeviceCoop1;
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
bool Settings::audioJackDividedPickup = false;
bool Settings::audioJackDividedPickupAsMainInput = false;
std::string Settings::audioJackDividedPickupChannelString0;
std::string Settings::audioJackDividedPickupChannelString1;
std::string Settings::audioJackDividedPickupChannelString2;
std::string Settings::audioJackDividedPickupChannelString3;
std::string Settings::audioJackDividedPickupChannelString4;
std::string Settings::audioJackDividedPickupChannelString5;
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_JACK
#ifdef SHR3D_AUDIO_PIPEWIRE
std::string Settings::audioPipewireInputDevice0;
std::string Settings::audioPipewireInputDevice1;
std::string Settings::audioPipewireOutputDevice0;
std::string Settings::audioPipewireOutputDevice1;
#ifdef SHR3D_COOP
std::string Settings::audioPipewireInputDeviceCoop0;
std::string Settings::audioPipewireInputDeviceCoop1;
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
bool Settings::audioPipewireDividedPickup = false;
bool Settings::audioPipewireDividedPickupAsMainInput = false;
std::string Settings::audioPipewireDividedPickupChannelString0;
std::string Settings::audioPipewireDividedPickupChannelString1;
std::string Settings::audioPipewireDividedPickupChannelString2;
std::string Settings::audioPipewireDividedPickupChannelString3;
std::string Settings::audioPipewireDividedPickupChannelString4;
std::string Settings::audioPipewireDividedPickupChannelString5;
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_PIPEWIRE
#ifdef SHR3D_AUDIO_SDL
i32 Settings::audioSdlBlockSize = 128;
i32 Settings::audioSdlChannelInput;
#ifdef SHR3D_COOP
i32 Settings::audioSdlChannelInputCoop;
#endif // SHR3D_COOP
std::string Settings::audioSdlDeviceInput = "Default";
std::string Settings::audioSdlDeviceOutput = "Default";
i32 Settings::audioSdlSampleRate = 48000;
#endif // SHR3D_AUDIO_SDL
#ifdef SHR3D_AUDIO_SUPERPOWERED
i32 Settings::audioSuperpoweredBlockSize = 512;
std::string Settings::audioSuperpoweredCofiguration;
i32 Settings::audioSuperpoweredChannelInput;
i32 Settings::audioSuperpoweredChannelOutput;
std::string Settings::audioSuperpoweredDeviceInput;
std::string Settings::audioSuperpoweredDeviceOutput;
bool Settings::audioSuperpoweredSustainedPerformanceMode = false;
std::string Settings::audioSuperpoweredInputPathName;
std::vector<char> Settings::audioSuperpoweredInputMutes;
std::vector<f32> Settings::audioSuperpoweredInputVolume;
std::string Settings::audioSuperpoweredOutputPathName;
std::vector<char> Settings::audioSuperpoweredOutputMutes;
std::vector<f32> Settings::audioSuperpoweredOutputVolume;
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
bool Settings::audioSuperpoweredDividedPickup = false;
i32 Settings::audioSuperpoweredDividedPickupChannelString0;
i32 Settings::audioSuperpoweredDividedPickupChannelString1;
i32 Settings::audioSuperpoweredDividedPickupChannelString2;
i32 Settings::audioSuperpoweredDividedPickupChannelString3;
i32 Settings::audioSuperpoweredDividedPickupChannelString4;
i32 Settings::audioSuperpoweredDividedPickupChannelString5;
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_SUPERPOWERED
#ifdef SHR3D_AUDIO_WASAPI
i32 Settings::audioWasapiChannelInput0;
#ifdef SHR3D_COOP
i32 Settings::audioWasapiChannelInput1;
#endif // SHR3D_COOP
std::string Settings::audioWasapiDeviceInput = "Default";
std::string Settings::audioWasapiDeviceOutput = "Default";
i32 Settings::audioWasapiBlockSize = 128;
bool Settings::audioWasapiExclusiveMode = false;
i32 Settings::audioWasapiSampleRate = 48000;
#endif // SHR3D_AUDIO_WASAPI
#ifdef SHR3D_AUDIO_WEBAUDIO
i32 Settings::audioWebAudioChannelInput0;
i32 Settings::audioWebAudioSampleRate = 48000;
#endif // SHR3D_AUDIO_WEBAUDIO
vec4 Settings::environmentClearColor = colorVec4("#00000000");
#ifdef SHR3D_ENVIRONMENT_MILK
bool Settings::environmentMilk = false;
std::string Settings::environmentMilkActivePresets;
f32 Settings::environmentMilkBeatSensitivity = 1.0f;
i32 Settings::environmentMilkDuration = 60;
i32 Settings::environmentMilkMeshSize = 128;
i32 Settings::environmentMilkFrameSkip = 0;
f32 Settings::environmentMilkFrameSpeed = 1.0f;
bool Settings::environmentMilkShuffle = false;
#endif // SHR3D_ENVIRONMENT_MILK
#ifdef SHR3D_ENVIRONMENT_SKYBOX
std::string Settings::environmentSkybox;
f32 Settings::environmentSkyboxRotation = 0.0f;
#endif // SHR3D_ENVIRONMENT_SKYBOX
#ifdef SHR3D_ENVIRONMENT_STAGE
std::string Settings::environmentStage;
#ifndef PLATFORM_OPENXR_ANDROID
f32 Settings::environmentStagePlayerHeight = 1.7f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::environmentStageRotation;
f32 Settings::environmentStageScale = 1.0f;
f32 Settings::environmentStageX;
f32 Settings::environmentStageY;
f32 Settings::environmentStageZ;
#endif // SHR3D_ENVIRONMENT_STAGE
CameraMode Settings::cameraMode = CameraMode::parallax;
#ifndef PLATFORM_OPENXR_ANDROID
f32 Settings::cameraFieldOfView = 60.0f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraFixedX = -12.0f;
f32 Settings::cameraFixedXRotation = 0.185f;
f32 Settings::cameraFixedY = -8.0f;
f32 Settings::cameraFixedYRotation = 0.0f;
f32 Settings::cameraFixedZ = -12.0f;
f32 Settings::cameraParallaxAnchorTackingDuration = 3.0f;
f32 Settings::cameraParallaxHighwayRotation =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayRotation;
#else
0.06f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayScale =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayScale;
#else
0.18f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayX =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayX;
#else
- 1.49f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayXFactor =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayXFactor;
#else
0.08f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayY =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayY;
#else
-3.95f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayYFactor =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayYFactor;
#else
0.0f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayZ =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayZ;
#else
- 5.17f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxHighwayZFactor =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxHighwayZFactor;
#else
0.099f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxX =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxX;
#else
0.0f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxXFactor =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxXFactor;
#else
0.08f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxXRotation =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxXRotation;
#else
0.309f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxY =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxY;
#else
0.0f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxYFactor =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxYFactor;
#else
0.073f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxYRotation =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxYRotation;
#else
0.0f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxZ =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxZ;
#else
0.0f;
#endif // PLATFORM_OPENXR_ANDROID
f32 Settings::cameraParallaxZFactor =
#ifdef PLATFORM_OPENXR_ANDROID
cameraXrParallaxZFactor;
#else
0.0f;
#endif // PLATFORM_OPENXR_ANDROID
#ifdef SHR3D_OPENXR_PCVR
CameraMode Settings::cameraPcVrMode = CameraMode::pcVrParallax;
f32 Settings::cameraPcVrParallaxAnchorTackingDuration = 3.0f;
f32 Settings::cameraPcVrParallaxHighwayRotation = cameraXrParallaxHighwayRotation;
f32 Settings::cameraPcVrParallaxHighwayScale = cameraXrParallaxHighwayScale;
f32 Settings::cameraPcVrParallaxHighwayX = cameraXrParallaxHighwayX;
f32 Settings::cameraPcVrParallaxHighwayXFactor = cameraXrParallaxHighwayXFactor;
f32 Settings::cameraPcVrParallaxHighwayY = cameraXrParallaxHighwayY;
f32 Settings::cameraPcVrParallaxHighwayYFactor = cameraXrParallaxHighwayYFactor;
f32 Settings::cameraPcVrParallaxHighwayZ = cameraXrParallaxHighwayZ;
f32 Settings::cameraPcVrParallaxHighwayZFactor = cameraXrParallaxHighwayZFactor;
f32 Settings::cameraPcVrParallaxX = cameraXrParallaxX;
f32 Settings::cameraPcVrParallaxXFactor = cameraXrParallaxXFactor;
f32 Settings::cameraPcVrParallaxXRotation = cameraXrParallaxXRotation;
f32 Settings::cameraPcVrParallaxY = cameraXrParallaxY;
f32 Settings::cameraPcVrParallaxYFactor = cameraXrParallaxYFactor;
f32 Settings::cameraPcVrParallaxYRotation = cameraXrParallaxYRotation;
f32 Settings::cameraPcVrParallaxZ = cameraXrParallaxZ;
f32 Settings::cameraPcVrParallaxZFactor = cameraXrParallaxZFactor;
#endif // SHR3D_OPENXR_PCVR
FullscreenMode Settings::graphicsFullscreen =
#ifdef __ANDROID__
FullscreenMode::borderless;
#else // __ANDROID__
FullscreenMode::windowed;
#endif // __ANDROID__
#ifdef SHR3D_GRAPHICS_MSAA
i32 Settings::graphicsMSAA = 2; // 0=Off, 1=2x, 2=4x, 3=8x
#endif // SHR3D_GRAPHICS_MSAA
#ifdef SHR3D_OPENGL_SPIR_V
bool Settings::graphicsSpirV = false;
#endif // SHR3D_OPENGL_SPIR_V
ScalingMode Settings::graphicsScaling = ScalingMode::HorPlus;
#ifdef PLATFORM_QUEST_3
i32 Settings::graphicsRefreshRate = 0;
#endif // PLATFORM_QUEST_3
#if !defined(PLATFORM_EMSCRIPTEN) && !defined(PLATFORM_QUEST_3)
VSyncMode Settings::graphicsVSync = VSyncMode::noVSync;
#endif // !PLATFORM_EMSCRIPTEN && !PLATFORM_QUEST_3
i32 Settings::graphicsWindowWidth = 1600;
i32 Settings::graphicsWindowHeight = 900;
f32 Settings::highwayFadeFarDistance = 40.0f;
f32 Settings::highwayFadeNearDistance = 5.0;
f32 Settings::highwayFadeNearStrength = 0.2f;
vec4 Settings::highwayAnchorColor[4] = {
  colorVec4("#2E1168FF"),
  colorVec4("#193EA0FF"),
  colorVec4("#00072FF3"),
  colorVec4("#00072FF3")
};
f32 Settings::highwayAnchorColorExponent = 0.5f;
vec4 Settings::highwayCapoColor = colorVec4("#AFAFAF7C");
bool Settings::highwayChordBox = true;
vec4 Settings::highwayChordBoxColor = {
  colorVec4("#DA741FE9"),
};
bool Settings::highwayChordBoxArpeggio = true;
vec4 Settings::highwayChordBoxArpeggioColor = colorVec4("#F8300CE9");
bool Settings::highwayChordFretNumbers = true;
bool Settings::highwayChordName = false;
vec4 Settings::highwayChordNameColor = colorVec4("#FFFFFF88");
vec4 Settings::highwayDotInlayColor[4] = {
  colorVec4("#EB8D176D"),
  colorVec4("#F8B92287"),
  colorVec4("#119CD26D"),
  colorVec4("#45469E87")
};
bool Settings::highwayBeat = true;
vec4 Settings::highwayBeatColor[2] = {
  colorVec4("#8795E5FF"),
  colorVec4("#423E6DFF")
};
bool Settings::highwayBeatStrumDirection = false;
vec4 Settings::highwayBeatStrumDirectionColor[2] = {
  colorVec4("#2BE11AFF"),
  colorVec4("#E11717FF")
};
StrumDirection Settings::highwayBeatStrumDirectionPrimary = StrumDirection::downStroke;
StrumDirection Settings::highwayBeatStrumDirectionNext = StrumDirection::downStroke;
int Settings::highwayBeatStrumsBetweenBeats = 0;
vec4 Settings::highwayFingerNumberColor = colorVec4("#FFFFFFFF");
bool Settings::highwayFingerNumbers = true;
bool Settings::highwayFretboardFrets = true;
vec4 Settings::highwayFretboardFretColor = colorVec4("#AFAFAF7C");
vec4 Settings::highwayFretboardFretNumberColor[3] = {
  colorVec4("#FFBA17CC"),
  colorVec4("#8795E5CC"),
  colorVec4("#4A609ACC")
};
bool Settings::highwayFretboardNoteNames = false;
vec4 Settings::highwayFretboardNoteNameColor[2] = {
  colorVec4("#BCBED4FF"),
  colorVec4("#8795E5FF")
};
f32 Settings::highwayFretboardNoteHeight = 1.06f;
f32 Settings::highwayFretboardNoteWidth = 1.36f;
bool Settings::highwayFretboardCollisionNotes = true;
vec4 Settings::highwayFretboardCollisionNotesColor[2] = {
  colorVec4("#D81212FF"),
  colorVec4("#31CDC9F8")
};
bool Settings::highwayFretboardPlayedNotesDot = true;
vec4 Settings::highwayFretboardPlayedNotesDotColor[2] = {
  colorVec4("#D81212FF"),
  colorVec4("#31CDC9F8")
};
bool Settings::highwayFretboardStrings = true;
bool Settings::highwayFretboardStringNoteNames = true;
#ifdef SHR3D_SFX_CORE_HEXFIN
bool Settings::highwayFretboardPlayedNotesTuner = true;
#endif // SHR3D_SFX_CORE_HEXFIN
vec4 Settings::highwayGroundFretColor[2] = {
  colorVec4("#2037A5FF"),
  colorVec4("#151D4800")
};
bool Settings::highwayStringFadeUnplayed = true;
vec4 Settings::highwaySustainColor = colorVec4("#977DFFCD");
bool Settings::highwayInstrumentBass5StringHideString0 = false;
i32 Settings::highwayInstrumentBass5StringTuning[4] = { -4, -4, -4, -4 };
i32 Settings::highwayInstrumentBassFirstWoundString = 0;
f32 Settings::highwayInstrumentBassFretSpacing = 1.0f;
f32 Settings::highwayInstrumentBassFretSpacingFactor = 0.0f;
vec4 Settings::highwayInstrumentBassStringColor[6] = {
  colorVec4("#E05A01AA"),
  colorVec4("#2381E9AA"),
  colorVec4("#D2A20DAA"),
  colorVec4("#D20000AA"),
  colorVec4("#009B71AA"),
  colorVec4("#999999AA")
};
f32 Settings::highwayInstrumentBassStringSpacing = 0.46f;
bool Settings::highwayInstrumentGuitar7StringHideString0 = false;
i32 Settings::highwayInstrumentGuitar7StringTuning[6] = { -4, -4, -4, -4, -4, -4 };
i32 Settings::highwayInstrumentGuitarFirstWoundString = 3;
f32 Settings::highwayInstrumentGuitarFretSpacing = 1.0f;
f32 Settings::highwayInstrumentGuitarFretSpacingFactor = 0.0f;
vec4 Settings::highwayInstrumentGuitarStringColor[8] = {
  colorVec4("#940FB0AA"),
  colorVec4("#1F9601AA"),
  colorVec4("#E05A01AA"),
  colorVec4("#2381E9AA"),
  colorVec4("#D2A20DAA"),
  colorVec4("#D20000AA"),
  colorVec4("#009B71AA"),
  colorVec4("#999999AA")
};
f32 Settings::highwayInstrumentGuitarStringSpacing = 0.42f;
f32 Settings::highwayNoteBendCurve = 0.5f;
f32 Settings::highwayNoteBendEndTime = 0.5f;
f32 Settings::highwayNoteBendSpeed = 2.0f;
f32 Settings::highwayNoteBendHintOffset = 0.1f;
f32 Settings::highwayNoteBendHintDistance = 0.2f;
f32 Settings::highwayNoteHeight = 1.0f;
i32 Settings::highwayNoteRotate = 0;
f32 Settings::highwayNoteRotateEndTime = 0.5f;
f32 Settings::highwayNoteRotateSpeed = 2.0f;
NoteShape Settings::highwayNoteShape = NoteShape::hex;
NoteSymbols Settings::highwayNoteSymbolFretMute = NoteSymbols::fretMute;
NoteSymbols Settings::highwayNoteSymbolHammerOn = NoteSymbols::hammerOn;
NoteSymbols Settings::highwayNoteSymbolHarmonic = NoteSymbols::harmonic;
NoteSymbols Settings::highwayNoteSymbolPinchHarmonic = NoteSymbols::pinchHarmonic;
NoteSymbols Settings::highwayNoteSymbolPalmMute = NoteSymbols::palmMute;
NoteSymbols Settings::highwayNoteSymbolPop = NoteSymbols::pop;
NoteSymbols Settings::highwayNoteSymbolPullOff = NoteSymbols::pullOff;
NoteSymbols Settings::highwayNoteSymbolSlap = NoteSymbols::slap;
NoteSymbols Settings::highwayNoteSymbolTap = NoteSymbols::tap;
bool Settings::highwayNoteStand = true;
bool Settings::highwayNoteStandZero = true;
f32 Settings::highwayNoteWidth = 1.0f;
f32 Settings::highwayNoteSustainCurveSampleDistance = 0.01f;
f32 Settings::highwayNoteSustainTremoloSampleDistance = 0.02f;
f32 Settings::highwayNoteSustainTremoloShakeStrength = 0.1f;
f32 Settings::highwayNoteSustainWidth = 0.3f;
f32 Settings::highwayNoteSustainWidthZero = 0.75f;
#ifdef SHR3D_PARTICLE
bool Settings::highwayParticlePlayedNotes = false;
bool Settings::highwayParticleCollisionNotes = false;
i32 Settings::highwayParticleShape = 1;
i32 Settings::highwayParticleMaxCount = 10000;
f32 Settings::highwayParticleSpawnsPerSecond = 4000.0f;
f32 Settings::highwayParticleSpawnRadius = 0.75f;
f32 Settings::highwayParticleMinSize = 0.07f;
f32 Settings::highwayParticleMaxSize = 0.17f;
f32 Settings::highwayParticleMinLifeTime = 0.1f;
f32 Settings::highwayParticleMaxLifeTime = 0.5f;
f32 Settings::highwayParticleColorVariation = 0.7f;
f32 Settings::highwayParticleMinVelocityX = -0.3f;
f32 Settings::highwayParticleMaxVelocityX = 0.3f;
f32 Settings::highwayParticleMinVelocityY = -0.1f;
f32 Settings::highwayParticleMaxVelocityY = 0.1f;
f32 Settings::highwayParticleMinVelocityZ = 3.8f;
f32 Settings::highwayParticleMaxVelocityZ = 4.1f;
f32 Settings::highwayParticleAccelerationX = 0.0f;
f32 Settings::highwayParticleAccelerationY = -4.0f;
f32 Settings::highwayParticleAccelerationZ = -2.0f;
f32 Settings::highwayParticleMinRotationAngle = -3.1415f;
f32 Settings::highwayParticleMaxRotationAngle = 3.1415f;
#endif // SHR3D_PARTICLE
#ifdef SHR3D_RENDERER_DEVELOPMENT
Renderer Settings::highwayRenderer = Renderer::production;
#endif // SHR3D_RENDERER_DEVELOPMENT
bool Settings::highwayReverseStrings = false;
f32 Settings::highwayScrollSpeed = 14.0f;
#ifdef SHR3D_SFX_CORE_HEXFIN
bool Settings::highwayTuner =
#ifdef PLATFORM_EMSCRIPTEN
false;
#else // PLATFORM_EMSCRIPTEN
true;
#endif // PLATFORM_EMSCRIPTEN
vec4 Settings::highwayTunerColor[4] = {
  colorVec4("#6B6B6B40"),
  colorVec4("#FFFFFFFF"),
  colorVec4("#3265CFFF"),
  colorVec4("#F8F8F8FF")
};
#endif // SHR3D_SFX_CORE_HEXFIN
bool Settings::highwayVUMeter = true;
vec4 Settings::highwayVUMeterColor[5] = {
  colorVec4("#6B6B6B40"),
  colorVec4("#5DEB24D8"),
  colorVec4("#FF0000D8"),
  colorVec4("#3265CFFF"),
  colorVec4("#F8F8F8FF")
};
f32 Settings::highwayViewDistance = 100.0f;
#ifdef SHR3D_OPENXR
f32 Settings::hudDebugXrScale = 0.01f;
f32 Settings::hudDebugXrX = -20.0f;
f32 Settings::hudDebugXrY = 20.0f;
f32 Settings::hudDebugXrZ = -45.0f;
#endif // SHR3D_OPENXR
bool Settings::hudLyrics = true;
vec4 Settings::hudLyricsColor[3] = {
  colorVec4("#6A2491FF"),
  colorVec4("#E18616FF"),
  colorVec4("#5752E9FF")
};
f32 Settings::hudLyricsScale = 2.0f;
f32 Settings::hudLyricsX = -0.96f;
f32 Settings::hudLyricsY[2] = { 0.69f, 0.51f };
//bool Settings::hudNewHighscore = true;
#ifdef SHR3D_HUD_DEVELOPMENT
Renderer Settings::hudRenderer = Renderer::production;
#endif // SHR3D_HUD_DEVELOPMENT
bool Settings::hudTimelineLevel = true;
vec4 Settings::hudTimelineLevelColor[8] = {
  colorVec4("#4F0505FF"),
  colorVec4("#000E40FF"),
  colorVec4("#730101FF"),
  colorVec4("#062B8FFF"),
  colorVec4("#404040A0"),
  colorVec4("#808080A0"),
  colorVec4("#404040A0"),
  colorVec4("#808080A0")
};
bool Settings::hudTimelineLevelFlipY = false;
f32 Settings::hudTimelineLevelScaleX = 1.0f;
f32 Settings::hudTimelineLevelScaleY = 0.2f;
f32 Settings::hudTimelineLevelSpacing = 0.2f;
f32 Settings::hudTimelineLevelX = 0.0f;
f32 Settings::hudTimelineLevelY = 0.988f;
#ifdef SHR3D_OPENXR
bool Settings::hudTimelineLevelXrFlipY = false;
f32 Settings::hudTimelineLevelXrScaleX = 50.0f;
f32 Settings::hudTimelineLevelXrScaleY = 5.0f;
f32 Settings::hudTimelineLevelXrSpacing = 20.0f;
f32 Settings::hudTimelineLevelXrX = 0.0f;
f32 Settings::hudTimelineLevelXrY = 30.0f;
f32 Settings::hudTimelineLevelXrZ = -60.0f;
#endif // SHR3D_OPENXR
#ifdef SHR3D_MUSIC_STRETCHER
bool Settings::hudTimelineMusicStretcher = true;
vec4 Settings::hudTimelineMusicStretcherColor[2] = {
  colorVec4("#FFFFFF00"),
  colorVec4("#D64919FF")
};
f32 Settings::hudTimelineMusicStretcherScaleX = 1.0f;
f32 Settings::hudTimelineMusicStretcherScaleY = 0.01f;
f32 Settings::hudTimelineMusicStretcherX = 0.0f;
f32 Settings::hudTimelineMusicStretcherY = 0.96f;
#ifdef SHR3D_OPENXR
f32 Settings::hudTimelineMusicStretcherXrScaleX = 50.0f;
f32 Settings::hudTimelineMusicStretcherXrScaleY = 0.3f;
f32 Settings::hudTimelineMusicStretcherXrX = 0.0f;
f32 Settings::hudTimelineMusicStretcherXrY = 30.0f;
f32 Settings::hudTimelineMusicStretcherXrZ = -59.95f;
#endif // SHR3D_OPENXR
#endif // SHR3D_MUSIC_STRETCHER
bool Settings::hudTimelineTone = true;
vec4 Settings::hudTimelineToneColor[11] = {
  colorVec4("#404040FF"),
  colorVec4("#940FB0FF"),
  colorVec4("#1F9601FF"),
  colorVec4("#E05A01FF"),
  colorVec4("#2381E9FF"),
  colorVec4("#D2A20DFF"),
  colorVec4("#D20000FF"),
  colorVec4("#009B71FF"),
  colorVec4("#999999FF"),
  colorVec4("#CC81EDFF"),
  colorVec4("#C2E96BFF")
};
f32 Settings::hudTimelineToneScaleX = 1.0f;
f32 Settings::hudTimelineToneScaleY = 0.04f;
f32 Settings::hudTimelineToneX = 0.0f;
f32 Settings::hudTimelineToneY = 0.96f;
#ifdef SHR3D_OPENXR
f32 Settings::hudTimelineToneXrScaleX = 50.0f;
f32 Settings::hudTimelineToneXrScaleY = 1.0f;
f32 Settings::hudTimelineToneXrX = 0.0f;
f32 Settings::hudTimelineToneXrY = 30.0f;
f32 Settings::hudTimelineToneXrZ = -60.0f;
#endif // SHR3D_OPENXR
vec4 Settings::hudTimelineQuickRepeaterColor[2] = {
  colorVec4("#0065FFFF"),
  colorVec4("#FF9A00FF")
};
bool Settings::hudTimelineQuickRepeaterFlipY = false;
f32 Settings::hudTimelineQuickRepeaterScaleY = 0.08f;
f32 Settings::hudTimelineQuickRepeaterX = 0.0f;
f32 Settings::hudTimelineQuickRepeaterY = 0.96f;
#ifdef SHR3D_OPENXR
f32 Settings::hudTimelineQuickRepeaterXrScaleX = 50.0f;
f32 Settings::hudTimelineQuickRepeaterXrScaleY = 1.0f;
f32 Settings::hudTimelineQuickRepeaterXrX = 0.0f;
f32 Settings::hudTimelineQuickRepeaterXrY = 30.0f;
f32 Settings::hudTimelineQuickRepeaterXrZ = -60.0f;
#endif // SHR3D_OPENXR
bool Settings::hudScore = false;
vec4 Settings::hudScoreColor[4] = {
  colorVec4("#666666FF"),
  colorVec4("#1263BCFF"),
  colorVec4("#666666FF"),
  colorVec4("#1263BCFF")
};
bool Settings::hudSongInfo = true;
vec4 Settings::hudSongInfoColor[2] = {
  colorVec4("#FFFFFFAA"),
  colorVec4("#FFFFFFAA"),
};
f32 Settings::hudSongInfoScale[2] = { 2.0f, 1.0f };
f32 Settings::hudSongInfoX = 0.95f;
f32 Settings::hudSongInfoY[2] = { 0.3f, 0.2f };
bool Settings::hudArrangementSwitch = true;
vec4 Settings::hudArrangementSwitchColor = colorVec4("#FFFFFFAA");
f32 Settings::hudArrangementSwitchScaleX = 3.0f;
f32 Settings::hudArrangementSwitchScaleY = 3.0f;
f32 Settings::hudArrangementSwitchX = 0.0f;
f32 Settings::hudArrangementSwitchY = 0.60f;
#ifdef SHR3D_OPENXR
f32 Settings::hudArrangementSwitchXrScaleX = 0.1f;
f32 Settings::hudArrangementSwitchXrScaleY = 0.1f;
f32 Settings::hudArrangementSwitchXrX = 0.0f;
f32 Settings::hudArrangementSwitchXrY = 15.0f;
f32 Settings::hudArrangementSwitchXrZ = -60.0f;
#endif // SHR3D_OPENXR
bool Settings::hudToneSwitch = true;
bool Settings::hudToneSwitchTimer = false;
vec4 Settings::hudToneSwitchColor = colorVec4("#FFFFFFAA");
vec4 Settings::hudToneSwitchHintColor = colorVec4("#E79619AA");
f32 Settings::hudToneSwitchScale[2] = { 1.0f, 2.0f };
f32 Settings::hudToneSwitchX = 0.95f;
f32 Settings::hudToneSwitchY[2] = { 0.6f, 0.47f };
#ifdef SHR3D_OPENXR
f32 Settings::hudToneSwitchXrScale[2] = { 1.5f, 1.25f };
f32 Settings::hudToneSwitchXrX = 33.0f;
f32 Settings::hudToneSwitchXrY[2] = { 10.0f, 8.0f };
f32 Settings::hudToneSwitchXrZ = -60.0f;
#endif // SHR3D_OPENXR
bool Settings::hudWatermark = true;
vec4 Settings::hudWatermarkColor = colorVec4("#FFFFFF40");
#ifdef SHR3D_OPENXR
f32 Settings::hudWatermarkXrX = 40.0f;
f32 Settings::hudWatermarkXrY = -2.0f;
f32 Settings::hudWatermarkXrZ = -30.0f;
#endif // SHR3D_OPENXR
bool Settings::metronomeEnabled = false;
f32 Settings::metronomeVolume = 0.5f;
bool Settings::metronomeDecay = true;
f32 Settings::metronomeFrequency0 = 2000.0f;
f32 Settings::metronomeFrequency1 = 1400.0f;
i32 Settings::metronomeClickLength = 100;
MetronomeSide Settings::metronomeSide = MetronomeSide::stereo;
std::string Settings::midiAutoConnectDevices;
u8 Settings::midiBinding[128] = { ARRAY_SET128(0xFF) };
f32 Settings::midiFineValueFactor = 0.1f;
NoteDetectionSource Settings::tunerNoteDetectionSource = NoteDetectionSource::pickup;
std::string Settings::pathStatsIni = "stats.ini";
std::string Settings::pathTonesIni = "tones.ini";
std::string Settings::pathBackup = "backup/";
#ifdef SHR3D_SHRED_OR_PSARC
std::string Settings::pathCache = "cache/";
#endif // SHR3D_SHRED_OR_PSARC
#ifdef SHR3D_SFX_PLUGIN_CLAP
std::string Settings::pathClap = "clap/"
#ifdef PLATFORM_WINDOWS
//"|%COMMONPROGRAMFILES%/CLAP/|%LOCALAPPDATA%/Programs/Common/CLAP/|%CLAP_PATH%/"
#endif // PLATFORM_WINDOWS
;
#endif // SHR3D_SFX_PLUGIN_CLAP
//#ifdef SHR3D_SFX_PLUGIN_LV2
//std::string Settings::pathLv2 = "lv2/
//#ifdef PLATFORM_WINDOWS
//"|%COMMONPROGRAMFILES%/LV2/|%APPDATA%/LV2/"
//#endif // PLATFORM_WINDOWS
//;
//#endif // SHR3D_SFX_PLUGIN_LV2
#ifdef SHR3D_ENVIRONMENT_MILK
std::string Settings::pathMilk = "milk/";
#endif // SHR3D_ENVIRONMENT_MILK
#ifdef SHR3D_SFX_CORE_NEURALAMPMODELER
std::string Settings::pathNam = "nam/";
#endif // SHR3D_SFX_CORE_NEURALAMPMODELER
#ifdef SHR3D_PSARC
std::string Settings::pathPsarc =
#ifdef PLATFORM_PICO_4
"/sdcard/Download/";
#else // PLATFORM_PICO_4
"psarc/";
#endif // PLATFORM_PICO_4
#endif // SHR3D_PSARC
#ifdef SHR3D_SHRED
std::string Settings::pathShred =
#ifdef PLATFORM_PICO_4
"/sdcard/Download/";
#else // PLATFORM_PICO_4
"shred/";
#endif // PLATFORM_PICO_4
#endif // SHR3D_SHRED
#ifdef SHR3D_RECORDER
std::string Settings::pathRecorder =
#ifdef PLATFORM_PICO_4
"/sdcard/Download/";
#else // PLATFORM_PICO_4
"recorder/";
#endif // PLATFORM_PICO_4
#endif // SHR3D_RECORDER
#ifdef SHR3D_SFX_PLUGIN_VST
std::string Settings::pathVst = "vst/"
#ifdef PLATFORM_WINDOWS
//"|%PROGRAMFILES(X86)%/Steinberg/VstPlugins|%PROGRAMFILES%/Steinberg/VstPlugins"
#endif // PLATFORM_WINDOWS
;
#endif // SHR3D_SFX_PLUGIN_VST
#ifdef SHR3D_SFX_PLUGIN_VST3
std::string Settings::pathVst3 = "vst3/"
#ifdef PLATFORM_WINDOWS
//"|%COMMONPROGRAMFILES%/VST3|%LOCALAPPDATA%/Programs/Common/VST3"
#endif // PLATFORM_WINDOWS
;
#endif // SHR3D_SFX_PLUGIN_VST3
#ifdef SHR3D_ENVIRONMENT_SKYBOX
std::string Settings::pathSkybox =
#ifdef PLATFORM_PICO_4
"/sdcard/Download/";
#else // PLATFORM_PICO_4
"skybox/";
#endif // PLATFORM_PICO_4
#endif // SHR3D_ENVIRONMENT_SKYBOX
#ifdef SHR3D_ENVIRONMENT_STAGE
std::string Settings::pathStage =
#ifdef PLATFORM_PICO_4
"/sdcard/Download/";
#else // PLATFORM_PICO_4
"stage/";
#endif // PLATFORM_PICO_4
#endif // SHR3D_ENVIRONMENT_STAGE
#ifdef SHR3D_SPOTIFY
std::string Settings::spotifyRedirectUri = "http://127.0.0.1:8888/callback";
std::string Settings::spotifyClientId = "";
std::string Settings::spotifyClientSecret = "";
#endif // SHR3D_SPOTIFY
#ifdef SHR3D_SFX
std::string Settings::tunerPlugin
#ifdef SHR3D_SFX_CORE_HEXFIN
= "Core,Hexfin";
#else // SHR3D_SFX_CORE_HEXFIN
;
#endif // SHR3D_SFX_CORE_HEXFIN
#ifdef SHR3D_MIDI
std::string Settings::tunerMidiDevice;
#endif // SHR3D_MIDI
std::string Settings::tunerMidiPlugin;
#endif // SHR3D_SFX
#ifdef SHR3D_SFX_CORE_HEXFIN
f32 Settings::tunerHexfinOnsetThreshold = -35.0;
f32 Settings::tunerHexfinReleaseThreshold = -60.0;
#endif // SHR3D_SFX_CORE_HEXFIN
f32 Settings::uiScale = 1.0f;
#ifdef SHR3D_OPENXR
f32 Settings::uiXrZ = -1.0f;
#endif // SHR3D_OPENXR
#ifdef SHR3D_CUSTOM_CURSOR
bool Settings::uiCursorCustom = true;
i32 Settings::uiCursorSize = 64;
#endif // SHR3D_CUSTOM_CURSOR
vec4 Settings::uiColor[30] = {
  colorVec4("#EDE013B6"), // 0
  colorVec4("#1C1717E6"), // 1
  colorVec4("#4F1313F3"), // 2
  colorVec4("#4D4B4B6F"), // 3
  colorVec4("#4B1073FF"), // 4
  colorVec4("#30CACFFF"), // 5
  colorVec4("#AB14F0FF"), // 6
  colorVec4("#3B3B3BFF"), // 7
  colorVec4("#C00CA7FF"), // 8
  colorVec4("#42FF25FF"), // 9
  colorVec4("#00000000"), // 10
  colorVec4("#70317CFF"), // 11
  colorVec4("#02B8B5FF"), // 12
  colorVec4("#1F9601FF"), // 13
  colorVec4("#1F9601FF"), // 14
  colorVec4("#E05A03FF"), // 15
  colorVec4("#2C2B2BFF"), // 16
  colorVec4("#686868FF"), // 17
  colorVec4("#D66A6AFF"), // 18
  colorVec4("#191919FF"), // 19
  colorVec4("#CF3662FF"), // 20
  colorVec4("#6C3073FF"), // 21
  colorVec4("#49535EFF"), // 22
  colorVec4("#000000FF"), // 23
  colorVec4("#3E234DFF"), // 24
  colorVec4("#4921CBFF"), // 25
  colorVec4("#4244BEFF"), // 26
  colorVec4("#570101FF"), // 27
  // additional custom colors:
  colorVec4("#330084FF"), // 28
  colorVec4("#CB7218FF")  // 29
};
#ifdef SHR3D_OPENXR
#ifdef SHR3D_OPENXR_PCVR
bool Settings::xrEnabled = false;
#endif // SHR3D_OPENXR_PCVR
#ifdef SHR3D_OPENXR_CONTROLLER_PICO4_AND_QUEST3
XrController Settings::xrController =
#ifndef PLATFORM_PICO_4
XrController::quest3;
#else // PLATFORM_PICO_4
XrController::pico4;
#endif // PLATFORM_PICO_4
#endif // SHR3D_OPENXR_CONTROLLER_PICO4_AND_QUEST3
vec4 Settings::xrControllerColor[2] = {
  colorVec4("#AB0000FF"),
  colorVec4("#1A9C15FF")
};
vec4 Settings::xrCursorColor[2] = {
  colorVec4("#FFFFFFFF"),
  colorVec4("#55555555")
};
vec4 Settings::xrPointerColor = colorVec4("#FFFFFFAA");
//    f32 xrUiCircularProjection = 0.0f;
#endif // SHR3D_OPENXR




















static std::map<std::string, std::map<std::string, std::string>> commandLineSettings;

#ifdef SHR3D_GETOPT


#ifndef PLATFORM_EMSCRIPTEN
static void printUsage() {
  puts("Usage: Shr3D.exe [OPTIONS] [FILE]\n"
    "OPTIONS will overwrite some default settings and are mostly for debugging.\n"
    "Using OPTIONS will skip the installation window and it will prevent saving changes in settings.ini.\n"
    "\n"
    "OPTIONS | example       | Description:\n"
    "--------+---------------+----------------------\n"
    " -s     | settings2.ini | Path to settings.ini\n"
    " -p     | psarc2/       | Directory .psarc files\n"
    " -c     | cache2/       | Directory for the cache\n"
    " -r     | 48000         | Audio Sample Rate\n"
    " -b     | 128           | Audio Block Size\n"
    " -f     | 1             | Fullscreen\n"
    " -w     | 1920          | Window width\n"
    " -h     | 1080          | Window height\n"
    " -u     | 1.5           | Ui Scaling\n"
    "\n"
    "FILE is a .psarc file this will be loaded first in the Collection\n"
    "On Emscripten FILE can also be a urls.txt containing paths/urls to .shred and .psarc files\n");

  fflush(stdout);
}
#endif // PLATFORM_EMSCRIPTEN

static void parseCommandLineArgSettingsIni(int argc, char* argv[])
{
  int c;
  while ((c = getopt(argc, argv, "s:")) != -1)
  {
    switch (c)
    {
    case 's':
      Global::pathSettingsIni = reinterpret_cast<const char*>(optarg_);
      goto end;
    }
  }
end:
  optind_ = 0; // reset index for the second parsing of the args
}

static void parseCommandLineArgs(int argc, char* argv[])
{
  int c;
  while ((c = getopt(argc, argv, "s:p:c:r:b:f:w:h:u:")) != -1)
  {
    Global::installMode = InstallMode::continueWithoutSaving;
    // this skips the installation window and prevent writing changes to settings.ini
    switch (c)
    {
    case 's':
      // already handled by parseCommandLineArgSettingsIni
      break;
#ifdef SHR3D_PSARC
    case 'p':
      Settings::pathPsarc = reinterpret_cast<const char*>(optarg_);
      break;
#endif // SHR3D_PSARC
#ifdef SHR3D_SHRED_OR_PSARC
    case 'c':
      Settings::pathCache = reinterpret_cast<const char*>(optarg_);
      break;
#endif // SHR3D_SHRED_OR_PSARC
    case 'r':
      sampleRate() = atoi(optarg_);
      break;
    case 'b':
      blockSize() = atoi(optarg_);
      break;
    case 'f':
      Settings::graphicsFullscreen = FullscreenMode(atoi(optarg_));
      break;
    case 'w':
      Settings::graphicsWindowWidth = atoi(optarg_);
      break;
    case 'h':
      Settings::graphicsWindowHeight = atoi(optarg_);
      break;
    case 'u':
      Settings::uiScale = f32(atof(optarg_));
      break;
    default:
#ifndef PLATFORM_EMSCRIPTEN
      printUsage();
      quick_exit(0);
#endif // PLATFORM_EMSCRIPTEN
      break;
    }
  }

  if (optarg_ != nullptr)
  {
    const std::string optarg = reinterpret_cast<const char*>(optarg_);
    DEBUG_PRINT("optarg: %s\n", optarg_);

    if (!optarg.empty())
    {
      u64 found = optarg.find("#");
      if (found == std::string::npos)
        found = optarg.find("|");

      std::string filePath;
      std::string autoplayArrangement;

      if (found != std::string::npos)
      {
        filePath = optarg.substr(0, found);
        autoplayArrangement = optarg.substr(found + 1);
      }
      else
      {
        filePath = optarg;
      }

#ifdef PLATFORM_EMSCRIPTEN
      if (found != std::string::npos)
        Global::inputHideMenu.toggled = true;

      Global::autoFetchUrl = filePath;
      Global::downloadAutoplayArrangement = autoplayArrangement;
#else // PLATFORM_EMSCRIPTEN
      Global::skipFetchingCollection = true;

      if (File::exists(filePath.c_str()))
      {
        const SongIndex songIndex = SongIndex(Global::songInfos.size());
        {
          const std::vector<u8> fileData = File::read(filePath.c_str());
          Collection::addSongFile(filePath, fileData.data(), fileData.size());
        }

        if (!autoplayArrangement.empty())
        {
          ArrangementIndex arrangementIndex = -1;
          for (i32 i = 0; i < i32(Global::songInfos[songIndex].arrangementInfos.size()); ++i)
          {
            if (autoplayArrangement == Global::songInfos[songIndex].arrangementInfos[i].arrangementName)
            {
              arrangementIndex = i;
              break;
            }
          }

          Player::playSong(songIndex, arrangementIndex);
        }
      }
#endif // PLATFORM_EMSCRIPTEN
    }
  }
}
#endif // SHR3D_GETOPT

static std::map<std::string, std::map<std::string, std::string>> serializeSettings()
{
  std::map<std::string, std::map<std::string, std::string>> serializedSettings =
  {
    {
      "Application",
      {
        { "Instrument",                         to_string(to_underlying_(Settings::applicationInstrument)) },
        { "BackupMode",                         to_string(to_underlying_(Settings::applicationBackupMode)) },
        { "EndOfSong",                          to_string(to_underlying_(Settings::applicationEndOfSong)) },
        { "ToneSwitch",                         to_string(Settings::applicationToneSwitch) },
      }
    },
    {
      "Audio",
      {
        { "System",                             to_string(to_underlying_(Settings::audioSystem)) },
#ifdef SHR3D_AUDIO_AAUDIO
        { "AAudioBlockSize",                    to_string(Settings::audioAAudioBlockSize) },
        { "AAudioChannelInput",                 to_string(Settings::audioAAudioChannelInput) },
#ifdef SHR3D_COOP
        { "AAudioChannelInputCoop",             to_string(Settings::audioAAudioChannelInputCoop) },
#endif // SHR3D_COOP
        { "AAudioDeviceInput",                  Settings::audioAAudioDeviceInput },
        { "AAudioDeviceOutput",                 Settings::audioAAudioDeviceOutput },
        { "AAudioChannelInput",                 to_string(Settings::audioAAudioChannelInput) },
#ifdef SHR3D_COOP
        { "AAudioChannelInputCoop",             to_string(Settings::audioAAudioChannelInputCoop) },
#endif // SHR3D_COOP
        { "AAudioSampleRate",                   to_string(Settings::audioAAudioSampleRate) },
        { "AAudioExclusiveMode",                to_string(Settings::audioAAudioExclusiveMode) },
        { "AAudioPerformanceMode",              to_string(to_underlying_(Settings::audioAAudioPerformanceMode)) },
#endif // SHR3D_AUDIO_AAUDIO
#ifdef SHR3D_AUDIO_ASIO
        { "AsioDevice",                         Settings::audioAsioDevice },
        { "AsioBlockSize",                      to_string(Settings::audioAsioBlockSize) },
        { "AsioSampleRate",                     to_string(Settings::audioAsioSampleRate) },
        { "AsioChannelInput0",                  to_string(Settings::audioAsioChannelInput0) },
        { "AsioChannelInput1",                  to_string(Settings::audioAsioChannelInput1) },
        { "AsioChannelOutput",                  to_string(Settings::audioAsioChannelOutput) },
#ifdef SHR3D_COOP
        { "AsioChannelInputCoop0",              to_string(Settings::audioAsioChannelInputCoop0) },
        { "AsioChannelInputCoop1",              to_string(Settings::audioAsioChannelInputCoop1) },
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
#ifdef SHR3D_AUDIO_ASIO_SECOND_DEVICE_FOR_TUNER_DIVIDED
        { "AsioSecondDeviceForTunerDivided",    Settings::audioAsioSecondDeviceForTunerDivided },
#endif // SHR3D_AUDIO_ASIO_SECOND_DEVICE_FOR_TUNER_DIVIDED
        { "AsioDividedPickup",                  to_string(Settings::audioAsioDividedPickup) },
        { "AsioDividedPickupAsMainInput",       to_string(Settings::audioAsioDividedPickupAsMainInput) },
        { "AsioDividedPickupChannelString0",    to_string(Settings::audioAsioDividedPickupChannelString0) },
        { "AsioDividedPickupChannelString1",    to_string(Settings::audioAsioDividedPickupChannelString1) },
        { "AsioDividedPickupChannelString2",    to_string(Settings::audioAsioDividedPickupChannelString2) },
        { "AsioDividedPickupChannelString3",    to_string(Settings::audioAsioDividedPickupChannelString3) },
        { "AsioDividedPickupChannelString4",    to_string(Settings::audioAsioDividedPickupChannelString4) },
        { "AsioDividedPickupChannelString5",    to_string(Settings::audioAsioDividedPickupChannelString5) },
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_ASIO
#ifdef SHR3D_AUDIO_JACK
        { "JackInputDevice0",                   Settings::audioJackInputDevice0 },
        { "JackInputDevice1",                   Settings::audioJackInputDevice1 },
        { "JackOutputDevice0",                  Settings::audioJackOutputDevice0 },
        { "JackOutputDevice1",                  Settings::audioJackOutputDevice1 },
#ifdef SHR3D_COOP
        { "JackInputDeviceCoop0",               Settings::audioJackInputDeviceCoop0 },
        { "JackInputDeviceCoop1",               Settings::audioJackInputDeviceCoop1 },
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
        { "JackDividedPickup",                  to_string(Settings::audioJackDividedPickup) },
        { "JackDividedPickupAsMainInput",       to_string(Settings::audioJackDividedPickupAsMainInput) },
        { "JackDividedPickupChannelString0",    Settings::audioJackDividedPickupChannelString0 },
        { "JackDividedPickupChannelString1",    Settings::audioJackDividedPickupChannelString1 },
        { "JackDividedPickupChannelString2",    Settings::audioJackDividedPickupChannelString2 },
        { "JackDividedPickupChannelString3",    Settings::audioJackDividedPickupChannelString3 },
        { "JackDividedPickupChannelString4",    Settings::audioJackDividedPickupChannelString4 },
        { "JackDividedPickupChannelString5",    Settings::audioJackDividedPickupChannelString5 },
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_JACK
#ifdef SHR3D_AUDIO_PIPEWIRE
        { "PipewireInputDevice0",               Settings::audioPipewireInputDevice0 },
        { "PipewireInputDevice1",               Settings::audioPipewireInputDevice1 },
        { "PipewireOutputDevice0",              Settings::audioPipewireOutputDevice0 },
        { "PipewireOutputDevice1",              Settings::audioPipewireOutputDevice1 },
#ifdef SHR3D_COOP
        { "PipewireInputDeviceCoop0",           Settings::audioPipewireInputDeviceCoop0 },
        { "PipewireInputDeviceCoop1",           Settings::audioPipewireInputDeviceCoop1 },
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
        { "PipewireDividedPickup",              to_string(Settings::audioPipewireDividedPickup) },
        { "PipewireDividedPickupAsMainInput",   to_string(Settings::audioPipewireDividedPickupAsMainInput) },
        { "PipewireDividedPickupChannelString0",Settings::audioPipewireDividedPickupChannelString0 },
        { "PipewireDividedPickupChannelString1",Settings::audioPipewireDividedPickupChannelString1 },
        { "PipewireDividedPickupChannelString2",Settings::audioPipewireDividedPickupChannelString2 },
        { "PipewireDividedPickupChannelString3",Settings::audioPipewireDividedPickupChannelString3 },
        { "PipewireDividedPickupChannelString4",Settings::audioPipewireDividedPickupChannelString4 },
        { "PipewireDividedPickupChannelString5",Settings::audioPipewireDividedPickupChannelString5 },
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_PIPEWIRE
#ifdef SHR3D_AUDIO_SDL
        { "SdlBlockSize",                       to_string(Settings::audioSdlBlockSize) },
        { "SdlChannelInput",                    to_string(Settings::audioSdlChannelInput) },
#ifdef SHR3D_COOP
        { "SdlChannelInputCoop",                to_string(Settings::audioSdlChannelInputCoop) },
#endif // SHR3D_COOP
        { "SdlDeviceInput",                     Settings::audioSdlDeviceInput },
        { "SdlDeviceOutput",                    Settings::audioSdlDeviceOutput },
        { "SdlSampleRate",                      to_string(Settings::audioSdlSampleRate) },
#endif // SHR3D_AUDIO_SDL
#ifdef SHR3D_AUDIO_SUPERPOWERED
        { "SuperpoweredBlockSize",                   to_string(Settings::audioSuperpoweredBlockSize) },
        { "SuperpoweredCofiguration",                Settings::audioSuperpoweredCofiguration },
        { "SuperpoweredChannelInput",                to_string(Settings::audioSuperpoweredChannelInput) },
        { "SuperpoweredChannelOutput",               to_string(Settings::audioSuperpoweredChannelOutput) },
        { "SuperpoweredDeviceInput",                 Settings::audioSuperpoweredDeviceInput },
        { "SuperpoweredDeviceOutput",                Settings::audioSuperpoweredDeviceOutput },
        { "SuperpoweredSustainedPerformanceMode",    to_string(Settings::audioSuperpoweredSustainedPerformanceMode) },
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
        { "SuperpoweredDividedPickup",               to_string(Settings::audioSuperpoweredDividedPickup) },
        { "SuperpoweredDividedPickupChannelString0", to_string(Settings::audioSuperpoweredDividedPickupChannelString0) },
        { "SuperpoweredDividedPickupChannelString1", to_string(Settings::audioSuperpoweredDividedPickupChannelString1) },
        { "SuperpoweredDividedPickupChannelString2", to_string(Settings::audioSuperpoweredDividedPickupChannelString2) },
        { "SuperpoweredDividedPickupChannelString3", to_string(Settings::audioSuperpoweredDividedPickupChannelString3) },
        { "SuperpoweredDividedPickupChannelString4", to_string(Settings::audioSuperpoweredDividedPickupChannelString4) },
        { "SuperpoweredDividedPickupChannelString5", to_string(Settings::audioSuperpoweredDividedPickupChannelString5) },
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_SUPERPOWERED
#ifdef SHR3D_AUDIO_WASAPI
        { "WasapiBlockSize",                    to_string(Settings::audioWasapiBlockSize) },
        { "WasapiChannelInput0",                to_string(Settings::audioWasapiChannelInput0) },
#ifdef SHR3D_COOP
        { "WasapiChannelInput1",                to_string(Settings::audioWasapiChannelInput1) },
#endif // SHR3D_COOP
        { "WasapiDeviceInput",                  Settings::audioWasapiDeviceInput },
        { "WasapiDeviceOutput",                 Settings::audioWasapiDeviceOutput },
        { "WasapiSampleRate",                   to_string(Settings::audioWasapiSampleRate) },
        { "WasapiExclusiveMode",                to_string(Settings::audioWasapiExclusiveMode) },
#endif // SHR3D_AUDIO_WASAPI
#ifdef SHR3D_AUDIO_WEBAUDIO
        { "WebAudioChannelInput0",              to_string(Settings::audioWebAudioChannelInput0) },
        { "WebAudioSampleRate",                 to_string(Settings::audioWebAudioSampleRate) },
#endif // SHR3D_AUDIO_WEBAUDIO
        { "InstrumentVolume",                   to_string(Settings::audioEffectVolume) },
        { "InstrumentVolumeCoop",               to_string(Settings::audioEffectVolumeCoop) },
        { "MusicVolume",                        to_string(Settings::audioMusicVolume) }
      }
    },
    {
      "Environment",
      {
        { "ClearColor",                         hexColor(Settings::environmentClearColor) },
#ifdef SHR3D_ENVIRONMENT_MILK
        { "Milk",                               to_string(Settings::environmentMilk) },
        { "MilkBeatSensitivity",                to_string(Settings::environmentMilkBeatSensitivity) },
        { "MilkDuration",                       to_string(Settings::environmentMilkDuration) },
        { "MilkMeshSize",                       to_string(Settings::environmentMilkMeshSize) },
        { "MilkFrameSkip",                      to_string(Settings::environmentMilkFrameSkip) },
        { "MilkFrameSpeed",                     to_string(Settings::environmentMilkFrameSpeed) },
        { "MilkShuffle",                        to_string(Settings::environmentMilkShuffle) },
#endif // SHR3D_ENVIRONMENT_MILK
#ifdef SHR3D_ENVIRONMENT_SKYBOX
        { "Skybox",                             Settings::environmentSkybox },
        { "SkyboxRotation",                     to_string(Settings::environmentSkyboxRotation) },
#endif //  SHR3D_ENVIRONMENT_SKYBOX
      }
    },
    {
      "Camera",
      {
        { "Mode",                               to_string(to_underlying_(Settings::cameraMode)) },
#ifndef PLATFORM_OPENXR_ANDROID
        { "FieldOfView",                        to_string(Settings::cameraFieldOfView) },
#endif // PLATFORM_OPENXR_ANDROID
        { "FixedX",                             to_string(Settings::cameraFixedX) },
        { "FixedXRotation",                     to_string(Settings::cameraFixedXRotation) },
        { "FixedY",                             to_string(Settings::cameraFixedY) },
        { "FixedYRotation",                     to_string(Settings::cameraFixedYRotation) },
        { "FixedZ",                             to_string(Settings::cameraFixedZ) },
        { "ParallaxAnchorTackingDuration",      to_string(Settings::cameraParallaxAnchorTackingDuration) },
        { "ParallaxHighwayRotation",            to_string(Settings::cameraParallaxHighwayRotation) },
        { "ParallaxHighwayScale",               to_string(Settings::cameraParallaxHighwayScale) },
        { "ParallaxHighwayX",                   to_string(Settings::cameraParallaxHighwayX) },
        { "ParallaxHighwayXFactor",             to_string(Settings::cameraParallaxHighwayXFactor) },
        { "ParallaxHighwayY",                   to_string(Settings::cameraParallaxHighwayY) },
        { "ParallaxHighwayYFactor",             to_string(Settings::cameraParallaxHighwayYFactor) },
        { "ParallaxHighwayZ",                   to_string(Settings::cameraParallaxHighwayZ) },
        { "ParallaxHighwayZFactor",             to_string(Settings::cameraParallaxHighwayZFactor) },
        { "ParallaxX",                          to_string(Settings::cameraParallaxX) },
        { "ParallaxXFactor",                    to_string(Settings::cameraParallaxXFactor) },
        { "ParallaxXRotation",                  to_string(Settings::cameraParallaxXRotation) },
        { "ParallaxY",                          to_string(Settings::cameraParallaxY) },
        { "ParallaxYFactor",                    to_string(Settings::cameraParallaxYFactor) },
        { "ParallaxYRotation",                  to_string(Settings::cameraParallaxYRotation) },
        { "ParallaxZ",                          to_string(Settings::cameraParallaxZ) },
        { "ParallaxZFactor",                    to_string(Settings::cameraParallaxZFactor) },
#ifdef SHR3D_OPENXR_PCVR
        { "PcVrMode",                           to_string(to_underlying_(Settings::cameraPcVrMode)) },
        { "PcVrParallaxAnchorTackingDuration",  to_string(Settings::cameraPcVrParallaxAnchorTackingDuration) },
        { "PcVrParallaxHighwayRotation",        to_string(Settings::cameraPcVrParallaxHighwayRotation) },
        { "PcVrParallaxHighwayScale",           to_string(Settings::cameraPcVrParallaxHighwayScale) },
        { "PcVrParallaxHighwayX",               to_string(Settings::cameraPcVrParallaxHighwayX) },
        { "PcVrParallaxHighwayXFactor",         to_string(Settings::cameraPcVrParallaxHighwayXFactor) },
        { "PcVrParallaxHighwayY",               to_string(Settings::cameraPcVrParallaxHighwayY) },
        { "PcVrParallaxHighwayYFactor",         to_string(Settings::cameraPcVrParallaxHighwayYFactor) },
        { "PcVrParallaxHighwayZ",               to_string(Settings::cameraPcVrParallaxHighwayZ) },
        { "PcVrParallaxHighwayZFactor",         to_string(Settings::cameraPcVrParallaxHighwayZFactor) },
        { "PcVrParallaxXFactor",                to_string(Settings::cameraPcVrParallaxXFactor) },
        { "PcVrParallaxX",                      to_string(Settings::cameraPcVrParallaxX) },
        { "PcVrParallaxXRotation",              to_string(Settings::cameraPcVrParallaxXRotation) },
        { "PcVrParallaxYFactor",                to_string(Settings::cameraPcVrParallaxYFactor) },
        { "PcVrParallaxY",                      to_string(Settings::cameraPcVrParallaxY) },
        { "PcVrParallaxYRotation",              to_string(Settings::cameraPcVrParallaxYRotation) },
        { "PcVrParallaxZFactor",                to_string(Settings::cameraPcVrParallaxZFactor) },
        { "PcVrParallaxZ",                      to_string(Settings::cameraPcVrParallaxZ) },
#endif // SHR3D_OPENXR_PCVR
      }
    },
    {
      "Graphics",
      {
        { "Fullscreen",                         to_string(to_underlying_(Settings::graphicsFullscreen)) },
#ifdef SHR3D_GRAPHICS_MSAA
        { "MSAA",                               to_string(Settings::graphicsMSAA) },
#endif // SHR3D_GRAPHICS_MSAA
        { "Scaling",                            to_string(to_underlying_(Settings::graphicsScaling)) },
#ifdef SHR3D_OPENGL_SPIR_V
        { "SpirV",                              to_string(Settings::graphicsSpirV) },
#endif // SHR3D_OPENGL_SPIR_V
#ifdef PLATFORM_QUEST_3
        { "RefreshRate",                        to_string(Settings::graphicsRefreshRate) },
#endif // PLATFORM_QUEST_3
#if !defined(PLATFORM_EMSCRIPTEN) && !defined(PLATFORM_QUEST_3)
        { "VSync",                              to_string(to_underlying_(Settings::graphicsVSync)) },
#endif // !PLATFORM_EMSCRIPTEN && !PLATFORM_QUEST_3
        { "WindowWidth",                        to_string(Settings::graphicsWindowWidth) },
        { "WindowHeight",                       to_string(Settings::graphicsWindowHeight) },
      }
    },
    {
      "Highway",
      {
        { "AnchorColor0",                       hexColor(Settings::highwayAnchorColor[0]) },
        { "AnchorColor1",                       hexColor(Settings::highwayAnchorColor[1]) },
        { "AnchorColor2",                       hexColor(Settings::highwayAnchorColor[2]) },
        { "AnchorColor3",                       hexColor(Settings::highwayAnchorColor[3]) },
        { "AnchorColorExponent",                to_string(Settings::highwayAnchorColorExponent) },
        { "Beat",                               to_string(Settings::highwayBeat) },
        { "BeatColor0",                         hexColor(Settings::highwayBeatColor[0]) },
        { "BeatColor1",                         hexColor(Settings::highwayBeatColor[1]) },
        { "BeatStrumDirection",                 to_string(Settings::highwayBeatStrumDirection) },
        { "BeatStrumDirectionColor0",           hexColor(Settings::highwayBeatStrumDirectionColor[0]) },
        { "BeatStrumDirectionColor1",           hexColor(Settings::highwayBeatStrumDirectionColor[1]) },
        { "BeatStrumDirectionPrimary",          to_string(to_underlying_(Settings::highwayBeatStrumDirectionPrimary)) },
        { "BeatStrumDirectionNext",             to_string(to_underlying_(Settings::highwayBeatStrumDirectionNext)) },
        { "BeatStrumsBetweenBeats",             to_string(Settings::highwayBeatStrumsBetweenBeats) },
        { "CapoColor",                          hexColor(Settings::highwayCapoColor) },
        { "ChordBox",                           to_string(Settings::highwayChordBox) },
        { "ChordBoxArpeggio",                   to_string(Settings::highwayChordBoxArpeggio) },
        { "ChordBoxArpeggioColor",              hexColor(Settings::highwayChordBoxArpeggioColor) },
        { "ChordBoxColor",                      hexColor(Settings::highwayChordBoxColor) },
        { "ChordFretNumbers",                   to_string(Settings::highwayChordFretNumbers) },
        { "ChordName",                          to_string(Settings::highwayChordName) },
        { "ChordNameColor",                     hexColor(Settings::highwayChordNameColor) },
        { "DotInlayColor0",                     hexColor(Settings::highwayDotInlayColor[0]) },
        { "DotInlayColor1",                     hexColor(Settings::highwayDotInlayColor[1]) },
        { "DotInlayColor2",                     hexColor(Settings::highwayDotInlayColor[2]) },
        { "DotInlayColor3",                     hexColor(Settings::highwayDotInlayColor[3]) },
        { "FadeFarDistance",                    to_string(Settings::highwayFadeFarDistance) },
        { "FadeNearDistance",                   to_string(Settings::highwayFadeNearDistance) },
        { "FadeNearStrength",                   to_string(Settings::highwayFadeNearStrength) },
        { "FingerNumberColor",                  hexColor(Settings::highwayFingerNumberColor) },
        { "FingerNumbers",                      to_string(Settings::highwayFingerNumbers) },
        { "FretboardFrets",                     to_string(Settings::highwayFretboardFrets) },
        { "FretboardFretColor",                 hexColor(Settings::highwayFretboardFretColor)},
        { "FretboardFretNumberColor0",          hexColor(Settings::highwayFretboardFretNumberColor[0])},
        { "FretboardFretNumberColor1",          hexColor(Settings::highwayFretboardFretNumberColor[1])},
        { "FretboardFretNumberColor2",          hexColor(Settings::highwayFretboardFretNumberColor[2])},
        { "FretboardNoteHeight",                to_string(Settings::highwayFretboardNoteHeight) },
        { "FretboardNoteNames",                 to_string(Settings::highwayFretboardNoteNames) },
        { "FretboardNoteNameColor0",            hexColor(Settings::highwayFretboardNoteNameColor[0]) },
        { "FretboardNoteNameColor1",            hexColor(Settings::highwayFretboardNoteNameColor[1]) },
        { "FretboardNoteWidth",                 to_string(Settings::highwayFretboardNoteWidth) },
        { "FretboardCollisionNotes",            to_string(Settings::highwayFretboardCollisionNotes) },
        { "FretboardCollisionNotesColor0",      hexColor(Settings::highwayFretboardCollisionNotesColor[0])},
        { "FretboardCollisionNotesColor1",      hexColor(Settings::highwayFretboardCollisionNotesColor[1])},
        { "FretboardPlayedNotes",               to_string(Settings::highwayFretboardPlayedNotesDot) },
        { "FretboardPlayedNotesColor0",         hexColor(Settings::highwayFretboardPlayedNotesDotColor[0])},
        { "FretboardPlayedNotesColor1",         hexColor(Settings::highwayFretboardPlayedNotesDotColor[1])},
#ifdef SHR3D_SFX_CORE_HEXFIN
        { "FretboardPlayedNotesTuner",          to_string(Settings::highwayFretboardPlayedNotesTuner) },
#endif // SHR3D_SFX_CORE_HEXFIN
        { "FretboardStrings",                   to_string(Settings::highwayFretboardStrings)},
        { "FretboardStringNoteNames",           to_string(Settings::highwayFretboardStringNoteNames) },
#ifdef SHR3D_PARTICLE
        { "ParticlePlayedNotes",                to_string(Settings::highwayParticlePlayedNotes) },
        { "ParticleCollisionNotes",             to_string(Settings::highwayParticleCollisionNotes) },
        { "ParticleShape",                      to_string(Settings::highwayParticleShape) },
        { "ParticleMaxCount",                   to_string(Settings::highwayParticleMaxCount) },
        { "ParticleSpawnsPerSecond",            to_string(Settings::highwayParticleSpawnsPerSecond) },
        { "ParticleSpawnRadius",                to_string(Settings::highwayParticleSpawnRadius) },
        { "ParticleMinSize",                    to_string(Settings::highwayParticleMinSize) },
        { "ParticleMaxSize",                    to_string(Settings::highwayParticleMaxSize) },
        { "ParticleMinLifeTime",                to_string(Settings::highwayParticleMinLifeTime) },
        { "ParticleMaxLifeTime",                to_string(Settings::highwayParticleMaxLifeTime) },
        { "ParticleColorVariation",             to_string(Settings::highwayParticleColorVariation) },
        { "ParticleMinVelocityX",               to_string(Settings::highwayParticleMinVelocityX) },
        { "ParticleMaxVelocityX",               to_string(Settings::highwayParticleMaxVelocityX) },
        { "ParticleMinVelocityY",               to_string(Settings::highwayParticleMinVelocityY) },
        { "ParticleMaxVelocityY",               to_string(Settings::highwayParticleMaxVelocityY) },
        { "ParticleMinVelocityZ",               to_string(Settings::highwayParticleMinVelocityZ) },
        { "ParticleMaxVelocityZ",               to_string(Settings::highwayParticleMaxVelocityZ) },
        { "ParticleAccelerationX",              to_string(Settings::highwayParticleAccelerationX) },
        { "ParticleAccelerationY",              to_string(Settings::highwayParticleAccelerationY) },
        { "ParticleAccelerationZ",              to_string(Settings::highwayParticleAccelerationZ) },
        { "ParticleMinRotationAngle",           to_string(Settings::highwayParticleMinRotationAngle) },
        { "ParticleMaxRotationAngle",           to_string(Settings::highwayParticleMaxRotationAngle) },
#endif // SHR3D_PARTICLE
        { "GroundFretColor0",                   hexColor(Settings::highwayGroundFretColor[0]) },
        { "GroundFretColor1",                   hexColor(Settings::highwayGroundFretColor[1]) },
        { "InstrumentBass5StringHideString0",   to_string(Settings::highwayInstrumentBass5StringHideString0) } ,
        { "InstrumentBass5StringTuning0",       to_string(Settings::highwayInstrumentBass5StringTuning[0]) },
        { "InstrumentBass5StringTuning1",       to_string(Settings::highwayInstrumentBass5StringTuning[1]) },
        { "InstrumentBass5StringTuning2",       to_string(Settings::highwayInstrumentBass5StringTuning[2]) },
        { "InstrumentBass5StringTuning3",       to_string(Settings::highwayInstrumentBass5StringTuning[3]) },
        { "InstrumentBassFirstWoundString",     to_string(Settings::highwayInstrumentBassFirstWoundString) },
        { "InstrumentBassFretSpacing",          to_string(Settings::highwayInstrumentBassFretSpacing) },
        { "InstrumentBassFretSpacingFactor",    to_string(Settings::highwayInstrumentBassFretSpacingFactor) },
        { "InstrumentBassStringColor0",         hexColor(Settings::highwayInstrumentBassStringColor[0]) },
        { "InstrumentBassStringColor1",         hexColor(Settings::highwayInstrumentBassStringColor[1]) },
        { "InstrumentBassStringColor2",         hexColor(Settings::highwayInstrumentBassStringColor[2]) },
        { "InstrumentBassStringColor3",         hexColor(Settings::highwayInstrumentBassStringColor[3]) },
        { "InstrumentBassStringColor4",         hexColor(Settings::highwayInstrumentBassStringColor[4]) },
        { "InstrumentBassStringColor5",         hexColor(Settings::highwayInstrumentBassStringColor[5]) },
        { "InstrumentBassStringSpacing",        to_string(Settings::highwayInstrumentBassStringSpacing) },
        { "InstrumentGuitar7StringHideString0", to_string(Settings::highwayInstrumentGuitar7StringHideString0) } ,
        { "InstrumentGuitar7StringTuning0",     to_string(Settings::highwayInstrumentGuitar7StringTuning[0]) },
        { "InstrumentGuitar7StringTuning1",     to_string(Settings::highwayInstrumentGuitar7StringTuning[1]) },
        { "InstrumentGuitar7StringTuning2",     to_string(Settings::highwayInstrumentGuitar7StringTuning[2]) },
        { "InstrumentGuitar7StringTuning3",     to_string(Settings::highwayInstrumentGuitar7StringTuning[3]) },
        { "InstrumentGuitar7StringTuning4",     to_string(Settings::highwayInstrumentGuitar7StringTuning[4]) },
        { "InstrumentGuitar7StringTuning5",     to_string(Settings::highwayInstrumentGuitar7StringTuning[5]) },
        { "InstrumentGuitarFirstWoundString",   to_string(Settings::highwayInstrumentGuitarFirstWoundString) },
        { "InstrumentGuitarFretSpacing",        to_string(Settings::highwayInstrumentGuitarFretSpacing) },
        { "InstrumentGuitarFretSpacingFactor",  to_string(Settings::highwayInstrumentGuitarFretSpacingFactor) },
        { "InstrumentGuitarStringColor0",       hexColor(Settings::highwayInstrumentGuitarStringColor[0]) },
        { "InstrumentGuitarStringColor1",       hexColor(Settings::highwayInstrumentGuitarStringColor[1]) },
        { "InstrumentGuitarStringColor2",       hexColor(Settings::highwayInstrumentGuitarStringColor[2]) },
        { "InstrumentGuitarStringColor3",       hexColor(Settings::highwayInstrumentGuitarStringColor[3]) },
        { "InstrumentGuitarStringColor4",       hexColor(Settings::highwayInstrumentGuitarStringColor[4]) },
        { "InstrumentGuitarStringColor5",       hexColor(Settings::highwayInstrumentGuitarStringColor[5]) },
        { "InstrumentGuitarStringColor6",       hexColor(Settings::highwayInstrumentGuitarStringColor[6]) },
        { "InstrumentGuitarStringColor7",       hexColor(Settings::highwayInstrumentGuitarStringColor[7]) },
        { "InstrumentGuitarStringSpacing",      to_string(Settings::highwayInstrumentGuitarStringSpacing) },
        { "NoteBendCurve",                      to_string(Settings::highwayNoteBendCurve) },
        { "NoteBendEndTime",                    to_string(Settings::highwayNoteBendEndTime) },
        { "NoteBendHintDistance",               to_string(Settings::highwayNoteBendHintDistance) },
        { "NoteBendHintOffset",                 to_string(Settings::highwayNoteBendHintOffset) },
        { "NoteBendSpeed",                      to_string(Settings::highwayNoteBendSpeed) },
        { "NoteHeight",                         to_string(Settings::highwayNoteHeight) },
        { "NoteRotate",                         to_string(Settings::highwayNoteRotate) },
        { "NoteRotateEndTime",                  to_string(Settings::highwayNoteRotateEndTime) },
        { "NoteRotateSpeed",                    to_string(Settings::highwayNoteRotateSpeed) },
        { "NoteShape",                          to_string(to_underlying_(Settings::highwayNoteShape)) },
        { "NoteStand",                          to_string(Settings::highwayNoteStand) },
        { "NoteStandZero",                      to_string(Settings::highwayNoteStandZero) },
        { "NoteSustainCurveSampleDistance",     to_string(Settings::highwayNoteSustainCurveSampleDistance) },
        { "NoteSustainTremoloSampleDistance",   to_string(Settings::highwayNoteSustainTremoloSampleDistance) },
        { "NoteSustainTremoloShakeStrength",    to_string(Settings::highwayNoteSustainTremoloShakeStrength) },
        { "NoteSustainWidth",                   to_string(Settings::highwayNoteSustainWidth) },
        { "NoteSustainWidthZero",               to_string(Settings::highwayNoteSustainWidthZero) },
        { "NoteSymbolFretMute",                 to_string(to_underlying_(Settings::highwayNoteSymbolFretMute)) },
        { "NoteSymbolHammerOn",                 to_string(to_underlying_(Settings::highwayNoteSymbolHammerOn)) },
        { "NoteSymbolHarmonic",                 to_string(to_underlying_(Settings::highwayNoteSymbolHarmonic)) },
        { "NoteSymbolPinchHarmonic",            to_string(to_underlying_(Settings::highwayNoteSymbolPinchHarmonic)) },
        { "NoteSymbolPalmMute",                 to_string(to_underlying_(Settings::highwayNoteSymbolPalmMute)) },
        { "NoteSymbolPop",                      to_string(to_underlying_(Settings::highwayNoteSymbolPop)) },
        { "NoteSymbolPullOff",                  to_string(to_underlying_(Settings::highwayNoteSymbolPullOff)) },
        { "NoteSymbolSlap",                     to_string(to_underlying_(Settings::highwayNoteSymbolSlap)) },
        { "NoteSymbolTap",                      to_string(to_underlying_(Settings::highwayNoteSymbolTap)) },
        { "NoteWidth",                          to_string(Settings::highwayNoteWidth) },
#ifdef SHR3D_RENDERER_DEVELOPMENT
        { "Renderer",                           to_string(to_underlying_(Settings::highwayRenderer)) },
#endif // SHR3D_RENDERER_DEVELOPMENT
        { "ReverseStrings",                     to_string(Settings::highwayReverseStrings) },
        { "StringFadeUnplayed",                 to_string(Settings::highwayStringFadeUnplayed) },
        { "ScrollSpeed",                        to_string(Settings::highwayScrollSpeed) },
        { "SustainColor",                       hexColor(Settings::highwaySustainColor) },
#ifdef SHR3D_SFX_CORE_HEXFIN
        { "Tuner",                              to_string(Settings::highwayTuner) },
        { "TunerColor0",                        hexColor(Settings::highwayTunerColor[0]) },
        { "TunerColor1",                        hexColor(Settings::highwayTunerColor[1]) },
        { "TunerColor2",                        hexColor(Settings::highwayTunerColor[2]) },
        { "TunerColor3",                        hexColor(Settings::highwayTunerColor[3]) },
#endif // SHR3D_SFX_CORE_HEXFIN
        { "VUMeter",                            to_string(Settings::highwayVUMeter) },
        { "VUMeterColor0",                      hexColor(Settings::highwayVUMeterColor[0]) },
        { "VUMeterColor1",                      hexColor(Settings::highwayVUMeterColor[1]) },
        { "VUMeterColor2",                      hexColor(Settings::highwayVUMeterColor[2]) },
        { "VUMeterColor3",                      hexColor(Settings::highwayVUMeterColor[3]) },
        { "VUMeterColor4",                      hexColor(Settings::highwayVUMeterColor[4]) },
        { "ViewDistance",                       to_string(Settings::highwayViewDistance) }
      }
    },
    {
      "Hud",
      {
        { "Lyrics",                             to_string(Settings::hudLyrics) },
        { "LyricsColor0",                       hexColor(Settings::hudLyricsColor[0]) },
        { "LyricsColor1",                       hexColor(Settings::hudLyricsColor[1]) },
        { "LyricsColor2",                       hexColor(Settings::hudLyricsColor[2]) },
        { "LyricsScale",                        to_string(Settings::hudLyricsScale) },
        { "LyricsX",                            to_string(Settings::hudLyricsX)},
        { "LyricsY0",                           to_string(Settings::hudLyricsY[0]) },
        { "LyricsY1",                           to_string(Settings::hudLyricsY[1]) },
        { "ArrangementSwitch",                     to_string(Settings::hudArrangementSwitch) },
        { "ArrangementSwitchColor",                hexColor(Settings::hudArrangementSwitchColor) },
        { "ArrangementSwitchScaleX",               to_string(Settings::hudArrangementSwitchScaleX)},
        { "ArrangementSwitchScaleY",               to_string(Settings::hudArrangementSwitchScaleY)},
        { "ArrangementSwitchX",                    to_string(Settings::hudArrangementSwitchX)},
        { "ArrangementSwitchY",                    to_string(Settings::hudArrangementSwitchY)},
#ifdef SHR3D_OPENXR
        { "ArrangementSwitchXrScaleX",             to_string(Settings::hudArrangementSwitchXrScaleX) },
        { "ArrangementSwitchXrScaleY",             to_string(Settings::hudArrangementSwitchXrScaleY) },
        { "ArrangementSwitchXrX",                  to_string(Settings::hudArrangementSwitchXrX) },
        { "ArrangementSwitchXrY",                  to_string(Settings::hudArrangementSwitchXrY) },
        { "ArrangementSwitchXrZ",                  to_string(Settings::hudArrangementSwitchXrZ) },
#endif // SHR3D_OPENXR
        //{ "NewHighscore",                       to_string(Settings::hudNewHighscore) },
#ifdef SHR3D_RENDERER_DEVELOPMENT
        { "Renderer",                           to_string(to_underlying_(Settings::hudRenderer)) },
#endif // SHR3D_RENDERER_DEVELOPMENT
        { "Score",                              to_string(Settings::hudScore) },
        { "ScoreColor0",                        hexColor(Settings::hudScoreColor[0]) },
        { "ScoreColor1",                        hexColor(Settings::hudScoreColor[1]) },
        { "ScoreColor2",                        hexColor(Settings::hudScoreColor[2]) },
        { "ScoreColor3",                        hexColor(Settings::hudScoreColor[3]) },
        { "SongInfo",                           to_string(Settings::hudSongInfo) },
        { "SongInfoColor0",                     hexColor(Settings::hudSongInfoColor[0])},
        { "SongInfoColor1",                     hexColor(Settings::hudSongInfoColor[1])},
        { "SongInfoScale0",                     to_string(Settings::hudSongInfoScale[0])},
        { "SongInfoScale1",                     to_string(Settings::hudSongInfoScale[1])},
        { "SongInfoX",                          to_string(Settings::hudSongInfoX) },
        { "SongInfoY0",                         to_string(Settings::hudSongInfoY[0])},
        { "SongInfoY1",                         to_string(Settings::hudSongInfoY[1])},
        { "TimelineLevel",                      to_string(Settings::hudTimelineLevel) },
        { "TimelineLevelColor0",                hexColor(Settings::hudTimelineLevelColor[0]) },
        { "TimelineLevelColor1",                hexColor(Settings::hudTimelineLevelColor[1]) },
        { "TimelineLevelColor2",                hexColor(Settings::hudTimelineLevelColor[2]) },
        { "TimelineLevelColor3",                hexColor(Settings::hudTimelineLevelColor[3]) },
        { "TimelineLevelColor4",                hexColor(Settings::hudTimelineLevelColor[4]) },
        { "TimelineLevelColor5",                hexColor(Settings::hudTimelineLevelColor[5]) },
        { "TimelineLevelColor6",                hexColor(Settings::hudTimelineLevelColor[6]) },
        { "TimelineLevelColor7",                hexColor(Settings::hudTimelineLevelColor[7]) },
        { "TimelineLevelFlipY",                 to_string(Settings::hudTimelineLevelFlipY) },
        { "TimelineLevelScaleX",                to_string(Settings::hudTimelineLevelScaleX) },
        { "TimelineLevelScaleY",                to_string(Settings::hudTimelineLevelScaleY) },
        { "TimelineLevelSpacing",               to_string(Settings::hudTimelineLevelSpacing) },
        { "TimelineLevelX",                     to_string(Settings::hudTimelineLevelX) },
        { "TimelineLevelY",                     to_string(Settings::hudTimelineLevelY) },
#ifdef SHR3D_OPENXR
        { "TimelineLevelXrFlipY",               to_string(Settings::hudTimelineLevelXrFlipY) },
        { "TimelineLevelXrScaleX",              to_string(Settings::hudTimelineLevelXrScaleX) },
        { "TimelineLevelXrScaleY",              to_string(Settings::hudTimelineLevelXrScaleY) },
        { "TimelineLevelXrSpacing",             to_string(Settings::hudTimelineLevelXrSpacing) },
        { "TimelineLevelXrX",                   to_string(Settings::hudTimelineLevelXrX) },
        { "TimelineLevelXrY",                   to_string(Settings::hudTimelineLevelXrY) },
        { "TimelineLevelXrZ",                   to_string(Settings::hudTimelineLevelXrZ) },
#endif // SHR3D_OPENXR
#ifdef SHR3D_MUSIC_STRETCHER
        { "TimelineMusicStretcher",             to_string(Settings::hudTimelineMusicStretcher)},
        { "TimelineMusicStretcherColor0",       hexColor(Settings::hudTimelineMusicStretcherColor[0]) },
        { "TimelineMusicStretcherColor1",       hexColor(Settings::hudTimelineMusicStretcherColor[1]) },
        { "TimelineMusicStretcherScaleX",       to_string(Settings::hudTimelineMusicStretcherScaleX) },
        { "TimelineMusicStretcherScaleY",       to_string(Settings::hudTimelineMusicStretcherScaleY) },
        { "TimelineMusicStretcherX",            to_string(Settings::hudTimelineMusicStretcherX) },
        { "TimelineMusicStretcherY",            to_string(Settings::hudTimelineMusicStretcherY) },
#ifdef SHR3D_OPENXR
        { "TimelineMusicStretcherXrScaleX",     to_string(Settings::hudTimelineMusicStretcherXrScaleX) },
        { "TimelineMusicStretcherXrScaleY",     to_string(Settings::hudTimelineMusicStretcherXrScaleY) },
        { "TimelineMusicStretcherXrX",          to_string(Settings::hudTimelineMusicStretcherXrX) },
        { "TimelineMusicStretcherXrY",          to_string(Settings::hudTimelineMusicStretcherXrY) },
        { "TimelineMusicStretcherXrZ",          to_string(Settings::hudTimelineMusicStretcherXrZ) },
#endif // SHR3D_OPENXR
#endif // SHR3D_MUSIC_STRETCHER
        { "TimelineQuickRepeaterColor0",        hexColor(Settings::hudTimelineQuickRepeaterColor[0]) },
        { "TimelineQuickRepeaterColor1",        hexColor(Settings::hudTimelineQuickRepeaterColor[1]) },
        { "TimelineQuickRepeaterFlipY",         to_string(Settings::hudTimelineQuickRepeaterFlipY) },
        { "TimelineQuickRepeaterScaleY",        to_string(Settings::hudTimelineQuickRepeaterScaleY) },
        { "TimelineQuickRepeaterX",             to_string(Settings::hudTimelineQuickRepeaterX) },
        { "TimelineQuickRepeaterY",             to_string(Settings::hudTimelineQuickRepeaterY) },
#ifdef SHR3D_OPENXR
        { "TimelineQuickRepeaterXrScaleX",      to_string(Settings::hudTimelineQuickRepeaterXrScaleX) },
        { "TimelineQuickRepeaterXrScaleY",      to_string(Settings::hudTimelineQuickRepeaterXrScaleY) },
        { "TimelineQuickRepeaterXrX",           to_string(Settings::hudTimelineQuickRepeaterXrX) },
        { "TimelineQuickRepeaterXrY",           to_string(Settings::hudTimelineQuickRepeaterXrY) },
        { "TimelineQuickRepeaterXrZ",           to_string(Settings::hudTimelineQuickRepeaterXrZ) },
#endif // SHR3D_OPENXR
        { "TimelineTone",                       to_string(Settings::hudTimelineTone)},
        { "TimelineToneColor0",                 hexColor(Settings::hudTimelineToneColor[0]) },
        { "TimelineToneColor1",                 hexColor(Settings::hudTimelineToneColor[1]) },
        { "TimelineToneColor2",                 hexColor(Settings::hudTimelineToneColor[2]) },
        { "TimelineToneColor3",                 hexColor(Settings::hudTimelineToneColor[3]) },
        { "TimelineToneColor4",                 hexColor(Settings::hudTimelineToneColor[4]) },
        { "TimelineToneColor5",                 hexColor(Settings::hudTimelineToneColor[5]) },
        { "TimelineToneColor6",                 hexColor(Settings::hudTimelineToneColor[6]) },
        { "TimelineToneColor7",                 hexColor(Settings::hudTimelineToneColor[7]) },
        { "TimelineToneColor8",                 hexColor(Settings::hudTimelineToneColor[8]) },
        { "TimelineToneColor9",                 hexColor(Settings::hudTimelineToneColor[9]) },
        { "TimelineToneColor10",                hexColor(Settings::hudTimelineToneColor[10]) },
        { "TimelineToneScaleX",                 to_string(Settings::hudTimelineToneScaleX) },
        { "TimelineToneScaleY",                 to_string(Settings::hudTimelineToneScaleY) },
        { "TimelineToneX",                      to_string(Settings::hudTimelineToneX) },
        { "TimelineToneY",                      to_string(Settings::hudTimelineToneY) },
#ifdef SHR3D_OPENXR
        { "TimelineToneXrScaleX",               to_string(Settings::hudTimelineToneXrScaleX) },
        { "TimelineToneXrScaleY",               to_string(Settings::hudTimelineToneXrScaleY) },
        { "TimelineToneXrX",                    to_string(Settings::hudTimelineToneXrX) },
        { "TimelineToneXrY",                    to_string(Settings::hudTimelineToneXrY) },
        { "TimelineToneXrZ",                    to_string(Settings::hudTimelineToneXrZ) },
#endif // SHR3D_OPENXR
        { "ToneSwitch",                         to_string(Settings::hudToneSwitch) },
        { "ToneSwitchTimer",                    to_string(Settings::hudToneSwitchTimer) },
        { "ToneSwitchColor",                    hexColor(Settings::hudToneSwitchColor) },
        { "ToneSwitchHintColor",                hexColor(Settings::hudToneSwitchHintColor) },
        { "ToneSwitchScale0",                   to_string(Settings::hudToneSwitchScale[0])},
        { "ToneSwitchScale1",                   to_string(Settings::hudToneSwitchScale[1])},
        { "ToneSwitchX",                        to_string(Settings::hudToneSwitchX) },
        { "ToneSwitchY0",                       to_string(Settings::hudToneSwitchY[0])},
        { "ToneSwitchY1",                       to_string(Settings::hudToneSwitchY[1])},
#ifdef SHR3D_OPENXR
        { "ToneSwitchXrScale0",                 to_string(Settings::hudToneSwitchXrScale[0])},
        { "ToneSwitchXrScale1",                 to_string(Settings::hudToneSwitchXrScale[1])},
        { "ToneSwitchXrX",                      to_string(Settings::hudToneSwitchXrX) },
        { "ToneSwitchXrY0",                     to_string(Settings::hudToneSwitchXrY[0])},
        { "ToneSwitchXrY1",                     to_string(Settings::hudToneSwitchXrY[1])},
        { "ToneSwitchXrZ",                      to_string(Settings::hudToneSwitchXrZ) },
#endif // SHR3D_OPENXR
        { "Watermark",                          to_string(Settings::hudWatermark) },
        { "WatermarkColor",                     hexColor(Settings::hudWatermarkColor) },
#ifdef SHR3D_OPENXR
        { "WatermarkXrX",                       to_string(Settings::hudWatermarkXrX) },
        { "WatermarkXrY",                       to_string(Settings::hudWatermarkXrY) },
        { "WatermarkXrZ",                       to_string(Settings::hudWatermarkXrZ) }
#endif // SHR3D_OPENXR
      }
    },
    {
      "Metronome",
      {
        { "Enabled",                            to_string(Settings::metronomeEnabled) },
        { "Volume",                             to_string(Settings::metronomeVolume) },
        { "Decay",                              to_string(Settings::metronomeDecay) },
        { "Frequency0",                         to_string(Settings::metronomeFrequency0) },
        { "Frequency1",                         to_string(Settings::metronomeFrequency1) },
        { "ClickLength",                        to_string(Settings::metronomeClickLength) },
        { "Side",                               to_string(to_underlying_(Settings::metronomeSide)) }
      }
    },
    {
      "Midi",
      {
        { "FineValueFactor",                    to_string(Settings::midiFineValueFactor) },
        { "AutoConnectDevices",                 Settings::midiAutoConnectDevices }
      }
    },
    {
      "Paths",
      {
        { "StatsIni", Settings::pathStatsIni },
        { "TonesIni", Settings::pathTonesIni },
        { "Backup", Settings::pathBackup },
#ifdef SHR3D_SHRED_OR_PSARC
        { "Cache", Settings::pathCache },
#endif // SHR3D_SHRED_OR_PSARC
#ifdef SHR3D_SFX_PLUGIN_CLAP
        { "Clap", Settings::pathClap },
#endif // SHR3D_SFX_PLUGIN_CLAP
#ifdef SHR3D_ENVIRONMENT_MILK
        { "Milk", Settings::pathMilk },
#endif // SHR3D_ENVIRONMENT_MILK
#ifdef SHR3D_SFX_CORE_NEURALAMPMODELER
        { "Nam", Settings::pathNam },
#endif // SHR3D_SFX_CORE_NEURALAMPMODELER
#ifdef SHR3D_PSARC
        { "Psarc", Settings::pathPsarc },
#endif // SHR3D_PSARC
#ifdef SHR3D_SHRED
        { "Shred", Settings::pathShred },
#endif // SHR3D_SHRED
#ifdef SHR3D_RECORDER
        { "Recorder", Settings::pathRecorder },
#endif // SHR3D_RECORDER
#ifdef SHR3D_SFX_PLUGIN_VST
        { "Vst", Settings::pathVst },
#endif // SHR3D_SFX_PLUGIN_VST
#ifdef SHR3D_SFX_PLUGIN_VST3
        { "Vst3", Settings::pathVst3 },
#endif // SHR3D_SFX_PLUGIN_VST3
#ifdef SHR3D_ENVIRONMENT_SKYBOX
        { "Skybox", Settings::pathSkybox },
#endif // SHR3D_ENVIRONMENT_SKYBOX
#ifdef SHR3D_ENVIRONMENT_STAGE
        { "Stage", Settings::pathStage }
#endif // SHR3D_ENVIRONMENT_STAGE
      }
    },
#ifdef SHR3D_SPOTIFY
    {
      "Spotify",
      {
        { "ClientId",     Settings::spotifyClientId },
        { "ClientSecret", Settings::spotifyClientSecret },
        { "RedirectUri",  Settings::spotifyRedirectUri }
      }
    },
#endif // SHR3D_SPOTIFY
    {
      "Tuner",
      {
        { "NoteDetectionSource", to_string(to_underlying_(Settings::tunerNoteDetectionSource)) },
#ifdef SHR3D_SFX
        { "TunerPlugin",         Settings::tunerPlugin },
        { "MidiPlugin",          Settings::tunerMidiPlugin },
#endif // SHR3D_SFX
#ifdef SHR3D_SFX_CORE_HEXFIN
        { "HexfinOnsetThreshold",   to_string(Settings::tunerHexfinOnsetThreshold) },
        { "HexfinReleaseThreshold", to_string(Settings::tunerHexfinReleaseThreshold) }
#endif // SHR3D_SFX_CORE_HEXFIN
      }
    },
    {
      "Ui",
      {
        { "Scale",        to_string(Settings::uiScale) },
#ifdef SHR3D_OPENXR
        { "XrZ",        to_string(Settings::uiXrZ) },
#endif // SHR3D_OPENXR
#ifdef SHR3D_CUSTOM_CURSOR
        { "CursorCustom", to_string(Settings::uiCursorCustom) },
        { "CursorSize",   to_string(Settings::uiCursorSize) },
#endif // SHR3D_CUSTOM_CURSOR
        { "Color0",       hexColor(Settings::uiColor[0]) },
        { "Color1",       hexColor(Settings::uiColor[1]) },
        { "Color2",       hexColor(Settings::uiColor[2]) },
        { "Color3",       hexColor(Settings::uiColor[3]) },
        { "Color4",       hexColor(Settings::uiColor[4]) },
        { "Color5",       hexColor(Settings::uiColor[5]) },
        { "Color6",       hexColor(Settings::uiColor[6]) },
        { "Color7",       hexColor(Settings::uiColor[7]) },
        { "Color8",       hexColor(Settings::uiColor[8]) },
        { "Color9",       hexColor(Settings::uiColor[9]) },
        { "Color10",      hexColor(Settings::uiColor[10]) },
        { "Color11",      hexColor(Settings::uiColor[11]) },
        { "Color12",      hexColor(Settings::uiColor[12]) },
        { "Color13",      hexColor(Settings::uiColor[13]) },
        { "Color14",      hexColor(Settings::uiColor[14]) },
        { "Color15",      hexColor(Settings::uiColor[15]) },
        { "Color16",      hexColor(Settings::uiColor[16]) },
        { "Color17",      hexColor(Settings::uiColor[17]) },
        { "Color18",      hexColor(Settings::uiColor[18]) },
        { "Color19",      hexColor(Settings::uiColor[19]) },
        { "Color20",      hexColor(Settings::uiColor[20]) },
        { "Color21",      hexColor(Settings::uiColor[21]) },
        { "Color22",      hexColor(Settings::uiColor[22]) },
        { "Color23",      hexColor(Settings::uiColor[23]) },
        { "Color24",      hexColor(Settings::uiColor[24]) },
        { "Color25",      hexColor(Settings::uiColor[25]) },
        { "Color26",      hexColor(Settings::uiColor[26]) },
        { "Color27",      hexColor(Settings::uiColor[27]) },
        // additional custom colors:
        { "Color28",      hexColor(Settings::uiColor[28]) },
        { "Color29",      hexColor(Settings::uiColor[29]) },
      }
    },
#ifdef SHR3D_OPENXR
    {
      "XR",
      {
#ifdef SHR3D_OPENXR_PCVR
        { "Enabled",              to_string(Settings::xrEnabled) },
#endif // SHR3D_OPENXR_PCVR
#ifdef SHR3D_OPENXR_CONTROLLER_PICO4_AND_QUEST3
        { "Controller",           to_string(to_underlying_(Settings::xrController)) },
#endif // SHR3D_OPENXR_CONTROLLER_PICO4_AND_QUEST3
        { "ControllerColor0",     hexColor(Settings::xrControllerColor[0]) },
        { "ControllerColor1",     hexColor(Settings::xrControllerColor[1]) },
        { "CursorColor0",         hexColor(Settings::xrCursorColor[0]) },
        { "CursorColor1",         hexColor(Settings::xrCursorColor[1]) },
        { "PointerColor",         hexColor(Settings::xrPointerColor) },
        //{ "UiCircularProjection", to_string(Settings::xrUiCircularProjection) },
      }
    }
#endif // SHR3D_OPENXR
  };

#ifdef SHR3D_MIDI
  for (i32 i = 0; i < ARRAY_SIZE(Const::midiBindingsNames); ++i)
  {
    if (Settings::midiBinding[i] == 0xFF)
      serializedSettings["Midi"].insert({ std::string("Binding") + Const::midiBindingsNames[i], "" });
    else
      serializedSettings["Midi"].insert({ std::string("Binding") + Const::midiBindingsNames[i], to_string(Settings::midiBinding[i]) + ';' + to_string(to_underlying_(Global::midiNoteMode[Settings::midiBinding[i]])) });
  }
#endif // SHR3D_MIDI

#ifdef SHR3D_AUDIO_SUPERPOWERED
  {
    const i32 inputCounts = Settings::audioSuperpoweredInputVolume.size();
    for (i32 i = 0; i < inputCounts; ++i)
    {
      const std::string mute = std::string("SuperpoweredInput") + to_string(i) + "Mute";
      serializedSettings["Audio"][mute] = to_string(Settings::audioSuperpoweredInputMutes[i]);
      const std::string volume = std::string("SuperpoweredInput") + to_string(i) + "Volume";
      serializedSettings["Audio"][volume] = to_string(Settings::audioSuperpoweredInputVolume[i]);
    }
    const i32 outputCounts = Settings::audioSuperpoweredOutputVolume.size();
    for (i32 i = 0; i < inputCounts; ++i)
    {
      const std::string mute = std::string("SuperpoweredOutput") + to_string(i) + "Mute";
      serializedSettings["Audio"][mute] = to_string(Settings::audioSuperpoweredOutputMutes[i]);
      const std::string volume = std::string("SuperpoweredOutput") + to_string(i) + "Volume";
      serializedSettings["Audio"][volume] = to_string(Settings::audioSuperpoweredOutputVolume[i]);
    }
  }
#endif // SHR3D_AUDIO_SUPERPOWERED

#ifdef SHR3D_ENVIRONMENT_MILK
  if (Global::milkActivePresets.size() >= 1)
  {
    serializedSettings["Environment"]["MilkActivePresets"] += Global::milkPresetNames[Global::milkActivePresets[0]];
    for (i32 i = 1; i < Global::milkActivePresets.size(); ++i)
    {
      serializedSettings["Environment"]["MilkActivePresets"] += '|' + Global::milkPresetNames[Global::milkActivePresets[i]];
    }
  }
  else
  {
    serializedSettings["Environment"]["MilkActivePresets"] = "";
  }
#endif // SHR3D_ENVIRONMENT_MILK

#ifdef SHR3D_MIDI
  if (Global::tunerMidiDevice != 0)
  {
    serializedSettings["Tuner"]["MidiDevice"] = Global::midiDeviceNames[Global::tunerMidiDevice];
  }
#endif // SHR3D_MIDI

  if (Global::tunerMidiPlugin.system != SfxSystem::empty)
  {
    std::string& tunerMidiPlugin = serializedSettings["Tuner"]["MidiPlugin"];

    // remove old parameters
    const u64 splitPos = tunerMidiPlugin.find_first_of(',');
    if (splitPos != std::string::npos)
      tunerMidiPlugin.resize(splitPos);

    // add new paramters
    const std::string parameters = Sfx::saveParameters(Global::tunerMidiPlugin, 0);
    const std::string parametersBase64 = Base64::encode(reinterpret_cast<const u8*>(parameters.data()), parameters.size());

    tunerMidiPlugin += ',' + parametersBase64;
  }

#ifdef SHR3D_ENVIRONMENT_STAGE
  {
    std::map<std::string, std::string>& environment = serializedSettings["Environment"];

    environment.insert({ "Stage", Settings::environmentStage });
#ifndef PLATFORM_OPENXR_ANDROID
    environment.insert({ "StagePlayerHeight", to_string(Settings::environmentStagePlayerHeight) });
#endif // PLATFORM_OPENXR_ANDROID
    environment.insert({ "StageRotation", to_string(Settings::environmentStageRotation) });
    environment.insert({ "StageScale", to_string(Settings::environmentStageScale) });
    environment.insert({ "StageX", to_string(Settings::environmentStageX) });
    environment.insert({ "StageY", to_string(Settings::environmentStageY) });
    environment.insert({ "StageZ", to_string(Settings::environmentStageZ) });
  }
#endif // SHR3D_ENVIRONMENT_STAGE

  return serializedSettings;
}

static void deserializeSettings(const std::map<std::string, std::map<std::string, std::string>>& serializedSettings)
{
  if (serializedSettings.contains("Application"))
  {
    const auto& application = serializedSettings.at("Application");
    if (application.contains("Instrument"))
      Settings::applicationInstrument = Instrument(atoi2(application.at("Instrument").c_str()));
    if (application.contains("BackupMode"))
      Settings::applicationBackupMode = BackupMode(atoi2(application.at("BackupMode").c_str()));
    if (application.contains("EndOfSong"))
      Settings::applicationEndOfSong = EndOfSong(atoi2(application.at("EndOfSong").c_str()));
    if (application.contains("ToneSwitch"))
      Settings::applicationToneSwitch = bool(atoi2(application.at("ToneSwitch").c_str()));
  }
  if (serializedSettings.contains("Audio"))
  {
    const auto& audio = serializedSettings.at("Audio");
    if (audio.contains("System"))
      Settings::audioSystem = AudioSystem(atoi2(audio.at("System").c_str()));
    if (audio.contains("InstrumentVolume"))
      Settings::audioEffectVolume = f32(atof2(audio.at("InstrumentVolume").c_str()));
    if (audio.contains("InstrumentVolumeCoop"))
      Settings::audioEffectVolumeCoop = f32(atof2(audio.at("InstrumentVolumeCoop").c_str()));
    if (audio.contains("MusicVolume"))
      Settings::audioMusicVolume = f32(atof2(audio.at("MusicVolume").c_str()));
#ifdef SHR3D_AUDIO_AAUDIO
    if (audio.contains("AAudioBlockSize"))
      Settings::audioAAudioBlockSize = atoi2(audio.at("AAudioBlockSize").c_str());
    if (audio.contains("AAudioChannelInput"))
      Settings::audioAAudioChannelInput = atoi2(audio.at("AAudioChannelInput").c_str());
#ifdef SHR3D_COOP
    if (audio.contains("AAudioChannelInputCoop"))
      Settings::audioAAudioChannelInputCoop = atoi2(audio.at("AAudioChannelInputCoop").c_str());
#endif // SHR3D_COOP
    if (audio.contains("AAudioDeviceInput"))
      Settings::audioAAudioDeviceInput = audio.at("AAudioDeviceInput");
    if (audio.contains("AAudioDeviceOutput"))
      Settings::audioAAudioDeviceOutput = audio.at("AAudioDeviceOutput");
    if (audio.contains("AAudioChannelInput"))
      Settings::audioAAudioChannelInput = atoi2(audio.at("AAudioChannelInput").c_str());
#ifdef SHR3D_COOP
    if (audio.contains("AAudioChannelInputCoop"))
      Settings::audioAAudioChannelInputCoop = atoi2(audio.at("AAudioChannelInputCoop").c_str());
#endif // SHR3D_COOP
    if (audio.contains("AAudioSampleRate"))
      Settings::audioAAudioSampleRate = atoi2(audio.at("AAudioSampleRate").c_str());
    if (audio.contains("AAudioExclusiveMode"))
      Settings::audioAAudioExclusiveMode = bool(atoi2(audio.at("AAudioExclusiveMode").c_str()));
    if (audio.contains("AAudioPerformanceMode"))
      Settings::audioAAudioPerformanceMode = AAudioPerformanceMode(atoi2(audio.at("AAudioPerformanceMode").c_str()));
#endif // SHR3D_AUDIO_AAUDIO
#ifdef SHR3D_AUDIO_ASIO
    if (audio.contains("AsioDevice"))
      Settings::audioAsioDevice = audio.at("AsioDevice");
    if (audio.contains("AsioBlockSize"))
      Settings::audioAsioBlockSize = atoi2(audio.at("AsioBlockSize").c_str());
    if (audio.contains("AsioSampleRate"))
      Settings::audioAsioSampleRate = atoi2(audio.at("AsioSampleRate").c_str());
    if (audio.contains("AsioChannelOutput"))
      Settings::audioAsioChannelOutput = atoi2(audio.at("AsioChannelOutput").c_str());
    if (audio.contains("AsioChannelInput0"))
      Settings::audioAsioChannelInput0 = atoi2(audio.at("AsioChannelInput0").c_str());
    if (audio.contains("AsioChannelInput1"))
      Settings::audioAsioChannelInput1 = atoi2(audio.at("AsioChannelInput1").c_str());
#ifdef SHR3D_COOP
    if (audio.contains("AsioChannelInputCoop0"))
      Settings::audioAsioChannelInputCoop0 = atoi2(audio.at("AsioChannelInputCoop0").c_str());
    if (audio.contains("AsioChannelInputCoop1"))
      Settings::audioAsioChannelInputCoop1 = atoi2(audio.at("AsioChannelInputCoop1").c_str());
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
#ifdef SHR3D_AUDIO_ASIO_SECOND_DEVICE_FOR_TUNER_DIVIDED
    if (audio.contains("AsioSecondDeviceForTunerDivided"))
      Settings::audioAsioSecondDeviceForTunerDivided = audio.at("AsioSecondDeviceForTunerDivided");
#endif // SHR3D_AUDIO_ASIO_SECOND_DEVICE_FOR_TUNER_DIVIDED
    if (audio.contains("AsioDividedPickup"))
      Settings::audioAsioDividedPickup = bool(atoi2(audio.at("AsioDividedPickup").c_str()));
    if (audio.contains("AsioDividedPickupAsMainInput"))
      Settings::audioAsioDividedPickupAsMainInput = bool(atoi2(audio.at("AsioDividedPickupAsMainInput").c_str()));
    if (audio.contains("AsioDividedPickupChannelString0"))
      Settings::audioAsioDividedPickupChannelString0 = atoi2(audio.at("AsioDividedPickupChannelString0").c_str());
    if (audio.contains("AsioDividedPickupChannelString1"))
      Settings::audioAsioDividedPickupChannelString1 = atoi2(audio.at("AsioDividedPickupChannelString1").c_str());
    if (audio.contains("AsioDividedPickupChannelString2"))
      Settings::audioAsioDividedPickupChannelString2 = atoi2(audio.at("AsioDividedPickupChannelString2").c_str());
    if (audio.contains("AsioDividedPickupChannelString3"))
      Settings::audioAsioDividedPickupChannelString3 = atoi2(audio.at("AsioDividedPickupChannelString3").c_str());
    if (audio.contains("AsioDividedPickupChannelString4"))
      Settings::audioAsioDividedPickupChannelString4 = atoi2(audio.at("AsioDividedPickupChannelString4").c_str());
    if (audio.contains("AsioDividedPickupChannelString5"))
      Settings::audioAsioDividedPickupChannelString5 = atoi2(audio.at("AsioDividedPickupChannelString5").c_str());
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_ASIO
#ifdef SHR3D_AUDIO_JACK
    if (audio.contains("JackInputDevice0"))
      Settings::audioJackInputDevice0 = audio.at("JackInputDevice0");
    if (audio.contains("JackInputDevice1"))
      Settings::audioJackInputDevice1 = audio.at("JackInputDevice1");
    if (audio.contains("JackOutputDevice0"))
      Settings::audioJackOutputDevice0 = audio.at("JackOutputDevice0");
    if (audio.contains("JackOutputDevice1"))
      Settings::audioJackOutputDevice1 = audio.at("JackOutputDevice1");
#ifdef SHR3D_COOP
    if (audio.contains("JackInputDeviceCoop0"))
      Settings::audioJackInputDeviceCoop0 = audio.at("JackInputDeviceCoop0");
    if (audio.contains("JackInputDeviceCoop1"))
      Settings::audioJackInputDeviceCoop1 = audio.at("JackInputDeviceCoop1");
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
    if (audio.contains("JackDividedPickup"))
      Settings::audioJackDividedPickup = bool(atoi2(audio.at("JackDividedPickup").c_str()));
    if (audio.contains("JackDividedPickupAsMainInput"))
      Settings::audioJackDividedPickupAsMainInput = bool(atoi2(audio.at("JackDividedPickupAsMainInput").c_str()));
    if (audio.contains("JackDividedPickupChannelString0"))
      Settings::audioJackDividedPickupChannelString0 = audio.at("JackDividedPickupChannelString0");
    if (audio.contains("JackDividedPickupChannelString1"))
      Settings::audioJackDividedPickupChannelString1 = audio.at("JackDividedPickupChannelString1");
    if (audio.contains("JackDividedPickupChannelString2"))
      Settings::audioJackDividedPickupChannelString2 = audio.at("JackDividedPickupChannelString2");
    if (audio.contains("JackDividedPickupChannelString3"))
      Settings::audioJackDividedPickupChannelString3 = audio.at("JackDividedPickupChannelString3");
    if (audio.contains("JackDividedPickupChannelString4"))
      Settings::audioJackDividedPickupChannelString4 = audio.at("JackDividedPickupChannelString4");
    if (audio.contains("JackDividedPickupChannelString5"))
      Settings::audioJackDividedPickupChannelString5 = audio.at("JackDividedPickupChannelString5");
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_JACK
#ifdef SHR3D_AUDIO_PIPEWIRE
    if (audio.contains("PipewireInputDevice0"))
      Settings::audioPipewireInputDevice0 = audio.at("PipewireInputDevice0");
    if (audio.contains("PipewireInputDevice1"))
      Settings::audioPipewireInputDevice1 = audio.at("PipewireInputDevice1");
    if (audio.contains("PipewireOutputDevice0"))
      Settings::audioPipewireOutputDevice0 = audio.at("PipewireOutputDevice0");
    if (audio.contains("PipewireOutputDevice1"))
      Settings::audioPipewireOutputDevice1 = audio.at("PipewireOutputDevice1");
#ifdef SHR3D_COOP
    if (audio.contains("PipewireInputDeviceCoop0"))
      Settings::audioPipewireInputDeviceCoop0 = audio.at("PipewireInputDeviceCoop0");
    if (audio.contains("PipewireInputDeviceCoop1"))
      Settings::audioPipewireInputDeviceCoop1 = audio.at("PipewireInputDeviceCoop1");
#endif // SHR3D_COOP
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
    if (audio.contains("PipewireDividedPickup"))
      Settings::audioPipewireDividedPickup = bool(atoi2(audio.at("PipewireDividedPickup").c_str()));
    if (audio.contains("PipewireDividedPickupAsMainInput"))
      Settings::audioPipewireDividedPickupAsMainInput = bool(atoi2(audio.at("PipewireDividedPickupAsMainInput").c_str()));
    if (audio.contains("PipewireDividedPickupChannelString0"))
      Settings::audioPipewireDividedPickupChannelString0 = audio.at("PipewireDividedPickupChannelString0");
    if (audio.contains("PipewireDividedPickupChannelString1"))
      Settings::audioPipewireDividedPickupChannelString1 = audio.at("PipewireDividedPickupChannelString1");
    if (audio.contains("PipewireDividedPickupChannelString2"))
      Settings::audioPipewireDividedPickupChannelString2 = audio.at("PipewireDividedPickupChannelString2");
    if (audio.contains("PipewireDividedPickupChannelString3"))
      Settings::audioPipewireDividedPickupChannelString3 = audio.at("PipewireDividedPickupChannelString3");
    if (audio.contains("PipewireDividedPickupChannelString4"))
      Settings::audioPipewireDividedPickupChannelString4 = audio.at("PipewireDividedPickupChannelString4");
    if (audio.contains("PipewireDividedPickupChannelString5"))
      Settings::audioPipewireDividedPickupChannelString5 = audio.at("PipewireDividedPickupChannelString5");
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_PIPEWIRE
#ifdef SHR3D_AUDIO_SDL
    if (audio.contains("SdlBlockSize"))
      Settings::audioSdlBlockSize = atoi2(audio.at("SdlBlockSize").c_str());
    if (audio.contains("SdlChannelInput"))
      Settings::audioSdlChannelInput = atoi2(audio.at("SdlChannelInput").c_str());
#ifdef SHR3D_COOP
    if (audio.contains("SdlChannelInputCoop"))
      Settings::audioSdlChannelInputCoop = atoi2(audio.at("SdlChannelInputCoop").c_str());
#endif // SHR3D_COOP
    if (audio.contains("SdlDeviceInput"))
      Settings::audioSdlDeviceInput = audio.at("SdlDeviceInput");
    if (audio.contains("SdlDeviceOutput"))
      Settings::audioSdlDeviceOutput = audio.at("SdlDeviceOutput");
    if (audio.contains("SdlSampleRate"))
      Settings::audioSdlSampleRate = atoi2(audio.at("SdlSampleRate").c_str());
#endif // SHR3D_AUDIO_SDL
#ifdef SHR3D_AUDIO_SUPERPOWERED
    if (audio.contains("SuperpoweredBlockSize"))
      Settings::audioSuperpoweredBlockSize = atoi2(audio.at("SuperpoweredBlockSize").c_str());
    if (audio.contains("SuperpoweredCofiguration"))
      Settings::audioSuperpoweredCofiguration = audio.at("SuperpoweredCofiguration");
    if (audio.contains("SuperpoweredChannelInput"))
      Settings::audioSuperpoweredChannelInput = atoi2(audio.at("SuperpoweredChannelInput").c_str());
    if (audio.contains("SuperpoweredChannelOutput"))
      Settings::audioSuperpoweredChannelOutput = atoi2(audio.at("SuperpoweredChannelOutput").c_str());
    if (audio.contains("SuperpoweredDeviceInput"))
      Settings::audioSuperpoweredDeviceInput = audio.at("SuperpoweredDeviceInput");
    if (audio.contains("SuperpoweredDeviceOutput"))
      Settings::audioSuperpoweredDeviceOutput = audio.at("SuperpoweredDeviceOutput");
    if (audio.contains("SuperpoweredSustainedPerformanceMode"))
      Settings::audioSuperpoweredSustainedPerformanceMode = bool(atoi2(audio.at("SuperpoweredSustainedPerformanceMode").c_str()));
    if (audio.contains("SuperpoweredInputPathName"))
      Settings::audioSuperpoweredInputPathName = audio.at("SuperpoweredInputPathName");
    if (audio.contains("SuperpoweredOutputPathName"))
      Settings::audioSuperpoweredOutputPathName = audio.at("SuperpoweredOutputPathName");
#ifdef SHR3D_SFX_CORE_HEXFIN_DIVIDED
    if (audio.contains("SuperpoweredDividedPickup"))
      Settings::audioSuperpoweredDividedPickup = bool(atoi2(audio.at("SuperpoweredDividedPickup").c_str()));;
    if (audio.contains("SuperpoweredDividedPickupChannelString0"))
      Settings::audioSuperpoweredDividedPickupChannelString0 = atoi2(audio.at("SuperpoweredDividedPickupChannelString0").c_str());
    if (audio.contains("SuperpoweredDividedPickupChannelString1"))
      Settings::audioSuperpoweredDividedPickupChannelString1 = atoi2(audio.at("SuperpoweredDividedPickupChannelString1").c_str());
    if (audio.contains("SuperpoweredDividedPickupChannelString2"))
      Settings::audioSuperpoweredDividedPickupChannelString2 = atoi2(audio.at("SuperpoweredDividedPickupChannelString2").c_str());
    if (audio.contains("SuperpoweredDividedPickupChannelString3"))
      Settings::audioSuperpoweredDividedPickupChannelString3 = atoi2(audio.at("SuperpoweredDividedPickupChannelString3").c_str());
    if (audio.contains("SuperpoweredDividedPickupChannelString4"))
      Settings::audioSuperpoweredDividedPickupChannelString4 = atoi2(audio.at("SuperpoweredDividedPickupChannelString4").c_str());
    if (audio.contains("SuperpoweredDividedPickupChannelString5"))
      Settings::audioSuperpoweredDividedPickupChannelString5 = atoi2(audio.at("SuperpoweredDividedPickupChannelString5").c_str());
#endif // SHR3D_SFX_CORE_HEXFIN_DIVIDED
#endif // SHR3D_AUDIO_SUPERPOWERED
#ifdef SHR3D_AUDIO_WASAPI
    if (audio.contains("WasapiBlockSize"))
      Settings::audioWasapiBlockSize = atoi2(audio.at("WasapiBlockSize").c_str());
    if (audio.contains("WasapiChannelInput0"))
      Settings::audioWasapiChannelInput0 = atoi2(audio.at("WasapiChannelInput0").c_str());
#ifdef SHR3D_COOP
    if (audio.contains("WasapiChannelInput1"))
      Settings::audioWasapiChannelInput1 = atoi2(audio.at("WasapiChannelInput1").c_str());
#endif // SHR3D_COOP
    if (audio.contains("WasapiDeviceInput"))
      Settings::audioWasapiDeviceInput = audio.at("WasapiDeviceInput");
    if (audio.contains("WasapiDeviceOutput"))
      Settings::audioWasapiDeviceOutput = audio.at("WasapiDeviceOutput");
    if (audio.contains("WasapiSampleRate"))
      Settings::audioWasapiSampleRate = atoi2(audio.at("WasapiSampleRate").c_str());
    if (audio.contains("WasapiExclusiveMode"))
      Settings::audioWasapiExclusiveMode = bool(atoi2(audio.at("WasapiExclusiveMode").c_str()));
#endif // SHR3D_AUDIO_WASAPI
#ifdef SHR3D_AUDIO_WEBAUDIO
    if (audio.contains("WebAudioChannelInput0"))
      Settings::audioWebAudioChannelInput0 = atoi2(audio.at("WebAudioChannelInput0").c_str());
    if (audio.contains("WebAudioSampleRate"))
      Settings::audioWebAudioSampleRate = atoi2(audio.at("WebAudioSampleRate").c_str());
#endif // SHR3D_AUDIO_WEBAUDIO
  }
  if (serializedSettings.contains("Environment"))
  {
    const auto& environment = serializedSettings.at("Environment");
    if (environment.contains("ClearColor"))
      Settings::environmentClearColor = colorVec4(environment.at("ClearColor").c_str());
#ifdef SHR3D_ENVIRONMENT_MILK
    if (environment.contains("Milk"))
      Settings::environmentMilk = bool(atoi2(environment.at("Milk").c_str()));
    if (environment.contains("MilkActivePresets"))
      Settings::environmentMilkActivePresets = environment.at("MilkActivePresets");
    if (environment.contains("MilkBeatSensitivity"))
      Settings::environmentMilkBeatSensitivity = f32(atof2(environment.at("MilkBeatSensitivity").c_str()));
    if (environment.contains("MilkDuration"))
      Settings::environmentMilkDuration = atoi2(environment.at("MilkDuration").c_str());
    if (environment.contains("MilkMeshSize"))
      Settings::environmentMilkMeshSize = atoi2(environment.at("MilkMeshSize").c_str());
    if (environment.contains("MilkFrameSkip"))
      Settings::environmentMilkFrameSkip = atoi2(environment.at("MilkFrameSkip").c_str());
    if (environment.contains("MilkFrameSpeed"))
      Settings::environmentMilkFrameSpeed = f32(atof2(environment.at("MilkFrameSpeed").c_str()));
    if (environment.contains("MilkShuffle"))
      Settings::environmentMilkShuffle = bool(atoi2(environment.at("MilkShuffle").c_str()));
#endif // SHR3D_ENVIRONMENT_MILK
#ifdef SHR3D_ENVIRONMENT_SKYBOX
    if (environment.contains("Skybox"))
      Settings::environmentSkybox = environment.at("Skybox");
    if (environment.contains("SkyboxRotation"))
      Settings::environmentSkyboxRotation = f32(atof2(environment.at("SkyboxRotation").c_str()));
#endif // SHR3D_ENVIRONMENT_SKYBOX
#ifdef SHR3D_ENVIRONMENT_STAGE
    if (environment.contains("Stage"))
      Settings::environmentStage = environment.at("Stage");
#ifndef PLATFORM_OPENXR_ANDROID
    if (environment.contains("StagePlayerHeight"))
      Settings::environmentStagePlayerHeight = f32(atof2(environment.at("StagePlayerHeight").c_str()));
#endif // PLATFORM_OPENXR_ANDROID
    if (environment.contains("StageRotation"))
      Settings::environmentStageRotation = f32(atof2(environment.at("StageRotation").c_str()));
    if (environment.contains("StageScale"))
      Settings::environmentStageScale = f32(atof2(environment.at("StageScale").c_str()));
    if (environment.contains("StageX"))
      Settings::environmentStageX = f32(atof2(environment.at("StageX").c_str()));
    if (environment.contains("StageY"))
      Settings::environmentStageY = f32(atof2(environment.at("StageY").c_str()));
    if (environment.contains("StageZ"))
      Settings::environmentStageZ = f32(atof2(environment.at("StageZ").c_str()));
#endif // SHR3D_ENVIRONMENT_STAGE
  }
  if (serializedSettings.contains("Camera"))
  {
    const auto& camera = serializedSettings.at("Camera");
    if (camera.contains("Mode"))
      Settings::cameraMode = CameraMode(atoi2(camera.at("Mode").c_str()));
#ifndef PLATFORM_OPENXR_ANDROID
    if (camera.contains("FieldOfView"))
      Settings::cameraFieldOfView = f32(atof2(camera.at("FieldOfView").c_str()));
#endif // PLATFORM_OPENXR_ANDROID
    if (camera.contains("FixedX"))
      Settings::cameraFixedX = f32(atof2(camera.at("FixedX").c_str()));
    if (camera.contains("FixedXRotation"))
      Settings::cameraFixedXRotation = f32(atof2(camera.at("FixedXRotation").c_str()));
    if (camera.contains("FixedY"))
      Settings::cameraFixedY = f32(atof2(camera.at("FixedY").c_str()));
    if (camera.contains("FixedYRotation"))
      Settings::cameraFixedYRotation = f32(atof2(camera.at("FixedYRotation").c_str()));
    if (camera.contains("FixedZ"))
      Settings::cameraFixedZ = f32(atof2(camera.at("FixedZ").c_str()));
    if (camera.contains("ParallaxAnchorTackingDuration"))
      Settings::cameraParallaxAnchorTackingDuration = f32(atof2(camera.at("ParallaxAnchorTackingDuration").c_str()));
    if (camera.contains("ParallaxHighwayRotation"))
      Settings::cameraParallaxHighwayRotation = f32(atof2(camera.at("ParallaxHighwayRotation").c_str()));
    if (camera.contains("ParallaxHighwayScale"))
      Settings::cameraParallaxHighwayScale = f32(atof2(camera.at("ParallaxHighwayScale").c_str()));
    if (camera.contains("ParallaxHighwayX"))
      Settings::cameraParallaxHighwayX = f32(atof2(camera.at("ParallaxHighwayX").c_str()));
    if (camera.contains("ParallaxHighwayXFactor"))
      Settings::cameraParallaxHighwayXFactor = f32(atof2(camera.at("ParallaxHighwayXFactor").c_str()));
    if (camera.contains("ParallaxHighwayY"))
      Settings::cameraParallaxHighwayY = f32(atof2(camera.at("ParallaxHighwayY").c_str()));
    if (camera.contains("ParallaxHighwayYFactor"))
      Settings::cameraParallaxHighwayYFactor = f32(atof2(camera.at("ParallaxHighwayYFactor").c_str()));
    if (camera.contains("ParallaxHighwayZ"))
      Settings::cameraParallaxHighwayZ = f32(atof2(camera.at("ParallaxHighwayZ").c_str()));
    if (camera.contains("ParallaxHighwayZFactor"))
      Settings::cameraParallaxHighwayZFactor = f32(atof2(camera.at("ParallaxHighwayZFactor").c_str()));
    if (camera.contains("ParallaxX"))
      Settings::cameraParallaxX = f32(atof2(camera.at("ParallaxX").c_str()));
    if (camera.contains("ParallaxXFactor"))
      Settings::cameraParallaxXFactor = f32(atof2(camera.at("ParallaxXFactor").c_str()));
    if (camera.contains("ParallaxXRotation"))
      Settings::cameraParallaxXRotation = f32(atof2(camera.at("ParallaxXRotation").c_str()));
    if (camera.contains("ParallaxY"))
      Settings::cameraParallaxY = f32(atof2(camera.at("ParallaxY").c_str()));
    if (camera.contains("ParallaxYFactor"))
      Settings::cameraParallaxYFactor = f32(atof2(camera.at("ParallaxYFactor").c_str()));
    if (camera.contains("ParallaxYRotation"))
      Settings::cameraParallaxYRotation = f32(atof2(camera.at("ParallaxYRotation").c_str()));
    if (camera.contains("ParallaxZ"))
      Settings::cameraParallaxZ = f32(atof2(camera.at("ParallaxZ").c_str()));
    if (camera.contains("ParallaxZFactor"))
      Settings::cameraParallaxZFactor = f32(atof2(camera.at("ParallaxZFactor").c_str()));
#ifdef SHR3D_OPENXR_PCVR
    if (camera.contains("PcVrMode"))
      Settings::cameraPcVrMode = CameraMode(atoi2(camera.at("PcVrMode").c_str()));
    if (camera.contains("PcVrParallaxAnchorTackingDuration"))
      Settings::cameraPcVrParallaxAnchorTackingDuration = f32(atof2(camera.at("PcVrParallaxAnchorTackingDuration").c_str()));
    if (camera.contains("PcVrParallaxHighwayRotation"))
      Settings::cameraPcVrParallaxHighwayRotation = f32(atof2(camera.at("PcVrParallaxHighwayRotation").c_str()));
    if (camera.contains("PcVrParallaxHighwayScale"))
      Settings::cameraPcVrParallaxHighwayScale = f32(atof2(camera.at("PcVrParallaxHighwayScale").c_str()));
    if (camera.contains("PcVrParallaxHighwayX"))
      Settings::cameraPcVrParallaxHighwayX = f32(atof2(camera.at("PcVrParallaxHighwayX").c_str()));
    if (camera.contains("PcVrParallaxHighwayXFactor"))
      Settings::cameraPcVrParallaxHighwayXFactor = f32(atof2(camera.at("PcVrParallaxHighwayXFactor").c_str()));
    if (camera.contains("PcVrParallaxHighwayY"))
      Settings::cameraPcVrParallaxHighwayY = f32(atof2(camera.at("PcVrParallaxHighwayY").c_str()));
    if (camera.contains("PcVrParallaxHighwayYFactor"))
      Settings::cameraPcVrParallaxHighwayYFactor = f32(atof2(camera.at("PcVrParallaxHighwayYFactor").c_str()));
    if (camera.contains("PcVrParallaxHighwayZ"))
      Settings::cameraPcVrParallaxHighwayZ = f32(atof2(camera.at("PcVrParallaxHighwayZ").c_str()));
    if (camera.contains("PcVrParallaxHighwayZFactor"))
      Settings::cameraPcVrParallaxHighwayZFactor = f32(atof2(camera.at("PcVrParallaxHighwayZFactor").c_str()));
    if (camera.contains("PcVrParallaxX"))
      Settings::cameraPcVrParallaxX = f32(atof2(camera.at("PcVrParallaxX").c_str()));
    if (camera.contains("PcVrParallaxXFactor"))
      Settings::cameraPcVrParallaxXFactor = f32(atof2(camera.at("PcVrParallaxXFactor").c_str()));
    if (camera.contains("PcVrParallaxXRotation"))
      Settings::cameraPcVrParallaxXRotation = f32(atof2(camera.at("PcVrParallaxXRotation").c_str()));
    if (camera.contains("PcVrParallaxY"))
      Settings::cameraPcVrParallaxY = f32(atof2(camera.at("PcVrParallaxY").c_str()));
    if (camera.contains("PcVrParallaxYFactor"))
      Settings::cameraPcVrParallaxYFactor = f32(atof2(camera.at("PcVrParallaxYFactor").c_str()));
    if (camera.contains("PcVrParallaxYRotation"))
      Settings::cameraPcVrParallaxYRotation = f32(atof2(camera.at("PcVrParallaxYRotation").c_str()));
    if (camera.contains("PcVrParallaxZ"))
      Settings::cameraPcVrParallaxZ = f32(atof2(camera.at("PcVrParallaxZ").c_str()));
    if (camera.contains("PcVrParallaxZFactor"))
      Settings::cameraPcVrParallaxZFactor = f32(atof2(camera.at("PcVrParallaxZFactor").c_str()));
#endif // SHR3D_OPENXR_PCVR
  }
  if (serializedSettings.contains("Graphics"))
  {
    const auto& graphics = serializedSettings.at("Graphics");
    if (graphics.contains("Fullscreen"))
      Settings::graphicsFullscreen = FullscreenMode(atoi2(graphics.at("Fullscreen").c_str()));
#ifdef SHR3D_GRAPHICS_MSAA
    if (graphics.contains("MSAA"))
      Settings::graphicsMSAA = atoi2(graphics.at("MSAA").c_str());
#endif // SHR3D_GRAPHICS_MSAA
    if (graphics.contains("Scaling"))
      Settings::graphicsScaling = ScalingMode(atoi2(graphics.at("Scaling").c_str()));
#ifdef SHR3D_OPENGL_SPIR_V
    if (graphics.contains("SpirV"))
      Settings::graphicsSpirV = atoi2(graphics.at("SpirV").c_str());
#endif // SHR3D_OPENGL_SPIR_V
#ifdef PLATFORM_QUEST_3
    if (graphics.contains("RefreshRate"))
      Settings::graphicsRefreshRate = atoi2(graphics.at("RefreshRate").c_str());
#endif // PLATFORM_QUEST_3
#if !defined(PLATFORM_EMSCRIPTEN) && !defined(PLATFORM_QUEST_3)
    if (graphics.contains("VSync"))
      Settings::graphicsVSync = VSyncMode(atoi2(graphics.at("VSync").c_str()));
#endif // !PLATFORM_EMSCRIPTEN && !PLATFORM_QUEST_3
    if (graphics.contains("WindowWidth"))
      Settings::graphicsWindowWidth = atoi2(graphics.at("WindowWidth").c_str());
    if (graphics.contains("WindowHeight"))
      Settings::graphicsWindowHeight = atoi2(graphics.at("WindowHeight").c_str());
  }
  if (serializedSettings.contains("Highway"))
  {
    const auto& highway = serializedSettings.at("Highway");
    if (highway.contains("AnchorColor0"))
      Settings::highwayAnchorColor[0] = colorVec4(highway.at("AnchorColor0").c_str());
    if (highway.contains("AnchorColor1"))
      Settings::highwayAnchorColor[1] = colorVec4(highway.at("AnchorColor1").c_str());
    if (highway.contains("AnchorColor2"))
      Settings::highwayAnchorColor[2] = colorVec4(highway.at("AnchorColor2").c_str());
    if (highway.contains("AnchorColor3"))
      Settings::highwayAnchorColor[3] = colorVec4(highway.at("AnchorColor3").c_str());
    if (highway.contains("AnchorColorExponent"))
      Settings::highwayAnchorColorExponent = f32(atof2(highway.at("AnchorColorExponent").c_str()));
    if (highway.contains("Beat"))
      Settings::highwayBeat = bool(atoi2(highway.at("Beat").c_str()));
    if (highway.contains("BeatColor0"))
      Settings::highwayBeatColor[0] = colorVec4(highway.at("BeatColor0").c_str());
    if (highway.contains("BeatColor1"))
      Settings::highwayBeatColor[1] = colorVec4(highway.at("BeatColor1").c_str());
    if (highway.contains("BeatStrumDirection"))
      Settings::highwayBeatStrumDirection = bool(atoi2(highway.at("BeatStrumDirection").c_str()));
    if (highway.contains("BeatStrumDirectionColor0"))
      Settings::highwayBeatStrumDirectionColor[0] = colorVec4(highway.at("BeatStrumDirectionColor0").c_str());
    if (highway.contains("BeatStrumDirectionColor1"))
      Settings::highwayBeatStrumDirectionColor[1] = colorVec4(highway.at("BeatStrumDirectionColor1").c_str());
    if (highway.contains("BeatStrumDirectionPrimary"))
      Settings::highwayBeatStrumDirectionPrimary = StrumDirection(atoi2(highway.at("BeatStrumDirectionPrimary").c_str()));
    if (highway.contains("BeatStrumDirectionNext"))
      Settings::highwayBeatStrumDirectionNext = StrumDirection(atoi2(highway.at("BeatStrumDirectionNext").c_str()));
    if (highway.contains("BeatStrumsBetweenBeats"))
      Settings::highwayBeatStrumsBetweenBeats = atoi2(highway.at("BeatStrumsBetweenBeats").c_str());
    if (highway.contains("CapoColor"))
      Settings::highwayCapoColor = colorVec4(highway.at("CapoColor").c_str());
    if (highway.contains("ChordBox"))
      Settings::highwayChordBox = bool(atoi2(highway.at("ChordBox").c_str()));
    if (highway.contains("ChordBoxColor"))
      Settings::highwayChordBoxColor = colorVec4(highway.at("ChordBoxColor").c_str());
    if (highway.contains("ChordBoxArpeggio"))
      Settings::highwayChordBoxArpeggio = bool(atoi2(highway.at("ChordBoxArpeggio").c_str()));
    if (highway.contains("ChordBoxArpeggioColor"))
      Settings::highwayChordBoxArpeggioColor = colorVec4(highway.at("ChordBoxArpeggioColor").c_str());
    if (highway.contains("ChordFretNumbers"))
      Settings::highwayChordFretNumbers = bool(atoi2(highway.at("ChordFretNumbers").c_str()));
    if (highway.contains("ChordName"))
      Settings::highwayChordName = bool(atoi2(highway.at("ChordName").c_str()));
    if (highway.contains("ChordNameColor"))
      Settings::highwayChordNameColor = colorVec4(highway.at("ChordNameColor").c_str());
    if (highway.contains("DotInlayColor0"))
      Settings::highwayDotInlayColor[0] = colorVec4(highway.at("DotInlayColor0").c_str());
    if (highway.contains("DotInlayColor1"))
      Settings::highwayDotInlayColor[1] = colorVec4(highway.at("DotInlayColor1").c_str());
    if (highway.contains("DotInlayColor2"))
      Settings::highwayDotInlayColor[2] = colorVec4(highway.at("DotInlayColor2").c_str());
    if (highway.contains("DotInlayColor3"))
      Settings::highwayDotInlayColor[3] = colorVec4(highway.at("DotInlayColor3").c_str());
    if (highway.contains("FadeFarDistance"))
      Settings::highwayFadeFarDistance = f32(atof2(highway.at("FadeFarDistance").c_str()));
    if (highway.contains("FadeNearDistance"))
      Settings::highwayFadeNearDistance = f32(atof2(highway.at("FadeNearDistance").c_str()));
    if (highway.contains("FadeNearStrength"))
      Settings::highwayFadeNearStrength = f32(atof2(highway.at("FadeNearStrength").c_str()));
    if (highway.contains("FingerNumberColor"))
      Settings::highwayFingerNumberColor = colorVec4(highway.at("FingerNumberColor").c_str());
    if (highway.contains("FingerNumbers"))
      Settings::highwayFingerNumbers = bool(atoi2(highway.at("FingerNumbers").c_str()));
    if (highway.contains("FretboardFrets"))
      Settings::highwayFretboardFrets = bool(atoi2(highway.at("FretboardFrets").c_str()));
    if (highway.contains("FretboardFretColor"))
      Settings::highwayFretboardFretColor = colorVec4(highway.at("FretboardFretColor").c_str());
    if (highway.contains("FretboardFretNumberColor0"))
      Settings::highwayFretboardFretNumberColor[0] = colorVec4(highway.at("FretboardFretNumberColor0").c_str());
    if (highway.contains("FretboardFretNumberColor1"))
      Settings::highwayFretboardFretNumberColor[1] = colorVec4(highway.at("FretboardFretNumberColor1").c_str());
    if (highway.contains("FretboardFretNumberColor2"))
      Settings::highwayFretboardFretNumberColor[2] = colorVec4(highway.at("FretboardFretNumberColor2").c_str());
    if (highway.contains("FretboardNoteNames"))
      Settings::highwayFretboardNoteNames = bool(atoi2(highway.at("FretboardNoteNames").c_str()));
    if (highway.contains("FretboardNoteNameColor0"))
      Settings::highwayFretboardNoteNameColor[0] = colorVec4(highway.at("FretboardNoteNameColor0").c_str());
    if (highway.contains("FretboardNoteNameColor1"))
      Settings::highwayFretboardNoteNameColor[1] = colorVec4(highway.at("FretboardNoteNameColor1").c_str());
    if (highway.contains("FretboardCollisionNotes"))
      Settings::highwayFretboardCollisionNotes = bool(atoi2(highway.at("FretboardCollisionNotes").c_str()));
    if (highway.contains("FretboardCollisionNotesColor0"))
      Settings::highwayFretboardCollisionNotesColor[0] = colorVec4(highway.at("FretboardCollisionNotesColor0").c_str());
    if (highway.contains("FretboardCollisionNotesColor1"))
      Settings::highwayFretboardCollisionNotesColor[1] = colorVec4(highway.at("FretboardCollisionNotesColor1").c_str());
    if (highway.contains("FretboardPlayedNotes"))
      Settings::highwayFretboardPlayedNotesDot = bool(atoi2(highway.at("FretboardPlayedNotes").c_str()));
    if (highway.contains("FretboardPlayedNotesColor0"))
      Settings::highwayFretboardPlayedNotesDotColor[0] = colorVec4(highway.at("FretboardPlayedNotesColor0").c_str());
    if (highway.contains("FretboardPlayedNotesColor1"))
      Settings::highwayFretboardPlayedNotesDotColor[1] = colorVec4(highway.at("FretboardPlayedNotesColor1").c_str());
    if (highway.contains("FretboardStrings"))
      Settings::highwayFretboardStrings = bool(atoi2(highway.at("FretboardStrings").c_str()));
    if (highway.contains("FretboardStringNoteNames"))
      Settings::highwayFretboardStringNoteNames = bool(atoi2(highway.at("FretboardStringNoteNames").c_str()));
#ifdef SHR3D_SFX_CORE_HEXFIN
    if (highway.contains("FretboardPlayedNotesTuner"))
      Settings::highwayFretboardPlayedNotesTuner = bool(atoi2(highway.at("FretboardPlayedNotesTuner").c_str()));
#endif // SHR3D_SFX_CORE_HEXFIN
#ifdef SHR3D_PARTICLE
    if (highway.contains("ParticleDetectedNotes"))
      Settings::highwayParticlePlayedNotes = bool(atoi2(highway.at("ParticleDetectedNotes").c_str()));
    if (highway.contains("ParticleCollisionNotes"))
      Settings::highwayParticleCollisionNotes = bool(atoi2(highway.at("ParticleCollisionNotes").c_str()));
    if (highway.contains("ParticleShape"))
      Settings::highwayParticleShape = atoi2(highway.at("ParticleShape").c_str());
    if (highway.contains("ParticleMaxCount"))
      Settings::highwayParticleMaxCount = atoi2(highway.at("ParticleMaxCount").c_str());
    if (highway.contains("ParticleSpawnsPerSecond"))
      Settings::highwayParticleSpawnsPerSecond = f32(atof2(highway.at("ParticleSpawnsPerSecond").c_str()));
    if (highway.contains("ParticleSpawnRadius"))
      Settings::highwayParticleSpawnRadius = f32(atof2(highway.at("ParticleSpawnRadius").c_str()));
    if (highway.contains("ParticleMinSize"))
      Settings::highwayParticleMinSize = f32(atof2(highway.at("ParticleMinSize").c_str()));
    if (highway.contains("ParticleMaxSize"))
      Settings::highwayParticleMaxSize = f32(atof2(highway.at("ParticleMaxSize").c_str()));
    if (highway.contains("ParticleMinLifeTime"))
      Settings::highwayParticleMinLifeTime = f32(atof2(highway.at("ParticleMinLifeTime").c_str()));
    if (highway.contains("ParticleMaxLifeTime"))
      Settings::highwayParticleMaxLifeTime = f32(atof2(highway.at("ParticleMaxLifeTime").c_str()));
    if (highway.contains("ParticleColorVariation"))
      Settings::highwayParticleColorVariation = f32(atof2(highway.at("ParticleColorVariation").c_str()));
    if (highway.contains("ParticleMinVelocityX"))
      Settings::highwayParticleMinVelocityX = f32(atof2(highway.at("ParticleMinVelocityX").c_str()));
    if (highway.contains("ParticleMaxVelocityX"))
      Settings::highwayParticleMaxVelocityX = f32(atof2(highway.at("ParticleMaxVelocityX").c_str()));
    if (highway.contains("ParticleMinVelocityY"))
      Settings::highwayParticleMinVelocityY = f32(atof2(highway.at("ParticleMinVelocityY").c_str()));
    if (highway.contains("ParticleMaxVelocityY"))
      Settings::highwayParticleMaxVelocityY = f32(atof2(highway.at("ParticleMaxVelocityY").c_str()));
    if (highway.contains("ParticleMinVelocityZ"))
      Settings::highwayParticleMinVelocityZ = f32(atof2(highway.at("ParticleMinVelocityZ").c_str()));
    if (highway.contains("ParticleMaxVelocityZ"))
      Settings::highwayParticleMaxVelocityZ = f32(atof2(highway.at("ParticleMaxVelocityZ").c_str()));
    if (highway.contains("ParticleAccelerationX"))
      Settings::highwayParticleAccelerationX = f32(atof2(highway.at("ParticleAccelerationX").c_str()));
    if (highway.contains("ParticleAccelerationY"))
      Settings::highwayParticleAccelerationY = f32(atof2(highway.at("ParticleAccelerationY").c_str()));
    if (highway.contains("ParticleAccelerationZ"))
      Settings::highwayParticleAccelerationZ = f32(atof2(highway.at("ParticleAccelerationZ").c_str()));
    if (highway.contains("ParticleMinRotationAngle"))
      Settings::highwayParticleMinRotationAngle = f32(atof2(highway.at("ParticleMinRotationAngle").c_str()));
    if (highway.contains("ParticleMaxRotationAngle"))
      Settings::highwayParticleMaxRotationAngle = f32(atof2(highway.at("ParticleMaxRotationAngle").c_str()));
#endif // SHR3D_PARTICLE
    if (highway.contains("GroundFretColor0"))
      Settings::highwayGroundFretColor[0] = colorVec4(highway.at("GroundFretColor0").c_str());
    if (highway.contains("GroundFretColor1"))
      Settings::highwayGroundFretColor[1] = colorVec4(highway.at("GroundFretColor1").c_str());
    if (highway.contains("InstrumentBass5StringHideString0"))
      Settings::highwayInstrumentBass5StringHideString0 = bool(atoi2(highway.at("InstrumentBass5StringHideString0").c_str()));
    if (highway.contains("InstrumentBass5StringTuning0"))
      Settings::highwayInstrumentBass5StringTuning[0] = atoi2(highway.at("InstrumentBass5StringTuning0").c_str());
    if (highway.contains("InstrumentBass5StringTuning1"))
      Settings::highwayInstrumentBass5StringTuning[1] = atoi2(highway.at("InstrumentBass5StringTuning1").c_str());
    if (highway.contains("InstrumentBass5StringTuning2"))
      Settings::highwayInstrumentBass5StringTuning[2] = atoi2(highway.at("InstrumentBass5StringTuning2").c_str());
    if (highway.contains("InstrumentBass5StringTuning3"))
      Settings::highwayInstrumentBass5StringTuning[3] = atoi2(highway.at("InstrumentBass5StringTuning3").c_str());
    if (highway.contains("InstrumentBassFirstWoundString"))
      Settings::highwayInstrumentBassFirstWoundString = atoi2(highway.at("InstrumentBassFirstWoundString").c_str());
    if (highway.contains("InstrumentBassFretSpacing"))
      Settings::highwayInstrumentBassFretSpacing = f32(atof2(highway.at("InstrumentBassFretSpacing").c_str()));
    if (highway.contains("InstrumentBassFretSpacingFactor"))
      Settings::highwayInstrumentBassFretSpacingFactor = f32(atof2(highway.at("InstrumentBassFretSpacingFactor").c_str()));
    if (highway.contains("InstrumentBassStringColor0"))
      Settings::highwayInstrumentBassStringColor[0] = colorVec4(highway.at("InstrumentBassStringColor0").c_str());
    if (highway.contains("InstrumentBassStringColor1"))
      Settings::highwayInstrumentBassStringColor[1] = colorVec4(highway.at("InstrumentBassStringColor1").c_str());
    if (highway.contains("InstrumentBassStringColor2"))
      Settings::highwayInstrumentBassStringColor[2] = colorVec4(highway.at("InstrumentBassStringColor2").c_str());
    if (highway.contains("InstrumentBassStringColor3"))
      Settings::highwayInstrumentBassStringColor[3] = colorVec4(highway.at("InstrumentBassStringColor3").c_str());
    if (highway.contains("InstrumentBassStringColor4"))
      Settings::highwayInstrumentBassStringColor[4] = colorVec4(highway.at("InstrumentBassStringColor4").c_str());
    if (highway.contains("InstrumentBassStringColor5"))
      Settings::highwayInstrumentBassStringColor[5] = colorVec4(highway.at("InstrumentBassStringColor5").c_str());
    if (highway.contains("InstrumentBassStringSpacing"))
      Settings::highwayInstrumentBassStringSpacing = f32(atof2(highway.at("InstrumentBassStringSpacing").c_str()));
    if (highway.contains("InstrumentGuitar7StringHideString0"))
      Settings::highwayInstrumentGuitar7StringHideString0 = bool(atoi2(highway.at("InstrumentGuitar7StringHideString0").c_str()));
    if (highway.contains("InstrumentGuitar7StringTuning0"))
      Settings::highwayInstrumentGuitar7StringTuning[0] = atoi2(highway.at("InstrumentGuitar7StringTuning0").c_str());
    if (highway.contains("InstrumentGuitar7StringTuning1"))
      Settings::highwayInstrumentGuitar7StringTuning[1] = atoi2(highway.at("InstrumentGuitar7StringTuning1").c_str());
    if (highway.contains("InstrumentGuitar7StringTuning2"))
      Settings::highwayInstrumentGuitar7StringTuning[2] = atoi2(highway.at("InstrumentGuitar7StringTuning2").c_str());
    if (highway.contains("InstrumentGuitar7StringTuning3"))
      Settings::highwayInstrumentGuitar7StringTuning[3] = atoi2(highway.at("InstrumentGuitar7StringTuning3").c_str());
    if (highway.contains("InstrumentGuitar7StringTuning4"))
      Settings::highwayInstrumentGuitar7StringTuning[4] = atoi2(highway.at("InstrumentGuitar7StringTuning4").c_str());
    if (highway.contains("InstrumentGuitar7StringTuning5"))
      Settings::highwayInstrumentGuitar7StringTuning[5] = atoi2(highway.at("InstrumentGuitar7StringTuning5").c_str());
    if (highway.contains("InstrumentGuitarFirstWoundString"))
      Settings::highwayInstrumentGuitarFirstWoundString = atoi2(highway.at("InstrumentGuitarFirstWoundString").c_str());
    if (highway.contains("InstrumentGuitarFretSpacing"))
      Settings::highwayInstrumentGuitarFretSpacing = f32(atof2(highway.at("InstrumentGuitarFretSpacing").c_str()));
    if (highway.contains("InstrumentGuitarFretSpacingFactor"))
      Settings::highwayInstrumentGuitarFretSpacingFactor = f32(atof2(highway.at("InstrumentGuitarFretSpacingFactor").c_str()));
    if (highway.contains("InstrumentGuitarStringColor0"))
      Settings::highwayInstrumentGuitarStringColor[0] = colorVec4(highway.at("InstrumentGuitarStringColor0").c_str());
    if (highway.contains("InstrumentGuitarStringColor1"))
      Settings::highwayInstrumentGuitarStringColor[1] = colorVec4(highway.at("InstrumentGuitarStringColor1").c_str());
    if (highway.contains("InstrumentGuitarStringColor2"))
      Settings::highwayInstrumentGuitarStringColor[2] = colorVec4(highway.at("InstrumentGuitarStringColor2").c_str());
    if (highway.contains("InstrumentGuitarStringColor3"))
      Settings::highwayInstrumentGuitarStringColor[3] = colorVec4(highway.at("InstrumentGuitarStringColor3").c_str());
    if (highway.contains("InstrumentGuitarStringColor4"))
      Settings::highwayInstrumentGuitarStringColor[4] = colorVec4(highway.at("InstrumentGuitarStringColor4").c_str());
    if (highway.contains("InstrumentGuitarStringColor5"))
      Settings::highwayInstrumentGuitarStringColor[5] = colorVec4(highway.at("InstrumentGuitarStringColor5").c_str());
    if (highway.contains("InstrumentGuitarStringColor6"))
      Settings::highwayInstrumentGuitarStringColor[6] = colorVec4(highway.at("InstrumentGuitarStringColor6").c_str());
    if (highway.contains("InstrumentGuitarStringColor7"))
      Settings::highwayInstrumentGuitarStringColor[7] = colorVec4(highway.at("InstrumentGuitarStringColor7").c_str());
    if (highway.contains("InstrumentGuitarStringSpacing"))
      Settings::highwayInstrumentGuitarStringSpacing = f32(atof2(highway.at("InstrumentGuitarStringSpacing").c_str()));
    if (highway.contains("NoteBendCurve"))
      Settings::highwayNoteBendCurve = f32(atof2(highway.at("NoteBendCurve").c_str()));
    if (highway.contains("NoteBendEndTime"))
      Settings::highwayNoteBendEndTime = f32(atof2(highway.at("NoteBendEndTime").c_str()));
    if (highway.contains("NoteBendSpeed"))
      Settings::highwayNoteBendSpeed = f32(atof2(highway.at("NoteBendSpeed").c_str()));
    if (highway.contains("NoteBendHintOffset"))
      Settings::highwayNoteBendHintOffset = f32(atof2(highway.at("NoteBendHintOffset").c_str()));
    if (highway.contains("NoteBendHintDistance"))
      Settings::highwayNoteBendHintDistance = f32(atof2(highway.at("NoteBendHintDistance").c_str()));
    if (highway.contains("NoteHeight"))
      Settings::highwayNoteHeight = f32(atof2(highway.at("NoteHeight").c_str()));
    if (highway.contains("NoteRotate"))
      Settings::highwayNoteRotate = atoi2(highway.at("NoteRotate").c_str());
    if (highway.contains("NoteRotateEndTime"))
      Settings::highwayNoteRotateEndTime = f32(atof2(highway.at("NoteRotateEndTime").c_str()));
    if (highway.contains("NoteRotateSpeed"))
      Settings::highwayNoteRotateSpeed = f32(atof2(highway.at("NoteRotateSpeed").c_str()));
    if (highway.contains("NoteShape"))
      Settings::highwayNoteShape = NoteShape(atoi2(highway.at("NoteShape").c_str()));
    if (highway.contains("NoteSymbolFretMute"))
      Settings::highwayNoteSymbolFretMute = NoteSymbols(atoi2(highway.at("NoteSymbolFretMute").c_str()));
    if (highway.contains("NoteSymbolHammerOn"))
      Settings::highwayNoteSymbolHammerOn = NoteSymbols(atoi2(highway.at("NoteSymbolHammerOn").c_str()));
    if (highway.contains("NoteSymbolHarmonic"))
      Settings::highwayNoteSymbolHarmonic = NoteSymbols(atoi2(highway.at("NoteSymbolHarmonic").c_str()));
    if (highway.contains("NoteSymbolPinchHarmonic"))
      Settings::highwayNoteSymbolPinchHarmonic = NoteSymbols(atoi2(highway.at("NoteSymbolPinchHarmonic").c_str()));
    if (highway.contains("NoteSymbolPalmMute"))
      Settings::highwayNoteSymbolPalmMute = NoteSymbols(atoi2(highway.at("NoteSymbolPalmMute").c_str()));
    if (highway.contains("NoteSymbolPop"))
      Settings::highwayNoteSymbolPop = NoteSymbols(atoi2(highway.at("NoteSymbolPop").c_str()));
    if (highway.contains("NoteSymbolPullOff"))
      Settings::highwayNoteSymbolPullOff = NoteSymbols(atoi2(highway.at("NoteSymbolPullOff").c_str()));
    if (highway.contains("NoteSymbolSlap"))
      Settings::highwayNoteSymbolSlap = NoteSymbols(atoi2(highway.at("NoteSymbolSlap").c_str()));
    if (highway.contains("NoteSymbolTap"))
      Settings::highwayNoteSymbolTap = NoteSymbols(atoi2(highway.at("NoteSymbolTap").c_str()));
    if (highway.contains("NoteStand"))
      Settings::highwayNoteStand = bool(atoi2(highway.at("NoteStand").c_str()));
    if (highway.contains("NoteStandZero"))
      Settings::highwayNoteStandZero = bool(atoi2(highway.at("NoteStandZero").c_str()));
    if (highway.contains("NoteWidth"))
      Settings::highwayNoteWidth = f32(atof2(highway.at("NoteWidth").c_str()));
    if (highway.contains("NoteSustainCurveSampleDistance"))
      Settings::highwayNoteSustainCurveSampleDistance = f32(atof2(highway.at("NoteSustainCurveSampleDistance").c_str()));
    if (highway.contains("NoteSustainTremoloSampleDistance"))
      Settings::highwayNoteSustainTremoloSampleDistance = f32(atof2(highway.at("NoteSustainTremoloSampleDistance").c_str()));
    if (highway.contains("NoteSustainTremoloShakeStrength"))
      Settings::highwayNoteSustainTremoloShakeStrength = f32(atof2(highway.at("NoteSustainTremoloShakeStrength").c_str()));
    if (highway.contains("NoteSustainWidth"))
      Settings::highwayNoteSustainWidth = f32(atof2(highway.at("NoteSustainWidth").c_str()));
    if (highway.contains("NoteSustainWidthZero"))
      Settings::highwayNoteSustainWidthZero = f32(atof2(highway.at("NoteSustainWidthZero").c_str()));
    if (highway.contains("FretboardNoteHeight"))
      Settings::highwayFretboardNoteHeight = f32(atof2(highway.at("FretboardNoteHeight").c_str()));
    if (highway.contains("FretboardNoteWidth"))
      Settings::highwayFretboardNoteWidth = f32(atof2(highway.at("FretboardNoteWidth").c_str()));
#ifdef SHR3D_RENDERER_DEVELOPMENT
    if (highway.contains("Renderer"))
      Settings::highwayRenderer = Renderer(atoi2(highway.at("Renderer").c_str()));
#endif // SHR3D_RENDERER_DEVELOPMENT
    if (highway.contains("ReverseStrings"))
      Settings::highwayReverseStrings = bool(atoi2(highway.at("ReverseStrings").c_str()));
    if (highway.contains("StringFadeUnplayed"))
      Settings::highwayStringFadeUnplayed = bool(atoi2(highway.at("StringFadeUnplayed").c_str()));
    if (highway.contains("ScrollSpeed"))
      Settings::highwayScrollSpeed = f32(atof2(highway.at("ScrollSpeed").c_str()));
    if (highway.contains("SustainColor"))
      Settings::highwaySustainColor = colorVec4(highway.at("SustainColor").c_str());
#ifdef SHR3D_SFX_CORE_HEXFIN
    if (highway.contains("Tuner"))
      Settings::highwayTuner = bool(atoi2(highway.at("Tuner").c_str()));
    if (highway.contains("TunerColor0"))
      Settings::highwayTunerColor[0] = colorVec4(highway.at("TunerColor0").c_str());
    if (highway.contains("TunerColor1"))
      Settings::highwayTunerColor[1] = colorVec4(highway.at("TunerColor1").c_str());
    if (highway.contains("TunerColor2"))
      Settings::highwayTunerColor[2] = colorVec4(highway.at("TunerColor2").c_str());
    if (highway.contains("TunerColor3"))
      Settings::highwayTunerColor[3] = colorVec4(highway.at("TunerColor3").c_str());
#endif // SHR3D_SFX_CORE_HEXFIN
    if (highway.contains("VUMeter"))
      Settings::highwayVUMeter = bool(atoi2(highway.at("VUMeter").c_str()));
    if (highway.contains("VUMeterColor0"))
      Settings::highwayVUMeterColor[0] = colorVec4(highway.at("VUMeterColor0").c_str());
    if (highway.contains("VUMeterColor1"))
      Settings::highwayVUMeterColor[1] = colorVec4(highway.at("VUMeterColor1").c_str());
    if (highway.contains("VUMeterColor2"))
      Settings::highwayVUMeterColor[2] = colorVec4(highway.at("VUMeterColor2").c_str());
    if (highway.contains("VUMeterColor3"))
      Settings::highwayVUMeterColor[3] = colorVec4(highway.at("VUMeterColor3").c_str());
    if (highway.contains("VUMeterColor4"))
      Settings::highwayVUMeterColor[4] = colorVec4(highway.at("VUMeterColor4").c_str());
    if (highway.contains("ViewDistance"))
      Settings::highwayViewDistance = f32(atof2(highway.at("ViewDistance").c_str()));
  }
  if (serializedSettings.contains("Hud"))
  {
    const auto& hud = serializedSettings.at("Hud");
    if (hud.contains("Lyrics"))
      Settings::hudLyrics = bool(atoi2(hud.at("Lyrics").c_str()));
    if (hud.contains("LyricsColor0"))
      Settings::hudLyricsColor[0] = colorVec4(hud.at("LyricsColor0").c_str());
    if (hud.contains("LyricsColor1"))
      Settings::hudLyricsColor[1] = colorVec4(hud.at("LyricsColor1").c_str());
    if (hud.contains("LyricsColor2"))
      Settings::hudLyricsColor[2] = colorVec4(hud.at("LyricsColor2").c_str());
    if (hud.contains("LyricsScale"))
      Settings::hudLyricsScale = f32(atof2(hud.at("LyricsScale").c_str()));
    if (hud.contains("LyricsX"))
      Settings::hudLyricsX = f32(atof2(hud.at("LyricsX").c_str()));
    if (hud.contains("LyricsY0"))
      Settings::hudLyricsY[0] = f32(atof2(hud.at("LyricsY0").c_str()));
    if (hud.contains("LyricsY1"))
      Settings::hudLyricsY[1] = f32(atof2(hud.at("LyricsY1").c_str()));
    // if (hud.contains("NewHighscore"))
    //   Settings::hudNewHighscore = bool(atoi2(hud.at("NewHighscore").c_str()));
#ifdef SHR3D_RENDERER_DEVELOPMENT
    if (hud.contains("Renderer"))
      Settings::hudRenderer = Renderer(atoi2(hud.at("Renderer").c_str()));
#endif // SHR3D_RENDERER_DEVELOPMENT
    if (hud.contains("TimelineLevel"))
      Settings::hudTimelineLevel = bool(atoi2(hud.at("TimelineLevel").c_str()));
    if (hud.contains("TimelineLevelColor0"))
      Settings::hudTimelineLevelColor[0] = colorVec4(hud.at("TimelineLevelColor0").c_str());
    if (hud.contains("TimelineLevelColor1"))
      Settings::hudTimelineLevelColor[1] = colorVec4(hud.at("TimelineLevelColor1").c_str());
    if (hud.contains("TimelineLevelColor2"))
      Settings::hudTimelineLevelColor[2] = colorVec4(hud.at("TimelineLevelColor2").c_str());
    if (hud.contains("TimelineLevelColor3"))
      Settings::hudTimelineLevelColor[3] = colorVec4(hud.at("TimelineLevelColor3").c_str());
    if (hud.contains("TimelineLevelColor4"))
      Settings::hudTimelineLevelColor[4] = colorVec4(hud.at("TimelineLevelColor4").c_str());
    if (hud.contains("TimelineLevelColor5"))
      Settings::hudTimelineLevelColor[5] = colorVec4(hud.at("TimelineLevelColor5").c_str());
    if (hud.contains("TimelineLevelColor6"))
      Settings::hudTimelineLevelColor[6] = colorVec4(hud.at("TimelineLevelColor6").c_str());
    if (hud.contains("TimelineLevelColor7"))
      Settings::hudTimelineLevelColor[7] = colorVec4(hud.at("TimelineLevelColor7").c_str());
    if (hud.contains("TimelineLevelFlipY"))
      Settings::hudTimelineLevelFlipY = bool(atoi2(hud.at("TimelineLevelFlipY").c_str()));
    if (hud.contains("TimelineLevelScaleX"))
      Settings::hudTimelineLevelScaleX = f32(atof2(hud.at("TimelineLevelScaleX").c_str()));
    if (hud.contains("TimelineLevelScaleY"))
      Settings::hudTimelineLevelScaleY = f32(atof2(hud.at("TimelineLevelScaleY").c_str()));
    if (hud.contains("TimelineLevelSpacing"))
      Settings::hudTimelineLevelSpacing = f32(atof2(hud.at("TimelineLevelSpacing").c_str()));
    if (hud.contains("TimelineLevelX"))
      Settings::hudTimelineLevelX = f32(atof2(hud.at("TimelineLevelX").c_str()));
    if (hud.contains("TimelineLevelY"))
      Settings::hudTimelineLevelY = f32(atof2(hud.at("TimelineLevelY").c_str()));
#ifdef SHR3D_OPENXR
    if (hud.contains("TimelineLevelXrFlipY"))
      Settings::hudTimelineLevelXrFlipY = bool(atoi2(hud.at("TimelineLevelXrFlipY").c_str()));
    if (hud.contains("TimelineLevelXrScaleX"))
      Settings::hudTimelineLevelXrScaleX = f32(atof2(hud.at("TimelineLevelXrScaleX").c_str()));
    if (hud.contains("TimelineLevelXrScaleY"))
      Settings::hudTimelineLevelXrScaleY = f32(atof2(hud.at("TimelineLevelXrScaleY").c_str()));
    if (hud.contains("TimelineLevelXrSpacing"))
      Settings::hudTimelineLevelXrSpacing = f32(atof2(hud.at("TimelineLevelXrSpacing").c_str()));
    if (hud.contains("TimelineLevelXrX"))
      Settings::hudTimelineLevelXrX = f32(atof2(hud.at("TimelineLevelXrX").c_str()));
    if (hud.contains("TimelineLevelXrY"))
      Settings::hudTimelineLevelXrY = f32(atof2(hud.at("TimelineLevelXrY").c_str()));
    if (hud.contains("TimelineLevelXrZ"))
      Settings::hudTimelineLevelXrZ = f32(atof2(hud.at("TimelineLevelXrZ").c_str()));
#endif // SHR3D_OPENXR
#ifdef SHR3D_MUSIC_STRETCHER
    if (hud.contains("TimelineMusicStretcher"))
      Settings::hudTimelineMusicStretcher = bool(atoi2(hud.at("TimelineMusicStretcher").c_str()));
    if (hud.contains("TimelineMusicStretcherColor0"))
      Settings::hudTimelineMusicStretcherColor[0] = colorVec4(hud.at("TimelineMusicStretcherColor0").c_str());
    if (hud.contains("TimelineMusicStretcherColor1"))
      Settings::hudTimelineMusicStretcherColor[1] = colorVec4(hud.at("TimelineMusicStretcherColor1").c_str());
    if (hud.contains("TimelineMusicStretcherScaleX"))
      Settings::hudTimelineMusicStretcherScaleX = f32(atof2(hud.at("TimelineMusicStretcherScaleX").c_str()));
    if (hud.contains("TimelineMusicStretcherScaleY"))
      Settings::hudTimelineMusicStretcherScaleY = f32(atof2(hud.at("TimelineMusicStretcherScaleY").c_str()));
    if (hud.contains("TimelineMusicStretcherX"))
      Settings::hudTimelineMusicStretcherX = f32(atof2(hud.at("TimelineMusicStretcherX").c_str()));
    if (hud.contains("TimelineMusicStretcherY"))
      Settings::hudTimelineMusicStretcherY = f32(atof2(hud.at("TimelineMusicStretcherY").c_str()));
#ifdef SHR3D_OPENXR
    if (hud.contains("TimelineMusicStretcherXrScaleX"))
      Settings::hudTimelineMusicStretcherXrScaleX = f32(atof2(hud.at("TimelineMusicStretcherXrScaleX").c_str()));
    if (hud.contains("TimelineMusicStretcherXrScaleY"))
      Settings::hudTimelineMusicStretcherXrScaleY = f32(atof2(hud.at("TimelineMusicStretcherXrScaleY").c_str()));
    if (hud.contains("TimelineMusicStretcherXrX"))
      Settings::hudTimelineMusicStretcherXrX = f32(atof2(hud.at("TimelineMusicStretcherXrX").c_str()));
    if (hud.contains("TimelineMusicStretcherXrY"))
      Settings::hudTimelineMusicStretcherXrY = f32(atof2(hud.at("TimelineMusicStretcherXrY").c_str()));
    if (hud.contains("TimelineMusicStretcherXrZ"))
      Settings::hudTimelineMusicStretcherXrZ = f32(atof2(hud.at("TimelineMusicStretcherXrZ").c_str()));
#endif // SHR3D_OPENXR
#endif // SHR3D_MUSIC_STRETCHER
    if (hud.contains("TimelineTone"))
      Settings::hudTimelineTone = bool(atoi2(hud.at("TimelineTone").c_str()));
    if (hud.contains("TimelineToneColor0"))
      Settings::hudTimelineToneColor[0] = colorVec4(hud.at("TimelineToneColor0").c_str());
    if (hud.contains("TimelineToneColor1"))
      Settings::hudTimelineToneColor[1] = colorVec4(hud.at("TimelineToneColor1").c_str());
    if (hud.contains("TimelineToneColor2"))
      Settings::hudTimelineToneColor[2] = colorVec4(hud.at("TimelineToneColor2").c_str());
    if (hud.contains("TimelineToneColor3"))
      Settings::hudTimelineToneColor[3] = colorVec4(hud.at("TimelineToneColor3").c_str());
    if (hud.contains("TimelineToneColor4"))
      Settings::hudTimelineToneColor[4] = colorVec4(hud.at("TimelineToneColor4").c_str());
    if (hud.contains("TimelineToneColor5"))
      Settings::hudTimelineToneColor[5] = colorVec4(hud.at("TimelineToneColor5").c_str());
    if (hud.contains("TimelineToneColor6"))
      Settings::hudTimelineToneColor[6] = colorVec4(hud.at("TimelineToneColor6").c_str());
    if (hud.contains("TimelineToneColor7"))
      Settings::hudTimelineToneColor[7] = colorVec4(hud.at("TimelineToneColor7").c_str());
    if (hud.contains("TimelineToneColor8"))
      Settings::hudTimelineToneColor[8] = colorVec4(hud.at("TimelineToneColor8").c_str());
    if (hud.contains("TimelineToneColor9"))
      Settings::hudTimelineToneColor[9] = colorVec4(hud.at("TimelineToneColor9").c_str());
    if (hud.contains("TimelineToneColor10"))
      Settings::hudTimelineToneColor[10] = colorVec4(hud.at("TimelineToneColor10").c_str());
    if (hud.contains("TimelineToneScaleX"))
      Settings::hudTimelineToneScaleX = f32(atof2(hud.at("TimelineToneScaleX").c_str()));
    if (hud.contains("TimelineToneScaleY"))
      Settings::hudTimelineToneScaleY = f32(atof2(hud.at("TimelineToneScaleY").c_str()));
    if (hud.contains("TimelineToneX"))
      Settings::hudTimelineToneX = f32(atof2(hud.at("TimelineToneX").c_str()));
    if (hud.contains("TimelineToneY"))
      Settings::hudTimelineToneY = f32(atof2(hud.at("TimelineToneY").c_str()));
#ifdef SHR3D_OPENXR
    if (hud.contains("TimelineToneXrScaleX"))
      Settings::hudTimelineToneXrScaleX = f32(atof2(hud.at("TimelineToneXrScaleX").c_str()));
    if (hud.contains("TimelineToneXrScaleY"))
      Settings::hudTimelineToneXrScaleY = f32(atof2(hud.at("TimelineToneXrScaleY").c_str()));
    if (hud.contains("TimelineToneXrX"))
      Settings::hudTimelineToneXrX = f32(atof2(hud.at("TimelineToneXrX").c_str()));
    if (hud.contains("TimelineToneXrY"))
      Settings::hudTimelineToneXrY = f32(atof2(hud.at("TimelineToneXrY").c_str()));
    if (hud.contains("TimelineToneXrZ"))
      Settings::hudTimelineToneXrZ = f32(atof2(hud.at("TimelineToneXrZ").c_str()));
#endif // SHR3D_OPENXR
    if (hud.contains("TimelineQuickRepeaterColor0"))
      Settings::hudTimelineQuickRepeaterColor[0] = colorVec4(hud.at("TimelineQuickRepeaterColor0").c_str());
    if (hud.contains("TimelineQuickRepeaterColor1"))
      Settings::hudTimelineQuickRepeaterColor[1] = colorVec4(hud.at("TimelineQuickRepeaterColor1").c_str());
    if (hud.contains("TimelineQuickRepeaterFlipY"))
      Settings::hudTimelineQuickRepeaterFlipY = bool(atoi2(hud.at("TimelineQuickRepeaterFlipY").c_str()));
    if (hud.contains("TimelineQuickRepeaterScaleY"))
      Settings::hudTimelineQuickRepeaterScaleY = f32(atof2(hud.at("TimelineQuickRepeaterScaleY").c_str()));
    if (hud.contains("TimelineQuickRepeaterX"))
      Settings::hudTimelineQuickRepeaterX = f32(atof2(hud.at("TimelineQuickRepeaterX").c_str()));
    if (hud.contains("TimelineQuickRepeaterY"))
      Settings::hudTimelineQuickRepeaterY = f32(atof2(hud.at("TimelineQuickRepeaterY").c_str()));
#ifdef SHR3D_OPENXR
    if (hud.contains("TimelineQuickRepeaterXrScaleX"))
      Settings::hudTimelineQuickRepeaterXrScaleX = f32(atof2(hud.at("TimelineQuickRepeaterXrScaleX").c_str()));
    if (hud.contains("TimelineQuickRepeaterXrScaleY"))
      Settings::hudTimelineQuickRepeaterXrScaleY = f32(atof2(hud.at("TimelineQuickRepeaterXrScaleY").c_str()));
    if (hud.contains("TimelineQuickRepeaterXrX"))
      Settings::hudTimelineQuickRepeaterXrX = f32(atof2(hud.at("TimelineQuickRepeaterXrX").c_str()));
    if (hud.contains("TimelineQuickRepeaterXrY"))
      Settings::hudTimelineQuickRepeaterXrY = f32(atof2(hud.at("TimelineQuickRepeaterXrY").c_str()));
    if (hud.contains("TimelineQuickRepeaterXrZ"))
      Settings::hudTimelineQuickRepeaterXrZ = f32(atof2(hud.at("TimelineQuickRepeaterXrZ").c_str()));
#endif // SHR3D_OPENXR
    if (hud.contains("Score"))
      Settings::hudScore = bool(atoi2(hud.at("Score").c_str()));
    if (hud.contains("SongInfo"))
      Settings::hudSongInfo = bool(atoi2(hud.at("SongInfo").c_str()));
    if (hud.contains("SongInfoColor0"))
      Settings::hudSongInfoColor[0] = colorVec4(hud.at("SongInfoColor0").c_str());
    if (hud.contains("SongInfoColor1"))
      Settings::hudSongInfoColor[1] = colorVec4(hud.at("SongInfoColor1").c_str());
    if (hud.contains("SongInfoScale0"))
      Settings::hudSongInfoScale[0] = f32(atof2(hud.at("SongInfoScale0").c_str()));
    if (hud.contains("SongInfoScale1"))
      Settings::hudSongInfoScale[1] = f32(atof2(hud.at("SongInfoScale1").c_str()));
    if (hud.contains("SongInfoX"))
      Settings::hudSongInfoX = f32(atof2(hud.at("SongInfoX").c_str()));
    if (hud.contains("SongInfoY0"))
      Settings::hudSongInfoY[0] = f32(atof2(hud.at("SongInfoY0").c_str()));
    if (hud.contains("SongInfoY1"))
      Settings::hudSongInfoY[1] = f32(atof2(hud.at("SongInfoY1").c_str()));
    if (hud.contains("ArrangementSwitch"))
      Settings::hudArrangementSwitch = bool(atoi2(hud.at("ArrangementSwitch").c_str()));
    if (hud.contains("ArrangementSwitchColor"))
      Settings::hudArrangementSwitchColor = colorVec4(hud.at("ArrangementSwitchColor").c_str());
    if (hud.contains("ArrangementSwitchScaleX"))
      Settings::hudArrangementSwitchScaleX = f32(atof2(hud.at("ArrangementSwitchScaleX").c_str()));
    if (hud.contains("ArrangementSwitchScaleY"))
      Settings::hudArrangementSwitchScaleY = f32(atof2(hud.at("ArrangementSwitchScaleY").c_str()));
    if (hud.contains("ArrangementSwitchX"))
      Settings::hudArrangementSwitchX = f32(atof2(hud.at("ArrangementSwitchX").c_str()));
    if (hud.contains("ArrangementSwitchY"))
      Settings::hudArrangementSwitchY = f32(atof2(hud.at("ArrangementSwitchY").c_str()));
#ifdef SHR3D_OPENXR
    if (hud.contains("ArrangementSwitchXrScaleX"))
      Settings::hudArrangementSwitchXrScaleX = f32(atof2(hud.at("ArrangementSwitchXrScaleX").c_str()));
    if (hud.contains("ArrangementSwitchXrScaleY"))
      Settings::hudArrangementSwitchXrScaleY = f32(atof2(hud.at("ArrangementSwitchXrScaleY").c_str()));
    if (hud.contains("ArrangementSwitchXrX"))
      Settings::hudArrangementSwitchXrX = f32(atof2(hud.at("ArrangementSwitchXrX").c_str()));
    if (hud.contains("ArrangementSwitchXrY"))
      Settings::hudArrangementSwitchXrY = f32(atof2(hud.at("ArrangementSwitchXrY").c_str()));
    if (hud.contains("ArrangementSwitchXrZ"))
      Settings::hudArrangementSwitchXrZ = f32(atof2(hud.at("ArrangementSwitchXrZ").c_str()));
#endif // SHR3D_OPENXR
    if (hud.contains("ToneSwitch"))
      Settings::hudToneSwitch = bool(atoi2(hud.at("ToneSwitch").c_str()));
    if (hud.contains("ToneSwitchTimer"))
      Settings::hudToneSwitchTimer = bool(atoi2(hud.at("ToneSwitchTimer").c_str()));
    if (hud.contains("ToneSwitchColor"))
      Settings::hudToneSwitchColor = colorVec4(hud.at("ToneSwitchColor").c_str());
    if (hud.contains("ToneSwitchHintColor"))
      Settings::hudToneSwitchHintColor = colorVec4(hud.at("ToneSwitchHintColor").c_str());
    if (hud.contains("ToneSwitchScale0"))
      Settings::hudToneSwitchScale[0] = f32(atof2(hud.at("ToneSwitchScale0").c_str()));
    if (hud.contains("ToneSwitchScale1"))
      Settings::hudToneSwitchScale[1] = f32(atof2(hud.at("ToneSwitchScale1").c_str()));
    if (hud.contains("ToneSwitchX"))
      Settings::hudToneSwitchX = f32(atof2(hud.at("ToneSwitchX").c_str()));
    if (hud.contains("ToneSwitchY0"))
      Settings::hudToneSwitchY[0] = f32(atof2(hud.at("ToneSwitchY0").c_str()));
    if (hud.contains("ToneSwitchY1"))
      Settings::hudToneSwitchY[1] = f32(atof2(hud.at("ToneSwitchY1").c_str()));
#ifdef SHR3D_OPENXR
    if (hud.contains("ToneSwitchXrScale0"))
      Settings::hudToneSwitchXrScale[0] = f32(atof2(hud.at("ToneSwitchXrScale0").c_str()));
    if (hud.contains("ToneSwitchXrScale1"))
      Settings::hudToneSwitchXrScale[1] = f32(atof2(hud.at("ToneSwitchXrScale1").c_str()));
    if (hud.contains("ToneSwitchXrX"))
      Settings::hudToneSwitchXrX = f32(atof2(hud.at("ToneSwitchXrX").c_str()));
    if (hud.contains("ToneSwitchXrY0"))
      Settings::hudToneSwitchXrY[0] = f32(atof2(hud.at("ToneSwitchXrY0").c_str()));
    if (hud.contains("ToneSwitchXrY1"))
      Settings::hudToneSwitchXrY[1] = f32(atof2(hud.at("ToneSwitchXrY1").c_str()));
    if (hud.contains("ToneSwitchXrZ"))
      Settings::hudToneSwitchXrZ = f32(atof2(hud.at("ToneSwitchXrZ").c_str()));
#endif // SHR3D_OPENXR
    if (hud.contains("Watermark"))
      Settings::hudWatermark = bool(atoi2(hud.at("Watermark").c_str()));
    if (hud.contains("WatermarkColor"))
      Settings::hudWatermarkColor = colorVec4(hud.at("WatermarkColor").c_str());
#ifdef SHR3D_OPENXR
    if (hud.contains("WatermarkXrX"))
      Settings::hudWatermarkXrX = f32(atof2(hud.at("WatermarkXrX").c_str()));
    if (hud.contains("WatermarkXrY"))
      Settings::hudWatermarkXrY = f32(atof2(hud.at("WatermarkXrY").c_str()));
    if (hud.contains("WatermarkXrZ"))
      Settings::hudWatermarkXrZ = f32(atof2(hud.at("WatermarkXrZ").c_str()));
#endif // SHR3D_OPENXR
  }
  if (serializedSettings.contains("Metronome"))
  {
    const auto& metronome = serializedSettings.at("Metronome");
    if (metronome.contains("Enabled"))
      Settings::metronomeEnabled = bool(atoi2(metronome.at("Enabled").c_str()));
    if (metronome.contains("Volume"))
      Settings::metronomeVolume = f32(atof2(metronome.at("Volume").c_str()));
    if (metronome.contains("Decay"))
      Settings::metronomeDecay = bool(atoi2(metronome.at("Decay").c_str()));
    if (metronome.contains("Frequency0"))
      Settings::metronomeFrequency0 = f32(atof2(metronome.at("Frequency0").c_str()));
    if (metronome.contains("Frequency1"))
      Settings::metronomeFrequency1 = f32(atof2(metronome.at("Frequency1").c_str()));
    if (metronome.contains("ClickLength"))
      Settings::metronomeClickLength = atoi2(metronome.at("ClickLength").c_str());
    if (metronome.contains("Side"))
      Settings::metronomeSide = MetronomeSide(atoi2(metronome.at("Side").c_str()));
  }
#ifdef SHR3D_MIDI
  if (serializedSettings.contains("Midi"))
  {
    const auto& midi = serializedSettings.at("Midi");
    if (midi.contains("FineValueFactor"))
      Settings::midiFineValueFactor = f32(atof2(midi.at("FineValueFactor").c_str()));
    if (midi.contains("AutoConnectDevices"))
      Settings::midiAutoConnectDevices = midi.at("AutoConnectDevices");
    for (u8 i = 0; i < ARRAY_SIZE(Const::midiBindingsNames); ++i)
    {
      const std::string bindingName = std::string("Binding") + Const::midiBindingsNames[i];
      if (midi.contains(bindingName) && !midi.at(bindingName).empty())
      {
        const std::string value = serializedSettings.at("Midi").at(bindingName);
        const u64 seperator = value.find_last_of(';');
        ASSERT(seperator != std::string::npos);
        Settings::midiBinding[i] = u8(atoi2(value.substr(0, seperator).c_str()));
        Global::midiNoteMode[Settings::midiBinding[i]] = MidiNoteMode(atoi2(value.substr(seperator + 1).c_str()));
        Global::midiNoteBinding[Settings::midiBinding[i]] = i;
      }
    }
  }
#endif // SHR3D_MIDI
  if (serializedSettings.contains("Paths"))
  {
    const auto& paths = serializedSettings.at("Paths");
    if (paths.contains("StatsIni"))
      Settings::pathStatsIni = paths.at("StatsIni");
    if (paths.contains("TonesIni"))
      Settings::pathTonesIni = paths.at("TonesIni");
    if (paths.contains("Backup"))
      Settings::pathBackup = paths.at("Backup");
#ifdef SHR3D_SHRED_OR_PSARC
    if (paths.contains("Cache"))
      Settings::pathCache = paths.at("Cache");
#endif // SHR3D_SHRED_OR_PSARC
#ifdef SHR3D_SFX_PLUGIN_CLAP
    if (paths.contains("Clap"))
      Settings::pathClap = paths.at("Clap");
#endif // SHR3D_SFX_PLUGIN_CLAP
#ifdef SHR3D_ENVIRONMENT_MILK
    if (paths.contains("Milk"))
      Settings::pathMilk = paths.at("Milk");
#endif // SHR3D_ENVIRONMENT_MILK
#ifdef SHR3D_SFX_CORE_NEURALAMPMODELER
    if (paths.contains("Nam"))
      Settings::pathNam = paths.at("Nam");
#endif // SHR3D_SFX_CORE_NEURALAMPMODELER
    if (paths.contains("Psarc"))
      Settings::pathPsarc = paths.at("Psarc");
#ifdef SHR3D_SHRED
    if (paths.contains("Shred"))
      Settings::pathShred = paths.at("Shred");
#endif // SHR3D_SHRED
#ifdef SHR3D_SFX_PLUGIN_VST
    if (paths.contains("Vst"))
      Settings::pathVst = paths.at("Vst");
#endif // SHR3D_SFX_PLUGIN_VST
#ifdef SHR3D_SFX_PLUGIN_VST3
    if (paths.contains("Vst3"))
      Settings::pathVst3 = paths.at("Vst3");
#endif // SHR3D_SFX_PLUGIN_VST3
#ifdef SHR3D_ENVIRONMENT_SKYBOX
    if (paths.contains("Skybox"))
      Settings::pathSkybox = paths.at("Skybox");
#endif // SHR3D_ENVIRONMENT_SKYBOX
#ifdef SHR3D_ENVIRONMENT_STAGE
    if (paths.contains("Stage"))
      Settings::pathStage = paths.at("Stage");
#endif // SHR3D_ENVIRONMENT_STAGE
  }
#ifdef SHR3D_SPOTIFY
  if (serializedSettings.contains("Spotify"))
  {
    const auto& spotify = serializedSettings.at("Spotify");
    if (spotify.contains("ClientId"))
      Settings::spotifyClientId = spotify.at("ClientId");
    if (spotify.contains("ClientSecret"))
      Settings::spotifyClientSecret = spotify.at("ClientSecret");
    if (spotify.contains("RedirectUri"))
      Settings::spotifyRedirectUri = spotify.at("RedirectUri");
  }
#endif // SHR3D_SPOTIFY
  if (serializedSettings.contains("Tuner"))
  {
    const auto& tuner = serializedSettings.at("Tuner");
    if (tuner.contains("NoteDetectionSource"))
      Settings::tunerNoteDetectionSource = NoteDetectionSource(atoi2(tuner.at("NoteDetectionSource").c_str()));
#ifdef SHR3D_SFX
    if (tuner.contains("TunerPlugin"))
      Settings::tunerPlugin = tuner.at("TunerPlugin");
#ifdef SHR3D_MIDI
    if (tuner.contains("MidiDevice"))
      Settings::tunerMidiDevice = tuner.at("MidiDevice");
#endif // SHR3D_MIDI
    if (tuner.contains("MidiPlugin"))
      Settings::tunerMidiPlugin = tuner.at("MidiPlugin");
#endif // SHR3D_SFX
#ifdef SHR3D_SFX_CORE_HEXFIN
    if (tuner.contains("HexfinOnsetThreshold"))
      Settings::tunerHexfinOnsetThreshold = f32(atof2(tuner.at("HexfinOnsetThreshold").c_str()));
    if (tuner.contains("HexfinReleaseThreshold"))
      Settings::tunerHexfinReleaseThreshold = f32(atof2(tuner.at("HexfinReleaseThreshold").c_str()));
#endif // SHR3D_SFX_CORE_HEXFIN
  }
  if (serializedSettings.contains("Ui"))
  {
    const auto& ui = serializedSettings.at("Ui");
    if (ui.contains("Scale"))
      Settings::uiScale = f32(atof2(ui.at("Scale").c_str()));
#ifdef SHR3D_OPENXR
    if (ui.contains("XrZ"))
      Settings::uiXrZ = f32(atof2(ui.at("XrZ").c_str()));
#endif // SHR3D_OPENXR
#ifdef SHR3D_CUSTOM_CURSOR
    if (ui.contains("CursorCustom"))
      Settings::uiCursorCustom = bool(atoi2(ui.at("CursorCustom").c_str()));
    if (ui.contains("CursorSize"))
      Settings::uiCursorSize = atoi2(ui.at("CursorSize").c_str());
#endif // SHR3D_CUSTOM_CURSOR
    if (ui.contains("Color0"))
      Settings::uiColor[0] = colorVec4(ui.at("Color0").c_str());
    if (ui.contains("Color1"))
      Settings::uiColor[1] = colorVec4(ui.at("Color1").c_str());
    if (ui.contains("Color2"))
      Settings::uiColor[2] = colorVec4(ui.at("Color2").c_str());
    if (ui.contains("Color3"))
      Settings::uiColor[3] = colorVec4(ui.at("Color3").c_str());
    if (ui.contains("Color4"))
      Settings::uiColor[4] = colorVec4(ui.at("Color4").c_str());
    if (ui.contains("Color5"))
      Settings::uiColor[5] = colorVec4(ui.at("Color5").c_str());
    if (ui.contains("Color6"))
      Settings::uiColor[6] = colorVec4(ui.at("Color6").c_str());
    if (ui.contains("Color7"))
      Settings::uiColor[7] = colorVec4(ui.at("Color7").c_str());
    if (ui.contains("Color8"))
      Settings::uiColor[8] = colorVec4(ui.at("Color8").c_str());
    if (ui.contains("Color9"))
      Settings::uiColor[9] = colorVec4(ui.at("Color9").c_str());
    if (ui.contains("Color10"))
      Settings::uiColor[10] = colorVec4(ui.at("Color10").c_str());
    if (ui.contains("Color11"))
      Settings::uiColor[11] = colorVec4(ui.at("Color11").c_str());
    if (ui.contains("Color12"))
      Settings::uiColor[12] = colorVec4(ui.at("Color12").c_str());
    if (ui.contains("Color13"))
      Settings::uiColor[13] = colorVec4(ui.at("Color13").c_str());
    if (ui.contains("Color14"))
      Settings::uiColor[14] = colorVec4(ui.at("Color14").c_str());
    if (ui.contains("Color15"))
      Settings::uiColor[15] = colorVec4(ui.at("Color15").c_str());
    if (ui.contains("Color16"))
      Settings::uiColor[16] = colorVec4(ui.at("Color16").c_str());
    if (ui.contains("Color17"))
      Settings::uiColor[17] = colorVec4(ui.at("Color17").c_str());
    if (ui.contains("Color18"))
      Settings::uiColor[18] = colorVec4(ui.at("Color18").c_str());
    if (ui.contains("Color19"))
      Settings::uiColor[19] = colorVec4(ui.at("Color19").c_str());
    if (ui.contains("Color20"))
      Settings::uiColor[20] = colorVec4(ui.at("Color20").c_str());
    if (ui.contains("Color21"))
      Settings::uiColor[21] = colorVec4(ui.at("Color21").c_str());
    if (ui.contains("Color22"))
      Settings::uiColor[22] = colorVec4(ui.at("Color22").c_str());
    if (ui.contains("Color23"))
      Settings::uiColor[23] = colorVec4(ui.at("Color23").c_str());
    if (ui.contains("Color24"))
      Settings::uiColor[24] = colorVec4(ui.at("Color24").c_str());
    if (ui.contains("Color25"))
      Settings::uiColor[25] = colorVec4(ui.at("Color25").c_str());
    if (ui.contains("Color26"))
      Settings::uiColor[26] = colorVec4(ui.at("Color26").c_str());
    if (ui.contains("Color27"))
      Settings::uiColor[27] = colorVec4(ui.at("Color27").c_str());
    // additional custom colors:
    if (ui.contains("Color28"))
      Settings::uiColor[28] = colorVec4(ui.at("Color28").c_str());
    if (ui.contains("Color29"))
      Settings::uiColor[29] = colorVec4(ui.at("Color29").c_str());
  }

#ifdef SHR3D_AUDIO_SUPERPOWERED
  if (serializedSettings.contains("Audio"))
  {
    const auto& audio = serializedSettings.at("Audio");
    for (i32 i = 0;; ++i)
    {
      const std::string mute = std::string("SuperpoweredInput") + to_string(i) + "Mute";
      if (!audio.contains(mute))
        break;
      Settings::audioSuperpoweredInputMutes.push_back(atoi2(audio.at(mute).c_str()));
    }
    for (i32 i = 0;; ++i)
    {
      const std::string volume = std::string("SuperpoweredInput") + to_string(i) + "Volume";
      if (!audio.contains(volume))
        break;
      Settings::audioSuperpoweredInputVolume.push_back(f32(atof2(audio.at(volume).c_str())));
    }
    for (i32 i = 0;; ++i)
    {
      const std::string mute = std::string("SuperpoweredOutput") + to_string(i) + "Mute";
      if (!audio.contains(mute))
        break;
      Settings::audioSuperpoweredOutputMutes.push_back(atoi2(audio.at(mute).c_str()));
    }
    for (i32 i = 0;; ++i)
    {
      const std::string volume = std::string("SuperpoweredOutput") + to_string(i) + "Volume";
      if (!audio.contains(volume))
        break;
      Settings::audioSuperpoweredOutputVolume.push_back(f32(atof2(audio.at(volume).c_str())));
    }
  }
#endif // SHR3D_AUDIO_SUPERPOWERED

#ifdef SHR3D_OPENXR
  if (serializedSettings.contains("XR"))
  {
    const auto& xr = serializedSettings.at("XR");
#ifdef SHR3D_OPENXR_PCVR
    if (xr.contains("Enabled"))
      Settings::xrEnabled = bool(atoi2(xr.at("Enabled").c_str()));
#endif // SHR3D_OPENXR_PCVR
#ifdef SHR3D_OPENXR_CONTROLLER_PICO4_AND_QUEST3
    if (xr.contains("Controller"))
      Settings::xrController = XrController(atoi2(xr.at("Controller").c_str()));
#endif // SHR3D_OPENXR_CONTROLLER_PICO4_AND_QUEST3
    if (xr.contains("ControllerColor0"))
      Settings::xrControllerColor[0] = colorVec4(xr.at("ControllerColor0").c_str());
    if (xr.contains("ControllerColor1"))
      Settings::xrControllerColor[1] = colorVec4(xr.at("ControllerColor1").c_str());
    if (xr.contains("CursorColor0"))
      Settings::xrCursorColor[0] = colorVec4(xr.at("CursorColor0").c_str());
    if (xr.contains("CursorColor1"))
      Settings::xrCursorColor[1] = colorVec4(xr.at("CursorColor1").c_str());
    if (xr.contains("PointerColor"))
      Settings::xrPointerColor = colorVec4(xr.at("PointerColor").c_str());
    //if (xr.contains("CircularProjection"))
    //  Settings::xrUiCircularProjection = f32(atof2(xr.at("CircularProjection").c_str()));
  }
#endif // SHR3D_OPENXR
}

void Settings::init(
#ifdef SHR3D_GETOPT
  int argc, char* argv[]
#endif // SHR3D_GETOPT
)
{
  // 1. check if a different settings.ini is specified to be loaded
#ifdef SHR3D_GETOPT

  // on emscripten a command line argument uses '=' instead of ' ' as the separator.
#ifdef PLATFORM_EMSCRIPTEN
  std::vector<std::string> emArgs;
  emArgs.push_back(argv[0]);
  for (i32 i = 1; i < argc; ++i)
  {
    i32 split = 0;
    for (u32 j = 0;; ++j)
    {
      switch (argv[i][j])
      {
      case '\0':
        emArgs.push_back({ &argv[i][split], j });
        goto nextArg;
      case '=':
        emArgs.push_back({ &argv[i][0], j });
        split = j + 1;
      }
    }
  nextArg:;
  }
  argc = emArgs.size();
  std::vector<char*> emArgv(argc);
  for (i32 i = 0; i < argc; ++i)
    emArgv[i] = emArgs[i].data();
  argv = emArgv.data();
#endif // PLATFORM_EMSCRIPTEN

#ifndef NDEBUG
  printf("argc: %d\n", argc);
  for (int i = 0; i < argc; ++i)
    printf("argv[%d]: %s\n", i, argv[i]);
#endif // NDEBUG

  parseCommandLineArgSettingsIni(argc, argv);
#endif // SHR3D_GETOPT

  // 2. load that settings.ini or the default one
  if (File::exists(Global::pathSettingsIni.c_str()))
  {
    const std::vector<u8> settingsIniData = File::read(Global::pathSettingsIni.c_str());
    deserializeSettings(Ini::loadIniContent(reinterpret_cast<const char*>(settingsIniData.data()), settingsIniData.size()));
  }

  // 3. parse the rest of the args
#ifdef SHR3D_GETOPT
  parseCommandLineArgs(argc, argv);
#endif // SHR3D_GETOPT
}

void Settings::fini()
{
  const auto serializedSettings = serializeSettings();
  Ini::saveIniFile(Global::pathSettingsIni.c_str(), serializedSettings);
}
