901 lines
24 KiB
C
901 lines
24 KiB
C
|
//==========================================================================;
|
|||
|
//
|
|||
|
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
|
|||
|
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
|||
|
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
|
|||
|
// PURPOSE.
|
|||
|
//
|
|||
|
// Copyright (c) 1992 - 1994 Microsoft Corporation. All Rights Reserved.
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
//
|
|||
|
// aaprops.c
|
|||
|
//
|
|||
|
// Description:
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
//==========================================================================;
|
|||
|
|
|||
|
#include <windows.h>
|
|||
|
#include <windowsx.h>
|
|||
|
#include <mmsystem.h>
|
|||
|
#include <memory.h>
|
|||
|
|
|||
|
#include <mmreg.h>
|
|||
|
#include <msacm.h>
|
|||
|
|
|||
|
#include "muldiv32.h"
|
|||
|
|
|||
|
#include "appport.h"
|
|||
|
#include "acmapp.h"
|
|||
|
|
|||
|
#include "debug.h"
|
|||
|
|
|||
|
|
|||
|
//==========================================================================;
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
//==========================================================================;
|
|||
|
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
//
|
|||
|
// BOOL AcmAppGetErrorString
|
|||
|
//
|
|||
|
// Description:
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
// MMRESULT mmr:
|
|||
|
//
|
|||
|
// PTSTR psz:
|
|||
|
//
|
|||
|
// Return (BOOL):
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
|
|||
|
BOOL FNGLOBAL AcmAppGetErrorString
|
|||
|
(
|
|||
|
MMRESULT mmr,
|
|||
|
LPTSTR pszError
|
|||
|
)
|
|||
|
{
|
|||
|
PTSTR psz;
|
|||
|
|
|||
|
switch (mmr)
|
|||
|
{
|
|||
|
case MMSYSERR_NOERROR:
|
|||
|
psz = TEXT("MMSYSERR_NOERROR");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_ERROR:
|
|||
|
psz = TEXT("MMSYSERR_ERROR");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_BADDEVICEID:
|
|||
|
psz = TEXT("MMSYSERR_BADDEVICEID");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_NOTENABLED:
|
|||
|
psz = TEXT("MMSYSERR_NOTENABLED");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_ALLOCATED:
|
|||
|
psz = TEXT("MMSYSERR_ALLOCATED");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_INVALHANDLE:
|
|||
|
psz = TEXT("MMSYSERR_INVALHANDLE");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_NODRIVER:
|
|||
|
psz = TEXT("MMSYSERR_NODRIVER");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_NOMEM:
|
|||
|
psz = TEXT("MMSYSERR_NOMEM");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_NOTSUPPORTED:
|
|||
|
psz = TEXT("MMSYSERR_NOTSUPPORTED");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_BADERRNUM:
|
|||
|
psz = TEXT("MMSYSERR_BADERRNUM");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_INVALFLAG:
|
|||
|
psz = TEXT("MMSYSERR_INVALFLAG");
|
|||
|
break;
|
|||
|
|
|||
|
case MMSYSERR_INVALPARAM:
|
|||
|
psz = TEXT("MMSYSERR_INVALPARAM");
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case WAVERR_BADFORMAT:
|
|||
|
psz = TEXT("WAVERR_BADFORMAT");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVERR_STILLPLAYING:
|
|||
|
psz = TEXT("WAVERR_STILLPLAYING");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVERR_UNPREPARED:
|
|||
|
psz = TEXT("WAVERR_UNPREPARED");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVERR_SYNC:
|
|||
|
psz = TEXT("WAVERR_SYNC");
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
case ACMERR_NOTPOSSIBLE:
|
|||
|
psz = TEXT("ACMERR_NOTPOSSIBLE");
|
|||
|
break;
|
|||
|
|
|||
|
case ACMERR_BUSY:
|
|||
|
psz = TEXT("ACMERR_BUSY");
|
|||
|
break;
|
|||
|
|
|||
|
case ACMERR_UNPREPARED:
|
|||
|
psz = TEXT("ACMERR_UNPREPARED");
|
|||
|
break;
|
|||
|
|
|||
|
case ACMERR_CANCELED:
|
|||
|
psz = TEXT("ACMERR_CANCELED");
|
|||
|
break;
|
|||
|
|
|||
|
|
|||
|
default:
|
|||
|
lstrcpy(pszError, TEXT("(unknown)"));
|
|||
|
return (FALSE);
|
|||
|
}
|
|||
|
|
|||
|
lstrcpy(pszError, psz);
|
|||
|
return (TRUE);
|
|||
|
} // AcmAppGetErrorString()
|
|||
|
|
|||
|
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
//
|
|||
|
// BOOL AcmAppGetFormatDescription
|
|||
|
//
|
|||
|
// Description:
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
// LPWAVEFORMATEX pwfx:
|
|||
|
//
|
|||
|
// LPSTR pszFormatTag:
|
|||
|
//
|
|||
|
// LPSTR pszFormat:
|
|||
|
//
|
|||
|
// Return (BOOL):
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
|
|||
|
TCHAR gszIntl[] = TEXT("Intl");
|
|||
|
TCHAR gszIntlList[] = TEXT("sList");
|
|||
|
TCHAR gszIntlDecimal[] = TEXT("sDecimal");
|
|||
|
TCHAR gchIntlList = ',';
|
|||
|
TCHAR gchIntlDecimal = '.';
|
|||
|
|
|||
|
BOOL FNGLOBAL AcmAppGetFormatDescription
|
|||
|
(
|
|||
|
LPWAVEFORMATEX pwfx,
|
|||
|
LPTSTR pszFormatTag,
|
|||
|
LPTSTR pszFormat
|
|||
|
)
|
|||
|
{
|
|||
|
MMRESULT mmr;
|
|||
|
BOOL f;
|
|||
|
|
|||
|
f = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// get the name for the format tag of the specified format
|
|||
|
//
|
|||
|
if (NULL != pszFormatTag)
|
|||
|
{
|
|||
|
ACMFORMATTAGDETAILS aftd;
|
|||
|
|
|||
|
//
|
|||
|
// initialize all unused members of the ACMFORMATTAGDETAILS
|
|||
|
// structure to zero
|
|||
|
//
|
|||
|
memset(&aftd, 0, sizeof(aftd));
|
|||
|
|
|||
|
//
|
|||
|
// fill in the required members of the ACMFORMATTAGDETAILS
|
|||
|
// structure for the ACM_FORMATTAGDETAILSF_FORMATTAG query
|
|||
|
//
|
|||
|
aftd.cbStruct = sizeof(aftd);
|
|||
|
aftd.dwFormatTag = pwfx->wFormatTag;
|
|||
|
|
|||
|
//
|
|||
|
// ask the ACM to find the first available driver that
|
|||
|
// supports the specified format tag
|
|||
|
//
|
|||
|
mmr = acmFormatTagDetails(NULL,
|
|||
|
&aftd,
|
|||
|
ACM_FORMATTAGDETAILSF_FORMATTAG);
|
|||
|
if (MMSYSERR_NOERROR == mmr)
|
|||
|
{
|
|||
|
//
|
|||
|
// copy the format tag name into the caller's buffer
|
|||
|
//
|
|||
|
lstrcpy(pszFormatTag, aftd.szFormatTag);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PTSTR psz;
|
|||
|
|
|||
|
//
|
|||
|
// no ACM driver is available that supports the
|
|||
|
// specified format tag
|
|||
|
//
|
|||
|
|
|||
|
f = FALSE;
|
|||
|
psz = NULL;
|
|||
|
|
|||
|
//
|
|||
|
// the following stuff if proof that the world does NOT need
|
|||
|
// yet another ADPCM algorithm!!
|
|||
|
//
|
|||
|
switch (pwfx->wFormatTag)
|
|||
|
{
|
|||
|
case WAVE_FORMAT_UNKNOWN:
|
|||
|
psz = TEXT("** RESERVED INVALID TAG **");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_PCM:
|
|||
|
psz = TEXT("PCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_ADPCM:
|
|||
|
psz = TEXT("Microsoft ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case 0x0003:
|
|||
|
psz = TEXT("MV's *UNREGISTERED* ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_IBM_CVSD:
|
|||
|
psz = TEXT("IBM CVSD");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_ALAW:
|
|||
|
psz = TEXT("A-Law");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_MULAW:
|
|||
|
psz = TEXT("u-Law");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_OKI_ADPCM:
|
|||
|
psz = TEXT("OKI ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_IMA_ADPCM:
|
|||
|
psz = TEXT("IMA/DVI ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_DIGISTD:
|
|||
|
psz = TEXT("DIGI STD");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_DIGIFIX:
|
|||
|
psz = TEXT("DIGI FIX");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_YAMAHA_ADPCM:
|
|||
|
psz = TEXT("Yamaha ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_SONARC:
|
|||
|
psz = TEXT("Sonarc");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_DSPGROUP_TRUESPEECH:
|
|||
|
psz = TEXT("DSP Group TrueSpeech");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_ECHOSC1:
|
|||
|
psz = TEXT("Echo SC1");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_AUDIOFILE_AF36:
|
|||
|
psz = TEXT("Audiofile AF36");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_CREATIVE_ADPCM:
|
|||
|
psz = TEXT("Creative Labs ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_APTX:
|
|||
|
psz = TEXT("APTX");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_AUDIOFILE_AF10:
|
|||
|
psz = TEXT("Audiofile AF10");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_DOLBY_AC2:
|
|||
|
psz = TEXT("Dolby AC2");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_MEDIASPACE_ADPCM:
|
|||
|
psz = TEXT("Media Space ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_SIERRA_ADPCM:
|
|||
|
psz = TEXT("Sierra ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_G723_ADPCM:
|
|||
|
psz = TEXT("CCITT G.723 ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_GSM610:
|
|||
|
psz = TEXT("GSM 6.10");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_G721_ADPCM:
|
|||
|
psz = TEXT("CCITT G.721 ADPCM");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FORMAT_DEVELOPMENT:
|
|||
|
psz = TEXT("** RESERVED DEVELOPMENT ONLY TAG **");
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
wsprintf(pszFormatTag, TEXT("[%u] (unknown)"), pwfx->wFormatTag);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != psz)
|
|||
|
{
|
|||
|
lstrcpy(pszFormatTag, psz);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get the description of the attributes for the specified
|
|||
|
// format
|
|||
|
//
|
|||
|
if (NULL != pszFormat)
|
|||
|
{
|
|||
|
ACMFORMATDETAILS afd;
|
|||
|
|
|||
|
//
|
|||
|
// initialize all unused members of the ACMFORMATDETAILS
|
|||
|
// structure to zero
|
|||
|
//
|
|||
|
memset(&afd, 0, sizeof(afd));
|
|||
|
|
|||
|
//
|
|||
|
// fill in the required members of the ACMFORMATDETAILS
|
|||
|
// structure for the ACM_FORMATDETAILSF_FORMAT query
|
|||
|
//
|
|||
|
afd.cbStruct = sizeof(afd);
|
|||
|
afd.dwFormatTag = pwfx->wFormatTag;
|
|||
|
afd.pwfx = pwfx;
|
|||
|
|
|||
|
//
|
|||
|
// the cbwfx member must be initialized to the total size
|
|||
|
// in bytes needed for the specified format. for a PCM
|
|||
|
// format, the cbSize member of the WAVEFORMATEX structure
|
|||
|
// is not valid.
|
|||
|
//
|
|||
|
if (WAVE_FORMAT_PCM == pwfx->wFormatTag)
|
|||
|
{
|
|||
|
afd.cbwfx = sizeof(PCMWAVEFORMAT);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
afd.cbwfx = sizeof(WAVEFORMATEX) + pwfx->cbSize;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// ask the ACM to find the first available driver that
|
|||
|
// supports the specified format
|
|||
|
//
|
|||
|
mmr = acmFormatDetails(NULL, &afd, ACM_FORMATDETAILSF_FORMAT);
|
|||
|
if (MMSYSERR_NOERROR == mmr)
|
|||
|
{
|
|||
|
//
|
|||
|
// copy the format attributes description into the caller's
|
|||
|
// buffer
|
|||
|
//
|
|||
|
lstrcpy(pszFormat, afd.szFormat);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
TCHAR ach[2];
|
|||
|
TCHAR szChannels[24];
|
|||
|
UINT cBits;
|
|||
|
|
|||
|
//
|
|||
|
// no ACM driver is available that supports the
|
|||
|
// specified format
|
|||
|
//
|
|||
|
|
|||
|
f = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
ach[0] = gchIntlList;
|
|||
|
ach[1] = '\0';
|
|||
|
|
|||
|
GetProfileString(gszIntl, gszIntlList, ach, ach, sizeof(ach));
|
|||
|
gchIntlList = ach[0];
|
|||
|
|
|||
|
ach[0] = gchIntlDecimal;
|
|||
|
ach[1] = '\0';
|
|||
|
|
|||
|
GetProfileString(gszIntl, gszIntlDecimal, ach, ach, sizeof(ach));
|
|||
|
gchIntlDecimal = ach[0];
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// compute the bit depth--this _should_ be the same as
|
|||
|
// wBitsPerSample, but isn't always...
|
|||
|
//
|
|||
|
cBits = (UINT)(pwfx->nAvgBytesPerSec * 8 /
|
|||
|
pwfx->nSamplesPerSec /
|
|||
|
pwfx->nChannels);
|
|||
|
|
|||
|
if ((1 == pwfx->nChannels) || (2 == pwfx->nChannels))
|
|||
|
{
|
|||
|
if (1 == pwfx->nChannels)
|
|||
|
lstrcpy(szChannels, TEXT("Mono"));
|
|||
|
else
|
|||
|
lstrcpy(szChannels, TEXT("Stereo"));
|
|||
|
|
|||
|
wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %s"),
|
|||
|
pwfx->nSamplesPerSec / 1000,
|
|||
|
gchIntlDecimal,
|
|||
|
(UINT)(pwfx->nSamplesPerSec % 1000),
|
|||
|
gchIntlList,
|
|||
|
cBits,
|
|||
|
gchIntlList,
|
|||
|
(LPTSTR)szChannels);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
wsprintf(pszFormat, TEXT("%lu%c%.03u kHz%c %u Bit%c %u Channels"),
|
|||
|
pwfx->nSamplesPerSec / 1000,
|
|||
|
gchIntlDecimal,
|
|||
|
(UINT)(pwfx->nSamplesPerSec % 1000),
|
|||
|
gchIntlList,
|
|||
|
cBits,
|
|||
|
gchIntlList,
|
|||
|
pwfx->nChannels);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
return (f);
|
|||
|
} // AcmAppGetFormatDescription()
|
|||
|
|
|||
|
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
//
|
|||
|
// BOOL AcmAppGetFilterDescription
|
|||
|
//
|
|||
|
// Description:
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
// LPWAVEFILTER pwfltr:
|
|||
|
//
|
|||
|
// LPSTR pszFilterTag:
|
|||
|
//
|
|||
|
// LPSTR pszFilter:
|
|||
|
//
|
|||
|
// Return (BOOL):
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
|
|||
|
BOOL FNGLOBAL AcmAppGetFilterDescription
|
|||
|
(
|
|||
|
LPWAVEFILTER pwfltr,
|
|||
|
LPTSTR pszFilterTag,
|
|||
|
LPTSTR pszFilter
|
|||
|
)
|
|||
|
{
|
|||
|
MMRESULT mmr;
|
|||
|
BOOL f;
|
|||
|
|
|||
|
f = TRUE;
|
|||
|
|
|||
|
//
|
|||
|
// get the name for the filter tag of the specified filter
|
|||
|
//
|
|||
|
if (NULL != pszFilterTag)
|
|||
|
{
|
|||
|
ACMFILTERTAGDETAILS aftd;
|
|||
|
|
|||
|
//
|
|||
|
// initialize all unused members of the ACMFILTERTAGDETAILS
|
|||
|
// structure to zero
|
|||
|
//
|
|||
|
memset(&aftd, 0, sizeof(aftd));
|
|||
|
|
|||
|
//
|
|||
|
// fill in the required members of the ACMFILTERTAGDETAILS
|
|||
|
// structure for the ACM_FILTERTAGDETAILSF_FILTERTAG query
|
|||
|
//
|
|||
|
aftd.cbStruct = sizeof(aftd);
|
|||
|
aftd.dwFilterTag = pwfltr->dwFilterTag;
|
|||
|
|
|||
|
//
|
|||
|
// ask the ACM to find the first available driver that
|
|||
|
// supports the specified filter tag
|
|||
|
//
|
|||
|
mmr = acmFilterTagDetails(NULL,
|
|||
|
&aftd,
|
|||
|
ACM_FILTERTAGDETAILSF_FILTERTAG);
|
|||
|
if (MMSYSERR_NOERROR == mmr)
|
|||
|
{
|
|||
|
//
|
|||
|
// copy the filter tag name into the caller's buffer
|
|||
|
//
|
|||
|
lstrcpy(pszFilterTag, aftd.szFilterTag);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
PTSTR psz;
|
|||
|
|
|||
|
psz = NULL;
|
|||
|
f = FALSE;
|
|||
|
|
|||
|
//
|
|||
|
// no ACM driver is available that supports the
|
|||
|
// specified filter tag
|
|||
|
//
|
|||
|
switch (pwfltr->dwFilterTag)
|
|||
|
{
|
|||
|
case WAVE_FILTER_UNKNOWN:
|
|||
|
psz = TEXT("** RESERVED INVALID TAG **");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FILTER_VOLUME:
|
|||
|
psz = TEXT("Microsoft Volume Filter");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FILTER_ECHO:
|
|||
|
psz = TEXT("Microsoft Echo Filter");
|
|||
|
break;
|
|||
|
|
|||
|
case WAVE_FILTER_DEVELOPMENT:
|
|||
|
psz = TEXT("** RESERVED DEVELOPMENT ONLY TAG **");
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
wsprintf(pszFilterTag, TEXT("[%lu] (unknown)"),pwfltr->dwFilterTag);
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (NULL != psz)
|
|||
|
{
|
|||
|
lstrcpy(pszFilterTag, psz);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// get the description of the attributes for the specified
|
|||
|
// filter
|
|||
|
//
|
|||
|
if (NULL != pszFilter)
|
|||
|
{
|
|||
|
ACMFILTERDETAILS afd;
|
|||
|
|
|||
|
//
|
|||
|
// initialize all unused members of the ACMFILTERDETAILS
|
|||
|
// structure to zero
|
|||
|
//
|
|||
|
memset(&afd, 0, sizeof(afd));
|
|||
|
|
|||
|
//
|
|||
|
// fill in the required members of the ACMFILTERDETAILS
|
|||
|
// structure for the ACM_FILTERDETAILSF_FILTER query
|
|||
|
//
|
|||
|
afd.cbStruct = sizeof(afd);
|
|||
|
afd.dwFilterTag = pwfltr->dwFilterTag;
|
|||
|
afd.pwfltr = pwfltr;
|
|||
|
afd.cbwfltr = pwfltr->cbStruct;
|
|||
|
|
|||
|
//
|
|||
|
// ask the ACM to find the first available driver that
|
|||
|
// supports the specified filter
|
|||
|
//
|
|||
|
mmr = acmFilterDetails(NULL, &afd, ACM_FILTERDETAILSF_FILTER);
|
|||
|
if (MMSYSERR_NOERROR == mmr)
|
|||
|
{
|
|||
|
//
|
|||
|
// copy the filter attributes description into the caller's
|
|||
|
// buffer
|
|||
|
//
|
|||
|
lstrcpy(pszFilter, afd.szFilter);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
//
|
|||
|
// no ACM driver is available that supports the
|
|||
|
// specified filter
|
|||
|
//
|
|||
|
f = FALSE;
|
|||
|
|
|||
|
wsprintf(pszFilter, TEXT("Unknown Filter %lu, %.08lXh"),
|
|||
|
pwfltr->dwFilterTag, pwfltr->fdwFilter);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
return (f);
|
|||
|
} // AcmAppGetFilterDescription()
|
|||
|
|
|||
|
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
//
|
|||
|
// BOOL AcmAppDumpExtraHeaderData
|
|||
|
//
|
|||
|
// Description:
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
// HWND hedit:
|
|||
|
//
|
|||
|
// LPWAVEFORMATEX pwfx:
|
|||
|
//
|
|||
|
// Return (BOOL):
|
|||
|
//
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
|
|||
|
BOOL FNLOCAL AcmAppDumpExtraHeaderData
|
|||
|
(
|
|||
|
HWND hedit,
|
|||
|
LPWAVEFORMATEX pwfx
|
|||
|
)
|
|||
|
{
|
|||
|
static TCHAR szDisplayTitle[] = TEXT("Offset Data Bytes");
|
|||
|
|
|||
|
if ((WAVE_FORMAT_PCM == pwfx->wFormatTag) || (0 == pwfx->cbSize))
|
|||
|
return (TRUE);
|
|||
|
|
|||
|
MEditPrintF(hedit, szDisplayTitle);
|
|||
|
MEditPrintF(hedit, TEXT("------ -----------------------------------------------"));
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// !!! this is really horrible code !!!
|
|||
|
//
|
|||
|
{
|
|||
|
#define ACMAPP_DUMP_BYTES_PER_LINE 16
|
|||
|
|
|||
|
UINT u;
|
|||
|
UINT v;
|
|||
|
|
|||
|
for (u = 0; u < pwfx->cbSize; u += ACMAPP_DUMP_BYTES_PER_LINE)
|
|||
|
{
|
|||
|
MEditPrintF(hedit, TEXT("~0x%.04X"), u);
|
|||
|
|
|||
|
for (v = 0; v < ACMAPP_DUMP_BYTES_PER_LINE; v++)
|
|||
|
{
|
|||
|
if ((u + v) >= pwfx->cbSize)
|
|||
|
break;
|
|||
|
|
|||
|
MEditPrintF(hedit, TEXT("~ %.02X"), ((LPBYTE)(pwfx + 1))[u + v]);
|
|||
|
}
|
|||
|
|
|||
|
MEditPrintF(hedit, gszNull);
|
|||
|
}
|
|||
|
|
|||
|
#undef ACMAPP_DUMP_BYTES_PER_LINE
|
|||
|
}
|
|||
|
|
|||
|
return (TRUE);
|
|||
|
} // AcmAppDumpExtraHeaderData()
|
|||
|
|
|||
|
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
//
|
|||
|
// BOOL AcmAppDisplayFileProperties
|
|||
|
//
|
|||
|
// Description:
|
|||
|
//
|
|||
|
//
|
|||
|
// Arguments:
|
|||
|
// HWND hwnd:
|
|||
|
//
|
|||
|
// PACMAPPFILEDESC paafd:
|
|||
|
//
|
|||
|
// Return (BOOL):
|
|||
|
//
|
|||
|
//--------------------------------------------------------------------------;
|
|||
|
|
|||
|
BOOL FNGLOBAL AcmAppDisplayFileProperties
|
|||
|
(
|
|||
|
HWND hwnd,
|
|||
|
PACMAPPFILEDESC paafd
|
|||
|
)
|
|||
|
{
|
|||
|
static TCHAR szInvalidWaveFile[] = TEXT("No File");
|
|||
|
static TCHAR szDisplayTitle[] = TEXT("[Wave File Format Properties]\r\n");
|
|||
|
|
|||
|
MMRESULT mmr;
|
|||
|
TCHAR szFormatTag[ACMFORMATTAGDETAILS_FORMATTAG_CHARS];
|
|||
|
TCHAR ach[APP_MAX_STRING_CHARS];
|
|||
|
DWORD dw;
|
|||
|
LPWAVEFORMATEX pwfx;
|
|||
|
HWND hedit;
|
|||
|
HMENU hmenu;
|
|||
|
BOOL fCanPlayRecord;
|
|||
|
BOOL f;
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// clear the display
|
|||
|
//
|
|||
|
AppHourGlass(TRUE);
|
|||
|
|
|||
|
hedit = GetDlgItem(hwnd, IDD_ACMAPP_EDIT_DISPLAY);
|
|||
|
SetWindowRedraw(hedit, FALSE);
|
|||
|
|
|||
|
MEditPrintF(hedit, NULL);
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
MEditPrintF(hedit, szDisplayTitle);
|
|||
|
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Title"), (LPTSTR)paafd->szFileTitle);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Full Path"), (LPTSTR)paafd->szFilePath);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, paafd->cbFileSize);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s bytes"), (LPTSTR)TEXT("Total File Size"), (LPTSTR)ach);
|
|||
|
|
|||
|
AppFormatDosDateTime(ach, paafd->uDosChangeDate, paafd->uDosChangeTime);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Last Change Date/Time"), (LPTSTR)ach);
|
|||
|
|
|||
|
dw = paafd->fdwFileAttributes;
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %c %c%c%c%c %c%c%c%c (%.08lXh)"),
|
|||
|
(LPTSTR)TEXT("Attributes"),
|
|||
|
(dw & FILE_ATTRIBUTE_TEMPORARY) ? 't' : '-',
|
|||
|
(dw & FILE_ATTRIBUTE_NORMAL) ? 'n' : '-',
|
|||
|
(dw & 0x00000040) ? '?' : '-',
|
|||
|
(dw & FILE_ATTRIBUTE_ARCHIVE) ? 'a' : '-',
|
|||
|
(dw & FILE_ATTRIBUTE_DIRECTORY) ? 'd' : '-',
|
|||
|
(dw & 0x00000008) ? '?' : '-',
|
|||
|
(dw & FILE_ATTRIBUTE_SYSTEM) ? 's' : '-',
|
|||
|
(dw & FILE_ATTRIBUTE_HIDDEN) ? 'h' : '-',
|
|||
|
(dw & FILE_ATTRIBUTE_READONLY) ? 'r' : '-',
|
|||
|
dw);
|
|||
|
|
|||
|
|
|||
|
pwfx = paafd->pwfx;
|
|||
|
if (NULL == pwfx)
|
|||
|
{
|
|||
|
fCanPlayRecord = FALSE;
|
|||
|
goto AA_Display_File_Properties_Exit;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
f = AcmAppGetFormatDescription(pwfx, szFormatTag, ach);
|
|||
|
MEditPrintF(hedit, TEXT("\r\n%25s: %s%s"), (LPTSTR)TEXT("Format"),
|
|||
|
f ? (LPTSTR)gszNull : (LPTSTR)TEXT("*"),
|
|||
|
(LPTSTR)szFormatTag);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Attributes"), (LPTSTR)ach);
|
|||
|
|
|||
|
|
|||
|
AppFormatBigNumber(ach, paafd->dwDataBytes);
|
|||
|
MEditPrintF(hedit, TEXT("\r\n%25s: %s bytes"), (LPTSTR)TEXT("Data Size"), (LPTSTR)ach);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, paafd->dwDataBytes / pwfx->nAvgBytesPerSec);
|
|||
|
dw = paafd->dwDataBytes % pwfx->nAvgBytesPerSec;
|
|||
|
dw = (dw * 1000) / pwfx->nAvgBytesPerSec;
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (avg bytes)"), (LPTSTR)ach, dw);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, paafd->dwDataSamples);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Total Samples"), (LPTSTR)ach);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, paafd->dwDataSamples / pwfx->nSamplesPerSec);
|
|||
|
dw = paafd->dwDataSamples % pwfx->nSamplesPerSec;
|
|||
|
dw = (dw * 1000) / pwfx->nSamplesPerSec;
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s.%.03lu seconds"), (LPTSTR)TEXT("Play Time (samples)"), (LPTSTR)ach, dw);
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//
|
|||
|
MEditPrintF(hedit, TEXT("\r\n%25s: %u"), (LPTSTR)TEXT("Format Tag"), pwfx->wFormatTag);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Channels"), pwfx->nChannels);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, pwfx->nSamplesPerSec);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Samples Per Second"), (LPTSTR)ach);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, pwfx->nAvgBytesPerSec);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Avg Bytes Per Second"), (LPTSTR)ach);
|
|||
|
|
|||
|
AppFormatBigNumber(ach, pwfx->nBlockAlign);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s"), (LPTSTR)TEXT("Block Alignment"), (LPTSTR)ach);
|
|||
|
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %u"), (LPTSTR)TEXT("Bits Per Sample"), pwfx->wBitsPerSample);
|
|||
|
|
|||
|
if (WAVE_FORMAT_PCM != pwfx->wFormatTag)
|
|||
|
{
|
|||
|
AppFormatBigNumber(ach, pwfx->cbSize);
|
|||
|
MEditPrintF(hedit, TEXT("%25s: %s bytes\r\n"), (LPTSTR)TEXT("Extra Format Information"), (LPTSTR)ach);
|
|||
|
|
|||
|
AcmAppDumpExtraHeaderData(hedit, pwfx);
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// note that we do NOT set the 'WAVE_ALLOWSYNC' bit on queries because
|
|||
|
// the player/recorder dialog uses MCIWAVE--which cannot work with
|
|||
|
// SYNC devices.
|
|||
|
//
|
|||
|
mmr = waveOutOpen(NULL,
|
|||
|
guWaveOutId,
|
|||
|
#if (WINVER < 0x0400)
|
|||
|
(LPWAVEFORMAT)pwfx,
|
|||
|
#else
|
|||
|
pwfx,
|
|||
|
#endif
|
|||
|
0L, 0L, WAVE_FORMAT_QUERY);
|
|||
|
|
|||
|
fCanPlayRecord = (MMSYSERR_NOERROR == mmr);
|
|||
|
|
|||
|
if (!fCanPlayRecord)
|
|||
|
{
|
|||
|
//
|
|||
|
// this situation can happen with the 'preferred' device settings
|
|||
|
// for the Sound Mapper.
|
|||
|
//
|
|||
|
mmr = waveInOpen(NULL,
|
|||
|
guWaveInId,
|
|||
|
#if (WINVER < 0x0400)
|
|||
|
(LPWAVEFORMAT)pwfx,
|
|||
|
#else
|
|||
|
pwfx,
|
|||
|
#endif
|
|||
|
0L, 0L, WAVE_FORMAT_QUERY);
|
|||
|
|
|||
|
fCanPlayRecord = (MMSYSERR_NOERROR == mmr);
|
|||
|
}
|
|||
|
|
|||
|
AA_Display_File_Properties_Exit:
|
|||
|
|
|||
|
hmenu = GetMenu(hwnd);
|
|||
|
EnableMenuItem(hmenu, IDM_PLAYRECORD,
|
|||
|
MF_BYCOMMAND | (fCanPlayRecord ? MF_ENABLED : MF_GRAYED));
|
|||
|
DrawMenuBar(hwnd);
|
|||
|
|
|||
|
Edit_SetSel(hedit, (WPARAM)0, (LPARAM)0);
|
|||
|
|
|||
|
SetWindowRedraw(hedit, TRUE);
|
|||
|
AppHourGlass(FALSE);
|
|||
|
|
|||
|
return (fCanPlayRecord);
|
|||
|
} // AcmAppDisplayFileProperties()
|
|||
|
|