AudRecordLib
convert.h
Go to the documentation of this file.
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
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Defines