Windows2003-3790/termsrv/rdpclip/dumpcod.c

895 lines
24 KiB
C

#include <windows.h>
#include <stdlib.h>
#include <mmsystem.h>
#include <mmreg.h>
#include <msacm.h>
#include <stdlib.h>
#include <stdio.h>
#define TSSND_NATIVE_BITSPERSAMPLE 16
#define TSSND_NATIVE_CHANNELS 2
#define TSSND_NATIVE_SAMPLERATE 22050
#define TSSND_NATIVE_BLOCKALIGN ((TSSND_NATIVE_BITSPERSAMPLE * \
TSSND_NATIVE_CHANNELS) / 8)
#define TSSND_NATIVE_AVGBYTESPERSEC (TSSND_NATIVE_BLOCKALIGN * \
TSSND_NATIVE_SAMPLERATE)
#define TSSND_SAMPLESPERBLOCK 8192
//
// Defines
//
#undef ASSERT
#ifdef DBG
#define TRC _DebugMessage
#define ASSERT(_x_) if (!(_x_)) \
{ TRC(FATAL, "ASSERT failed, line %d, file %s\n", \
__LINE__, __FILE__); DebugBreak(); }
#else // !DBG
#define TRC
#define ASSERT
#endif // !DBG
#define TSMALLOC( _x_ ) malloc( _x_ )
#define TSFREE( _x_ ) free( _x_ )
#ifndef G723MAGICWORD1
#define G723MAGICWORD1 0xf7329ace
#endif
#ifndef G723MAGICWORD2
#define G723MAGICWORD2 0xacdeaea2
#endif
#ifndef VOXWARE_KEY
#define VOXWARE_KEY "35243410-F7340C0668-CD78867B74DAD857-AC71429AD8CAFCB5-E4E1A99E7FFD-371"
#endif
#ifndef WMAUDIO_KEY
#define WMAUDIO_KEY "F6DC9830-BC79-11d2-A9D0-006097926036"
#endif
#ifndef WMAUDIO_DEC_KEY
#define WMAUDIO_DEC_KEY "1A0F78F0-EC8A-11d2-BBBE-006008320064"
#endif
#define WAVE_FORMAT_WMAUDIO2 0x161
const CHAR *ALV = "TSSNDD::ALV - ";
const CHAR *INF = "TSSNDD::INF - ";
const CHAR *WRN = "TSSNDD::WRN - ";
const CHAR *ERR = "TSSNDD::ERR - ";
const CHAR *FATAL = "TSSNDD::FATAL - ";
typedef struct _VCSNDFORMATLIST {
struct _VCSNDFORMATLIST *pNext;
HACMDRIVERID hacmDriverId;
WAVEFORMATEX Format;
// additional data for the format
} VCSNDFORMATLIST, *PVCSNDFORMATLIST;
#ifdef _WIN32
#include <pshpack1.h>
#else
#ifndef RC_INVOKED
#pragma pack(1)
#endif
#endif
typedef struct wmaudio2waveformat_tag {
WAVEFORMATEX wfx;
DWORD dwSamplesPerBlock; // only counting "new" samples "= half of what will be used due to overlapping
WORD wEncodeOptions;
DWORD dwSuperBlockAlign; // the big size... should be multiples of wfx.nBlockAlign.
} WMAUDIO2WAVEFORMAT;
typedef struct msg723waveformat_tag {
WAVEFORMATEX wfx;
WORD wConfigWord;
DWORD dwCodeword1;
DWORD dwCodeword2;
} MSG723WAVEFORMAT;
typedef struct intelg723waveformat_tag {
WAVEFORMATEX wfx;
WORD wConfigWord;
DWORD dwCodeword1;
DWORD dwCodeword2;
} INTELG723WAVEFORMAT;
typedef struct tagVOXACM_WAVEFORMATEX
{
WAVEFORMATEX wfx;
DWORD dwCodecId;
DWORD dwMode;
char szKey[72];
} VOXACM_WAVEFORMATEX, *PVOXACM_WAVEFORMATEX, FAR *LPVOXACM_WAVEFORMATEX;
#ifdef _WIN32
#include <poppack.h>
#else
#ifndef RC_INVOKED
#pragma pack()
#endif
#endif
/////////////////////////////////////////////////////////////////////
//
// Tracing
//
/////////////////////////////////////////////////////////////////////
VOID
_cdecl
_DebugMessage(
LPCSTR szLevel,
LPCSTR szFormat,
...
)
{
CHAR szBuffer[256];
va_list arglist;
if (szLevel == ALV)
return;
va_start (arglist, szFormat);
_vsnprintf (szBuffer, sizeof(szBuffer), szFormat, arglist);
va_end (arglist);
// printf( "%s:%s", szLevel, szBuffer );
OutputDebugStringA(szLevel);
OutputDebugStringA(szBuffer);
}
/*
* Function:
* _VCSmdFindSuggestedConverter
*
* Description:
* Searches for intermidiate converter
*
*/
BOOL
_VCSndFindSuggestedConverter(
HACMDRIVERID hadid,
LPWAVEFORMATEX pDestFormat,
LPWAVEFORMATEX pInterrimFmt
)
{
BOOL rv = FALSE;
MMRESULT mmres;
HACMDRIVER hacmDriver = NULL;
HACMSTREAM hacmStream = NULL;
ASSERT( NULL != pDestFormat );
ASSERT( NULL != hadid );
ASSERT( NULL != pInterrimFmt );
//
// first, open the destination acm driver
//
mmres = acmDriverOpen(&hacmDriver, hadid, 0);
if ( MMSYSERR_NOERROR != mmres )
{
TRC(ERR, "_VCSndFindSuggestedConverter: can't "
"open the acm driver: %d\n",
mmres);
goto exitpt;
}
//
// first probe with the native format
// if it passes, we don't need intermidiate
// format converter
//
pInterrimFmt->wFormatTag = WAVE_FORMAT_PCM;
pInterrimFmt->nChannels = TSSND_NATIVE_CHANNELS;
pInterrimFmt->nSamplesPerSec = TSSND_NATIVE_SAMPLERATE;
pInterrimFmt->nAvgBytesPerSec = TSSND_NATIVE_AVGBYTESPERSEC;
pInterrimFmt->nBlockAlign = TSSND_NATIVE_BLOCKALIGN;
pInterrimFmt->wBitsPerSample = TSSND_NATIVE_BITSPERSAMPLE;
pInterrimFmt->cbSize = 0;
mmres = acmStreamOpen(
&hacmStream,
hacmDriver,
pInterrimFmt,
pDestFormat,
NULL, // filter
0, // callback
0, // dwinstance
ACM_STREAMOPENF_NONREALTIME
);
if ( MMSYSERR_NOERROR == mmres )
{
//
// format is supported
//
rv = TRUE;
goto exitpt;
} else {
TRC(ALV, "_VCSndFindSuggestedConverter: format is not supported\n");
}
//
// find a suggested intermidiate PCM format
//
mmres = acmFormatSuggest(
hacmDriver,
pDestFormat,
pInterrimFmt,
sizeof( *pInterrimFmt ),
ACM_FORMATSUGGESTF_WFORMATTAG
);
if ( MMSYSERR_NOERROR != mmres )
{
TRC(ALV, "_VCSndFindSuggestedConverter: can't find "
"interrim format: %d\n",
mmres);
goto exitpt;
}
if ( 16 != pInterrimFmt->wBitsPerSample ||
( 1 != pInterrimFmt->nChannels &&
2 != pInterrimFmt->nChannels) ||
( 8000 != pInterrimFmt->nSamplesPerSec &&
11025 != pInterrimFmt->nSamplesPerSec &&
12000 != pInterrimFmt->nSamplesPerSec &&
16000 != pInterrimFmt->nSamplesPerSec &&
22050 != pInterrimFmt->nSamplesPerSec)
)
{
TRC(ALV, "_VCSndFindSuggestedConverter: not supported "
"interrim format. Details:\n");
TRC(ALV, "Channels - %d\n", pInterrimFmt->nChannels);
TRC(ALV, "SamplesPerSec - %d\n", pInterrimFmt->nSamplesPerSec);
TRC(ALV, "AvgBytesPerSec - %d\n", pInterrimFmt->nAvgBytesPerSec);
TRC(ALV, "BlockAlign - %d\n", pInterrimFmt->nBlockAlign);
TRC(ALV, "BitsPerSample - %d\n", pInterrimFmt->wBitsPerSample);
goto exitpt;
}
if ( 1 == pInterrimFmt->nChannels )
{
switch ( pInterrimFmt->nSamplesPerSec )
{
case 8000:
case 11025:
case 12000:
case 16000:
case 22050:
break;
default:
ASSERT( 0 );
}
} else {
switch ( pInterrimFmt->nSamplesPerSec )
{
case 8000:
case 11025:
case 12000:
case 16000:
case 22050:
break;
default:
ASSERT( 0 );
}
}
//
// probe with this format
//
mmres = acmStreamOpen(
&hacmStream,
hacmDriver,
pInterrimFmt,
pDestFormat,
NULL, // filter
0, // callback
0, // dwinstance
ACM_STREAMOPENF_NONREALTIME
);
if ( MMSYSERR_NOERROR != mmres )
{
TRC(ALV, "_VCSndFindSuggestedConverter: probing the suggested "
"format failed: %d\n",
mmres);
goto exitpt;
}
TRC(ALV, "_VCSndFindSuggestedConverter: found intermidiate PCM format\n");
TRC(ALV, "Channels - %d\n", pInterrimFmt->nChannels);
TRC(ALV, "SamplesPerSec - %d\n", pInterrimFmt->nSamplesPerSec);
TRC(ALV, "AvgBytesPerSec - %d\n", pInterrimFmt->nAvgBytesPerSec);
TRC(ALV, "BlockAlign - %d\n", pInterrimFmt->nBlockAlign);
TRC(ALV, "BitsPerSample - %d\n", pInterrimFmt->wBitsPerSample);
rv = TRUE;
exitpt:
if ( NULL != hacmStream )
acmStreamClose( hacmStream, 0 );
if ( NULL != hacmDriver )
acmDriverClose( hacmDriver, 0 );
return rv;
}
/*
* Function:
* _VCSndOrderFormatList
*
* Description:
* Order all formats in descendant order
*
*/
VOID
_VCSndOrderFormatList(
PVCSNDFORMATLIST *ppFormatList,
DWORD *pdwNum
)
{
PVCSNDFORMATLIST pFormatList;
PVCSNDFORMATLIST pLessThan;
PVCSNDFORMATLIST pPrev;
PVCSNDFORMATLIST pNext;
PVCSNDFORMATLIST pIter;
PVCSNDFORMATLIST pIter2;
DWORD dwNum = 0;
ASSERT ( NULL != ppFormatList );
pFormatList = *ppFormatList;
pLessThan = NULL;
//
// fill both lists
//
pIter = pFormatList;
while ( NULL != pIter )
{
pNext = pIter->pNext;
pIter->pNext = NULL;
//
// descending order
//
pIter2 = pLessThan;
pPrev = NULL;
while ( NULL != pIter2 &&
pIter2->Format.nAvgBytesPerSec >
pIter->Format.nAvgBytesPerSec )
{
pPrev = pIter2;
pIter2 = pIter2->pNext;
}
pIter->pNext = pIter2;
if ( NULL == pPrev )
pLessThan = pIter;
else
pPrev->pNext = pIter;
pIter = pNext;
dwNum ++;
}
*ppFormatList = pLessThan;
if ( NULL != pdwNum )
*pdwNum = dwNum;
}
//
// puts code licensing codes into the header
//
BOOL
_VCSndFixHeader(
PWAVEFORMATEX pFmt,
PWAVEFORMATEX *ppNewFmt
)
{
BOOL rv = FALSE;
*ppNewFmt = NULL;
switch (pFmt->wFormatTag)
{
case WAVE_FORMAT_MSG723:
ASSERT(pFmt->cbSize == 10);
((MSG723WAVEFORMAT *) pFmt)->dwCodeword1 = G723MAGICWORD1;
((MSG723WAVEFORMAT *) pFmt)->dwCodeword2 = G723MAGICWORD2;
rv = TRUE;
break;
case WAVE_FORMAT_MSRT24:
//
// assume call control will take care of the other
// params ?
//
ASSERT(pFmt->cbSize == 80);
strncpy(((VOXACM_WAVEFORMATEX *) pFmt)->szKey, VOXWARE_KEY, 80);
rv = TRUE;
break;
case WAVE_FORMAT_WMAUDIO2:
if ( ((WMAUDIO2WAVEFORMAT *)pFmt)->dwSamplesPerBlock > TSSND_SAMPLESPERBLOCK )
{
//
// block is too big, too high latency
//
break;
}
ASSERT( pFmt->cbSize == sizeof( WMAUDIO2WAVEFORMAT ) - sizeof( WAVEFORMATEX ));
*ppNewFmt = TSMALLOC( sizeof( WMAUDIO2WAVEFORMAT ) + sizeof( WMAUDIO_KEY ));
if ( NULL == *ppNewFmt )
{
break;
}
memcpy( *ppNewFmt, pFmt, sizeof( WMAUDIO2WAVEFORMAT ));
strncpy((CHAR *)(((WMAUDIO2WAVEFORMAT *) *ppNewFmt) + 1), WMAUDIO_KEY, sizeof( WMAUDIO_KEY ));
(*ppNewFmt)->cbSize += sizeof( WMAUDIO_KEY );
rv = TRUE;
break;
default:
rv = TRUE;
}
return rv;
}
/*
* Function:
* acmFormatEnumCallback
*
* Description:
* All formats enumerator
*
*/
BOOL
CALLBACK
acmFormatEnumCallback(
HACMDRIVERID hadid,
LPACMFORMATDETAILS pAcmFormatDetails,
DWORD_PTR dwInstance,
DWORD fdwSupport
)
{
PVCSNDFORMATLIST *ppFormatList;
PWAVEFORMATEX pEntry, pFixedEntry = NULL;
ASSERT(0 != dwInstance);
ASSERT(NULL != pAcmFormatDetails);
ASSERT(NULL != pAcmFormatDetails->pwfx);
if ( 0 == dwInstance ||
NULL == pAcmFormatDetails ||
NULL == pAcmFormatDetails->pwfx )
{
TRC( ERR, "acmFormatEnumCallback: Invalid parameters\n" );
goto exitpt;
}
ppFormatList = (PVCSNDFORMATLIST *)dwInstance;
if (( 0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC ) ||
0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER )) &&
pAcmFormatDetails->pwfx->nAvgBytesPerSec < TSSND_NATIVE_AVGBYTESPERSEC
)
{
//
// this codec should be good, save it in the list
// keep the list sorted in descended order
//
PVCSNDFORMATLIST pIter;
PVCSNDFORMATLIST pPrev;
PVCSNDFORMATLIST pNewEntry;
WAVEFORMATEX WaveFormat; // dummy parameter
DWORD itemsize;
if (
WAVE_FORMAT_PCM == pAcmFormatDetails->pwfx->wFormatTag ||
!_VCSndFixHeader(pAcmFormatDetails->pwfx, &pFixedEntry )
)
{
TRC(ALV, "acmFormatEnumCallback: unsupported format, "
"don't use it\n");
goto exitpt;
}
pEntry = ( NULL == pFixedEntry )?pAcmFormatDetails->pwfx:pFixedEntry;
if (!_VCSndFindSuggestedConverter(
hadid,
pEntry,
&WaveFormat
))
{
TRC(ALV, "acmFormatEnumCallback: unsupported format, "
"don't use it\n");
goto exitpt;
}
TRC(ALV, "acmFormatEnumCallback: codec found %S (%d b/s)\n",
pAcmFormatDetails->szFormat,
pEntry->nAvgBytesPerSec);
itemsize = sizeof( *pNewEntry ) + pEntry->cbSize;
pNewEntry = (PVCSNDFORMATLIST) TSMALLOC( itemsize );
if (NULL == pNewEntry)
{
TRC(ERR, "acmFormatEnumCallback: can't allocate %d bytes\n",
itemsize);
goto exitpt;
}
memcpy( &pNewEntry->Format, pEntry,
sizeof (pNewEntry->Format) + pEntry->cbSize );
pNewEntry->hacmDriverId = hadid;
pNewEntry->pNext = *ppFormatList;
*ppFormatList = pNewEntry;
}
exitpt:
if ( NULL != pFixedEntry )
{
TSFREE( pFixedEntry );
}
return TRUE;
}
//
// returns true if this codec is shipped with windows
// because we are testing only the these
//
BOOL
AllowThisCodec(
HACMDRIVERID hadid
)
{
ACMDRIVERDETAILS Details;
BOOL rv = FALSE;
static DWORD AllowedCodecs[][2] =
{ MM_INTEL, 503,
MM_MICROSOFT, MM_MSFT_ACM_IMAADPCM,
MM_FRAUNHOFER_IIS, 12,
MM_MICROSOFT, 90,
MM_MICROSOFT, MM_MSFT_ACM_MSADPCM,
MM_MICROSOFT, 39,
MM_MICROSOFT, MM_MSFT_ACM_G711,
MM_MICROSOFT, 82,
MM_MICROSOFT, MM_MSFT_ACM_GSM610,
MM_SIPROLAB, 1,
MM_DSP_GROUP, 1,
MM_MICROSOFT, MM_MSFT_ACM_PCM };
RtlZeroMemory( &Details, sizeof( Details ));
Details.cbStruct = sizeof( Details );
if ( MMSYSERR_NOERROR ==
acmDriverDetails( hadid, &Details, 0 ))
{
//
// Is this one known
//
DWORD count;
for ( count = 0; count < sizeof( AllowedCodecs ) / (2 * sizeof( DWORD )); count ++ )
{
if ( Details.wMid == AllowedCodecs[count][0] &&
Details.wPid == AllowedCodecs[count][1] )
{
rv = TRUE;
goto exitpt;
}
}
}
exitpt:
if ( rv )
TRC( ALV, "ACMDRV: +++++++++++++++++++++ CODEC ALLOWED +++++++++++++++++++++++\n" );
else
TRC( ALV, "ACMDRV: ------------------- CODEC DISALLOWED ----------------------\n" );
TRC( ALV, "ACMDRV: Mid: %d\n", Details.wMid );
TRC( ALV, "ACMDRV: Pid: %d\n", Details.wPid );
TRC( ALV, "ACMDRV: ShortName: %S\n", Details.szShortName );
TRC( ALV, "ACMDRV: LongName: %S\n", Details.szLongName );
TRC( ALV, "ACMDRV: Copyright: %S\n", Details.szLicensing );
TRC( ALV, "ACMDRV: Features: %S\n", Details.szFeatures );
return rv;
}
/*
* Function:
* acmDriverEnumCallback
*
* Description:
* All drivers enumerator
*
*/
BOOL
CALLBACK
acmDriverEnumCallback(
HACMDRIVERID hadid,
DWORD_PTR dwInstance,
DWORD fdwSupport
)
{
PVCSNDFORMATLIST *ppFormatList;
MMRESULT mmres;
ASSERT(dwInstance);
ppFormatList = (PVCSNDFORMATLIST *)dwInstance;
if ( (0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CODEC ) ||
0 != ( fdwSupport & ACMDRIVERDETAILS_SUPPORTF_CONVERTER )) &&
AllowThisCodec(hadid) )
{
//
// a codec found
//
HACMDRIVER had;
mmres = acmDriverOpen(&had, hadid, 0);
if (MMSYSERR_NOERROR == mmres)
{
PWAVEFORMATEX pWaveFormat;
ACMFORMATDETAILS AcmFormatDetails;
DWORD dwMaxFormatSize;
//
// first find the max size for the format
//
mmres = acmMetrics( (HACMOBJ)had,
ACM_METRIC_MAX_SIZE_FORMAT,
(LPVOID)&dwMaxFormatSize);
if (MMSYSERR_NOERROR != mmres ||
dwMaxFormatSize < sizeof( *pWaveFormat ))
dwMaxFormatSize = sizeof( *pWaveFormat );
//
// Allocate the format structure
//
__try {
pWaveFormat = (PWAVEFORMATEX) _alloca ( dwMaxFormatSize );
} __except ( EXCEPTION_EXECUTE_HANDLER )
{
pWaveFormat = NULL;
}
if ( NULL == pWaveFormat )
{
TRC(ERR, "acmDriverEnumCallback: alloca failed for %d bytes\n",
dwMaxFormatSize);
goto close_acm_driver;
}
//
// clear the extra format data
//
memset( pWaveFormat + 1, 0, dwMaxFormatSize - sizeof( *pWaveFormat ));
//
// create the format to convert from
//
pWaveFormat->wFormatTag = WAVE_FORMAT_PCM;
pWaveFormat->nChannels = TSSND_NATIVE_CHANNELS;
pWaveFormat->nSamplesPerSec = TSSND_NATIVE_SAMPLERATE;
pWaveFormat->nAvgBytesPerSec = TSSND_NATIVE_AVGBYTESPERSEC;
pWaveFormat->nBlockAlign = TSSND_NATIVE_BLOCKALIGN;
pWaveFormat->wBitsPerSample = TSSND_NATIVE_BITSPERSAMPLE;
pWaveFormat->cbSize = 0;
AcmFormatDetails.cbStruct = sizeof( AcmFormatDetails );
AcmFormatDetails.dwFormatIndex= 0;
AcmFormatDetails.dwFormatTag = WAVE_FORMAT_PCM;
AcmFormatDetails.fdwSupport = 0;
AcmFormatDetails.pwfx = pWaveFormat;
AcmFormatDetails.cbwfx = dwMaxFormatSize;
//
// enum all formats supported by this driver
//
mmres = acmFormatEnum(
had,
&AcmFormatDetails,
acmFormatEnumCallback,
(DWORD_PTR)ppFormatList,
0 //ACM_FORMATENUMF_CONVERT
);
if (MMSYSERR_NOERROR != mmres)
{
TRC(ERR, "acmDriverEnumCallback: acmFormatEnum failed %d\n",
mmres);
}
close_acm_driver:
acmDriverClose(had, 0);
} else
TRC(ALV, "acmDriverEnumCallback: acmDriverOpen failed: %d\n",
mmres);
}
//
// continue to the next driver
//
return TRUE;
}
/*
* Function:
* VCSndEnumAllCodecFormats
*
* Description:
* Creates a list of all codecs/formats
*
*/
BOOL
VCSndEnumAllCodecFormats(
PVCSNDFORMATLIST *ppFormatList,
DWORD *pdwNumberOfFormats
)
{
BOOL rv = FALSE;
PVCSNDFORMATLIST pIter;
PVCSNDFORMATLIST pPrev;
PVCSNDFORMATLIST pNext;
MMRESULT mmres;
DWORD dwNum = 0;
ASSERT( ppFormatList );
ASSERT( pdwNumberOfFormats );
*ppFormatList = NULL;
mmres = acmDriverEnum(
acmDriverEnumCallback,
(DWORD_PTR)ppFormatList,
0
);
if (NULL == *ppFormatList)
{
TRC(WRN, "VCSndEnumAllCodecFormats: acmDriverEnum failed: %d\n",
mmres);
goto exitpt;
}
_VCSndOrderFormatList( ppFormatList, &dwNum );
pIter = *ppFormatList;
//
// number of formats is passed as UINT16, delete all after those
//
if ( dwNum > 0xffff )
{
DWORD dwLimit = 0xfffe;
while ( 0 != dwLimit )
{
pIter = pIter->pNext;
dwLimit --;
}
pNext = pIter->pNext;
pIter->pNext = NULL;
pIter = pNext;
while( NULL != pIter )
{
pNext = pIter->pNext;
TSFREE( pNext );
pIter = pNext;
}
dwNum = 0xffff;
}
rv = TRUE;
exitpt:
if (!rv)
{
//
// in case of error free the allocated list of formats
//
pIter = *ppFormatList;
while( NULL != pIter )
{
PVCSNDFORMATLIST pNext = pIter->pNext;
TSFREE( pIter );
pIter = pNext;
}
*ppFormatList = NULL;
}
*pdwNumberOfFormats = dwNum;
return rv;
}
int
_cdecl
wmain( void )
{
PVCSNDFORMATLIST pFormatList = NULL;
DWORD dwNumberOfFormats = 0;
printf( "// use dumpcod.c to generate this table\n" );
printf( "//\n" );
printf( "// FormatTag | Channels | SamplesPerSec | AvgBytesPerSec | BlockAlign | BitsPerSamepl | ExtraInfo\n" );
printf( "// ================================================================================================\n" );
printf( "//\n" );
printf( "BYTE KnownFormats[] = {\n" );
VCSndEnumAllCodecFormats( &pFormatList, &dwNumberOfFormats );
for ( ;pFormatList != NULL; pFormatList = pFormatList->pNext )
{
PWAVEFORMATEX pSndFmt = &(pFormatList->Format);
UINT i;
printf( "// %.3d, %.2d, %.5d, %.5d, %.3d, %.2d\n",
pSndFmt->wFormatTag,
pSndFmt->nChannels,
pSndFmt->nSamplesPerSec,
pSndFmt->nAvgBytesPerSec,
pSndFmt->nBlockAlign,
pSndFmt->wBitsPerSample);
for ( i = 0; i < sizeof( WAVEFORMATEX ); i ++ )
{
printf( "0x%02x", ((PBYTE)pSndFmt)[i]);
if ( i + 1 < sizeof( WAVEFORMATEX ) || pSndFmt->cbSize )
{
printf( ", " );
}
}
for ( i = 0; i < pSndFmt->cbSize; i++ )
{
printf( "0x%02x", (((PBYTE)pSndFmt) + sizeof( WAVEFORMATEX ))[i]);
if ( i + 1 < pSndFmt->cbSize )
{
printf( ", " );
}
}
if ( NULL != pFormatList->pNext )
{
printf ( ",\n" );
} else {
printf( " };\n" );
}
}
return 0;
}