aboutsummaryrefslogtreecommitdiff
path: root/Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp
diff options
context:
space:
mode:
authorJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
committerJef <jef@targetspot.com>2024-09-24 08:54:57 -0400
commit20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp
parent537bcbc86291b32fc04ae4133ce4d7cac8ebe9a7 (diff)
downloadwinamp-20d28e80a5c861a9d5f449ea911ab75b4f37ad0d.tar.gz
Initial community commit
Diffstat (limited to 'Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp')
-rw-r--r--Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp1605
1 files changed, 1605 insertions, 0 deletions
diff --git a/Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp b/Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp
new file mode 100644
index 00000000..dbf081a1
--- /dev/null
+++ b/Src/external_dependencies/openmpt-trunk/mptrack/TrackerSettings.cpp
@@ -0,0 +1,1605 @@
+/*
+ * TrackerSettings.cpp
+ * -------------------
+ * Purpose: Code for managing, loading and saving all applcation settings.
+ * Notes : (currently none)
+ * Authors: Olivier Lapicque
+ * OpenMPT Devs
+ * The OpenMPT source code is released under the BSD license. Read LICENSE for more details.
+ */
+
+
+#include "stdafx.h"
+#include "Mptrack.h"
+#include "Moddoc.h"
+#include "Mainfrm.h"
+#include "mpt/environment/environment.hpp"
+#include "mpt/uuid/uuid.hpp"
+#include "openmpt/sounddevice/SoundDevice.hpp"
+#include "openmpt/sounddevice/SoundDeviceManager.hpp"
+#include "../common/version.h"
+#include "UpdateCheck.h"
+#include "Mpdlgs.h"
+#include "../common/mptStringBuffer.h"
+#include "TrackerSettings.h"
+#include "../common/misc_util.h"
+#include "PatternClipboard.h"
+#include "../common/ComponentManager.h"
+#include "ExceptionHandler.h"
+#include "../soundlib/mod_specifications.h"
+#include "../soundlib/Tables.h"
+#include "../common/mptFileIO.h"
+#include "../soundlib/tuningcollection.h"
+#include "TuningDialog.h"
+
+
+#include <algorithm>
+
+
+OPENMPT_NAMESPACE_BEGIN
+
+
+#define OLD_SOUNDSETUP_REVERSESTEREO 0x20
+#define OLD_SOUNDSETUP_SECONDARY 0x40
+#define OLD_SOUNDSETUP_NOBOOSTTHREADPRIORITY 0x80
+
+#ifndef NO_EQ
+
+constexpr EQPreset FlatEQPreset = {"Flat", {16, 16, 16, 16, 16, 16}, {125, 300, 600, 1250, 4000, 8000}};
+
+#endif // !NO_EQ
+
+
+TrackerSettings &TrackerSettings::Instance()
+{
+ return theApp.GetTrackerSettings();
+}
+
+
+static Version GetPreviousSettingsVersion(const mpt::ustring &iniVersion)
+{
+ if(!iniVersion.empty())
+ {
+ return Version::Parse(iniVersion);
+ } else
+ {
+ // No version stored.
+ // This is the first run, thus set the previous version to our current
+ // version which will avoid running all settings upgrade code.
+ return Version::Current();
+ }
+}
+
+
+mpt::ustring SettingsModTypeToString(MODTYPE modtype)
+{
+ return mpt::ToUnicode(mpt::Charset::UTF8, CSoundFile::GetModSpecifications(modtype).fileExtension);
+}
+
+MODTYPE SettingsStringToModType(const mpt::ustring &str)
+{
+ return CModSpecifications::ExtensionToType(mpt::ToCharset(mpt::Charset::UTF8, str));
+}
+
+
+static uint32 GetDefaultPatternSetup()
+{
+ return PATTERN_PLAYNEWNOTE | PATTERN_EFFECTHILIGHT
+ | PATTERN_CENTERROW | PATTERN_DRAGNDROPEDIT
+ | PATTERN_FLATBUTTONS | PATTERN_NOEXTRALOUD | PATTERN_2NDHIGHLIGHT
+ | PATTERN_STDHIGHLIGHT | PATTERN_SHOWPREVIOUS | PATTERN_CONTSCROLL
+ | PATTERN_SYNCMUTE | PATTERN_AUTODELAY | PATTERN_NOTEFADE
+ | PATTERN_SHOWDEFAULTVOLUME | PATTERN_LIVEUPDATETREE | PATTERN_SYNCSAMPLEPOS;
+}
+
+
+void SampleUndoBufferSize::CalculateSize()
+{
+ if(sizePercent < 0)
+ sizePercent = 0;
+ MEMORYSTATUSEX memStatus;
+ memStatus.dwLength = sizeof(MEMORYSTATUSEX);
+ GlobalMemoryStatusEx(&memStatus);
+ // The setting is a percentage of the memory that's actually *available* to OpenMPT, which is a max of 4GB in 32-bit mode.
+ sizeByte = mpt::saturate_cast<size_t>(std::min(memStatus.ullTotalPhys, DWORDLONG(SIZE_T_MAX)) * sizePercent / 100);
+
+ // Pretend there's at least one MiB of memory (haha)
+ if(sizePercent != 0 && sizeByte < 1 * 1024 * 1024)
+ {
+ sizeByte = 1 * 1024 * 1024;
+ }
+}
+
+
+DebugSettings::DebugSettings(SettingsContainer &conf)
+ : conf(conf)
+ // Debug
+#if !defined(MPT_LOG_IS_DISABLED)
+ , DebugLogLevel(conf, U_("Debug"), U_("LogLevel"), static_cast<int>(mpt::log::GlobalLogLevel))
+ , DebugLogFacilitySolo(conf, U_("Debug"), U_("LogFacilitySolo"), std::string())
+ , DebugLogFacilityBlocked(conf, U_("Debug"), U_("LogFacilityBlocked"), std::string())
+ , DebugLogFileEnable(conf, U_("Debug"), U_("LogFileEnable"), mpt::log::FileEnabled)
+ , DebugLogDebuggerEnable(conf, U_("Debug"), U_("LogDebuggerEnable"), mpt::log::DebuggerEnabled)
+ , DebugLogConsoleEnable(conf, U_("Debug"), U_("LogConsoleEnable"), mpt::log::ConsoleEnabled)
+#endif
+ , DebugTraceEnable(conf, U_("Debug"), U_("TraceEnable"), false)
+ , DebugTraceSize(conf, U_("Debug"), U_("TraceSize"), 1000000)
+ , DebugTraceAlwaysDump(conf, U_("Debug"), U_("TraceAlwaysDump"), false)
+ , DebugStopSoundDeviceOnCrash(conf, U_("Debug"), U_("StopSoundDeviceOnCrash"), true)
+ , DebugStopSoundDeviceBeforeDump(conf, U_("Debug"), U_("StopSoundDeviceBeforeDump"), false)
+ , DebugDelegateToWindowsHandler(conf, U_("Debug"), U_("DelegateToWindowsHandler"), false)
+{
+
+ // Duplicate state for debug stuff in order to avoid calling into settings framework from crash context.
+ ExceptionHandler::stopSoundDeviceOnCrash = DebugStopSoundDeviceOnCrash;
+ ExceptionHandler::stopSoundDeviceBeforeDump = DebugStopSoundDeviceBeforeDump;
+ ExceptionHandler::delegateToWindowsHandler = DebugDelegateToWindowsHandler;
+
+ // enable debug features (as early as possible after reading the settings)
+ #if !defined(MPT_LOG_IS_DISABLED)
+ #if !defined(MPT_LOG_GLOBAL_LEVEL_STATIC)
+ mpt::log::GlobalLogLevel = DebugLogLevel;
+ #endif
+ mpt::log::SetFacilities(DebugLogFacilitySolo, DebugLogFacilityBlocked);
+ mpt::log::FileEnabled = DebugLogFileEnable;
+ mpt::log::DebuggerEnabled = DebugLogDebuggerEnable;
+ mpt::log::ConsoleEnabled = DebugLogConsoleEnable;
+ #endif
+ if(DebugTraceEnable)
+ {
+ mpt::log::Trace::Enable(DebugTraceSize);
+ }
+}
+
+
+DebugSettings::~DebugSettings()
+{
+ if(DebugTraceAlwaysDump)
+ {
+ DebugTraceDump();
+ }
+}
+
+
+TrackerSettings::TrackerSettings(SettingsContainer &conf)
+ : conf(conf)
+ // Version
+ , IniVersion(conf, U_("Version"), U_("Version"), mpt::ustring())
+ , FirstRun(IniVersion.Get() == mpt::ustring())
+ , PreviousSettingsVersion(GetPreviousSettingsVersion(IniVersion))
+ , VersionInstallGUID(conf, U_("Version"), U_("InstallGUID"), mpt::UUID())
+ // Display
+ , m_ShowSplashScreen(conf, U_("Display"), U_("ShowSplashScreen"), true)
+ , gbMdiMaximize(conf, U_("Display"), U_("MDIMaximize"), true)
+ , highResUI(conf, U_("Display"), U_("HighResUI"), false)
+ , glTreeSplitRatio(conf, U_("Display"), U_("MDITreeRatio"), 128)
+ , glTreeWindowWidth(conf, U_("Display"), U_("MDITreeWidth"), 160)
+ , glGeneralWindowHeight(conf, U_("Display"), U_("MDIGeneralHeight"), 222)
+ , glPatternWindowHeight(conf, U_("Display"), U_("MDIPatternHeight"), 152)
+ , glSampleWindowHeight(conf, U_("Display"), U_("MDISampleHeight"), 190)
+ , glInstrumentWindowHeight(conf, U_("Display"), U_("MDIInstrumentHeight"), 300)
+ , glCommentsWindowHeight(conf, U_("Display"), U_("MDICommentsHeight"), 288)
+ , glGraphWindowHeight(conf, U_("Display"), U_("MDIGraphHeight"), 288)
+ , gnPlugWindowX(conf, U_("Display"), U_("PlugSelectWindowX"), 243)
+ , gnPlugWindowY(conf, U_("Display"), U_("PlugSelectWindowY"), 273)
+ , gnPlugWindowWidth(conf, U_("Display"), U_("PlugSelectWindowWidth"), 450)
+ , gnPlugWindowHeight(conf, U_("Display"), U_("PlugSelectWindowHeight"), 540)
+ , gnPlugWindowLast(conf, U_("Display"), U_("PlugSelectWindowLast"), 0)
+ , gnMsgBoxVisiblityFlags(conf, U_("Display"), U_("MsgBoxVisibilityFlags"), uint32_max)
+ , GUIUpdateInterval(conf, U_("Display"), U_("GUIUpdateInterval"), 0)
+ , FSUpdateInterval(conf, U_("Display"), U_("FSUpdateInterval"), 500)
+ , VuMeterUpdateInterval(conf, U_("Display"), U_("VuMeterUpdateInterval"), 15)
+ , VuMeterDecaySpeedDecibelPerSecond(conf, U_("Display"), U_("VuMeterDecaySpeedDecibelPerSecond"), 88.0f)
+ , accidentalFlats(conf, U_("Display"), U_("AccidentalFlats"), false)
+ , rememberSongWindows(conf, U_("Display"), U_("RememberSongWindows"), true)
+ , showDirsInSampleBrowser(conf, U_("Display"), U_("ShowDirsInSampleBrowser"), false)
+ , commentsFont(conf, U_("Display"), U_("Comments Font"), FontSetting(U_("Courier New"), 120))
+ , defaultRainbowChannelColors(conf, U_("Display"), U_("DefaultChannelColors"), DefaultChannelColors::Random)
+ // Misc
+ , defaultModType(conf, U_("Misc"), U_("DefaultModType"), MOD_TYPE_IT)
+ , defaultNewFileAction(conf, U_("Misc"), U_("DefaultNewFileAction"), nfDefaultFormat)
+ , DefaultPlugVolumeHandling(conf, U_("Misc"), U_("DefaultPlugVolumeHandling"), PLUGIN_VOLUMEHANDLING_IGNORE)
+ , autoApplySmoothFT2Ramping(conf, U_("Misc"), U_("SmoothFT2Ramping"), false)
+ , MiscITCompressionStereo(conf, U_("Misc"), U_("ITCompressionStereo"), 4)
+ , MiscITCompressionMono(conf, U_("Misc"), U_("ITCompressionMono"), 4)
+ , MiscSaveChannelMuteStatus(conf, U_("Misc"), U_("SaveChannelMuteStatus"), true)
+ , MiscAllowMultipleCommandsPerKey(conf, U_("Misc"), U_("AllowMultipleCommandsPerKey"), false)
+ , MiscDistinguishModifiers(conf, U_("Misc"), U_("DistinguishModifiers"), false)
+ , MiscProcessPriorityClass(conf, U_("Misc"), U_("ProcessPriorityClass"), ProcessPriorityClassNORMAL)
+ , MiscFlushFileBuffersOnSave(conf, U_("Misc"), U_("FlushFileBuffersOnSave"), true)
+ , MiscCacheCompleteFileBeforeLoading(conf, U_("Misc"), U_("CacheCompleteFileBeforeLoading"), false)
+ , MiscUseSingleInstance(conf, U_("Misc"), U_("UseSingleInstance"), false)
+ // Sound Settings
+ , m_SoundShowRecordingSettings(false)
+ , m_SoundShowDeprecatedDevices(conf, U_("Sound Settings"), U_("ShowDeprecatedDevices"), false)
+ , m_SoundDeprecatedDeviceWarningShown(conf, U_("Sound Settings"), U_("DeprecatedDeviceWarningShown"), false)
+ , m_SoundSampleRates(conf, U_("Sound Settings"), U_("SampleRates"), GetDefaultSampleRates())
+ , m_SoundSettingsOpenDeviceAtStartup(conf, U_("Sound Settings"), U_("OpenDeviceAtStartup"), false)
+ , m_SoundSettingsStopMode(conf, U_("Sound Settings"), U_("StopMode"), SoundDeviceStopModeClosed)
+ , m_SoundDeviceSettingsUseOldDefaults(false)
+ , m_SoundDeviceID_DEPRECATED(SoundDevice::Legacy::ID())
+ , m_SoundDeviceIdentifier(conf, U_("Sound Settings"), U_("Device"), SoundDevice::Identifier())
+ , MixerMaxChannels(conf, U_("Sound Settings"), U_("MixChannels"), MixerSettings().m_nMaxMixChannels)
+ , MixerDSPMask(conf, U_("Sound Settings"), U_("Quality"), MixerSettings().DSPMask)
+ , MixerFlags(conf, U_("Sound Settings"), U_("SoundSetup"), MixerSettings().MixerFlags)
+ , MixerSamplerate(conf, U_("Sound Settings"), U_("Mixing_Rate"), MixerSettings().gdwMixingFreq)
+ , MixerOutputChannels(conf, U_("Sound Settings"), U_("ChannelMode"), MixerSettings().gnChannels)
+ , MixerPreAmp(conf, U_("Sound Settings"), U_("PreAmp"), MixerSettings().m_nPreAmp)
+ , MixerStereoSeparation(conf, U_("Sound Settings"), U_("StereoSeparation"), MixerSettings().m_nStereoSeparation)
+ , MixerVolumeRampUpMicroseconds(conf, U_("Sound Settings"), U_("VolumeRampUpMicroseconds"), MixerSettings().GetVolumeRampUpMicroseconds())
+ , MixerVolumeRampDownMicroseconds(conf, U_("Sound Settings"), U_("VolumeRampDownMicroseconds"), MixerSettings().GetVolumeRampDownMicroseconds())
+ , MixerNumInputChannels(conf, U_("Sound Settings"), U_("NumInputChannels"), static_cast<uint32>(MixerSettings().NumInputChannels))
+ , ResamplerMode(conf, U_("Sound Settings"), U_("SrcMode"), CResamplerSettings().SrcMode)
+ , ResamplerSubMode(conf, U_("Sound Settings"), U_("XMMSModplugResamplerWFIRType"), CResamplerSettings().gbWFIRType)
+ , ResamplerCutoffPercent(conf, U_("Sound Settings"), U_("ResamplerWFIRCutoff"), mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0))
+ , ResamplerEmulateAmiga(conf, U_("Sound Settings"), U_("ResamplerEmulateAmiga"), Resampling::AmigaFilter::A1200)
+ , SoundBoostedThreadPriority(conf, U_("Sound Settings"), U_("BoostedThreadPriority"), SoundDevice::AppInfo().BoostedThreadPriorityXP)
+ , SoundBoostedThreadMMCSSClass(conf, U_("Sound Settings"), U_("BoostedThreadMMCSSClass"), SoundDevice::AppInfo().BoostedThreadMMCSSClassVista)
+ , SoundBoostedThreadRealtimePosix(conf, U_("Sound Settings"), U_("BoostedThreadRealtimeLinux"), SoundDevice::AppInfo().BoostedThreadRealtimePosix)
+ , SoundBoostedThreadNicenessPosix(conf, U_("Sound Settings"), U_("BoostedThreadNicenessPosix"), SoundDevice::AppInfo().BoostedThreadNicenessPosix)
+ , SoundBoostedThreadRtprioPosix(conf, U_("Sound Settings"), U_("BoostedThreadRtprioLinux"), SoundDevice::AppInfo().BoostedThreadRtprioPosix)
+ , SoundMaskDriverCrashes(conf, U_("Sound Settings"), U_("MaskDriverCrashes"), SoundDevice::AppInfo().MaskDriverCrashes)
+ , SoundAllowDeferredProcessing(conf, U_("Sound Settings"), U_("AllowDeferredProcessing"), SoundDevice::AppInfo().AllowDeferredProcessing)
+ // MIDI Settings
+ , m_nMidiDevice(conf, U_("MIDI Settings"), U_("MidiDevice"), 0)
+ , midiDeviceName(conf, U_("MIDI Settings"), U_("MidiDeviceName"), _T(""))
+ , m_dwMidiSetup(conf, U_("MIDI Settings"), U_("MidiSetup"), MIDISETUP_RECORDVELOCITY | MIDISETUP_RECORDNOTEOFF | MIDISETUP_TRANSPOSEKEYBOARD | MIDISETUP_MIDITOPLUG)
+ , aftertouchBehaviour(conf, U_("MIDI Settings"), U_("AftertouchBehaviour"), atDoNotRecord)
+ , midiVelocityAmp(conf, U_("MIDI Settings"), U_("MidiVelocityAmp"), 100)
+ , midiIgnoreCCs(conf, U_("MIDI Settings"), U_("IgnoredCCs"), std::bitset<128>())
+ , midiImportPatternLen(conf, U_("MIDI Settings"), U_("MidiImportPatLen"), 128)
+ , midiImportQuantize(conf, U_("MIDI Settings"), U_("MidiImportQuantize"), 32)
+ , midiImportTicks(conf, U_("MIDI Settings"), U_("MidiImportTicks"), 6)
+ // Pattern Editor
+ , gbLoopSong(conf, U_("Pattern Editor"), U_("LoopSong"), true)
+ , gnPatternSpacing(conf, U_("Pattern Editor"), U_("Spacing"), 0)
+ , gbPatternVUMeters(conf, U_("Pattern Editor"), U_("VU-Meters"), true)
+ , gbPatternPluginNames(conf, U_("Pattern Editor"), U_("Plugin-Names"), true)
+ , gbPatternRecord(conf, U_("Pattern Editor"), U_("Record"), true)
+ , patternNoEditPopup(conf, U_("Pattern Editor"), U_("NoEditPopup"), false)
+ , patternStepCommands(conf, U_("Pattern Editor"), U_("EditStepAppliesToCommands"), false)
+ , m_dwPatternSetup(conf, U_("Pattern Editor"), U_("PatternSetup"), GetDefaultPatternSetup())
+ , m_nRowHighlightMeasures(conf, U_("Pattern Editor"), U_("RowSpacing"), 16)
+ , m_nRowHighlightBeats(conf, U_("Pattern Editor"), U_("RowSpacing2"), 4)
+ , recordQuantizeRows(conf, U_("Pattern Editor"), U_("RecordQuantize"), 0)
+ , gnAutoChordWaitTime(conf, U_("Pattern Editor"), U_("AutoChordWaitTime"), 60)
+ , orderlistMargins(conf, U_("Pattern Editor"), U_("DefaultSequenceMargins"), 0)
+ , rowDisplayOffset(conf, U_("Pattern Editor"), U_("RowDisplayOffset"), 0)
+ , patternFont(conf, U_("Pattern Editor"), U_("Font"), FontSetting(PATTERNFONT_SMALL, 0))
+ , patternFontDot(conf, U_("Pattern Editor"), U_("FontDot"), U_("."))
+ , effectVisWidth(conf, U_("Pattern Editor"), U_("EffectVisWidth"), -1)
+ , effectVisHeight(conf, U_("Pattern Editor"), U_("EffectVisHeight"), -1)
+ , effectVisX(conf, U_("Pattern Editor"), U_("EffectVisX"), int32_min)
+ , effectVisY(conf, U_("Pattern Editor"), U_("EffectVisY"), int32_min)
+ , patternAccessibilityFormat(conf, U_("Pattern Editor"), U_("AccessibilityFormat"), _T("Row %row%, Channel %channel%, %column_type%: %column_description%"))
+ , patternAlwaysDrawWholePatternOnScrollSlow(conf, U_("Pattern Editor"), U_("AlwaysDrawWholePatternOnScrollSlow"), false)
+ , orderListOldDropBehaviour(conf, U_("Pattern Editor"), U_("OrderListOldDropBehaviour"), false)
+ // Sample Editor
+ , m_SampleUndoBufferSize(conf, U_("Sample Editor"), U_("UndoBufferSize"), SampleUndoBufferSize())
+ , sampleEditorKeyBehaviour(conf, U_("Sample Editor"), U_("KeyBehaviour"), seNoteOffOnNewKey)
+ , m_defaultSampleFormat(conf, U_("Sample Editor"), U_("DefaultFormat"), dfFLAC)
+ , sampleEditorTimelineFormat(conf, U_("Sample Editor"), U_("TimelineFormat"), TimelineFormat::Seconds)
+ , sampleEditorDefaultResampler(conf, U_("Sample Editor"), U_("DefaultResampler"), SRCMODE_DEFAULT)
+ , m_nFinetuneStep(conf, U_("Sample Editor"), U_("FinetuneStep"), 10)
+ , m_FLACCompressionLevel(conf, U_("Sample Editor"), U_("FLACCompressionLevel"), 5)
+ , compressITI(conf, U_("Sample Editor"), U_("CompressITI"), true)
+ , m_MayNormalizeSamplesOnLoad(conf, U_("Sample Editor"), U_("MayNormalizeSamplesOnLoad"), true)
+ , previewInFileDialogs(conf, U_("Sample Editor"), U_("PreviewInFileDialogs"), false)
+ , cursorPositionInHex(conf, U_("Sample Editor"), U_("CursorPositionInHex"), false)
+ // Export
+ , ExportDefaultToSoundcardSamplerate(conf, U_("Export"), U_("DefaultToSoundcardSamplerate"), true)
+ , ExportStreamEncoderSettings(conf, U_("Export"))
+ // Components
+ , ComponentsLoadOnStartup(conf, U_("Components"), U_("LoadOnStartup"), ComponentManagerSettingsDefault().LoadOnStartup())
+ , ComponentsKeepLoaded(conf, U_("Components"), U_("KeepLoaded"), ComponentManagerSettingsDefault().KeepLoaded())
+ // AutoSave
+ , CreateBackupFiles(conf, U_("AutoSave"), U_("CreateBackupFiles"), true)
+ , AutosaveEnabled(conf, U_("AutoSave"), U_("Enabled"), true)
+ , AutosaveIntervalMinutes(conf, U_("AutoSave"), U_("IntervalMinutes"), 10)
+ , AutosaveHistoryDepth(conf, U_("AutoSave"), U_("BackupHistory"), 3)
+ , AutosaveUseOriginalPath(conf, U_("AutoSave"), U_("UseOriginalPath"), true)
+ , AutosavePath(conf, U_("AutoSave"), U_("Path"), mpt::GetTempDirectory())
+ // Paths
+ , PathSongs(conf, U_("Paths"), U_("Songs_Directory"), mpt::PathString())
+ , PathSamples(conf, U_("Paths"), U_("Samples_Directory"), mpt::PathString())
+ , PathInstruments(conf, U_("Paths"), U_("Instruments_Directory"), mpt::PathString())
+ , PathPlugins(conf, U_("Paths"), U_("Plugins_Directory"), mpt::PathString())
+ , PathPluginPresets(conf, U_("Paths"), U_("Plugin_Presets_Directory"), mpt::PathString())
+ , PathExport(conf, U_("Paths"), U_("Export_Directory"), mpt::PathString())
+ , PathTunings(theApp.GetConfigPath() + P_("tunings\\"))
+ , PathUserTemplates(theApp.GetConfigPath() + P_("TemplateModules\\"))
+ // Default template
+ , defaultTemplateFile(conf, U_("Paths"), U_("DefaultTemplate"), mpt::PathString())
+ , defaultArtist(conf, U_("Misc"), U_("DefaultArtist"), mpt::getenv(U_("USERNAME")).value_or(U_("")))
+ // MRU List
+ , mruListLength(conf, U_("Misc"), U_("MRUListLength"), 10)
+ // Plugins
+ , bridgeAllPlugins(conf, U_("VST Plugins"), U_("BridgeAllPlugins"), false)
+ , enableAutoSuspend(conf, U_("VST Plugins"), U_("EnableAutoSuspend"), false)
+ , midiMappingInPluginEditor(conf, U_("VST Plugins"), U_("EnableMidiMappingInEditor"), true)
+ , pluginProjectPath(conf, U_("VST Plugins"), U_("ProjectPath"), mpt::ustring())
+ , vstHostProductString(conf, U_("VST Plugins"), U_("HostProductString"), "OpenMPT")
+ , vstHostVendorString(conf, U_("VST Plugins"), U_("HostVendorString"), "OpenMPT project")
+ , vstHostVendorVersion(conf, U_("VST Plugins"), U_("HostVendorVersion"), Version::Current().GetRawVersion())
+ // Broken Plugins Workarounds
+ , BrokenPluginsWorkaroundVSTMaskAllCrashes(conf, U_("Broken Plugins Workarounds"), U_("VSTMaskAllCrashes"), true) // TODO: really should be false
+ , BrokenPluginsWorkaroundVSTNeverUnloadAnyPlugin(conf, U_("Broken Plugins Workarounds"), U_("VSTNeverUnloadAnyPlugin"), false)
+#if defined(MPT_ENABLE_UPDATE)
+ // Update
+ , UpdateEnabled(conf, U_("Update"), U_("Enabled"), true)
+ , UpdateInstallAutomatically(conf, U_("Update"), U_("InstallAutomatically"), false)
+ , UpdateLastUpdateCheck(conf, U_("Update"), U_("LastUpdateCheck"), mpt::Date::Unix(time_t()))
+ , UpdateUpdateCheckPeriod_DEPRECATED(conf, U_("Update"), U_("UpdateCheckPeriod"), 7)
+ , UpdateIntervalDays(conf, U_("Update"), U_("UpdateCheckIntervalDays"), 7)
+ , UpdateChannel(conf, U_("Update"), U_("Channel"), UpdateChannelRelease)
+ , UpdateUpdateURL_DEPRECATED(conf, U_("Update"), U_("UpdateURL"), U_("https://update.openmpt.org/check/$VERSION/$GUID"))
+ , UpdateAPIURL(conf, U_("Update"), U_("APIURL"), CUpdateCheck::GetDefaultAPIURL())
+ , UpdateStatisticsConsentAsked(conf, U_("Update"), U_("StatistisConsentAsked"), false)
+ , UpdateStatistics(conf, U_("Update"), U_("Statistis"), false)
+ , UpdateSendGUID_DEPRECATED(conf, U_("Update"), U_("SendGUID"), false)
+ , UpdateShowUpdateHint(conf, U_("Update"), U_("ShowUpdateHint"), true)
+ , UpdateIgnoreVersion(conf, U_("Update"), U_("IgnoreVersion"), _T(""))
+ , UpdateSkipSignatureVerificationUNSECURE(conf, U_("Update"), U_("SkipSignatureVerification"), false)
+ , UpdateSigningKeysRootAnchors(conf, U_("Update"), U_("SigningKeysRootAnchors"), CUpdateCheck::GetDefaultUpdateSigningKeysRootAnchors())
+#endif // MPT_ENABLE_UPDATE
+ // Wine suppport
+ , WineSupportEnabled(conf, U_("WineSupport"), U_("Enabled"), false)
+ , WineSupportAlwaysRecompile(conf, U_("WineSupport"), U_("AlwaysRecompile"), false)
+ , WineSupportAskCompile(conf, U_("WineSupport"), U_("AskCompile"), false)
+ , WineSupportCompileVerbosity(conf, U_("WineSupport"), U_("CompileVerbosity"), 2) // 0=silent 1=silentmake 2=progresswindow 3=standard 4=verbosemake 5=veryverbosemake 6=msgboxes
+ , WineSupportForeignOpenMPT(conf, U_("WineSupport"), U_("ForeignOpenMPT"), false)
+ , WineSupportAllowUnknownHost(conf, U_("WineSupport"), U_("AllowUnknownHost"), false)
+ , WineSupportEnablePulseAudio(conf, U_("WineSupport"), U_("EnablePulseAudio"), 1)
+ , WineSupportEnablePortAudio(conf, U_("WineSupport"), U_("EnablePortAudio"), 1)
+ , WineSupportEnableRtAudio(conf, U_("WineSupport"), U_("EnableRtAudio"), 1)
+{
+
+ // Effects
+#ifndef NO_DSP
+ m_MegaBassSettings.m_nXBassDepth = conf.Read<int32>(U_("Effects"), U_("XBassDepth"), m_MegaBassSettings.m_nXBassDepth);
+ m_MegaBassSettings.m_nXBassRange = conf.Read<int32>(U_("Effects"), U_("XBassRange"), m_MegaBassSettings.m_nXBassRange);
+#endif
+#ifndef NO_REVERB
+ m_ReverbSettings.m_nReverbDepth = conf.Read<int32>(U_("Effects"), U_("ReverbDepth"), m_ReverbSettings.m_nReverbDepth);
+ m_ReverbSettings.m_nReverbType = conf.Read<int32>(U_("Effects"), U_("ReverbType"), m_ReverbSettings.m_nReverbType);
+#endif
+#ifndef NO_DSP
+ m_SurroundSettings.m_nProLogicDepth = conf.Read<int32>(U_("Effects"), U_("ProLogicDepth"), m_SurroundSettings.m_nProLogicDepth);
+ m_SurroundSettings.m_nProLogicDelay = conf.Read<int32>(U_("Effects"), U_("ProLogicDelay"), m_SurroundSettings.m_nProLogicDelay);
+#endif
+#ifndef NO_EQ
+ m_EqSettings = conf.Read<EQPreset>(U_("Effects"), U_("EQ_Settings"), FlatEQPreset);
+ const EQPreset userPresets[] =
+ {
+ FlatEQPreset,
+ { "User 1", {16,16,16,16,16,16}, { 150, 350, 700, 1500, 4500, 8000 } },
+ { "User 2", {16,16,16,16,16,16}, { 200, 400, 800, 1750, 5000, 9000 } },
+ { "User 3", {16,16,16,16,16,16}, { 250, 450, 900, 2000, 5000, 10000 } }
+ };
+
+ m_EqUserPresets[0] = conf.Read<EQPreset>(U_("Effects"), U_("EQ_User1"), userPresets[0]);
+ m_EqUserPresets[1] = conf.Read<EQPreset>(U_("Effects"), U_("EQ_User2"), userPresets[1]);
+ m_EqUserPresets[2] = conf.Read<EQPreset>(U_("Effects"), U_("EQ_User3"), userPresets[2]);
+ m_EqUserPresets[3] = conf.Read<EQPreset>(U_("Effects"), U_("EQ_User4"), userPresets[3]);
+#endif
+#ifndef NO_DSP
+ m_BitCrushSettings.m_Bits = conf.Read<int32>(U_("Effects"), U_("BitCrushBits"), m_BitCrushSettings.m_Bits);
+#endif
+ // Display (Colors)
+ GetDefaultColourScheme(rgbCustomColors);
+ for(int ncol = 0; ncol < MAX_MODCOLORS; ncol++)
+ {
+ const mpt::ustring colorName = MPT_UFORMAT("Color{}")(mpt::ufmt::dec0<2>(ncol));
+ rgbCustomColors[ncol] = conf.Read<uint32>(U_("Display"), colorName, rgbCustomColors[ncol]);
+ }
+ // Paths
+ m_szKbdFile = conf.Read<mpt::PathString>(U_("Paths"), U_("Key_Config_File"), mpt::PathString());
+ conf.Forget(U_("Paths"), U_("Key_Config_File"));
+
+ // init old and messy stuff:
+
+ // Default chords
+ MemsetZero(Chords);
+ for(UINT ichord = 0; ichord < 3 * 12; ichord++)
+ {
+ Chords[ichord].key = (uint8)ichord;
+ Chords[ichord].notes[0] = MPTChord::noNote;
+ Chords[ichord].notes[1] = MPTChord::noNote;
+ Chords[ichord].notes[2] = MPTChord::noNote;
+
+ if(ichord < 12)
+ {
+ // Major Chords
+ Chords[ichord].notes[0] = (int8)(ichord + 4);
+ Chords[ichord].notes[1] = (int8)(ichord + 7);
+ Chords[ichord].notes[2] = (int8)(ichord + 10);
+ } else if(ichord < 24)
+ {
+ // Minor Chords
+ Chords[ichord].notes[0] = (int8)(ichord - 9);
+ Chords[ichord].notes[1] = (int8)(ichord - 5);
+ Chords[ichord].notes[2] = (int8)(ichord - 2);
+ }
+ }
+
+
+ // load old and messy stuff:
+
+ PatternClipboard::SetClipboardSize(conf.Read<int32>(U_("Pattern Editor"), U_("NumClipboards"), mpt::saturate_cast<int32>(PatternClipboard::GetClipboardSize())));
+
+ // Chords
+ LoadChords(Chords);
+
+ // Zxx Macros
+ MIDIMacroConfig macros;
+ theApp.GetDefaultMidiMacro(macros);
+ for(int i = 0; i < kSFxMacros; i++)
+ {
+ macros.SFx[i] = conf.Read<std::string>(U_("Zxx Macros"), MPT_UFORMAT("SF{}")(mpt::ufmt::HEX(i)), macros.SFx[i]);
+ }
+ for(int i = 0; i < kZxxMacros; i++)
+ {
+ macros.Zxx[i] = conf.Read<std::string>(U_("Zxx Macros"), MPT_UFORMAT("Z{}")(mpt::ufmt::HEX0<2>(i | 0x80)), macros.Zxx[i]);
+ }
+
+
+ // MRU list
+ Limit(mruListLength, 0u, 32u);
+ mruFiles.reserve(mruListLength);
+ for(uint32 i = 0; i < mruListLength; i++)
+ {
+ mpt::ustring key = MPT_UFORMAT("File{}")(i);
+
+ mpt::PathString path = theApp.PathInstallRelativeToAbsolute(conf.Read<mpt::PathString>(U_("Recent File List"), key, mpt::PathString()));
+ if(!path.empty())
+ {
+ mruFiles.push_back(path);
+ }
+ }
+
+ // Fixups:
+ // -------
+
+ const Version storedVersion = PreviousSettingsVersion;
+
+ // Version
+ if(!VersionInstallGUID.Get().IsValid())
+ {
+ // No UUID found - generate one.
+ VersionInstallGUID = mpt::UUID::Generate(mpt::global_prng());
+ }
+
+ // Plugins
+ if(storedVersion < MPT_V("1.19.03.01") && vstHostProductString.Get() == "OpenMPT")
+ {
+ vstHostVendorVersion = Version::Current().GetRawVersion();
+ }
+ if(storedVersion < MPT_V("1.30.00.24"))
+ {
+ BrokenPluginsWorkaroundVSTNeverUnloadAnyPlugin = !conf.Read<bool>(U_("VST Plugins"), U_("FullyUnloadPlugins"), true);
+ conf.Remove(U_("VST Plugins"), U_("FullyUnloadPlugins"));
+ }
+
+ // Sound Settings
+ if(storedVersion < MPT_V("1.22.07.30"))
+ {
+ if(conf.Read<bool>(U_("Sound Settings"), U_("KeepDeviceOpen"), false))
+ {
+ m_SoundSettingsStopMode = SoundDeviceStopModePlaying;
+ } else
+ {
+ m_SoundSettingsStopMode = SoundDeviceStopModeStopped;
+ }
+ }
+ if(storedVersion < MPT_V("1.22.07.04"))
+ {
+ std::vector<uint32> sampleRates = m_SoundSampleRates;
+ if(std::count(sampleRates.begin(), sampleRates.end(), MixerSamplerate) == 0)
+ {
+ sampleRates.push_back(MixerSamplerate);
+ std::sort(sampleRates.begin(), sampleRates.end());
+ std::reverse(sampleRates.begin(), sampleRates.end());
+ m_SoundSampleRates = sampleRates;
+ }
+ }
+ if(storedVersion < MPT_V("1.22.07.04"))
+ {
+ m_SoundDeviceID_DEPRECATED = conf.Read<SoundDevice::Legacy::ID>(U_("Sound Settings"), U_("WaveDevice"), SoundDevice::Legacy::ID());
+ Setting<uint32> m_BufferLength_DEPRECATED(conf, U_("Sound Settings"), U_("BufferLength"), 50);
+ Setting<uint32> m_LatencyMS(conf, U_("Sound Settings"), U_("Latency"), mpt::saturate_round<int32>(SoundDevice::Settings().Latency * 1000.0));
+ Setting<uint32> m_UpdateIntervalMS(conf, U_("Sound Settings"), U_("UpdateInterval"), mpt::saturate_round<int32>(SoundDevice::Settings().UpdateInterval * 1000.0));
+ Setting<SampleFormat> m_SampleFormat(conf, U_("Sound Settings"), U_("BitsPerSample"), SoundDevice::Settings().sampleFormat);
+ Setting<bool> m_SoundDeviceExclusiveMode(conf, U_("Sound Settings"), U_("ExclusiveMode"), SoundDevice::Settings().ExclusiveMode);
+ Setting<bool> m_SoundDeviceBoostThreadPriority(conf, U_("Sound Settings"), U_("BoostThreadPriority"), SoundDevice::Settings().BoostThreadPriority);
+ Setting<bool> m_SoundDeviceUseHardwareTiming(conf, U_("Sound Settings"), U_("UseHardwareTiming"), SoundDevice::Settings().UseHardwareTiming);
+ Setting<SoundDevice::ChannelMapping> m_SoundDeviceChannelMapping(conf, U_("Sound Settings"), U_("ChannelMapping"), SoundDevice::Settings().Channels);
+ if(storedVersion < MPT_V("1.21.01.26"))
+ {
+ if(m_BufferLength_DEPRECATED != 0)
+ {
+ if(m_BufferLength_DEPRECATED < 1) m_BufferLength_DEPRECATED = 1; // 1ms
+ if(m_BufferLength_DEPRECATED > 1000) m_BufferLength_DEPRECATED = 1000; // 1sec
+ if((m_SoundDeviceID_DEPRECATED & SoundDevice::Legacy::MaskType) == SoundDevice::Legacy::TypeASIO)
+ {
+ m_LatencyMS = m_BufferLength_DEPRECATED * 1;
+ m_UpdateIntervalMS = m_BufferLength_DEPRECATED / 8;
+ } else
+ {
+ m_LatencyMS = m_BufferLength_DEPRECATED * 3;
+ m_UpdateIntervalMS = m_BufferLength_DEPRECATED / 8;
+ }
+ if(!m_UpdateIntervalMS) m_UpdateIntervalMS = static_cast<uint32>(SoundDevice::Settings().UpdateInterval * 1000.0);
+ }
+ conf.Remove(m_BufferLength_DEPRECATED.GetPath());
+ }
+ if(storedVersion < MPT_V("1.22.01.03"))
+ {
+ m_SoundDeviceExclusiveMode = ((MixerFlags & OLD_SOUNDSETUP_SECONDARY) == 0);
+ }
+ if(storedVersion < MPT_V("1.22.01.03"))
+ {
+ m_SoundDeviceBoostThreadPriority = ((MixerFlags & OLD_SOUNDSETUP_NOBOOSTTHREADPRIORITY) == 0);
+ }
+ if(storedVersion < MPT_V("1.22.07.03"))
+ {
+ m_SoundDeviceChannelMapping = SoundDevice::ChannelMapping::BaseChannel(MixerOutputChannels, conf.Read<int>(U_("Sound Settings"), U_("ASIOBaseChannel"), 0));
+ }
+ m_SoundDeviceSettingsDefaults.Latency = m_LatencyMS / 1000.0;
+ m_SoundDeviceSettingsDefaults.UpdateInterval = m_UpdateIntervalMS / 1000.0;
+ m_SoundDeviceSettingsDefaults.Samplerate = MixerSamplerate;
+ if(m_SoundDeviceSettingsDefaults.Channels.GetNumHostChannels() != MixerOutputChannels)
+ {
+ // reset invalid channel mapping to default
+ m_SoundDeviceSettingsDefaults.Channels = SoundDevice::ChannelMapping(MixerOutputChannels);
+ }
+ m_SoundDeviceSettingsDefaults.InputChannels = 0;
+ m_SoundDeviceSettingsDefaults.sampleFormat = m_SampleFormat;
+ m_SoundDeviceSettingsDefaults.ExclusiveMode = m_SoundDeviceExclusiveMode;
+ m_SoundDeviceSettingsDefaults.BoostThreadPriority = m_SoundDeviceBoostThreadPriority;
+ m_SoundDeviceSettingsDefaults.UseHardwareTiming = m_SoundDeviceUseHardwareTiming;
+ m_SoundDeviceSettingsDefaults.InputSourceID = 0;
+ m_SoundDeviceSettingsUseOldDefaults = true;
+ }
+ if(storedVersion < MPT_V("1.28.00.41"))
+ {
+ // reset this setting to the default when updating,
+ // because we do not provide a GUI any more,
+ // and in general, it should not get changed anyway
+ ResamplerCutoffPercent = mpt::saturate_round<int32>(CResamplerSettings().gdWFIRCutoff * 100.0);
+ }
+ if(MixerSamplerate == 0)
+ {
+ MixerSamplerate = MixerSettings().gdwMixingFreq;
+ }
+ if(storedVersion < MPT_V("1.21.01.26"))
+ {
+ MixerFlags &= ~OLD_SOUNDSETUP_REVERSESTEREO;
+ }
+ if(storedVersion < MPT_V("1.22.01.03"))
+ {
+ MixerFlags &= ~OLD_SOUNDSETUP_SECONDARY;
+ }
+ if(storedVersion < MPT_V("1.22.01.03"))
+ {
+ MixerFlags &= ~OLD_SOUNDSETUP_NOBOOSTTHREADPRIORITY;
+ }
+ if(storedVersion < MPT_V("1.20.00.22"))
+ {
+ MixerSettings settings = GetMixerSettings();
+ settings.SetVolumeRampUpSamples(conf.Read<int32>(U_("Sound Settings"), U_("VolumeRampSamples"), 42));
+ settings.SetVolumeRampDownSamples(conf.Read<int32>(U_("Sound Settings"), U_("VolumeRampSamples"), 42));
+ SetMixerSettings(settings);
+ conf.Remove(U_("Sound Settings"), U_("VolumeRampSamples"));
+ } else if(storedVersion < MPT_V("1.22.07.18"))
+ {
+ MixerSettings settings = GetMixerSettings();
+ settings.SetVolumeRampUpSamples(conf.Read<int32>(U_("Sound Settings"), U_("VolumeRampUpSamples"), MixerSettings().GetVolumeRampUpSamples()));
+ settings.SetVolumeRampDownSamples(conf.Read<int32>(U_("Sound Settings"), U_("VolumeRampDownSamples"), MixerSettings().GetVolumeRampDownSamples()));
+ SetMixerSettings(settings);
+ }
+ Limit(ResamplerCutoffPercent, 0, 100);
+ if(storedVersion < MPT_V("1.29.00.11"))
+ {
+ MixerMaxChannels = MixerSettings().m_nMaxMixChannels; // reset to default on update because we removed the setting in the GUI
+ }
+ if(storedVersion < MPT_V("1.29.00.20"))
+ {
+ MixerDSPMask = MixerDSPMask & ~SNDDSP_BITCRUSH;
+ }
+
+ // Misc
+ if(defaultModType == MOD_TYPE_NONE)
+ {
+ defaultModType = MOD_TYPE_IT;
+ }
+
+ // MIDI Settings
+ if((m_dwMidiSetup & 0x40) != 0 && storedVersion < MPT_V("1.20.00.86"))
+ {
+ // This flag used to be "amplify MIDI Note Velocity" - with a fixed amplification factor of 2.
+ midiVelocityAmp = 200;
+ m_dwMidiSetup &= ~0x40;
+ }
+
+ // Pattern Editor
+ if(storedVersion < MPT_V("1.17.02.50"))
+ {
+ m_dwPatternSetup |= PATTERN_NOTEFADE;
+ }
+ if(storedVersion < MPT_V("1.17.03.01"))
+ {
+ m_dwPatternSetup |= PATTERN_RESETCHANNELS;
+ }
+ if(storedVersion < MPT_V("1.19.00.07"))
+ {
+ m_dwPatternSetup &= ~0x800; // this was previously deprecated and is now used for something else
+ }
+ if(storedVersion < MPT_V("1.20.00.04"))
+ {
+ m_dwPatternSetup &= ~0x200000; // ditto
+ }
+ if(storedVersion < MPT_V("1.20.00.07"))
+ {
+ m_dwPatternSetup &= ~0x400000; // ditto
+ }
+ if(storedVersion < MPT_V("1.20.00.39"))
+ {
+ m_dwPatternSetup &= ~0x10000000; // ditto
+ }
+ if(storedVersion < MPT_V("1.24.01.04"))
+ {
+ commentsFont = FontSetting(U_("Courier New"), (m_dwPatternSetup & 0x02) ? 120 : 90);
+ patternFont = FontSetting((m_dwPatternSetup & 0x08) ? PATTERNFONT_SMALL : PATTERNFONT_LARGE, 0);
+ m_dwPatternSetup &= ~(0x08 | 0x02);
+ }
+ if(storedVersion < MPT_V("1.25.00.08") && glGeneralWindowHeight < 222)
+ {
+ glGeneralWindowHeight += 44;
+ }
+ if(storedVersion < MPT_V("1.25.00.16") && (m_dwPatternSetup & 0x100000))
+ {
+ // Move MIDI recording to MIDI setup
+ m_dwPatternSetup &= ~0x100000;
+ m_dwMidiSetup |= MIDISETUP_ENABLE_RECORD_DEFAULT;
+ }
+ if(storedVersion < MPT_V("1.27.00.51"))
+ {
+ // Moving option out of pattern config
+ CreateBackupFiles = (m_dwPatternSetup & 0x200) != 0;
+ m_dwPatternSetup &= ~0x200;
+ }
+
+ // Export
+ if(storedVersion < MPT_V("1.30.00.38"))
+ {
+ {
+ conf.Write<Encoder::Mode>(U_("Export"), U_("FLAC_Mode"), Encoder::ModeLossless);
+ const int oldformat = conf.Read<int>(U_("Export"), U_("FLAC_Format"), 1);
+ Encoder::Format newformat = { Encoder::Format::Encoding::Integer, 24, mpt::get_endian() };
+ if (oldformat >= 0)
+ {
+ switch (oldformat % 3)
+ {
+ case 0:
+ newformat = { Encoder::Format::Encoding::Integer, 24, mpt::get_endian() };
+ break;
+ case 1:
+ newformat = { Encoder::Format::Encoding::Integer, 16, mpt::get_endian() };
+ break;
+ case 2:
+ newformat = { Encoder::Format::Encoding::Integer, 8, mpt::get_endian() };
+ break;
+ }
+ }
+ conf.Write<Encoder::Format>(U_("Export"), U_("FLAC_Format2"), newformat);
+ conf.Forget(U_("Export"), U_("FLAC_Format"));
+ }
+ {
+ conf.Write<Encoder::Mode>(U_("Export"), U_("Wave_Mode"), Encoder::ModeLossless);
+ const int oldformat = conf.Read<int>(U_("Export"), U_("Wave_Format"), 1);
+ Encoder::Format newformat = { Encoder::Format::Encoding::Float, 32, mpt::endian::little };
+ if (oldformat >= 0)
+ {
+ switch (oldformat % 6)
+ {
+ case 0:
+ newformat = { Encoder::Format::Encoding::Float, 64, mpt::endian::little };
+ break;
+ case 1:
+ newformat = { Encoder::Format::Encoding::Float, 32, mpt::endian::little };
+ break;
+ case 2:
+ newformat = { Encoder::Format::Encoding::Integer, 32, mpt::endian::little };
+ break;
+ case 3:
+ newformat = { Encoder::Format::Encoding::Integer, 24, mpt::endian::little };
+ break;
+ case 4:
+ newformat = { Encoder::Format::Encoding::Integer, 16, mpt::endian::little };
+ break;
+ case 5:
+ newformat = { Encoder::Format::Encoding::Unsigned, 8, mpt::endian::little };
+ break;
+ }
+ }
+ conf.Write<Encoder::Format>(U_("Export"), U_("Wave_Format2"), newformat);
+ conf.Forget(U_("Export"), U_("Wave_Format"));
+ }
+ {
+ conf.Write<Encoder::Mode>(U_("Export"), U_("AU_Mode"), Encoder::ModeLossless);
+ const int oldformat = conf.Read<int>(U_("Export"), U_("AU_Format"), 1);
+ Encoder::Format newformat = { Encoder::Format::Encoding::Float, 32, mpt::endian::big };
+ if(oldformat >= 0)
+ {
+ switch(oldformat % 6)
+ {
+ case 0:
+ newformat = { Encoder::Format::Encoding::Float, 64, mpt::endian::big };
+ break;
+ case 1:
+ newformat = { Encoder::Format::Encoding::Float, 32, mpt::endian::big };
+ break;
+ case 2:
+ newformat = { Encoder::Format::Encoding::Integer, 32, mpt::endian::big };
+ break;
+ case 3:
+ newformat = { Encoder::Format::Encoding::Integer, 24, mpt::endian::big };
+ break;
+ case 4:
+ newformat = { Encoder::Format::Encoding::Integer, 16, mpt::endian::big };
+ break;
+ case 5:
+ newformat = { Encoder::Format::Encoding::Integer, 8, mpt::endian::big };
+ break;
+ }
+ }
+ conf.Write<Encoder::Format>(U_("Export"), U_("AU_Format2"), newformat);
+ conf.Forget(U_("Export"), U_("AU_Format"));
+ }
+ {
+ conf.Write<Encoder::Mode>(U_("Export"), U_("RAW_Mode"), Encoder::ModeLossless);
+ const int oldformat = conf.Read<int>(U_("Export"), U_("RAW_Format"), 1);
+ Encoder::Format newformat = { Encoder::Format::Encoding::Float, 32, mpt::get_endian() };
+ if(oldformat >= 0)
+ {
+ switch(oldformat % 7)
+ {
+ case 0:
+ newformat = { Encoder::Format::Encoding::Float, 64, mpt::get_endian() };
+ break;
+ case 1:
+ newformat = { Encoder::Format::Encoding::Float, 32, mpt::get_endian() };
+ break;
+ case 2:
+ newformat = { Encoder::Format::Encoding::Integer, 32, mpt::get_endian() };
+ break;
+ case 3:
+ newformat = { Encoder::Format::Encoding::Integer, 24, mpt::get_endian() };
+ break;
+ case 4:
+ newformat = { Encoder::Format::Encoding::Integer, 16, mpt::get_endian() };
+ break;
+ case 5:
+ newformat = { Encoder::Format::Encoding::Integer, 8, mpt::get_endian() };
+ break;
+ case 6:
+ newformat = { Encoder::Format::Encoding::Unsigned, 8, mpt::get_endian() };
+ break;
+ }
+ }
+ conf.Write<Encoder::Format>(U_("Export"), U_("RAW_Format2"), newformat);
+ conf.Forget(U_("Export"), U_("RAW_Format"));
+ }
+ }
+
+#if defined(MPT_ENABLE_UPDATE)
+ // Update
+ if(storedVersion < MPT_V("1.28.00.39"))
+ {
+ if(UpdateUpdateCheckPeriod_DEPRECATED <= 0)
+ {
+ UpdateEnabled = true;
+ UpdateIntervalDays = -1;
+ } else
+ {
+ UpdateEnabled = true;
+ UpdateIntervalDays = UpdateUpdateCheckPeriod_DEPRECATED.Get();
+ }
+ const auto url = UpdateUpdateURL_DEPRECATED.Get();
+ if(url.empty() ||
+ url == UL_("http://update.openmpt.org/check/$VERSION/$GUID") ||
+ url == UL_("https://update.openmpt.org/check/$VERSION/$GUID"))
+ {
+ UpdateChannel = UpdateChannelRelease;
+ } else if(url == UL_("http://update.openmpt.org/check/testing/$VERSION/$GUID") ||
+ url == UL_("https://update.openmpt.org/check/testing/$VERSION/$GUID"))
+ {
+ UpdateChannel = UpdateChannelDevelopment;
+ } else
+ {
+ UpdateChannel = UpdateChannelDevelopment;
+ }
+ UpdateStatistics = UpdateSendGUID_DEPRECATED.Get();
+ conf.Forget(UpdateUpdateCheckPeriod_DEPRECATED.GetPath());
+ conf.Forget(UpdateUpdateURL_DEPRECATED.GetPath());
+ conf.Forget(UpdateSendGUID_DEPRECATED.GetPath());
+ }
+#endif // MPT_ENABLE_UPDATE
+
+ if(storedVersion < MPT_V("1.29.00.39"))
+ {
+ // ASIO device IDs are now normalized to upper-case in the device enumeration code.
+ // Previous device IDs could be mixed-case (as retrieved from the registry), which would make direct ID comparison fail now.
+ auto device = m_SoundDeviceIdentifier.Get();
+ if(device.substr(0, 5) == UL_("ASIO_"))
+ {
+ device = mpt::ToUpperCase(device);
+ m_SoundDeviceIdentifier = device;
+ }
+ }
+
+ // Effects
+#ifndef NO_EQ
+ FixupEQ(m_EqSettings);
+ FixupEQ(m_EqUserPresets[0]);
+ FixupEQ(m_EqUserPresets[1]);
+ FixupEQ(m_EqUserPresets[2]);
+ FixupEQ(m_EqUserPresets[3]);
+#endif // !NO_EQ
+
+ // Zxx Macros
+ if((MPT_V("1.17.00.00") <= storedVersion) && (storedVersion < MPT_V("1.20.00.00")))
+ {
+ // Fix old nasty broken (non-standard) MIDI configs in INI file.
+ macros.UpgradeMacros();
+ }
+ theApp.SetDefaultMidiMacro(macros);
+
+ // Paths
+ m_szKbdFile = theApp.PathInstallRelativeToAbsolute(m_szKbdFile);
+
+ // Sample undo buffer size (used to be a hidden, absolute setting in MiB)
+ int64 oldUndoSize = m_SampleUndoBufferSize.Get().GetSizeInPercent();
+ if(storedVersion < MPT_V("1.22.07.25") && oldUndoSize != SampleUndoBufferSize::defaultSize && oldUndoSize != 0)
+ {
+ m_SampleUndoBufferSize = SampleUndoBufferSize(static_cast<int32>(100 * (oldUndoSize << 20) / SampleUndoBufferSize(100).GetSizeInBytes()));
+ }
+
+ // More controls in the plugin selection dialog
+ if(storedVersion < MPT_V("1.26.00.26"))
+ {
+ gnPlugWindowHeight += 40;
+ }
+
+ // Sanitize resampling mode for sample editor
+ if(!Resampling::IsKnownMode(sampleEditorDefaultResampler) && sampleEditorDefaultResampler != SRCMODE_DEFAULT)
+ {
+ sampleEditorDefaultResampler = SRCMODE_DEFAULT;
+ }
+
+ // Migrate Tuning data
+ MigrateTunings(storedVersion);
+
+ // Sanitize MIDI import data
+ if(midiImportPatternLen < 1 || midiImportPatternLen > MAX_PATTERN_ROWS)
+ midiImportPatternLen = 128;
+ if(midiImportQuantize < 4 || midiImportQuantize > 256)
+ midiImportQuantize = 32;
+ if(midiImportTicks < 2 || midiImportTicks > 16)
+ midiImportTicks = 16;
+
+ // Last fixup: update config version
+ IniVersion = mpt::ufmt::val(Version::Current());
+
+ // Write updated settings
+ conf.Flush();
+}
+
+
+TrackerSettings::~TrackerSettings()
+{
+ return;
+}
+
+
+namespace SoundDevice
+{
+namespace Legacy
+{
+SoundDevice::Info FindDeviceInfo(SoundDevice::Manager &manager, SoundDevice::Legacy::ID id)
+{
+ if(manager.GetDeviceInfos().empty())
+ {
+ return SoundDevice::Info();
+ }
+ SoundDevice::Type type = SoundDevice::Type();
+ switch((id & SoundDevice::Legacy::MaskType) >> SoundDevice::Legacy::ShiftType)
+ {
+ case SoundDevice::Legacy::TypeWAVEOUT:
+ type = SoundDevice::TypeWAVEOUT;
+ break;
+ case SoundDevice::Legacy::TypeDSOUND:
+ type = SoundDevice::TypeDSOUND;
+ break;
+ case SoundDevice::Legacy::TypeASIO:
+ type = SoundDevice::TypeASIO;
+ break;
+ case SoundDevice::Legacy::TypePORTAUDIO_WASAPI:
+ type = SoundDevice::TypePORTAUDIO_WASAPI;
+ break;
+ case SoundDevice::Legacy::TypePORTAUDIO_WDMKS:
+ type = SoundDevice::TypePORTAUDIO_WDMKS;
+ break;
+ case SoundDevice::Legacy::TypePORTAUDIO_WMME:
+ type = SoundDevice::TypePORTAUDIO_WMME;
+ break;
+ case SoundDevice::Legacy::TypePORTAUDIO_DS:
+ type = SoundDevice::TypePORTAUDIO_DS;
+ break;
+ }
+ if(type.empty())
+ { // fallback to first device
+ return *manager.begin();
+ }
+ std::size_t index = static_cast<uint8>((id & SoundDevice::Legacy::MaskIndex) >> SoundDevice::Legacy::ShiftIndex);
+ std::size_t seenDevicesOfDesiredType = 0;
+ for(const auto &info : manager)
+ {
+ if(info.type == type)
+ {
+ if(seenDevicesOfDesiredType == index)
+ {
+ if(!info.IsValid())
+ { // fallback to first device
+ return *manager.begin();
+ }
+ return info;
+ }
+ seenDevicesOfDesiredType++;
+ }
+ }
+ // default to first device
+ return *manager.begin();
+}
+} // namespace Legacy
+} // namespace SoundDevice
+
+
+void TrackerSettings::MigrateOldSoundDeviceSettings(SoundDevice::Manager &manager)
+{
+ if(m_SoundDeviceSettingsUseOldDefaults)
+ {
+ // get the old default device
+ SetSoundDeviceIdentifier(SoundDevice::Legacy::FindDeviceInfo(manager, m_SoundDeviceID_DEPRECATED).GetIdentifier());
+ // apply old global sound device settings to each found device
+ for(const auto &it : manager)
+ {
+ SetSoundDeviceSettings(it.GetIdentifier(), GetSoundDeviceSettingsDefaults());
+ }
+ }
+}
+
+
+void TrackerSettings::MigrateTunings(const Version storedVersion)
+{
+ if(!PathTunings.GetDefaultDir().IsDirectory())
+ {
+ CreateDirectory(PathTunings.GetDefaultDir().AsNative().c_str(), 0);
+ }
+ if(!(PathTunings.GetDefaultDir() + P_("Built-in\\")).IsDirectory())
+ {
+ CreateDirectory((PathTunings.GetDefaultDir() + P_("Built-in\\")).AsNative().c_str(), 0);
+ }
+ if(!(PathTunings.GetDefaultDir() + P_("Locale\\")).IsDirectory())
+ {
+ CreateDirectory((PathTunings.GetDefaultDir() + P_("Local\\")).AsNative().c_str(), 0);
+ }
+ {
+ mpt::PathString fn = PathTunings.GetDefaultDir() + P_("Built-in\\12TET.tun");
+ if(!fn.FileOrDirectoryExists())
+ {
+ std::unique_ptr<CTuning> pT = CSoundFile::CreateTuning12TET(U_("12TET"));
+ mpt::SafeOutputFile sf(fn, std::ios::binary, mpt::FlushMode::Full);
+ pT->Serialize(sf);
+ }
+ }
+ {
+ mpt::PathString fn = PathTunings.GetDefaultDir() + P_("Built-in\\12TET [[fs15 1.17.02.49]].tun");
+ if(!fn.FileOrDirectoryExists())
+ {
+ std::unique_ptr<CTuning> pT = CSoundFile::CreateTuning12TET(U_("12TET [[fs15 1.17.02.49]]"));
+ mpt::SafeOutputFile sf(fn, std::ios::binary, mpt::FlushMode::Full);
+ pT->Serialize(sf);
+ }
+ }
+ oldLocalTunings = LoadLocalTunings();
+ if(storedVersion < MPT_V("1.27.00.56"))
+ {
+ UnpackTuningCollection(*oldLocalTunings, PathTunings.GetDefaultDir() + P_("Local\\"));
+ }
+}
+
+
+std::unique_ptr<CTuningCollection> TrackerSettings::LoadLocalTunings()
+{
+ std::unique_ptr<CTuningCollection> s_pTuningsSharedLocal = std::make_unique<CTuningCollection>();
+ mpt::ifstream f(
+ PathTunings.GetDefaultDir()
+ + P_("local_tunings")
+ + mpt::PathString::FromUTF8(CTuningCollection::s_FileExtension)
+ , std::ios::binary);
+ if(f.good())
+ {
+ mpt::ustring dummyName;
+ s_pTuningsSharedLocal->Deserialize(f, dummyName, TuningCharsetFallback);
+ }
+ return s_pTuningsSharedLocal;
+}
+
+
+struct StoredSoundDeviceSettings
+{
+
+private:
+ SettingsContainer &conf;
+ const SoundDevice::Info deviceInfo;
+
+private:
+ Setting<uint32> LatencyUS;
+ Setting<uint32> UpdateIntervalUS;
+ Setting<uint32> Samplerate;
+ Setting<uint8> ChannelsOld; // compatibility with older versions
+ Setting<SoundDevice::ChannelMapping> ChannelMapping;
+ Setting<uint8> InputChannels;
+ Setting<SampleFormat> sampleFormat;
+ Setting<bool> ExclusiveMode;
+ Setting<bool> BoostThreadPriority;
+ Setting<bool> KeepDeviceRunning;
+ Setting<bool> UseHardwareTiming;
+ Setting<int32> DitherType;
+ Setting<uint32> InputSourceID;
+
+public:
+
+ StoredSoundDeviceSettings(SettingsContainer &conf, const SoundDevice::Info & deviceInfo, const SoundDevice::Settings & defaults)
+ : conf(conf)
+ , deviceInfo(deviceInfo)
+ , LatencyUS(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("Latency"), mpt::saturate_round<int32>(defaults.Latency * 1000000.0))
+ , UpdateIntervalUS(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("UpdateInterval"), mpt::saturate_round<int32>(defaults.UpdateInterval * 1000000.0))
+ , Samplerate(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("SampleRate"), defaults.Samplerate)
+ , ChannelsOld(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("Channels"), mpt::saturate_cast<uint8>((int)defaults.Channels))
+ , ChannelMapping(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("ChannelMapping"), defaults.Channels)
+ , InputChannels(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("InputChannels"), defaults.InputChannels)
+ , sampleFormat(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("SampleFormat"), defaults.sampleFormat)
+ , ExclusiveMode(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("ExclusiveMode"), defaults.ExclusiveMode)
+ , BoostThreadPriority(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("BoostThreadPriority"), defaults.BoostThreadPriority)
+ , KeepDeviceRunning(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("KeepDeviceRunning"), defaults.KeepDeviceRunning)
+ , UseHardwareTiming(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("UseHardwareTiming"), defaults.UseHardwareTiming)
+ , DitherType(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("DitherType"), static_cast<int32>(defaults.DitherType))
+ , InputSourceID(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("InputSourceID"), defaults.InputSourceID)
+ {
+ if(ChannelMapping.Get().GetNumHostChannels() != ChannelsOld)
+ {
+ // If the stored channel count and the count of channels used in the channel mapping do not match,
+ // construct a default mapping from the channel count.
+ ChannelMapping = SoundDevice::ChannelMapping(ChannelsOld);
+ }
+ // store informational data (not read back, just to allow the user to mock with the raw ini file)
+ conf.Write(U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("Type"), deviceInfo.type);
+ conf.Write(U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("InternalID"), deviceInfo.internalID);
+ conf.Write(U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("API"), deviceInfo.apiName);
+ conf.Write(U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("Name"), deviceInfo.name);
+ }
+
+ StoredSoundDeviceSettings & operator = (const SoundDevice::Settings &settings)
+ {
+ LatencyUS = mpt::saturate_round<int32>(settings.Latency * 1000000.0);
+ UpdateIntervalUS = mpt::saturate_round<int32>(settings.UpdateInterval * 1000000.0);
+ Samplerate = settings.Samplerate;
+ ChannelsOld = mpt::saturate_cast<uint8>((int)settings.Channels);
+ ChannelMapping = settings.Channels;
+ InputChannels = settings.InputChannels;
+ sampleFormat = settings.sampleFormat;
+ ExclusiveMode = settings.ExclusiveMode;
+ BoostThreadPriority = settings.BoostThreadPriority;
+ KeepDeviceRunning = settings.KeepDeviceRunning;
+ UseHardwareTiming = settings.UseHardwareTiming;
+ DitherType = static_cast<int32>(settings.DitherType);
+ InputSourceID = settings.InputSourceID;
+ return *this;
+ }
+
+ operator SoundDevice::Settings () const
+ {
+ SoundDevice::Settings settings;
+ settings.Latency = LatencyUS / 1000000.0;
+ settings.UpdateInterval = UpdateIntervalUS / 1000000.0;
+ settings.Samplerate = Samplerate;
+ settings.Channels = ChannelMapping;
+ settings.InputChannels = InputChannels;
+ settings.sampleFormat = sampleFormat;
+ settings.ExclusiveMode = ExclusiveMode;
+ settings.BoostThreadPriority = BoostThreadPriority;
+ settings.KeepDeviceRunning = KeepDeviceRunning;
+ settings.UseHardwareTiming = UseHardwareTiming;
+ settings.DitherType = DitherType;
+ settings.InputSourceID = InputSourceID;
+ return settings;
+ }
+};
+
+SoundDevice::Settings TrackerSettings::GetSoundDeviceSettingsDefaults() const
+{
+ return m_SoundDeviceSettingsDefaults;
+}
+
+SoundDevice::Identifier TrackerSettings::GetSoundDeviceIdentifier() const
+{
+ return m_SoundDeviceIdentifier;
+}
+
+void TrackerSettings::SetSoundDeviceIdentifier(const SoundDevice::Identifier &identifier)
+{
+ m_SoundDeviceIdentifier = identifier;
+}
+
+SoundDevice::Settings TrackerSettings::GetSoundDeviceSettings(const SoundDevice::Identifier &device) const
+{
+ const SoundDevice::Info deviceInfo = theApp.GetSoundDevicesManager()->FindDeviceInfo(device);
+ if(!deviceInfo.IsValid())
+ {
+ return SoundDevice::Settings();
+ }
+ const SoundDevice::Caps deviceCaps = theApp.GetSoundDevicesManager()->GetDeviceCaps(device, CMainFrame::GetMainFrame()->gpSoundDevice);
+ SoundDevice::Settings settings = StoredSoundDeviceSettings(conf, deviceInfo, deviceCaps.DefaultSettings);
+ return settings;
+}
+
+void TrackerSettings::SetSoundDeviceSettings(const SoundDevice::Identifier &device, const SoundDevice::Settings &settings)
+{
+ const SoundDevice::Info deviceInfo = theApp.GetSoundDevicesManager()->FindDeviceInfo(device);
+ if(!deviceInfo.IsValid())
+ {
+ return;
+ }
+ const SoundDevice::Caps deviceCaps = theApp.GetSoundDevicesManager()->GetDeviceCaps(device, CMainFrame::GetMainFrame()->gpSoundDevice);
+ StoredSoundDeviceSettings(conf, deviceInfo, deviceCaps.DefaultSettings) = settings;
+}
+
+
+MixerSettings TrackerSettings::GetMixerSettings() const
+{
+ MixerSettings settings;
+ settings.m_nMaxMixChannels = MixerMaxChannels;
+ settings.DSPMask = MixerDSPMask;
+ settings.MixerFlags = MixerFlags;
+ settings.gdwMixingFreq = MixerSamplerate;
+ settings.gnChannels = MixerOutputChannels;
+ settings.m_nPreAmp = MixerPreAmp;
+ settings.m_nStereoSeparation = MixerStereoSeparation;
+ settings.VolumeRampUpMicroseconds = MixerVolumeRampUpMicroseconds;
+ settings.VolumeRampDownMicroseconds = MixerVolumeRampDownMicroseconds;
+ settings.NumInputChannels = MixerNumInputChannels;
+ return settings;
+}
+
+void TrackerSettings::SetMixerSettings(const MixerSettings &settings)
+{
+ MixerMaxChannels = settings.m_nMaxMixChannels;
+ MixerDSPMask = settings.DSPMask;
+ MixerFlags = settings.MixerFlags;
+ MixerSamplerate = settings.gdwMixingFreq;
+ MixerOutputChannels = settings.gnChannels;
+ MixerPreAmp = settings.m_nPreAmp;
+ MixerStereoSeparation = settings.m_nStereoSeparation;
+ MixerVolumeRampUpMicroseconds = settings.VolumeRampUpMicroseconds;
+ MixerVolumeRampDownMicroseconds = settings.VolumeRampDownMicroseconds;
+ MixerNumInputChannels = static_cast<uint32>(settings.NumInputChannels);
+}
+
+
+CResamplerSettings TrackerSettings::GetResamplerSettings() const
+{
+ CResamplerSettings settings;
+ settings.SrcMode = ResamplerMode;
+ settings.gbWFIRType = ResamplerSubMode;
+ settings.gdWFIRCutoff = ResamplerCutoffPercent * 0.01;
+ settings.emulateAmiga = ResamplerEmulateAmiga;
+ return settings;
+}
+
+void TrackerSettings::SetResamplerSettings(const CResamplerSettings &settings)
+{
+ ResamplerMode = settings.SrcMode;
+ ResamplerSubMode = settings.gbWFIRType;
+ ResamplerCutoffPercent = mpt::saturate_round<int32>(settings.gdWFIRCutoff * 100.0);
+ ResamplerEmulateAmiga = settings.emulateAmiga;
+}
+
+
+void TrackerSettings::GetDefaultColourScheme(std::array<COLORREF, MAX_MODCOLORS> &colours)
+{
+ colours[MODCOLOR_BACKNORMAL] = RGB(0xFF, 0xFF, 0xFF);
+ colours[MODCOLOR_TEXTNORMAL] = RGB(0x00, 0x00, 0x00);
+ colours[MODCOLOR_BACKCURROW] = RGB(0xC0, 0xC0, 0xC0);
+ colours[MODCOLOR_TEXTCURROW] = RGB(0x00, 0x00, 0x00);
+ colours[MODCOLOR_BACKSELECTED] = RGB(0x00, 0x00, 0x00);
+ colours[MODCOLOR_TEXTSELECTED] = RGB(0xFF, 0xFF, 0xFF);
+ colours[MODCOLOR_SAMPLE] = RGB(0xFF, 0x00, 0x00);
+ colours[MODCOLOR_BACKPLAYCURSOR] = RGB(0xFF, 0xFF, 0x80);
+ colours[MODCOLOR_TEXTPLAYCURSOR] = RGB(0x00, 0x00, 0x00);
+ colours[MODCOLOR_BACKHILIGHT] = RGB(0xE0, 0xE8, 0xE0);
+ // Effect Colors
+ colours[MODCOLOR_NOTE] = RGB(0x00, 0x00, 0x80);
+ colours[MODCOLOR_INSTRUMENT] = RGB(0x00, 0x80, 0x80);
+ colours[MODCOLOR_VOLUME] = RGB(0x00, 0x80, 0x00);
+ colours[MODCOLOR_PANNING] = RGB(0x00, 0x80, 0x80);
+ colours[MODCOLOR_PITCH] = RGB(0x80, 0x80, 0x00);
+ colours[MODCOLOR_GLOBALS] = RGB(0x80, 0x00, 0x00);
+ // VU-Meters
+ colours[MODCOLOR_VUMETER_LO] = RGB(0x00, 0xC8, 0x00);
+ colours[MODCOLOR_VUMETER_MED] = RGB(0xFF, 0xC8, 0x00);
+ colours[MODCOLOR_VUMETER_HI] = RGB(0xE1, 0x00, 0x00);
+ colours[MODCOLOR_VUMETER_LO_VST] = RGB(0x18, 0x96, 0xE1);
+ colours[MODCOLOR_VUMETER_MED_VST] = RGB(0xFF, 0xC8, 0x00);
+ colours[MODCOLOR_VUMETER_HI_VST] = RGB(0xE1, 0x00, 0x00);
+ // Channel separators
+ colours[MODCOLOR_SEPSHADOW] = GetSysColor(COLOR_BTNSHADOW);
+ colours[MODCOLOR_SEPFACE] = GetSysColor(COLOR_BTNFACE);
+ colours[MODCOLOR_SEPHILITE] = GetSysColor(COLOR_BTNHIGHLIGHT);
+ // Pattern blend colour
+ colours[MODCOLOR_BLENDCOLOR] = GetSysColor(COLOR_BTNFACE);
+ // Dodgy commands
+ colours[MODCOLOR_DODGY_COMMANDS] = RGB(0xC0, 0x00, 0x00);
+ // Sample / instrument editor
+ colours[MODCOLOR_BACKSAMPLE] = RGB(0x00, 0x00, 0x00);
+ colours[MODCOLOR_SAMPLESELECTED] = RGB(0xFF, 0xFF, 0xFF);
+ colours[MODCOLOR_BACKENV] = RGB(0x00, 0x00, 0x00);
+ colours[MODCOLOR_ENVELOPES] = RGB(0x00, 0x00, 0xFF);
+ colours[MODCOLOR_ENVELOPE_RELEASE] = RGB(0xFF, 0xFF, 0x00);
+ colours[MODCOLOR_SAMPLE_LOOPMARKER] = RGB(0x30, 0xCC, 0x30);
+ colours[MODCOLOR_SAMPLE_SUSTAINMARKER] = RGB(50, 0xCC, 0xCC);
+ colours[MODCOLOR_SAMPLE_CUEPOINT] = RGB(0xFF, 0xCC, 0x30);
+}
+
+
+#ifndef NO_EQ
+
+void TrackerSettings::FixupEQ(EQPreset &eqSettings)
+{
+ for(UINT i = 0; i < MAX_EQ_BANDS; i++)
+ {
+ if(eqSettings.Gains[i] > 32)
+ eqSettings.Gains[i] = 16;
+ if((eqSettings.Freqs[i] < 100) || (eqSettings.Freqs[i] > 10000))
+ eqSettings.Freqs[i] = FlatEQPreset.Freqs[i];
+ }
+ mpt::String::SetNullTerminator(eqSettings.szName);
+}
+
+#endif // !NO_EQ
+
+
+void TrackerSettings::SaveSettings()
+{
+
+ WINDOWPLACEMENT wpl;
+ wpl.length = sizeof(WINDOWPLACEMENT);
+ CMainFrame::GetMainFrame()->GetWindowPlacement(&wpl);
+ conf.Write<WINDOWPLACEMENT>(U_("Display"), U_("WindowPlacement"), wpl);
+
+ conf.Write<int32>(U_("Pattern Editor"), U_("NumClipboards"), mpt::saturate_cast<int32>(PatternClipboard::GetClipboardSize()));
+
+ // Effects
+#ifndef NO_DSP
+ conf.Write<int32>(U_("Effects"), U_("XBassDepth"), m_MegaBassSettings.m_nXBassDepth);
+ conf.Write<int32>(U_("Effects"), U_("XBassRange"), m_MegaBassSettings.m_nXBassRange);
+#endif
+#ifndef NO_REVERB
+ conf.Write<int32>(U_("Effects"), U_("ReverbDepth"), m_ReverbSettings.m_nReverbDepth);
+ conf.Write<int32>(U_("Effects"), U_("ReverbType"), m_ReverbSettings.m_nReverbType);
+#endif
+#ifndef NO_DSP
+ conf.Write<int32>(U_("Effects"), U_("ProLogicDepth"), m_SurroundSettings.m_nProLogicDepth);
+ conf.Write<int32>(U_("Effects"), U_("ProLogicDelay"), m_SurroundSettings.m_nProLogicDelay);
+#endif
+#ifndef NO_EQ
+ conf.Write<EQPreset>(U_("Effects"), U_("EQ_Settings"), m_EqSettings);
+ conf.Write<EQPreset>(U_("Effects"), U_("EQ_User1"), m_EqUserPresets[0]);
+ conf.Write<EQPreset>(U_("Effects"), U_("EQ_User2"), m_EqUserPresets[1]);
+ conf.Write<EQPreset>(U_("Effects"), U_("EQ_User3"), m_EqUserPresets[2]);
+ conf.Write<EQPreset>(U_("Effects"), U_("EQ_User4"), m_EqUserPresets[3]);
+#endif
+#ifndef NO_DSP
+ conf.Write<int32>(U_("Effects"), U_("BitCrushBits"), m_BitCrushSettings.m_Bits);
+#endif
+
+ // Display (Colors)
+ for(int ncol = 0; ncol < MAX_MODCOLORS; ncol++)
+ {
+ conf.Write<uint32>(U_("Display"), MPT_UFORMAT("Color{}")(mpt::ufmt::dec0<2>(ncol)), rgbCustomColors[ncol]);
+ }
+
+ // Paths
+ // Obsolete, since we always write to Keybindings.mkb now.
+ // Older versions of OpenMPT 1.18+ will look for this file if this entry is missing, so removing this entry after having read it is kind of backwards compatible.
+ conf.Remove(U_("Paths"), U_("Key_Config_File"));
+
+ // Chords
+ SaveChords(Chords);
+
+ // Save default macro configuration
+ MIDIMacroConfig macros;
+ theApp.GetDefaultMidiMacro(macros);
+ for(int isfx = 0; isfx < kSFxMacros; isfx++)
+ {
+ conf.Write<std::string>(U_("Zxx Macros"), MPT_UFORMAT("SF{}")(mpt::ufmt::HEX(isfx)), macros.SFx[isfx]);
+ }
+ for(int izxx = 0; izxx < kZxxMacros; izxx++)
+ {
+ conf.Write<std::string>(U_("Zxx Macros"), MPT_UFORMAT("Z{}")(mpt::ufmt::HEX0<2>(izxx | 0x80)), macros.Zxx[izxx]);
+ }
+
+ // MRU list
+ for(uint32 i = 0; i < (ID_MRU_LIST_LAST - ID_MRU_LIST_FIRST + 1); i++)
+ {
+ mpt::ustring key = MPT_UFORMAT("File{}")(i);
+
+ if(i < mruFiles.size())
+ {
+ mpt::PathString path = mruFiles[i];
+ if(theApp.IsPortableMode())
+ {
+ path = theApp.PathAbsoluteToInstallRelative(path);
+ }
+ conf.Write<mpt::PathString>(U_("Recent File List"), key, path);
+ } else
+ {
+ conf.Remove(U_("Recent File List"), key);
+ }
+ }
+}
+
+
+bool TrackerSettings::IsComponentBlocked(const std::string &key)
+{
+ return Setting<bool>(conf, U_("Components"), U_("Block") + mpt::ToUnicode(mpt::Charset::ASCII, key), ComponentManagerSettingsDefault().IsBlocked(key));
+}
+
+
+std::vector<uint32> TrackerSettings::GetSampleRates() const
+{
+ return m_SoundSampleRates;
+}
+
+
+std::vector<uint32> TrackerSettings::GetDefaultSampleRates()
+{
+ return std::vector<uint32>{
+ 192000,
+ 176400,
+ 96000,
+ 88200,
+ 48000,
+ 44100,
+ 32000,
+ 24000,
+ 22050,
+ 16000,
+ 11025,
+ 8000
+ };
+}
+
+
+////////////////////////////////////////////////////////////////////////////////
+// Chords
+
+void TrackerSettings::LoadChords(MPTChords &chords)
+{
+ for(std::size_t i = 0; i < std::size(chords); i++)
+ {
+ uint32 chord;
+ mpt::ustring noteName = MPT_UFORMAT("{}{}")(mpt::ustring(NoteNamesSharp[i % 12]), i / 12);
+ if((chord = conf.Read<int32>(U_("Chords"), noteName, -1)) != uint32(-1))
+ {
+ if((chord & 0xFFFFFFC0) || chords[i].notes[0] == MPTChord::noNote)
+ {
+ chords[i].key = (uint8)(chord & 0x3F);
+ int shift = 6;
+ for(auto &note : chords[i].notes)
+ {
+ // Extract 6 bits and sign-extend to 8 bits
+ const int signBit = ((chord >> (shift + 5)) & 1);
+ note = static_cast<MPTChord::NoteType>(((chord >> shift) & 0x3F) | (0xC0 * signBit));
+ shift += 6;
+ if(note == 0)
+ note = MPTChord::noNote;
+ else if(note > 0)
+ note--;
+ }
+ }
+ }
+ }
+}
+
+
+void TrackerSettings::SaveChords(MPTChords &chords)
+{
+ for(std::size_t i = 0; i < std::size(chords); i++)
+ {
+ auto notes = chords[i].notes;
+ for(auto &note : notes)
+ {
+ if(note == MPTChord::noNote)
+ note = 0;
+ else if(note >= 0)
+ note++;
+ note &= 0x3F;
+ }
+ int32 s = (chords[i].key) | (notes[0] << 6) | (notes[1] << 12) | (notes[2] << 18);
+ mpt::ustring noteName = MPT_UFORMAT("{}{}")(mpt::ustring(NoteNamesSharp[i % 12]), i / 12);
+ conf.Write<int32>(U_("Chords"), noteName, s);
+ }
+}
+
+
+void TrackerSettings::SetMIDIDevice(UINT id)
+{
+ m_nMidiDevice = id;
+ MIDIINCAPS mic;
+ mic.szPname[0] = 0;
+ if(midiInGetDevCaps(id, &mic, sizeof(mic)) == MMSYSERR_NOERROR)
+ {
+ midiDeviceName = mic.szPname;
+ }
+}
+
+
+UINT TrackerSettings::GetCurrentMIDIDevice()
+{
+ if(midiDeviceName.Get().IsEmpty())
+ return m_nMidiDevice;
+
+ CString deviceName = midiDeviceName;
+ deviceName.TrimRight();
+
+ MIDIINCAPS mic;
+ UINT candidate = m_nMidiDevice, numDevs = midiInGetNumDevs();
+ for(UINT i = 0; i < numDevs; i++)
+ {
+ mic.szPname[0] = 0;
+ if(midiInGetDevCaps(i, &mic, sizeof(mic)) != MMSYSERR_NOERROR)
+ continue;
+
+ // Some device names have trailing spaces (e.g. "USB MIDI Interface "), but those may get lost in our settings framework.
+ mpt::String::SetNullTerminator(mic.szPname);
+ size_t strLen = _tcslen(mic.szPname);
+ while(strLen-- > 0)
+ {
+ if(mic.szPname[strLen] == _T(' '))
+ mic.szPname[strLen] = 0;
+ else
+ break;
+ }
+ if(CString(mic.szPname) == deviceName)
+ {
+ candidate = i;
+ numDevs = m_nMidiDevice + 1;
+ // If the same device name exists twice, try to match both device number and name
+ if(candidate == m_nMidiDevice)
+ return candidate;
+ }
+ }
+ // If the device changed its ID, update it now.
+ m_nMidiDevice = candidate;
+ return candidate;
+}
+
+
+mpt::ustring IgnoredCCsToString(const std::bitset<128> &midiIgnoreCCs)
+{
+ mpt::ustring cc;
+ bool first = true;
+ for(int i = 0; i < 128; i++)
+ {
+ if(midiIgnoreCCs[i])
+ {
+ if(!first)
+ {
+ cc += U_(",");
+ }
+ cc += mpt::ufmt::val(i);
+ first = false;
+ }
+ }
+ return cc;
+}
+
+
+std::bitset<128> StringToIgnoredCCs(const mpt::ustring &in)
+{
+ CString cc = mpt::ToCString(in);
+ std::bitset<128> midiIgnoreCCs;
+ midiIgnoreCCs.reset();
+ int curPos = 0;
+ CString ccToken = cc.Tokenize(_T(", "), curPos);
+ while(ccToken != _T(""))
+ {
+ int ccNumber = ConvertStrTo<int>(ccToken);
+ if(ccNumber >= 0 && ccNumber <= 127)
+ midiIgnoreCCs.set(ccNumber);
+ ccToken = cc.Tokenize(_T(", "), curPos);
+ }
+ return midiIgnoreCCs;
+}
+
+
+DefaultAndWorkingDirectory::DefaultAndWorkingDirectory()
+{
+ return;
+}
+
+DefaultAndWorkingDirectory::DefaultAndWorkingDirectory(const mpt::PathString &def)
+ : m_Default(def)
+ , m_Working(def)
+{
+ return;
+}
+
+DefaultAndWorkingDirectory::~DefaultAndWorkingDirectory()
+{
+ return;
+}
+
+void DefaultAndWorkingDirectory::SetDefaultDir(const mpt::PathString &filenameFrom, bool stripFilename)
+{
+ if(InternalSet(m_Default, filenameFrom, stripFilename) && !m_Default.empty())
+ {
+ // When updating default directory, also update the working directory.
+ InternalSet(m_Working, filenameFrom, stripFilename);
+ }
+}
+
+void DefaultAndWorkingDirectory::SetWorkingDir(const mpt::PathString &filenameFrom, bool stripFilename)
+{
+ InternalSet(m_Working, filenameFrom, stripFilename);
+}
+
+mpt::PathString DefaultAndWorkingDirectory::GetDefaultDir() const
+{
+ return m_Default;
+}
+
+mpt::PathString DefaultAndWorkingDirectory::GetWorkingDir() const
+{
+ return m_Working;
+}
+
+// Retrieve / set default directory from given string and store it our setup variables
+// If stripFilename is true, the filenameFrom parameter is assumed to be a full path including a filename.
+// Return true if the value changed.
+bool DefaultAndWorkingDirectory::InternalSet(mpt::PathString &dest, const mpt::PathString &filenameFrom, bool stripFilename)
+{
+ mpt::PathString newPath = (stripFilename ? filenameFrom.GetPath() : filenameFrom);
+ newPath.EnsureTrailingSlash();
+ mpt::PathString oldPath = dest;
+ dest = newPath;
+ return newPath != oldPath;
+}
+
+ConfigurableDirectory::ConfigurableDirectory(SettingsContainer &conf, const AnyStringLocale &section, const AnyStringLocale &key, const mpt::PathString &def)
+ : conf(conf)
+ , m_Setting(conf, section, key, def)
+{
+ SetDefaultDir(theApp.PathInstallRelativeToAbsolute(m_Setting), false);
+}
+
+ConfigurableDirectory::~ConfigurableDirectory()
+{
+ m_Setting = theApp.IsPortableMode() ? theApp.PathAbsoluteToInstallRelative(m_Default) : m_Default;
+}
+
+
+
+OPENMPT_NAMESPACE_END