/* * 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 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(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(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(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(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(U_("Effects"), U_("XBassDepth"), m_MegaBassSettings.m_nXBassDepth); m_MegaBassSettings.m_nXBassRange = conf.Read(U_("Effects"), U_("XBassRange"), m_MegaBassSettings.m_nXBassRange); #endif #ifndef NO_REVERB m_ReverbSettings.m_nReverbDepth = conf.Read(U_("Effects"), U_("ReverbDepth"), m_ReverbSettings.m_nReverbDepth); m_ReverbSettings.m_nReverbType = conf.Read(U_("Effects"), U_("ReverbType"), m_ReverbSettings.m_nReverbType); #endif #ifndef NO_DSP m_SurroundSettings.m_nProLogicDepth = conf.Read(U_("Effects"), U_("ProLogicDepth"), m_SurroundSettings.m_nProLogicDepth); m_SurroundSettings.m_nProLogicDelay = conf.Read(U_("Effects"), U_("ProLogicDelay"), m_SurroundSettings.m_nProLogicDelay); #endif #ifndef NO_EQ m_EqSettings = conf.Read(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(U_("Effects"), U_("EQ_User1"), userPresets[0]); m_EqUserPresets[1] = conf.Read(U_("Effects"), U_("EQ_User2"), userPresets[1]); m_EqUserPresets[2] = conf.Read(U_("Effects"), U_("EQ_User3"), userPresets[2]); m_EqUserPresets[3] = conf.Read(U_("Effects"), U_("EQ_User4"), userPresets[3]); #endif #ifndef NO_DSP m_BitCrushSettings.m_Bits = conf.Read(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(U_("Display"), colorName, rgbCustomColors[ncol]); } // Paths m_szKbdFile = conf.Read(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(U_("Pattern Editor"), U_("NumClipboards"), mpt::saturate_cast(PatternClipboard::GetClipboardSize()))); // Chords LoadChords(Chords); // Zxx Macros MIDIMacroConfig macros; theApp.GetDefaultMidiMacro(macros); for(int i = 0; i < kSFxMacros; i++) { macros.SFx[i] = conf.Read(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(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(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(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(U_("Sound Settings"), U_("KeepDeviceOpen"), false)) { m_SoundSettingsStopMode = SoundDeviceStopModePlaying; } else { m_SoundSettingsStopMode = SoundDeviceStopModeStopped; } } if(storedVersion < MPT_V("1.22.07.04")) { std::vector 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(U_("Sound Settings"), U_("WaveDevice"), SoundDevice::Legacy::ID()); Setting m_BufferLength_DEPRECATED(conf, U_("Sound Settings"), U_("BufferLength"), 50); Setting m_LatencyMS(conf, U_("Sound Settings"), U_("Latency"), mpt::saturate_round(SoundDevice::Settings().Latency * 1000.0)); Setting m_UpdateIntervalMS(conf, U_("Sound Settings"), U_("UpdateInterval"), mpt::saturate_round(SoundDevice::Settings().UpdateInterval * 1000.0)); Setting m_SampleFormat(conf, U_("Sound Settings"), U_("BitsPerSample"), SoundDevice::Settings().sampleFormat); Setting m_SoundDeviceExclusiveMode(conf, U_("Sound Settings"), U_("ExclusiveMode"), SoundDevice::Settings().ExclusiveMode); Setting m_SoundDeviceBoostThreadPriority(conf, U_("Sound Settings"), U_("BoostThreadPriority"), SoundDevice::Settings().BoostThreadPriority); Setting m_SoundDeviceUseHardwareTiming(conf, U_("Sound Settings"), U_("UseHardwareTiming"), SoundDevice::Settings().UseHardwareTiming); Setting 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(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(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(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(U_("Sound Settings"), U_("VolumeRampSamples"), 42)); settings.SetVolumeRampDownSamples(conf.Read(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(U_("Sound Settings"), U_("VolumeRampUpSamples"), MixerSettings().GetVolumeRampUpSamples())); settings.SetVolumeRampDownSamples(conf.Read(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(U_("Export"), U_("FLAC_Mode"), Encoder::ModeLossless); const int oldformat = conf.Read(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(U_("Export"), U_("FLAC_Format2"), newformat); conf.Forget(U_("Export"), U_("FLAC_Format")); } { conf.Write(U_("Export"), U_("Wave_Mode"), Encoder::ModeLossless); const int oldformat = conf.Read(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(U_("Export"), U_("Wave_Format2"), newformat); conf.Forget(U_("Export"), U_("Wave_Format")); } { conf.Write(U_("Export"), U_("AU_Mode"), Encoder::ModeLossless); const int oldformat = conf.Read(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(U_("Export"), U_("AU_Format2"), newformat); conf.Forget(U_("Export"), U_("AU_Format")); } { conf.Write(U_("Export"), U_("RAW_Mode"), Encoder::ModeLossless); const int oldformat = conf.Read(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(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(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((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 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 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 TrackerSettings::LoadLocalTunings() { std::unique_ptr s_pTuningsSharedLocal = std::make_unique(); 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 LatencyUS; Setting UpdateIntervalUS; Setting Samplerate; Setting ChannelsOld; // compatibility with older versions Setting ChannelMapping; Setting InputChannels; Setting sampleFormat; Setting ExclusiveMode; Setting BoostThreadPriority; Setting KeepDeviceRunning; Setting UseHardwareTiming; Setting DitherType; Setting 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(defaults.Latency * 1000000.0)) , UpdateIntervalUS(conf, U_("Sound Settings"), deviceInfo.GetIdentifier() + U_("_") + U_("UpdateInterval"), mpt::saturate_round(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((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(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(settings.Latency * 1000000.0); UpdateIntervalUS = mpt::saturate_round(settings.UpdateInterval * 1000000.0); Samplerate = settings.Samplerate; ChannelsOld = mpt::saturate_cast((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(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(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(settings.gdWFIRCutoff * 100.0); ResamplerEmulateAmiga = settings.emulateAmiga; } void TrackerSettings::GetDefaultColourScheme(std::array &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(U_("Display"), U_("WindowPlacement"), wpl); conf.Write(U_("Pattern Editor"), U_("NumClipboards"), mpt::saturate_cast(PatternClipboard::GetClipboardSize())); // Effects #ifndef NO_DSP conf.Write(U_("Effects"), U_("XBassDepth"), m_MegaBassSettings.m_nXBassDepth); conf.Write(U_("Effects"), U_("XBassRange"), m_MegaBassSettings.m_nXBassRange); #endif #ifndef NO_REVERB conf.Write(U_("Effects"), U_("ReverbDepth"), m_ReverbSettings.m_nReverbDepth); conf.Write(U_("Effects"), U_("ReverbType"), m_ReverbSettings.m_nReverbType); #endif #ifndef NO_DSP conf.Write(U_("Effects"), U_("ProLogicDepth"), m_SurroundSettings.m_nProLogicDepth); conf.Write(U_("Effects"), U_("ProLogicDelay"), m_SurroundSettings.m_nProLogicDelay); #endif #ifndef NO_EQ conf.Write(U_("Effects"), U_("EQ_Settings"), m_EqSettings); conf.Write(U_("Effects"), U_("EQ_User1"), m_EqUserPresets[0]); conf.Write(U_("Effects"), U_("EQ_User2"), m_EqUserPresets[1]); conf.Write(U_("Effects"), U_("EQ_User3"), m_EqUserPresets[2]); conf.Write(U_("Effects"), U_("EQ_User4"), m_EqUserPresets[3]); #endif #ifndef NO_DSP conf.Write(U_("Effects"), U_("BitCrushBits"), m_BitCrushSettings.m_Bits); #endif // Display (Colors) for(int ncol = 0; ncol < MAX_MODCOLORS; ncol++) { conf.Write(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(U_("Zxx Macros"), MPT_UFORMAT("SF{}")(mpt::ufmt::HEX(isfx)), macros.SFx[isfx]); } for(int izxx = 0; izxx < kZxxMacros; izxx++) { conf.Write(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(U_("Recent File List"), key, path); } else { conf.Remove(U_("Recent File List"), key); } } } bool TrackerSettings::IsComponentBlocked(const std::string &key) { return Setting(conf, U_("Components"), U_("Block") + mpt::ToUnicode(mpt::Charset::ASCII, key), ComponentManagerSettingsDefault().IsBlocked(key)); } std::vector TrackerSettings::GetSampleRates() const { return m_SoundSampleRates; } std::vector TrackerSettings::GetDefaultSampleRates() { return std::vector{ 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(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 ¬e : chords[i].notes) { // Extract 6 bits and sign-extend to 8 bits const int signBit = ((chord >> (shift + 5)) & 1); note = static_cast(((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 ¬e : 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(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(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 §ion, 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