From: <man...@us...> - 2013-07-13 15:59:47
|
Revision: 2538 http://sourceforge.net/p/modplug/code/2538 Author: manxorist Date: 2013-07-13 15:59:38 +0000 (Sat, 13 Jul 2013) Log Message: ----------- [New] OpenMPT normalizes 24bit und 32bit integer and floating point samples on load to increase precision (because OpenMPT currently only supports 16bit integer samples internally) and to transparently support floating point samples with wrong full scale range. This adjusts the relative volume of samples which do not contain full amplitude values (or which have higher peaks). This is not always desireable, e.g. when sample were specifically recorded in the same environment and their relative maximum peak is different on purpose. This behaviour can now be globally disabled by setting the hidden setting "[Sample Editor]MayNormalizeSamplesOnLoad=0" (default is the old behaviour). [Mod] When loading such high resolution .wav files which are part of a DLS bank, OpenMPT now never normalizes them, ignoring the new setting. The rationale is, in a soundbank of multiple instruments you almost always want to preserve their relative volume. [Mod] On the other hand, when loading .wav files as a module, OpenMPT always normalizes because there is little use in not doing it here. [Mod] Furthermore, for samples which did get normalized, we now adjust the global sample volume so that their relative volume stays at least roughly in the same range as before normalization. Because of lack of precision of the global volume field and the fact that it only can attenuate and not amplify the sample, this is really just a rough approximation. [New] Support reading floating point .wav files written with old versions of Syntrillium CoolEdit. CoolEdit calls these formats 16.8 float and 24.0 float, referencing the amplitude of full scale values. These formats use a non-standard WAVEFORMAT. Details are documented in the code. [Fix] Adjust the heuristic of never trusting the WAVEFORMAT header value BlockAlign (which is a useful heuristic to load some corrupted samples) to only not trust BlockAlign if the value really is 0 or at least twice as big as expected. This fixes support for 20bit-in-24bit integer PCM .wav files without WAVEFORMATEXTENSIBLE. Modified Paths: -------------- trunk/OpenMPT/common/misc_util.h trunk/OpenMPT/mptrack/Ctrl_ins.cpp trunk/OpenMPT/mptrack/Ctrl_smp.cpp trunk/OpenMPT/mptrack/MainFrm.cpp trunk/OpenMPT/mptrack/Moddoc.cpp trunk/OpenMPT/mptrack/TrackerSettings.cpp trunk/OpenMPT/mptrack/TrackerSettings.h trunk/OpenMPT/mptrack/View_smp.cpp trunk/OpenMPT/soundlib/Dlsbank.cpp trunk/OpenMPT/soundlib/Load_itp.cpp trunk/OpenMPT/soundlib/Load_umx.cpp trunk/OpenMPT/soundlib/Load_wav.cpp trunk/OpenMPT/soundlib/SampleFormatConverters.h trunk/OpenMPT/soundlib/SampleFormats.cpp trunk/OpenMPT/soundlib/SampleIO.cpp trunk/OpenMPT/soundlib/SampleIO.h trunk/OpenMPT/soundlib/Sndfile.h trunk/OpenMPT/soundlib/WAVTools.cpp trunk/OpenMPT/soundlib/WAVTools.h Modified: trunk/OpenMPT/common/misc_util.h =================================================================== --- trunk/OpenMPT/common/misc_util.h 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/common/misc_util.h 2013-07-13 15:59:38 UTC (rev 2538) @@ -403,6 +403,16 @@ return static_cast<int32>( ( static_cast<int64>(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 ); + } + inline uint32 muldivr_unsigned(uint32 a, uint32 b, uint32 c) + { + return static_cast<uint32>( ( static_cast<uint64>(a) * b + ( c / 2 ) ) / c ); + } + inline int32 muldivrfloor(int64 a, uint32 b, uint32 c) { a *= b; Modified: trunk/OpenMPT/mptrack/Ctrl_ins.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/Ctrl_ins.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -1419,7 +1419,7 @@ m_modDoc.SetModified(); } if (!m_nInstrument) m_nInstrument = 1; - if (m_sndFile.ReadInstrumentFromFile(m_nInstrument, lpFile, len)) + if (m_sndFile.ReadInstrumentFromFile(m_nInstrument, lpFile, len, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad)) { m_modDoc.UpdateAllViews(NULL, HINT_SAMPLEINFO | HINT_MODTYPE, NULL); // -> CODE#0023 Modified: trunk/OpenMPT/mptrack/Ctrl_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/Ctrl_smp.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -754,7 +754,7 @@ { m_modDoc.GetSampleUndo().PrepareUndo(m_nSample, sundo_replace); FileReader file(lpFile, len); - bOk = m_sndFile.ReadSampleFromFile(m_nSample, file); + bOk = m_sndFile.ReadSampleFromFile(m_nSample, file, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad); } if (!bOk) @@ -779,6 +779,11 @@ SampleIO sampleIO = dlg.GetSampleFormat(); + if(TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad) + { + sampleIO.MayNormalize(); + } + if(sampleIO.GetBitDepth() != 8) { sample.nLength /= 2; Modified: trunk/OpenMPT/mptrack/MainFrm.cpp =================================================================== --- trunk/OpenMPT/mptrack/MainFrm.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/MainFrm.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -1575,13 +1575,13 @@ // Avoid hanging audio while reading file - we have removed all sample and instrument references before, // so it's safe to replace the sample / instrument now. cs.Leave(); - ok = m_WaveFile.ReadInstrumentFromFile(1, p, dwLen); + ok = m_WaveFile.ReadInstrumentFromFile(1, p, dwLen, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad); cs.Enter(); if(!ok) { // Try reading as sample if reading as instrument fails FileReader file(p, dwLen); - ok = m_WaveFile.ReadSampleFromFile(1, file); + ok = m_WaveFile.ReadSampleFromFile(1, file, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad); m_WaveFile.AllocateInstrument(1, 1); } } Modified: trunk/OpenMPT/mptrack/Moddoc.cpp =================================================================== --- trunk/OpenMPT/mptrack/Moddoc.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/Moddoc.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -342,7 +342,7 @@ if ((len) && ((lpFile = (LPBYTE)GlobalAllocPtr(GHND, len)) != NULL)) { f.Read(lpFile, len); - m_SndFile.ReadInstrumentFromFile(nIns, lpFile, len); + m_SndFile.ReadInstrumentFromFile(nIns, lpFile, len, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad); _splitpath(pszMidiMapName, NULL, NULL, szName, szExt); strncat(szName, szExt, sizeof(szName)); pIns = m_SndFile.Instruments[nIns]; Modified: trunk/OpenMPT/mptrack/TrackerSettings.cpp =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/TrackerSettings.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -106,6 +106,7 @@ // Sample Editor m_nSampleUndoMaxBuffer = 0; // Real sample buffer undo size will be set later. + m_MayNormalizeSamplesOnLoad = true; GetDefaultColourScheme(rgbCustomColors); @@ -469,6 +470,7 @@ m_nSampleUndoMaxBuffer = CMainFrame::GetPrivateProfileLong("Sample Editor" , "UndoBufferSize", m_nSampleUndoMaxBuffer >> 20, iniFile); m_nSampleUndoMaxBuffer = MAX(1, m_nSampleUndoMaxBuffer) << 20; + m_MayNormalizeSamplesOnLoad = CMainFrame::GetPrivateProfileBool("Sample Editor" , "MayNormalizeSamplesOnLoad", m_MayNormalizeSamplesOnLoad, iniFile); PatternClipboard::SetClipboardSize(GetPrivateProfileInt("Pattern Editor", "NumClipboards", PatternClipboard::GetClipboardSize(), iniFile)); @@ -870,6 +872,8 @@ CMainFrame::WritePrivateProfileDWord("Pattern Editor", "NumClipboards", PatternClipboard::GetClipboardSize(), iniFile); + CMainFrame::WritePrivateProfileBool("Sample Editor", "MayNormalizeSamplesOnLoad", m_MayNormalizeSamplesOnLoad, iniFile); + // Write default paths const bool bConvertPaths = theApp.IsPortableMode(); TCHAR szPath[_MAX_PATH] = ""; Modified: trunk/OpenMPT/mptrack/TrackerSettings.h =================================================================== --- trunk/OpenMPT/mptrack/TrackerSettings.h 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/TrackerSettings.h 2013-07-13 15:59:38 UTC (rev 2538) @@ -211,6 +211,7 @@ // Sample Editor Setup UINT m_nSampleUndoMaxBuffer; + bool m_MayNormalizeSamplesOnLoad; // key config TCHAR m_szKbdFile[_MAX_PATH]; Modified: trunk/OpenMPT/mptrack/View_smp.cpp =================================================================== --- trunk/OpenMPT/mptrack/View_smp.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/mptrack/View_smp.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -1969,7 +1969,7 @@ memcpy(s, pSndFile->m_szNames[m_nSample], 32); memcpy(s2, sample.filename, 22); FileReader file(p, dwMemSize); - pSndFile->ReadSampleFromFile(m_nSample, file); + pSndFile->ReadSampleFromFile(m_nSample, file, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad); if (!pSndFile->m_szNames[m_nSample][0]) { memcpy(pSndFile->m_szNames[m_nSample], s, 32); Modified: trunk/OpenMPT/soundlib/Dlsbank.cpp =================================================================== --- trunk/OpenMPT/soundlib/Dlsbank.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/Dlsbank.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -1565,7 +1565,7 @@ } else { FileReader file(pWaveForm, dwLen); - bWaveForm = sndFile.ReadWAVSample(nSample, file, &wsmpChunk); + bWaveForm = sndFile.ReadWAVSample(nSample, file, false, &wsmpChunk); } if (bWaveForm) { Modified: trunk/OpenMPT/soundlib/Load_itp.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_itp.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/Load_itp.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -16,6 +16,7 @@ #include "stdafx.h" #ifdef MODPLUG_TRACKER #include "../mptrack/mptrack.h" +#include "../mptrack/TrackerSettings.h" #endif #include "../common/version.h" #include "Loaders.h" @@ -228,7 +229,7 @@ LPBYTE lpFile = f.Lock(size); if(!lpFile) { f.Close(); continue; } - ReadInstrumentFromFile(ins + 1, lpFile, size); + ReadInstrumentFromFile(ins + 1, lpFile, size, TrackerSettings::Instance().m_MayNormalizeSamplesOnLoad); f.Close(); } Modified: trunk/OpenMPT/soundlib/Load_umx.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_umx.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/Load_umx.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -291,7 +291,7 @@ } else if(isSound && GetNumSamples() < MAX_SAMPLES - 1) { // Read as sample - if(ReadSampleFromFile(GetNumSamples() + 1, fileChunk)) + if(ReadSampleFromFile(GetNumSamples() + 1, fileChunk, true)) { m_nSamples++; if(static_cast<size_t>(objName) < names.size()) Modified: trunk/OpenMPT/soundlib/Load_wav.cpp =================================================================== --- trunk/OpenMPT/soundlib/Load_wav.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/Load_wav.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -19,14 +19,14 @@ // WAV file support -template <typename SampleConverter> -bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelIndex, size_t numChannels) -//----------------------------------------------------------------------------------------------------- +template <typename SampleConversion> +bool CopyWavChannel(ModSample &sample, const FileReader &file, size_t channelIndex, size_t numChannels, SampleConversion conv = SampleConversion()) +//------------------------------------------------------------------------------------------------------------------------------------------------- { ASSERT(sample.GetNumChannels() == 1); - ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConverter::output_t)); + ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); - const size_t offset = channelIndex * sizeof(typename SampleConverter::input_t) * SampleConverter::input_inc; + const size_t offset = channelIndex * sizeof(typename SampleConversion::input_t) * SampleConversion::input_inc; if(sample.AllocateSample() == 0 || !file.CanRead(offset)) { @@ -34,7 +34,7 @@ } const char *inBuf = file.GetRawData(); - CopySample<SampleConverter>(reinterpret_cast<typename SampleConverter::output_t*>(sample.pSample), sample.nLength, 1, inBuf + offset, file.BytesLeft() - offset, numChannels); + CopySample<SampleConversion>(reinterpret_cast<typename SampleConversion::output_t*>(sample.pSample), sample.nLength, 1, inBuf + offset, file.BytesLeft() - offset, numChannels, conv); CSoundFile::AdjustSampleLoop(sample); return true; } @@ -155,7 +155,7 @@ if(wavFile.GetSampleFormat() == WAVFormatChunk::fmtFloat) { - CopyWavChannel<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + CopyWavChannel<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); } else { if(wavFile.GetBitsPerSample() <= 8) @@ -166,10 +166,10 @@ CopyWavChannel<SC::DecodeInt16<0, littleEndian16> >(sample, sampleChunk, channel, wavFile.GetNumChannels()); } else if(wavFile.GetBitsPerSample() <= 24) { - CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + CopyWavChannel<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); } else if(wavFile.GetBitsPerSample() <= 32) { - CopyWavChannel<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); + CopyWavChannel<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sampleChunk, channel, wavFile.GetNumChannels()); } } Modified: trunk/OpenMPT/soundlib/SampleFormatConverters.h =================================================================== --- trunk/OpenMPT/soundlib/SampleFormatConverters.h 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/SampleFormatConverters.h 2013-07-13 15:59:38 UTC (rev 2538) @@ -163,6 +163,24 @@ } }; +template <size_t loLoByteIndex, size_t loHiByteIndex, size_t hiLoByteIndex, size_t hiHiByteIndex> +struct DecodeScaledFloat32 +{ + typedef char input_t; + typedef float32 output_t; + static const int input_inc = 4; + float factor; + forceinline output_t operator() (const input_t *inBuf) + { + return factor * DecodeFloatLE(uint8_4(uint8(inBuf[loLoByteIndex]), uint8(inBuf[loHiByteIndex]), uint8(inBuf[hiLoByteIndex]), uint8(inBuf[hiHiByteIndex]))); + } + forceinline DecodeScaledFloat32(float scaleFactor) + : factor(scaleFactor) + { + return; + } +}; + template <typename Tsample> struct ReadSample { @@ -307,6 +325,12 @@ typename Func1::output_t tmp = func1(inBuf); return func2(&tmp); } + forceinline ConversionChain(Func2 f2 = Func2(), Func1 f1 = Func1()) + : func1(f1) + , func2(f2) + { + return; + } }; @@ -319,6 +343,7 @@ { typedef int32 input_t; typedef int32 output_t; + typedef uint32 peak_t; static const int input_inc = 1; uint32 maxVal; Normalize() : maxVal(0) { } @@ -347,6 +372,10 @@ { return Util::muldivrfloor(*inBuf, (uint32)1 << 31, maxVal); } + forceinline peak_t GetSrcPeak() const + { + return maxVal; + } }; template <> @@ -354,6 +383,7 @@ { typedef float32 input_t; typedef float32 output_t; + typedef float32 peak_t; static const int input_inc = 1; uint32 intMaxVal; float maxValInv; @@ -386,6 +416,10 @@ { return *inBuf * maxValInv; } + forceinline peak_t GetSrcPeak() const + { + return DecodeFloatNE(intMaxVal); + } }; @@ -397,10 +431,12 @@ struct NormalizationChain { typedef typename Func1::input_t input_t; + typedef typename Func1::output_t normalize_t; + typedef typename Normalize<normalize_t>::peak_t peak_t; typedef typename Func2::output_t output_t; static const int input_inc = Func1::input_inc; Func1 func1; - Normalize<typename Func1::output_t> normalize; + Normalize<normalize_t> normalize; Func2 func2; forceinline void FindMax(const input_t *inBuf) { @@ -414,10 +450,20 @@ forceinline output_t operator() (const input_t *inBuf) { typename Func1::output_t tmp1 = func1(inBuf); - typename Func1::output_t norm = normalize(&tmp1); + normalize_t norm = normalize(&tmp1); typename Func2::output_t tmp2 = func2(&norm); return tmp2; } + forceinline peak_t GetSrcPeak() const + { + return normalize.GetSrcPeak(); + } + forceinline NormalizationChain(Func2 f2 = Func2(), Func1 f1 = Func1()) + : func1(f1) + , func2(f2) + { + return; + } }; @@ -440,14 +486,14 @@ // Template arguments: // SampleConversion: Functor of type SampleConversionFunctor to apply sample conversion (see above for existing functors). template <typename SampleConversion> -size_t CopySample(typename SampleConversion::output_t *outBuf, size_t numSamples, size_t incTarget, const typename SampleConversion::input_t *inBuf, size_t sourceSize, size_t incSource) -//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +size_t CopySample(typename SampleConversion::output_t *outBuf, size_t numSamples, size_t incTarget, const typename SampleConversion::input_t *inBuf, size_t sourceSize, size_t incSource, SampleConversion conv = SampleConversion()) +//----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- { const size_t sampleSize = incSource * SampleConversion::input_inc; LimitMax(numSamples, sourceSize / sampleSize); const size_t copySize = numSamples * sampleSize; - SampleConversion sampleConv; + SampleConversion sampleConv(conv); while(numSamples--) { *outBuf = sampleConv(inBuf); @@ -461,8 +507,8 @@ // Copy a mono sample data buffer. template <typename SampleConversion> -size_t CopyMonoSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize) -//----------------------------------------------------------------------------------- +size_t CopyMonoSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion()) +//------------------------------------------------------------------------------------------------------------------------------- { ASSERT(sample.GetNumChannels() == 1); ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); @@ -470,7 +516,7 @@ const size_t frameSize = SampleConversion::input_inc; const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength); size_t numFrames = countFrames; - SampleConversion sampleConv; + SampleConversion sampleConv(conv); const char * inBuf = sourceBuffer; typename SampleConversion::output_t * outBuf = reinterpret_cast<typename SampleConversion::output_t *>(sample.pSample); while(numFrames--) @@ -485,8 +531,8 @@ // Copy a stereo interleaved sample data buffer. template <typename SampleConversion> -size_t CopyStereoInterleavedSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize) -//------------------------------------------------------------------------------------------------ +size_t CopyStereoInterleavedSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion()) +//-------------------------------------------------------------------------------------------------------------------------------------------- { ASSERT(sample.GetNumChannels() == 2); ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); @@ -494,8 +540,8 @@ const size_t frameSize = 2 * SampleConversion::input_inc; const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength); size_t numFrames = countFrames; - SampleConversion sampleConvLeft; - SampleConversion sampleConvRight; + SampleConversion sampleConvLeft(conv); + SampleConversion sampleConvRight(conv); const char * inBuf = sourceBuffer; typename SampleConversion::output_t * outBuf = reinterpret_cast<typename SampleConversion::output_t *>(sample.pSample); while(numFrames--) @@ -513,8 +559,8 @@ // Copy a stereo split sample data buffer. template <typename SampleConversion> -size_t CopyStereoSplitSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize) -//------------------------------------------------------------------------------------------ +size_t CopyStereoSplitSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize, SampleConversion conv = SampleConversion()) +//-------------------------------------------------------------------------------------------------------------------------------------- { ASSERT(sample.GetNumChannels() == 2); ASSERT(sample.GetElementarySampleSize() == sizeof(typename SampleConversion::output_t)); @@ -522,8 +568,8 @@ const size_t frameSize = 2 * SampleConversion::input_inc; const size_t countFrames = std::min<size_t>(sourceSize / frameSize, sample.nLength); size_t numFrames = countFrames; - SampleConversion sampleConvLeft; - SampleConversion sampleConvRight; + SampleConversion sampleConvLeft(conv); + SampleConversion sampleConvRight(conv); const char * inBufLeft = sourceBuffer; const char * inBufRight = sourceBuffer + sample.nLength * SampleConversion::input_inc; typename SampleConversion::output_t * outBuf = reinterpret_cast<typename SampleConversion::output_t *>(sample.pSample); @@ -542,8 +588,8 @@ // Copy a sample data buffer and normalize it. Requires slightly advanced sample conversion functor. template<typename SampleConversion> -size_t CopyAndNormalizeSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize) -//------------------------------------------------------------------------------------------- +size_t CopyAndNormalizeSample(ModSample &sample, const char *sourceBuffer, size_t sourceSize, typename SampleConversion::peak_t *srcPeak = nullptr, SampleConversion conv = SampleConversion()) +//--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- { const size_t inSize = sizeof(typename SampleConversion::input_t); @@ -554,7 +600,7 @@ const char * inBuf = sourceBuffer; // Finding max value - SampleConversion sampleConv; + SampleConversion sampleConv(conv); for(size_t i = numSamples; i != 0; i--) { sampleConv.FindMax(inBuf); @@ -576,5 +622,10 @@ } } + if(srcPeak) + { + *srcPeak = sampleConv.GetSrcPeak(); + } + return numSamples * inSize; } Modified: trunk/OpenMPT/soundlib/SampleFormats.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/SampleFormats.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -57,8 +57,8 @@ #endif // NO_MP3_SAMPLES -bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file) -//------------------------------------------------------------------------ +bool CSoundFile::ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize) +//------------------------------------------------------------------------------------------- { file.Rewind(); @@ -66,10 +66,10 @@ const DWORD dwFileLength = file.GetLength(); if(!nSample || nSample >= MAX_SAMPLES) return false; - if(!ReadWAVSample(nSample, file) + if(!ReadWAVSample(nSample, file, mayNormalize) && !ReadXISample(nSample, file) && !ReadITISample(nSample, file) - && !ReadAIFFSample(nSample, file) + && !ReadAIFFSample(nSample, file, mayNormalize) && !ReadITSSample(nSample, file) && !ReadPATSample(nSample, const_cast<BYTE*>(lpMemFile), dwFileLength) && !Read8SVXSample(nSample, const_cast<BYTE*>(lpMemFile), dwFileLength) @@ -88,8 +88,8 @@ } -bool CSoundFile::ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength) -//--------------------------------------------------------------------------------------------------------- +bool CSoundFile::ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength, bool mayNormalize) +//---------------------------------------------------------------------------------------------------------------------------- { FileReader file(lpMemFile, dwFileLength); if ((!nInstr) || (nInstr >= MAX_INSTRUMENTS)) return false; @@ -97,15 +97,15 @@ && (!ReadPATInstrument(nInstr, lpMemFile, dwFileLength)) && (!ReadITIInstrument(nInstr, file)) // Generic read - && (!ReadSampleAsInstrument(nInstr, file))) return false; + && (!ReadSampleAsInstrument(nInstr, file, mayNormalize))) return false; if(nInstr > GetNumInstruments()) m_nInstruments = nInstr; return true; } -bool CSoundFile::ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file) -//------------------------------------------------------------------------------- +bool CSoundFile::ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize) +//-------------------------------------------------------------------------------------------------- { file.Rewind(); @@ -153,7 +153,7 @@ DestroyInstrument(nInstr, deleteAssociatedSamples); Instruments[nInstr] = pIns; - ReadSampleFromFile(nSample, file); + ReadSampleFromFile(nSample, file, mayNormalize); return true; } return false; @@ -352,8 +352,8 @@ extern bool IMAADPCMUnpack16(int16 *target, SmpLength sampleLen, FileReader file, uint16 blockAlign); -bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, FileReader *wsmpChunk) -//------------------------------------------------------------------------------------------ +bool CSoundFile::ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize, FileReader *wsmpChunk) +//------------------------------------------------------------------------------------------------------------- { WAVReader wavFile(file); @@ -393,6 +393,31 @@ { // MP3 in WAV return ReadMP3Sample(nSample, sampleChunk); + } else if(!wavFile.IsExtensibleFormat() && wavFile.MayBeCoolEdit16_8() && wavFile.GetSampleFormat() == WAVFormatChunk::fmtPCM && wavFile.GetBitsPerSample() == 32 && wavFile.GetBlockAlign() == wavFile.GetNumChannels() * 4) + { + // Syntrillium Cool Edit hack to store IEEE 32bit floating point + // Format is described as 32bit integer PCM contained in 32bit blocks and an WAVEFORMATEX extension size of 2 which contains a single 16 bit little endian value of 1. + // (This is parsed in WAVTools.cpp and returned via MayBeCoolEdit16_8()). + // The data actually stored in this case is little endian 32bit floating point PCM with 2**15 full scale. + // Cool Edit calls this format "16.8 float". + SampleIO sampleIO( + SampleIO::_32bit, + (wavFile.GetNumChannels() > 1) ? SampleIO::stereoInterleaved : SampleIO::mono, + SampleIO::littleEndian, + SampleIO::floatPCM15); + sampleIO.ReadSample(sample, sampleChunk); + } else if(!wavFile.IsExtensibleFormat() && wavFile.GetSampleFormat() == WAVFormatChunk::fmtPCM && wavFile.GetBitsPerSample() == 24 && wavFile.GetBlockAlign() == wavFile.GetNumChannels() * 4) + { + // Syntrillium Cool Edit hack to store IEEE 32bit floating point + // Format is described as 24bit integer PCM contained in 32bit blocks. + // The data actually stored in this case is little endian 32bit floating point PCM with 2**23 full scale. + // Cool Edit calls this format "24.0 float". + SampleIO sampleIO( + SampleIO::_32bit, + (wavFile.GetNumChannels() > 1) ? SampleIO::stereoInterleaved : SampleIO::mono, + SampleIO::littleEndian, + SampleIO::floatPCM23); + sampleIO.ReadSample(sample, sampleChunk); } else { // PCM / Float @@ -409,6 +434,11 @@ sampleIO |= SampleIO::floatPCM; } + if(mayNormalize) + { + sampleIO.MayNormalize(); + } + sampleIO.ReadSample(sample, sampleChunk); } @@ -1247,8 +1277,8 @@ #endif -bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file) -//-------------------------------------------------------------------- +bool CSoundFile::ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize) +//--------------------------------------------------------------------------------------- { file.Rewind(); ChunkReader chunkFile(file); @@ -1316,6 +1346,11 @@ sampleIO |= SampleIO::floatPCM; } + if(mayNormalize) + { + sampleIO.MayNormalize(); + } + soundChunk.Skip(sampleHeader.offset); ModSample &mptSample = Samples[nSample]; Modified: trunk/OpenMPT/soundlib/SampleIO.cpp =================================================================== --- trunk/OpenMPT/soundlib/SampleIO.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/SampleIO.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -230,54 +230,228 @@ } ////////////////////////////////////////////////////// + // 24-Bit / Signed / Mono / PCM + else if(GetBitDepth() == 24 && GetChannelFormat() == mono && GetEncoding() == signedPCM) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); + } else + { + bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); + } + } + + ////////////////////////////////////////////////////// + // 24-Bit / Signed / Stereo Interleaved / PCM + else if(GetBitDepth() == 24 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); + } else + { + bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Signed / Mono / PCM + else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == signedPCM) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); + } else + { + bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Signed / Stereo Interleaved / PCM + else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == signedPCM) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); + } else + { + bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Float / Mono / PCM + else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); + } else + { + bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Float / Stereo Interleaved / PCM + else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); + } else + { + bytesRead = CopyStereoInterleavedSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); + } + } + + ////////////////////////////////////////////////////// // 24-Bit / Signed / Mono, Stereo Interleaved / PCM - else if(GetBitDepth() == 24 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCM) + else if(GetBitDepth() == 24 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit + uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { - bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); - //bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize); + bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, littleEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } else { - bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); - //bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize); + bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt24<0, bigEndian24> > >(sample, sourceBuf, fileSize, &srcPeak); } + if(bytesRead) + { + // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. + sample.nGlobalVol = static_cast<uint16>(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(0), uint32(64))); + } } ////////////////////////////////////////////////////// // 32-Bit / Signed / Mono, Stereo Interleaved / PCM - else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCM) + else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == signedPCMnormalize) { // Normalize to 16-Bit + uint32 srcPeak = uint32(1)<<31; if(GetEndianness() == littleEndian) { - bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); - //bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize); + bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { - bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); - //bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize); + bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, int32>, SC::DecodeInt32<0, bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } + if(bytesRead) + { + // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. + sample.nGlobalVol = static_cast<uint16>(Clamp(Util::muldivr_unsigned(sample.nGlobalVol, srcPeak, uint32(1)<<31), uint32(0), uint32(64))); + } } ////////////////////////////////////////////////////// // 32-Bit / Float / Mono, Stereo Interleaved / PCM - else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == floatPCM) + else if(GetBitDepth() == 32 && (GetChannelFormat() == mono || GetChannelFormat() == stereoInterleaved) && GetEncoding() == floatPCMnormalize) { // Normalize to 16-Bit + float32 srcPeak = 1.0f; if(GetEndianness() == littleEndian) { - bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); - //bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize); + bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<littleEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } else { - bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); - //bytesRead = CopyMonoSample<SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize); + bytesRead = CopyAndNormalizeSample<SC::NormalizationChain<SC::Convert<int16, float32>, SC::DecodeFloat32<bigEndian32> > >(sample, sourceBuf, fileSize, &srcPeak); } + if(bytesRead) + { + // Adjust sample volume so we do not affect relative volume of the sample. Normalizing is only done to increase precision. + sample.nGlobalVol = Util::Round<uint16>(Clamp(sample.nGlobalVol * srcPeak, 0.0f, 64.0f)); + } } ////////////////////////////////////////////////////// + // 32-Bit / Float / Mono / PCM / full scale 2^15 + else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM15) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyMonoSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<15))) + ); + } else + { + bytesRead = CopyMonoSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<15))) + ); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^15 + else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM15) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyStereoInterleavedSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<15))) + ); + } else + { + bytesRead = CopyStereoInterleavedSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<15))) + ); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 + else if(GetBitDepth() == 32 && GetChannelFormat() == mono && GetEncoding() == floatPCM23) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyMonoSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<23))) + ); + } else + { + bytesRead = CopyMonoSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<23))) + ); + } + } + + ////////////////////////////////////////////////////// + // 32-Bit / Float / Stereo Interleaved / PCM / full scale 2^23 + else if(GetBitDepth() == 32 && GetChannelFormat() == stereoInterleaved && GetEncoding() == floatPCM23) + { + if(GetEndianness() == littleEndian) + { + bytesRead = CopyStereoInterleavedSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<littleEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<littleEndian32>(1.0f / static_cast<float>(1<<23))) + ); + } else + { + bytesRead = CopyStereoInterleavedSample + (sample, sourceBuf, fileSize, + SC::ConversionChain<SC::Convert<int16, float32>, SC::DecodeScaledFloat32<bigEndian32> > + (SC::Convert<int16, float32>(), SC::DecodeScaledFloat32<bigEndian32>(1.0f / static_cast<float>(1<<23))) + ); + } + } + + ////////////////////////////////////////////////////// // Compressed samples if(*this == SampleIO(_8bit, mono, littleEndian, ADPCM)) { Modified: trunk/OpenMPT/soundlib/SampleIO.h =================================================================== --- trunk/OpenMPT/soundlib/SampleIO.h 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/SampleIO.h 2013-07-13 15:59:38 UTC (rev 2538) @@ -66,19 +66,23 @@ // Sample encoding enum Encoding { - signedPCM = 0, // Integer PCM, signed - unsignedPCM, // Integer PCM, unsigned - deltaPCM, // Integer PCM, delta-encoded - floatPCM, // Floating point PCM - IT214, // Impulse Tracker 2.14 compressed - IT215, // Impulse Tracker 2.15 compressed - AMS, // AMS / Velvet Studio packed - DMF, // DMF Huffman compression - MDL, // MDL Huffman compression - PTM8Dto16, // PTM 8-Bit delta value -> 16-Bit sample - PCM7to8, // 8-Bit sample data with unused high bit - ADPCM, // 4-Bit ADPCM-packed - MT2, // MadTracker 2 stereo delta encoding + signedPCM = 0, // Integer PCM, signed + unsignedPCM, // Integer PCM, unsigned + deltaPCM, // Integer PCM, delta-encoded + floatPCM, // Floating point PCM + IT214, // Impulse Tracker 2.14 compressed + IT215, // Impulse Tracker 2.15 compressed + AMS, // AMS / Velvet Studio packed + DMF, // DMF Huffman compression + MDL, // MDL Huffman compression + PTM8Dto16, // PTM 8-Bit delta value -> 16-Bit sample + PCM7to8, // 8-Bit sample data with unused high bit + ADPCM, // 4-Bit ADPCM-packed + MT2, // MadTracker 2 stereo delta encoding + floatPCM15, // Floating point PCM with 2^15 full scale + floatPCM23, // Floating point PCM with 2^23 full scale + floatPCMnormalize, // Floating point PCM and data will be normalized while reading + signedPCMnormalize, // Integer PCM and data will be normalized while reading }; SampleIO(Bitdepth bits = _8bit, Channels channels = mono, Endianness endianness = littleEndian, Encoding encoding = signedPCM) @@ -117,6 +121,20 @@ format = (format & ~encodingMask) | (encoding << encodingOffset); } + void MayNormalize() + { + if(GetBitDepth() == 24 || GetBitDepth() == 32) + { + if(GetEncoding() == SampleIO::signedPCM) + { + (*this) |= SampleIO::signedPCMnormalize; + } else if(GetEncoding() == SampleIO::floatPCM) + { + (*this) |= SampleIO::floatPCMnormalize; + } + } + } + // Get bits per sample uint8 GetBitDepth() const { Modified: trunk/OpenMPT/soundlib/Sndfile.h =================================================================== --- trunk/OpenMPT/soundlib/Sndfile.h 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/Sndfile.h 2013-07-13 15:59:38 UTC (rev 2538) @@ -784,11 +784,11 @@ static void AdjustSampleLoop(ModSample &sample); // Samples file I/O - bool ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file); - bool ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, FileReader *wsmpChunk = nullptr); + bool ReadSampleFromFile(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize=false); + bool ReadWAVSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize=false, FileReader *wsmpChunk = nullptr); bool ReadPATSample(SAMPLEINDEX nSample, const LPBYTE lpMemFile, DWORD dwFileLength); bool ReadS3ISample(SAMPLEINDEX nSample, FileReader &file); - bool ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file); + bool ReadAIFFSample(SAMPLEINDEX nSample, FileReader &file, bool mayNormalize=false); bool ReadXISample(SAMPLEINDEX nSample, FileReader &file); bool ReadITSSample(SAMPLEINDEX nSample, FileReader &file, bool rewind = true); bool ReadITISample(SAMPLEINDEX nSample, FileReader &file); @@ -802,11 +802,11 @@ #endif // Instrument file I/O - bool ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); + bool ReadInstrumentFromFile(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength, bool mayNormalize=false); bool ReadXIInstrument(INSTRUMENTINDEX nInstr, FileReader &file); bool ReadITIInstrument(INSTRUMENTINDEX nInstr, FileReader &file); bool ReadPATInstrument(INSTRUMENTINDEX nInstr, const LPBYTE lpMemFile, DWORD dwFileLength); - bool ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file); + bool ReadSampleAsInstrument(INSTRUMENTINDEX nInstr, FileReader &file, bool mayNormalize=false); #ifndef MODPLUG_NO_FILESAVE bool SaveXIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName) const; bool SaveITIInstrument(INSTRUMENTINDEX nInstr, const LPCSTR lpszFileName, bool compress) const; Modified: trunk/OpenMPT/soundlib/WAVTools.cpp =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.cpp 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/WAVTools.cpp 2013-07-13 15:59:38 UTC (rev 2538) @@ -24,6 +24,8 @@ RIFFHeader fileHeader; isDLS = false; + extFormat = 0; + mayBeCoolEdit16_8 = false; if(!file.ReadConvertEndianness(fileHeader) || (fileHeader.magic != RIFFHeader::idRIFF && fileHeader.magic != RIFFHeader::idLIST) || (fileHeader.type != RIFFHeader::idWAVE && fileHeader.type != RIFFHeader::idwave)) @@ -62,14 +64,24 @@ { return; } - if(formatInfo.format == WAVFormatChunk::fmtExtensible) + if(formatInfo.format == WAVFormatChunk::fmtPCM && formatChunk.BytesLeft() == 4) { + uint16 size = formatChunk.ReadIntLE<uint16>(); + uint16 value = formatChunk.ReadIntLE<uint16>(); + if(size == 2 && value == 1) + { + // May be Cool Edit 16.8 format. + // See SampleFormats.cpp for details. + mayBeCoolEdit16_8 = true; + } + } else if(formatInfo.format == WAVFormatChunk::fmtExtensible) + { WAVFormatChunkExtension extFormat; if(!formatChunk.ReadConvertEndianness(extFormat)) { return; } - formatInfo.format = extFormat.subFormat; + this->extFormat = extFormat.subFormat; } // Read sample data @@ -87,8 +99,17 @@ if((formatInfo.format != WAVFormatChunk::fmtIMA_ADPCM || sampleLength == 0) && GetSampleSize() != 0) { - // Some samples have an incorrect blockAlign / sample size set (e.g. it's 8 in SQUARE.WAV while it should be 1), so let's better not trust this value. - sampleLength = sampleData.GetLength() / GetSampleSize(); + if((GetBlockAlign() == 0) || (GetBlockAlign() / GetNumChannels() >= 2 * GetSampleSize())) + { + // Some samples have an incorrect blockAlign / sample size set (e.g. it's 8 in SQUARE.WAV while it should be 1), so let's better not always trust this value. + // The idea here is, if block align is off by twice or more, it is unlikely to be describing sample padding inside the block. + // Ignore it in this case and calculate the length based on the single sample size and number of channels instead. + sampleLength = sampleData.GetLength() / GetSampleSize(); + } else + { + // Correct case (so that 20bit WAVEFORMATEX files work). + sampleLength = sampleData.GetLength() / GetBlockAlign(); + } } // Check for loop points, texts, etc... Modified: trunk/OpenMPT/soundlib/WAVTools.h =================================================================== --- trunk/OpenMPT/soundlib/WAVTools.h 2013-07-13 15:48:20 UTC (rev 2537) +++ trunk/OpenMPT/soundlib/WAVTools.h 2013-07-13 15:59:38 UTC (rev 2538) @@ -334,6 +334,8 @@ FileReader::off_t sampleLength; bool isDLS; WAVFormatChunk formatInfo; + uint16 extFormat; + bool mayBeCoolEdit16_8; public: WAVReader(FileReader &inputFile); @@ -343,13 +345,15 @@ void FindMetadataChunks(ChunkReader::ChunkList<RIFFChunk> &chunks); // Self-explanatory getters. - WAVFormatChunk::SampleFormats GetSampleFormat() const { return static_cast<WAVFormatChunk::SampleFormats>(formatInfo.format); } + WAVFormatChunk::SampleFormats GetSampleFormat() const { return IsExtensibleFormat() ? static_cast<WAVFormatChunk::SampleFormats>(extFormat) : static_cast<WAVFormatChunk::SampleFormats>(formatInfo.format); } uint16 GetNumChannels() const { return formatInfo.numChannels; } uint16 GetBitsPerSample() const { return formatInfo.bitsPerSample; } uint32 GetSampleRate() const { return formatInfo.sampleRate; } uint16 GetBlockAlign() const { return formatInfo.blockAlign; } FileReader GetSampleData() const { return sampleData; } FileReader GetWsmpChunk() const { return wsmpChunk; } + bool IsExtensibleFormat() const { return formatInfo.format == WAVFormatChunk::fmtExtensible; } + bool MayBeCoolEdit16_8() const { return mayBeCoolEdit16_8; } // Get size of a single sample point, in bytes. uint16 GetSampleSize() const { return ((GetNumChannels() * GetBitsPerSample()) + 7) / 8; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |