From: <sv...@op...> - 2024-06-06 19:55:38
|
Author: sagamusix Date: Thu Jun 6 21:55:31 2024 New Revision: 20938 URL: https://source.openmpt.org/browse/openmpt/?op=revision&rev=20938 Log: Merged revision(s) 20936-20937 from trunk/OpenMPT: [Imp] MED: Further improvements to effect juggling to potentially keep X-param if the other effect can be moved to the volume colum instead. ........ [Imp] MED: Emulate echo DSP through DMO Echo plugin (https://www.un4seen.com/forum/?topic=15448.msg143034#msg143034). ........ Modified: branches/OpenMPT-1.31/ (props changed) branches/OpenMPT-1.31/soundlib/Load_med.cpp Modified: branches/OpenMPT-1.31/soundlib/Load_med.cpp ============================================================================== --- branches/OpenMPT-1.31/soundlib/Load_med.cpp Thu Jun 6 21:55:09 2024 (r20937) +++ branches/OpenMPT-1.31/soundlib/Load_med.cpp Thu Jun 6 21:55:31 2024 (r20938) @@ -84,10 +84,10 @@ uint32be flags3; uint16be volAdjust; // Volume adjust (%) uint16be mixChannels; // Mixing channels, 0 means 4 - uint8be mixEchoType; // 0 = nothing, 1 = normal, 2 = cross - uint8be mixEchoDepth; // 1 - 6, 0 = default + uint8 mixEchoType; // 0 = nothing, 1 = normal, 2 = cross + uint8 mixEchoDepth; // 1 - 6, 0 = default uint16be mixEchoLength; // Echo length in milliseconds - int8be mixStereoSep; // Stereo separation + int8 mixStereoSep; // Stereo separation char pad0[223]; }; @@ -616,11 +616,11 @@ if(oldCmd.first != CMD_NONE && m->command != oldCmd.first) { - // Restore effect from previous page, or reset X-Param to 8-bit value if this cell was overwritten with a "useful" effect - if(row > 0 && oldCmd.first == CMD_XPARAM) - pattern.GetpModCommand(row - 1, chn)->param = Util::MaxValueOfType(m->param); - else if(!ModCommand::CombineEffects(m->command, m->param, oldCmd.first, oldCmd.second) && m->volcmd == VOLCMD_NONE) + if(!ModCommand::CombineEffects(m->command, m->param, oldCmd.first, oldCmd.second) && m->volcmd == VOLCMD_NONE) m->FillInTwoCommands(m->command, m->param, oldCmd.first, oldCmd.second); + // Reset X-Param to 8-bit value if this cell was overwritten with a "useful" effect + if(row > 0 && oldCmd.first == CMD_XPARAM && m->command != CMD_XPARAM) + pattern.GetpModCommand(row - 1, chn)->param = Util::MaxValueOfType(m->param); } if(extraCmd.first != CMD_NONE) { @@ -829,7 +829,7 @@ if(type == L"VST") { auto &mixPlug = m_MixPlugins[numPlugins]; - mixPlug = {}; + mpt::reconstruct(mixPlug); mixPlug.Info.dwPluginId1 = Vst::kEffectMagic; mixPlug.Info.gain = 10; mixPlug.Info.szName = mpt::ToCharset(mpt::Charset::Locale, name); @@ -1164,6 +1164,34 @@ SetupMODPanning(true); } +#ifndef NO_PLUGINS + if((header.mixEchoType == 1 || header.mixEchoType == 2) && numPlugins < MAX_MIXPLUGINS) + { + // Emulating MED echo using the DMO echo requires to compensate for the differences in initial feedback in the latter. + const float feedback = 1.0f / (1 << std::max(header.mixEchoDepth, uint8(1))); // The feedback we want + const float initialFeedback = std::sqrt(1.0f - (feedback * feedback)); // Actual strength of first delay's feedback + const float wetFactor = feedback / initialFeedback; // Factor to compensate for this + SNDMIXPLUGIN &mixPlug = m_MixPlugins[numPlugins]; + mpt::reconstruct(mixPlug); + memcpy(&mixPlug.Info.dwPluginId1, "OMXD", 4); + memcpy(&mixPlug.Info.dwPluginId2, "\x2C\x93\x3E\xEF", 4); + mixPlug.Info.routingFlags = SNDMIXPLUGININFO::irApplyToMaster | SNDMIXPLUGININFO::irAutoSuspend; + mixPlug.fDryRatio = 1.0f - wetFactor / (wetFactor + 1.0f); + mixPlug.Info.gain = 10; + mixPlug.Info.szName = "Echo"; + mixPlug.Info.szLibraryName = "Echo"; + + std::array<float32le, 6> params{}; + params[1] = 1.0f; // WetDryMix + params[2] = feedback; // Feedback + params[3] = header.mixEchoLength / 2000.0f; // LeftDelay + params[4] = params[3]; // RightDelay + params[5] = header.mixEchoType == 2 ? 1.0f : 0.0f; // PanDelay + mixPlug.pluginData.resize(sizeof(params)); + memcpy(mixPlug.pluginData.data(), params.data(), sizeof(params)); + } +#endif + std::vector<uint16be> sections; if(!file.Seek(header.sectionTableOffset) || !file.CanRead(songHeader.songLength * 2) |