AudRecordLib
|
00001 00006 #ifndef AUDRECORD_CONVERT_H 00007 #define AUDRECORD_CONVERT_H 00008 00009 #pragma once 00010 00011 #include <boost/function.hpp> 00012 #include "ctnumlimits.h" 00013 #include "misc.h" 00014 00016 typedef boost::function<DWORD (LPCVOID, DWORD, PVOID)> ConverterFnPtr; 00017 00023 namespace detail 00024 { 00032 template<bool cond, class TrueArg, class FalseArg> 00033 struct IfThenElse; 00034 00038 template<class TrueType, class FalseType> 00039 struct IfThenElse<true, TrueType, FalseType> 00040 { 00043 typedef TrueType type; 00044 }; 00045 00049 template<class TrueType, class FalseType> 00050 struct IfThenElse<false, TrueType, FalseType> 00051 { 00055 typedef FalseType type; 00056 }; 00057 00063 template<class Source, class Dest> 00064 struct ScaleFactor 00065 { 00069 typedef typename IfThenElse<(sizeof(Source) < sizeof(Dest)), float, Source>::type ScaleType; 00071 static const ScaleType value; 00072 }; 00073 00078 template<class Source, class Dest> 00079 const typename ScaleFactor<Source, Dest>::ScaleType ScaleFactor<Source, Dest>::value = CTNumLimits<Source>::max / static_cast<ScaleType>(CTNumLimits<Dest>::max); 00080 00084 template<class Source> 00085 struct ScaleFactor<Source, Source> 00086 { 00088 typedef Source ScaleType; 00090 static const unsigned value = 1; 00091 }; 00092 00098 #define CONVERT_PREAMBLE() \ 00099 const SourceSampleType* pSrcSamples = static_cast<const SourceSampleType*>(pSrcArray); \ 00100 DestSampleType* pDstSamples = static_cast<DestSampleType*>(pDstArray); \ 00101 typedef ScaleFactor<SourceSampleType, DestSampleType> ScaleFactorType; \ 00102 const typename ScaleFactorType::ScaleType scaleFactor = ScaleFactorType::value; 00103 00109 #define CONVERT_RETURN() \ 00110 return static_cast<DWORD>(reinterpret_cast<BYTE*>(pDstSamples) - static_cast<BYTE*>(pDstArray)); 00111 00125 template<class SourceSampleType, class DestSampleType> 00126 DWORD ConvertChannelEqual( 00127 LPCVOID pSrcArray, 00128 DWORD numFrames, 00129 PVOID pDstArray, 00130 WORD srcChannels, 00131 WORD 00132 ) 00133 { 00134 CONVERT_PREAMBLE(); 00135 DWORD frameCount = 0; 00136 while((frameCount++) < numFrames) 00137 { 00138 for(WORD i = 0; i < srcChannels; ++i) 00139 { 00140 *(pDstSamples++) = static_cast<DestSampleType>((*(pSrcSamples++)) / scaleFactor); 00141 } 00142 } 00143 CONVERT_RETURN(); 00144 } 00145 00158 template<class DestSampleType> 00159 DWORD ConvertChannelEqual( 00160 LPCVOID pSrcArray, 00161 DWORD numFrames, 00162 PVOID pDstArray, 00163 WORD srcChannels 00164 ) 00165 { 00166 const float* pSrcSamples = static_cast<const float*>(pSrcArray); 00167 DestSampleType* pDstSamples = static_cast<DestSampleType*>(pDstArray); 00168 static const float scaleFactor = static_cast<float>(CTNumLimits<DestSampleType>::max); 00169 DWORD frameCount = 0; 00170 while((frameCount++) < numFrames) 00171 { 00172 for(WORD i = 0; i < srcChannels; ++i) 00173 { 00174 *(pDstSamples++) = static_cast<DestSampleType>((*(pSrcSamples++)) * scaleFactor); 00175 } 00176 } 00177 CONVERT_RETURN(); 00178 } 00179 00180 namespace SSE 00181 { 00182 void StoreConvertedSamples(short* pDstSamples, const __m128& samples); 00183 void StoreConvertedSamples(long* pDstSamples, const __m128& samples); 00184 void StoreConvertedSamples(short*& pDstSamples, __m128 samples[4]); 00185 void StoreConvertedSamples(long*& pDstSamples, __m128 samples[4]); 00186 __m128i LongShortToShorts(__m128& samples); 00187 void Get16ConvertedSamples(const float*& pSrcSamples, __m128 samplePacks[4], const __m128& scaleFactors); 00188 00201 template<class DestSampleType> 00202 void Convert16SamplesLoop(const float*& pSrcSamples, DestSampleType*& pDstSamples, DWORD numPacks, const __m128& scaleFactors) 00203 { 00204 while(numPacks > 0) 00205 { 00206 __m128 samplePacks[4]; 00207 Get16ConvertedSamples(pSrcSamples, samplePacks, scaleFactors); 00208 StoreConvertedSamples(pDstSamples, samplePacks); 00209 --numPacks; 00210 } 00211 } 00212 } 00213 00227 template<class DestSampleType> 00228 DWORD ConvertChannelEqualSSE( 00229 LPCVOID pSrcArray, 00230 DWORD numFrames, 00231 PVOID pDstArray, 00232 WORD srcChannels 00233 ) 00234 { 00235 // assert that the source floats are 16 byte aligned 00236 ASSERT((PtrToUlong(pSrcArray) & 0xF) == 0); 00237 const float* pSrcSamples = static_cast<const float*>(pSrcArray); 00238 DestSampleType* pDstSamples = static_cast<DestSampleType*>(pDstArray); 00239 const float scaleFactor = static_cast<float>(CTNumLimits<DestSampleType>::max); 00240 UINT numFloats = numFrames * srcChannels; 00241 UINT numFloatPacks = numFloats / 16; 00242 __m128 scaleFactors = _mm_load1_ps(&scaleFactor); 00243 00244 // multiply floats on the scale of [-1.0 to 1.0] by scaleFactor in 16 float chunks 00245 SSE::Convert16SamplesLoop(pSrcSamples, pDstSamples, numFloatPacks, scaleFactors); 00246 00247 // then do any 4 float packs left over 00248 UINT num4Floats = (numFloats & 0xF) / 4; 00249 while(num4Floats > 0) 00250 { 00251 __m128 procSamples = _mm_load_ps(pSrcSamples); 00252 procSamples = _mm_mul_ps(procSamples, scaleFactors); 00253 SSE::StoreConvertedSamples(pDstSamples, procSamples); 00254 pDstSamples += 4; 00255 pSrcSamples += 4; 00256 --num4Floats; 00257 } 00258 // convert any odd samples left over 00259 switch(numFloats & 3) 00260 { 00261 case 3: 00262 { 00263 float sample = *(pSrcSamples++); 00264 *(pDstSamples++) = static_cast<DestSampleType>(sample * scaleFactor); 00265 } 00266 case 2: 00267 { 00268 float sample = *(pSrcSamples++); 00269 *(pDstSamples++) = static_cast<DestSampleType>(sample * scaleFactor); 00270 } 00271 case 1: 00272 { 00273 float sample = *(pSrcSamples++); 00274 *(pDstSamples++) = static_cast<DestSampleType>(sample * scaleFactor); 00275 } 00276 } 00277 CONVERT_RETURN(); 00278 } 00279 00294 template<class SourceSampleType, class DestSampleType> 00295 DWORD ConvertChannelDown( 00296 LPCVOID pSrcArray, 00297 DWORD numFrames, 00298 PVOID pDstArray, 00299 WORD srcChannels, 00300 WORD dstChannels 00301 ) 00302 { 00303 CONVERT_PREAMBLE(); 00304 DWORD frameCount = 0; 00305 WORD sourcesPerDest = srcChannels / dstChannels; 00306 const WORD leftOver = srcChannels % dstChannels; 00307 while((frameCount++) < numFrames) 00308 { 00309 WORD leftOverCount = leftOver; 00310 long thisChannelSample = 0; 00311 for(WORD i = 0; i < dstChannels; ++i) 00312 { 00313 WORD samplesConverted = sourcesPerDest; 00314 // accumulate converted samples 00315 for(WORD j = 0; j < sourcesPerDest; ++j) 00316 { 00317 thisChannelSample += static_cast<long>((*(pSrcSamples++) / scaleFactor)); 00318 } 00319 // include the unaccounted for samples/channels at the rate of 00320 // one extra per dstChannel until we've used them all 00321 if(leftOverCount > 0) 00322 { 00323 thisChannelSample += static_cast<long>((*(pSrcSamples++) / scaleFactor)); 00324 --leftOverCount; 00325 ++samplesConverted; 00326 } 00327 // average it 00328 thisChannelSample /= samplesConverted; 00329 // write the average 00330 *(pDstSamples++) = static_cast<DestSampleType>(thisChannelSample); 00331 } 00332 } 00333 CONVERT_RETURN(); 00334 } 00335 00350 template<class SourceSampleType, class DestSampleType> 00351 DWORD ConvertChannelUp( 00352 LPCVOID pSrcArray, 00353 DWORD numFrames, 00354 PVOID pDstArray, 00355 WORD srcChannels, 00356 WORD dstChannels 00357 ) 00358 { 00359 CONVERT_PREAMBLE(); 00360 DWORD frameCount = 0; 00361 WORD destsPerSources = dstChannels / srcChannels; 00362 WORD remainderChans = dstChannels % srcChannels; 00363 while((frameCount++) < numFrames) 00364 { 00365 WORD remainderCount = remainderChans; 00366 DestSampleType thisChannelSample = 0; 00367 for(WORD i = 0; i < srcChannels; ++i) 00368 { 00369 // replicate converted sample 00370 thisChannelSample = static_cast<DestSampleType>((*(pSrcSamples++)) / scaleFactor); 00371 for(WORD j = 0; j < destsPerSources; ++j) 00372 { 00373 *(pDstSamples++) = thisChannelSample; 00374 } 00375 // plus an extra one to deal with any unaccounted for channels 00376 if(remainderCount) 00377 { 00378 *(pDstSamples++) = thisChannelSample; 00379 --remainderCount; 00380 } 00381 } 00382 } 00383 CONVERT_RETURN(); 00384 } 00385 00386 // documented in the cpp file 00387 DWORD ConvertCopy(LPCVOID pSrcArray, DWORD numFrames, PVOID pDstArray, WORD sampleSize, WORD numChannels); 00388 00389 #undef CONVERT_PREAMBLE 00390 #undef CONVERT_RETURN 00391 } 00392 00393 // documented in the cpp file 00394 void DetermineSampleConverter(const tWAVEFORMATEX& inp, const tWAVEFORMATEX& out, ConverterFnPtr& converter); 00395 00398 #endif