From: <man...@us...> - 2013-11-23 08:18:46
|
Revision: 3293 http://sourceforge.net/p/modplug/code/3293 Author: manxorist Date: 2013-11-23 08:18:31 +0000 (Sat, 23 Nov 2013) Log Message: ----------- [Ref] sounddev: Pass a complete channel mapping around instead of just a base channel offset (there is no GUI yet though). [Ref] ASIO: Handle channel mappings. Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/common/versionNumber.h trunk/OpenMPT/mptrack/Mpdlgs.cpp trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/mptrack/TrackerSettings.h trunk/OpenMPT/sounddev/SoundDevice.cpp trunk/OpenMPT/sounddev/SoundDevice.h trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/common/misc_util.h 2013-11-23 08:18:31 UTC (rev 3293) @@ -107,6 +107,50 @@ } +namespace mpt { namespace String { + +// Combine a vector of values into a string, separated with the given separator. +// No escaping is performed. +template<typename T> +std::string Combine(const std::vector<T> &vals, const std::string &sep=",") +//------------------------------------------------------------------------- +{ + std::string str; + for(std::size_t i = 0; i < vals.size(); ++i) + { + if(i > 0) + { + str += sep; + } + str += mpt::ToString(vals[i]); + } + return str; +} + +// Split the given string at separator positions into individual values returned as a vector. +// An empty string results in an empty vector. +// Leading or trailing separators result in a default-constructed element being inserted before or after the other elements. +template<typename T> +std::vector<T> Split(const std::string &str, const std::string &sep=",") +//---------------------------------------------------------------------- +{ + std::vector<T> vals; + std::size_t pos = 0; + while(str.find(sep, pos) != std::string::npos) + { + vals.push_back(ConvertStrTo<int>(str.substr(pos, str.find(sep, pos) - pos))); + pos = str.find(sep, pos) + sep.length(); + } + if(!vals.empty() || (str.substr(pos).length() > 0)) + { + vals.push_back(ConvertStrTo<T>(str.substr(pos))); + } + return vals; +} + +} } // namespace mpt::String + + // Memset given object to zero. template <class T> inline void MemsetZero(T &a) Modified: trunk/OpenMPT/common/versionNumber.h =================================================================== --- trunk/OpenMPT/common/versionNumber.h 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/common/versionNumber.h 2013-11-23 08:18:31 UTC (rev 3293) @@ -17,7 +17,7 @@ #define VER_MAJORMAJOR 1 #define VER_MAJOR 22 #define VER_MINOR 07 -#define VER_MINORMINOR 02 +#define VER_MINORMINOR 03 //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 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/mptrack/Mpdlgs.cpp 2013-11-23 08:18:31 UTC (rev 3293) @@ -334,7 +334,7 @@ { int ndx = m_CbnBaseChannel.AddString(mpt::ToCString(m_CurrentDeviceCaps.channelNames[channel])); m_CbnBaseChannel.SetItemData(ndx, channel); - if(channel == m_Settings.BaseChannel) + if(channel == m_Settings.ChannelMapping.GetBaseChannel()) { sel = ndx; } @@ -595,7 +595,7 @@ { if(m_CurrentDeviceInfo.id.GetType() == SNDDEV_ASIO) { - m_Settings.BaseChannel = m_CbnBaseChannel.GetItemData(m_CbnBaseChannel.GetCurSel()); + m_Settings.ChannelMapping = SoundChannelMapping::BaseChannel(m_Settings.Channels, m_CbnBaseChannel.GetItemData(m_CbnBaseChannel.GetCurSel())); } } CMainFrame::GetMainFrame()->SetupSoundCard(m_Settings, m_CurrentDeviceInfo.id); Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-11-23 08:18:31 UTC (rev 3293) @@ -160,7 +160,7 @@ , m_SoundDeviceExclusiveMode(conf, "Sound Settings", "ExclusiveMode", SoundDeviceSettings().ExclusiveMode) , m_SoundDeviceBoostThreadPriority(conf, "Sound Settings", "BoostThreadPriority", SoundDeviceSettings().BoostThreadPriority) , m_SoundDeviceUseHardwareTiming(conf, "Sound Settings", "UseHardwareTiming", SoundDeviceSettings().UseHardwareTiming) - , m_SoundDeviceBaseChannel(conf, "Sound Settings", "ASIOBaseChannel", SoundDeviceSettings().BaseChannel) + , m_SoundDeviceChannelMapping(conf, "Sound Settings", "ChannelMapping", SoundDeviceSettings().ChannelMapping) , MixerMaxChannels(conf, "Sound Settings", "MixChannels", MixerSettings().m_nMaxMixChannels) , MixerDSPMask(conf, "Sound Settings", "Quality", MixerSettings().DSPMask) , MixerFlags(conf, "Sound Settings", "SoundSetup", MixerSettings().MixerFlags) @@ -337,6 +337,10 @@ } // Sound Settings + if(storedVersion < MAKE_VERSION_NUMERIC(1,22,07,03)) + { + m_SoundDeviceChannelMapping = SoundChannelMapping::BaseChannel(MixerOutputChannels, conf.Read<int>("Sound Settings", "ASIOBaseChannel", 0)); + } if(storedVersion < MAKE_VERSION_NUMERIC(1,21,01,26)) { if(m_BufferLength_DEPRECATED != 0) @@ -464,7 +468,7 @@ settings.sampleFormat = m_SampleFormat; settings.ExclusiveMode = m_SoundDeviceExclusiveMode; settings.BoostThreadPriority = m_SoundDeviceBoostThreadPriority; - settings.BaseChannel = m_SoundDeviceBaseChannel; + settings.ChannelMapping = m_SoundDeviceChannelMapping; return settings; } @@ -478,7 +482,7 @@ m_SampleFormat = settings.sampleFormat; m_SoundDeviceExclusiveMode = settings.ExclusiveMode; m_SoundDeviceBoostThreadPriority = settings.BoostThreadPriority; - m_SoundDeviceBaseChannel = settings.BaseChannel; + m_SoundDeviceChannelMapping = settings.ChannelMapping; } Modified: trunk/OpenMPT/mptrack/TrackerSettings.h =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.h 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/mptrack/TrackerSettings.h 2013-11-23 08:18:31 UTC (rev 3293) @@ -204,6 +204,9 @@ template<> inline SettingValue ToSettingValue(const SampleFormat &val) { return SettingValue(int32(val.value)); } template<> inline SampleFormat FromSettingValue(const SettingValue &val) { return SampleFormatEnum(val.as<int32>()); } +template<> inline SettingValue ToSettingValue(const SoundChannelMapping &val) { return SettingValue(val.ToString(), "ChannelMapping"); } +template<> inline SoundChannelMapping FromSettingValue(const SettingValue &val) { ASSERT(val.GetTypeTag() == "ChannelMapping"); return SoundChannelMapping::FromString(val.as<std::string>()); } + template<> inline SettingValue ToSettingValue(const ResamplingMode &val) { return SettingValue(int32(val)); } template<> inline ResamplingMode FromSettingValue(const SettingValue &val) { return ResamplingMode(val.as<int32>()); } @@ -277,7 +280,7 @@ Setting<bool> m_SoundDeviceExclusiveMode; Setting<bool> m_SoundDeviceBoostThreadPriority; Setting<bool> m_SoundDeviceUseHardwareTiming; - Setting<uint32> m_SoundDeviceBaseChannel; + Setting<SoundChannelMapping> m_SoundDeviceChannelMapping; SoundDeviceSettings GetSoundDeviceSettings() const; void SetSoundDeviceSettings(const SoundDeviceSettings &settings); Modified: trunk/OpenMPT/sounddev/SoundDevice.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.cpp 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/sounddev/SoundDevice.cpp 2013-11-23 08:18:31 UTC (rev 3293) @@ -26,6 +26,78 @@ #include <iterator> + +SoundChannelMapping::SoundChannelMapping() +//---------------------------------------- +{ + return; +} + + +SoundChannelMapping::SoundChannelMapping(const std::vector<uint32> &mapping) +//-------------------------------------------------------------------------- + : ChannelToDeviceChannel(mapping) +{ + return; +} + + +SoundChannelMapping SoundChannelMapping::BaseChannel(uint32 channels, uint32 baseChannel) +//--------------------------------------------------------------------------------------- +{ + SoundChannelMapping result; + result.ChannelToDeviceChannel.clear(); + if(baseChannel == 0) + { + return result; + } + result.ChannelToDeviceChannel.resize(channels); + for(uint32 channel = 0; channel < channels; ++channel) + { + result.ChannelToDeviceChannel[channel] = channel + baseChannel; + } + return result; +} + + +bool SoundChannelMapping::IsValid(uint32 channels) const +//------------------------------------------------------ +{ + if(ChannelToDeviceChannel.empty()) + { + return true; + } + if(ChannelToDeviceChannel.size() < channels) + { + return false; + } + std::map<uint32, uint32> inverseMapping; + for(uint32 channel = 0; channel < channels; ++channel) + { + inverseMapping[ChannelToDeviceChannel[channel]] = channel; + } + if(inverseMapping.size() != channels) + { + return false; + } + return true; +} + + +std::string SoundChannelMapping::ToString() const +//----------------------------------------------- +{ + return mpt::String::Combine<uint32>(ChannelToDeviceChannel); +} + + +SoundChannelMapping SoundChannelMapping::FromString(const std::string &str) +//------------------------------------------------------------------------- +{ + return SoundChannelMapping(mpt::String::Split<uint32>(str)); +} + + /////////////////////////////////////////////////////////////////////////////////////// // // ISoundDevice base class @@ -125,6 +197,10 @@ if(m_Settings.LatencyMS > SNDDEV_MAXLATENCY_MS) m_Settings.LatencyMS = SNDDEV_MAXLATENCY_MS; if(m_Settings.UpdateIntervalMS < SNDDEV_MINUPDATEINTERVAL_MS) m_Settings.UpdateIntervalMS = SNDDEV_MINUPDATEINTERVAL_MS; if(m_Settings.UpdateIntervalMS > SNDDEV_MAXUPDATEINTERVAL_MS) m_Settings.UpdateIntervalMS = SNDDEV_MAXUPDATEINTERVAL_MS; + if(!m_Settings.ChannelMapping.IsValid(m_Settings.Channels)) + { + return false; + } m_BufferAttributes.Latency = m_Settings.LatencyMS / 1000.0; m_BufferAttributes.UpdateInterval = m_Settings.UpdateIntervalMS / 1000.0; m_BufferAttributes.NumBuffers = 0; Modified: trunk/OpenMPT/sounddev/SoundDevice.h =================================================================== --- trunk/OpenMPT/sounddev/SoundDevice.h 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/sounddev/SoundDevice.h 2013-11-23 08:18:31 UTC (rev 3293) @@ -158,6 +158,83 @@ #define SNDDEV_MAXUPDATEINTERVAL_MS 200 +struct SoundChannelMapping +{ + +private: + + std::vector<uint32> ChannelToDeviceChannel; + +public: + + // Construct default identity mapping + SoundChannelMapping(); + + // Construct mapping from given vector. + SoundChannelMapping(const std::vector<uint32> &mapping); + + // Construct mapping for #channels with a baseChannel offset. + static SoundChannelMapping BaseChannel(uint32 channels, uint32 baseChannel); + +public: + + bool operator == (const SoundChannelMapping &cmp) const + { + return (ChannelToDeviceChannel == cmp.ChannelToDeviceChannel); + } + + // check that the channel mapping is actually a 1:1 mapping + bool IsValid(uint32 channels) const; + + // Get the base channel offset. Deprecated because this has no defined semantics for more complex mappings. + MPT_DEPRECATED uint32 GetBaseChannel() const + { + if(ChannelToDeviceChannel.empty()) + { + return 0; + } + return ChannelToDeviceChannel[0]; + } + + // Get the number of required device channels for this mapping. Derived from the maximum mapped-to channel number. + uint32 GetRequiredDeviceChannels() const + { + if(ChannelToDeviceChannel.empty()) + { + return 0; + } + uint32 maxChannel = 0; + for(uint32 channel = 0; channel < ChannelToDeviceChannel.size(); ++channel) + { + if(ChannelToDeviceChannel[channel] > maxChannel) + { + maxChannel = ChannelToDeviceChannel[channel]; + } + } + return maxChannel + 1; + } + + // Convert OpenMPT channel number to the mapped device channel number. + uint32 ToDevice(uint32 channel) const + { + if(ChannelToDeviceChannel.empty()) + { + return channel; + } + if(channel >= ChannelToDeviceChannel.size()) + { + return channel; + } + return ChannelToDeviceChannel[channel]; + } + + std::string ToString() const; + + static SoundChannelMapping FromString(const std::string &str); + +}; + + struct SoundDeviceSettings { HWND hWnd; @@ -169,7 +246,7 @@ bool ExclusiveMode; // Use hardware buffers directly bool BoostThreadPriority; // Boost thread priority for glitch-free audio rendering bool UseHardwareTiming; - uint32 BaseChannel; + SoundChannelMapping ChannelMapping; SoundDeviceSettings() : hWnd(NULL) , LatencyMS(100) @@ -180,7 +257,6 @@ , ExclusiveMode(false) , BoostThreadPriority(true) , UseHardwareTiming(false) - , BaseChannel(0) { return; } @@ -196,7 +272,7 @@ && ExclusiveMode == cmp.ExclusiveMode && BoostThreadPriority == cmp.BoostThreadPriority && UseHardwareTiming == cmp.UseHardwareTiming - && BaseChannel == cmp.BaseChannel + && ChannelMapping == cmp.ChannelMapping ; } bool operator != (const SoundDeviceSettings &cmp) const Modified: trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp =================================================================== --- trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-11-23 08:08:44 UTC (rev 3292) +++ trunk/OpenMPT/sounddev/SoundDeviceASIO.cpp 2013-11-23 08:18:31 UTC (rev 3293) @@ -243,6 +243,10 @@ { throw ASIOException("Not enough output channels."); } + if(m_Settings.ChannelMapping.GetRequiredDeviceChannels() > (std::size_t)outputChannels) + { + throw ASIOException("Channel mapping requires more channels than available."); + } Log(mpt::String::Print("ASIO: setSampleRate(sampleRate=%1)", m_Settings.Samplerate)); asioCall(setSampleRate(m_Settings.Samplerate)); @@ -320,7 +324,7 @@ { MemsetZero(m_BufferInfo[channel]); m_BufferInfo[channel].isInput = ASIOFalse; - m_BufferInfo[channel].channelNum = channel + m_Settings.BaseChannel; // map MPT channel i to ASIO channel i + m_BufferInfo[channel].channelNum = m_Settings.ChannelMapping.ToDevice(channel); } m_Callbacks.bufferSwitch = CallbackBufferSwitch; m_Callbacks.sampleRateDidChange = CallbackSampleRateDidChange; @@ -337,13 +341,13 @@ { MemsetZero(m_ChannelInfo[channel]); m_ChannelInfo[channel].isInput = ASIOFalse; - m_ChannelInfo[channel].channel = channel + m_Settings.BaseChannel; // map MPT channel i to ASIO channel i + m_ChannelInfo[channel].channel = m_Settings.ChannelMapping.ToDevice(channel); asioCall(getChannelInfo(&m_ChannelInfo[channel])); ASSERT(m_ChannelInfo[channel].isActive); mpt::String::SetNullTerminator(m_ChannelInfo[channel].name); Log(mpt::String::Print("ASIO: getChannelInfo(isInput=%1 channel=%2) => isActive=%3 channelGroup=%4 type=%5 name='%6'" , ASIOFalse - , channel + m_Settings.BaseChannel + , m_Settings.ChannelMapping.ToDevice(channel) , m_ChannelInfo[channel].isActive , m_ChannelInfo[channel].channelGroup , m_ChannelInfo[channel].type This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |