From: <sag...@us...> - 2014-11-06 20:49:11
|
Revision: 4555 http://sourceforge.net/p/modplug/code/4555 Author: saga-games Date: 2014-11-06 20:48:55 +0000 (Thu, 06 Nov 2014) Log Message: ----------- [Mod] Re-implemented stereo separation to be applied on the mix buffer. This has the following advantages: - It works with stereo samples - It also affects plugins The only drawback is that the setting is now limited to a 0...100% range, i.e. stereo widening is no longer possible. [Mod] Improve stereo separation slider granularity (http://bugs.openmpt.org/view.php?id=604) [Ref] Introduce mul32to64 and mul32to64_unsigned (used by stereo separation and muldiv code so far) to efficiently compute 32bit * 32bit to 64bit multiplication with MSVC, as the compiler often fails to replace such multipications with the x86 imul instructions and instead calls the way less efficient _allmul function. [Mod] OpenMPT: Version is now 1.24.00.16 Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/common/versionNumber.h trunk/OpenMPT/mptrack/Mpdlgs.cpp trunk/OpenMPT/soundlib/MixerSettings.h trunk/OpenMPT/soundlib/Sndmix.cpp Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2014-11-06 20:35:47 UTC (rev 4554) +++ trunk/OpenMPT/common/misc_util.h 2014-11-06 20:48:55 UTC (rev 4555) @@ -422,24 +422,44 @@ namespace Util { + // Multiply two 32-bit integers, receive 64-bit result. + // MSVC generates unnecessarily complicated code for the unoptimized variant using _allmul. + inline int64 mul32to64(int32 a, int32 b) + { +#if MPT_COMPILER_MSVC + return __emul(a, b); +#else + return static_cast<int64>(a) * b; +#endif + } + + inline uint64 mul32to64_unsigned(uint32 a, uint32 b) + { +#if MPT_COMPILER_MSVC + return __emulu(a, b); +#else + return static_cast<uint64>(a) * b; +#endif + } + inline int32 muldiv(int32 a, int32 b, int32 c) { - return static_cast<int32>( ( static_cast<int64>(a) * b ) / c ); + return static_cast<int32>( mul32to64( a, b ) / c ); } inline int32 muldivr(int32 a, int32 b, int32 c) { - return static_cast<int32>( ( static_cast<int64>(a) * b + ( c / 2 ) ) / c ); + return static_cast<int32>( ( mul32to64( a, b ) + ( c / 2 ) ) / c ); } // Do not use overloading because catching unsigned version by accident results in slower X86 code. inline uint32 muldiv_unsigned(uint32 a, uint32 b, uint32 c) { - return static_cast<uint32>( ( static_cast<uint64>(a) * b ) / c ); + return static_cast<uint32>( mul32to64_unsigned( a, b ) / c ); } inline uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c) { - return static_cast<uint32>( ( static_cast<uint64>(a) * b + ( c / 2 ) ) / c ); + return static_cast<uint32>( ( mul32to64_unsigned( a, b ) + ( c / 2 ) ) / c ); } inline int32 muldivrfloor(int64 a, uint32 b, uint32 c) @@ -449,6 +469,7 @@ return (a >= 0) ? mpt::saturate_cast<int32>(a / c) : mpt::saturate_cast<int32>((a - (c - 1)) / c); } + // Greatest Common Divisor. Always returns non-negative number. template <class T> T gcd(T a, T b) Modified: trunk/OpenMPT/common/versionNumber.h =================================================================== --- trunk/OpenMPT/common/versionNumber.h 2014-11-06 20:35:47 UTC (rev 4554) +++ trunk/OpenMPT/common/versionNumber.h 2014-11-06 20:48:55 UTC (rev 4555) @@ -19,7 +19,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 24 #define VER_MINOR 00 -#define VER_MINORMINOR 15 +#define VER_MINORMINOR 16 //Version string. For example "1.17.02.28" #define MPT_VERSION_STR VER_STRINGIZE(VER_MAJORMAJOR) "." VER_STRINGIZE(VER_MAJOR) "." VER_STRINGIZE(VER_MINOR) "." VER_STRINGIZE(VER_MINORMINOR) Modified: trunk/OpenMPT/mptrack/Mpdlgs.cpp =================================================================== --- trunk/OpenMPT/mptrack/Mpdlgs.cpp 2014-11-06 20:35:47 UTC (rev 4554) +++ trunk/OpenMPT/mptrack/Mpdlgs.cpp 2014-11-06 20:48:55 UTC (rev 4555) @@ -1010,11 +1010,11 @@ // Stereo Separation { - m_SliderStereoSep.SetRange(0, 4); - m_SliderStereoSep.SetPos(2); - for (int n=0; n<=4; n++) + m_SliderStereoSep.SetRange(0, 16); + m_SliderStereoSep.SetPos(16); + for (int n = 0; n <= 16; n++) { - if ((int)TrackerSettings::Instance().MixerStereoSeparation <= (int)(32 << n)) + if ((int)TrackerSettings::Instance().MixerStereoSeparation <= 8 * n) { m_SliderStereoSep.SetPos(n); break; @@ -1126,10 +1126,11 @@ { MPT_UNREFERENCED_PARAMETER(n); MPT_UNREFERENCED_PARAMETER(pos); - MPT_UNREFERENCED_PARAMETER(p); // stereo sep + if(p == (CScrollBar *)&m_SliderStereoSep) { UpdateStereoSep(); + OnSettingsChanged(); } } @@ -1154,7 +1155,7 @@ //----------------------------------- { CString s; - s.Format("%d%%", ((32 << m_SliderStereoSep.GetPos()) * 100) / 128); + s.Format(_T("%d%%"), ((8 * m_SliderStereoSep.GetPos()) * 100) / 128); SetDlgItemText(IDC_TEXT_STEREOSEP, s); } @@ -1218,7 +1219,7 @@ // stereo sep { - TrackerSettings::Instance().MixerStereoSeparation = 32 << m_SliderStereoSep.GetPos(); + TrackerSettings::Instance().MixerStereoSeparation = 8 * m_SliderStereoSep.GetPos(); } // soft pan Modified: trunk/OpenMPT/soundlib/MixerSettings.h =================================================================== --- trunk/OpenMPT/soundlib/MixerSettings.h 2014-11-06 20:35:47 UTC (rev 4554) +++ trunk/OpenMPT/soundlib/MixerSettings.h 2014-11-06 20:48:55 UTC (rev 4555) @@ -16,7 +16,7 @@ struct MixerSettings { - UINT m_nStereoSeparation; + int32 m_nStereoSeparation; UINT m_nMaxMixChannels; DWORD DSPMask; DWORD MixerFlags; Modified: trunk/OpenMPT/soundlib/Sndmix.cpp =================================================================== --- trunk/OpenMPT/soundlib/Sndmix.cpp 2014-11-06 20:35:47 UTC (rev 4554) +++ trunk/OpenMPT/soundlib/Sndmix.cpp 2014-11-06 20:48:55 UTC (rev 4555) @@ -127,6 +127,34 @@ } +// Apply stereo separation factor on an interleaved stereo/quad stream. +// count = Number of stereo sample pairs to process +// separation = 0...128 +static void ApplyStereoSeparation(mixsample_t *mixBuf, CSoundFile::samplecount_t count, int32 separation) +//------------------------------------------------------------------------------------------------------- +{ +#ifdef MPT_INTMIXER + const mixsample_t fac1 = 64 + separation / 2, fac2 = 64 - separation / 2; + for(CSoundFile::samplecount_t i = 0; i < count; i++) + { + mixsample_t l = mixBuf[0], r = mixBuf[1]; + mixBuf[0] = static_cast<mixsample_t>((Util::mul32to64(l, fac1) + Util::mul32to64(r, fac2)) >> 7); + mixBuf[1] = static_cast<mixsample_t>((Util::mul32to64(l, fac2) + Util::mul32to64(r, fac1)) >> 7); + mixBuf += 2; + } +#else + const mixsample_t fac1 = static_cast<mixsample_t>(64 + separation / 2), fac2 = static_cast<mixsample_t>(64 - separation / 2); + for(CSoundFile::samplecount_t i = 0; i < count; i++) + { + mixsample_t l = mixBuf[0], r = mixBuf[1]; + mixBuf[0] = (l * fac1 + r * fac2) / mixsample_t(128); + mixBuf[1] = (l * fac2 + r * fac1) / mixsample_t(128); + mixBuf += 2; + } +#endif +} + + CSoundFile::samplecount_t CSoundFile::Read(samplecount_t count, IAudioReadTarget &target) //--------------------------------------------------------------------------------------- { @@ -236,6 +264,12 @@ InterleaveFrontRear(MixSoundBuffer, MixRearBuffer, countChunk); } + if(m_MixerSettings.m_nStereoSeparation < 128 && m_MixerSettings.gnChannels >= 2) + { + // Apply stereo separation + ApplyStereoSeparation(MixSoundBuffer, count * m_MixerSettings.gnChannels / 2, m_MixerSettings.m_nStereoSeparation); + } + target.DataCallback(MixSoundBuffer, m_MixerSettings.gnChannels, countChunk); // Buffer ready @@ -1984,10 +2018,7 @@ // Adjusting volumes if (m_MixerSettings.gnChannels >= 2) { - int pan = ((int)pChn->nRealPan) - 128; - pan *= (int)m_MixerSettings.m_nStereoSeparation; - pan /= 128; - pan += 128; + int32 pan = pChn->nRealPan; Limit(pan, 0, 256); LONG realvol; This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |