📄 acm.c
字号:
padft->cbFilterSize = sizeof(ECHOWAVEFILTER);
padft->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
padft->cStandardFilters = ACM_DRIVER_MAX_ECHO_FILTERS;
uIds = IDS_ACM_DRIVER_TAG_NAME_ECHO;
break;
default:
return (ACMERR_NOTPOSSIBLE);
}
//
// return only the requested info
//
// the ACM will guarantee that the ACMFILTERTAGDETAILS structure
// passed is at least large enough to hold the base structure
//
padft->cbStruct = min(padft->cbStruct, sizeof(*padft));
LoadStringACM(pdi->hinst, uIds, padft->szFilterTag, SIZEOFACMSTR(padft->szFilterTag));
//
//
//
return (MMSYSERR_NOERROR);
} // acmdFilterTagDetails()
//--------------------------------------------------------------------------;
//
// UINT acmdFilterDetailsToString
//
// Description:
// This function has a special UNICODE string implementation for common
// binary ACMs between Chicago and Daytona.
//
// Arguments:
// LPWAVEFILTER pwf:
//
// LPTSTR szFilter:
//
// Return (UINT):
//
//
//--------------------------------------------------------------------------;
#if defined(WIN32) && !defined(UNICODE)
UINT FNLOCAL acmdFilterDetailsToString
(
PDRIVERINSTANCE pdi,
LPWAVEFILTER pwf,
LPWSTR szFilter
)
{
UINT u;
CHAR ach1[ACMFILTERDETAILS_FILTER_CHARS];
CHAR ach2[ACMFILTERDETAILS_FILTER_CHARS];
LPVOLUMEWAVEFILTER pwfVol;
LPECHOWAVEFILTER pwfEcho;
if( !szFilter ) {
return 0L;
}
*szFilter = L'\0';
if (volumeIsValidFilter(pwf))
{
pwfVol = (LPVOLUMEWAVEFILTER)pwf;
LoadStringA(pdi->hinst, IDS_ACM_DRIVER_FORMAT_VOLUME, ach1, SIZEOF(ach1));
u = wsprintfA( ach2, ach1,
(WORD)(((pwfVol->dwVolume * 100) / 0x10000)) );
MultiByteToWideChar( GetACP(), 0, ach2, u+1, szFilter,
ACMFILTERDETAILS_FILTER_CHARS );
return( u );
}
else if (echoIsValidFilter(pwf))
{
pwfEcho = (LPECHOWAVEFILTER)pwf;
LoadStringA(pdi->hinst, IDS_ACM_DRIVER_FORMAT_ECHO, ach1, SIZEOF(ach1));
u = wsprintfA( ach2, ach1,
(WORD)(((pwfEcho->dwVolume * 100) / 0x10000)),
(WORD)pwfEcho->dwDelay );
MultiByteToWideChar( GetACP(), 0, ach2, u+1, szFilter,
ACMFILTERDETAILS_FILTER_CHARS );
return( u );
}
return ( 0 );
} // acmdFilterDetailsToString()
#else
UINT FNLOCAL acmdFilterDetailsToString
(
PDRIVERINSTANCE pdi,
LPWAVEFILTER pwf,
LPTSTR szFilter
)
{
UINT u;
TCHAR ach[ACMFILTERDETAILS_FILTER_CHARS];
LPVOLUMEWAVEFILTER pwfVol;
LPECHOWAVEFILTER pwfEcho;
if( !szFilter ) {
return 0L;
}
*szFilter = TEXT('\0');
if (volumeIsValidFilter(pwf))
{
pwfVol = (LPVOLUMEWAVEFILTER)pwf;
LoadString(pdi->hinst, IDS_ACM_DRIVER_FORMAT_VOLUME, ach, SIZEOF(ach));
u = wsprintf( szFilter, ach,
(WORD)(((pwfVol->dwVolume * 100) / 0x10000)) );
return( u );
}
else if (echoIsValidFilter(pwf))
{
pwfEcho = (LPECHOWAVEFILTER)pwf;
LoadString(pdi->hinst, IDS_ACM_DRIVER_FORMAT_ECHO, ach, SIZEOF(ach));
u = wsprintf( szFilter, ach,
(WORD)(((pwfEcho->dwVolume * 100) / 0x10000)),
(WORD)pwfEcho->dwDelay );
return( u );
}
return ( 0 );
} // acmdFilterDetailsToString()
#endif
//--------------------------------------------------------------------------;
//
// LRESULT acmdFilterDetails
//
// Description:
//
//
// Arguments:
// PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
// This structure is [optionally] allocated during the DRV_OPEN message
// which is handled by the acmdDriverOpen function.
//
// LPACMFILTERDETAILS padf:
//
// DWORD fdwDetails:
//
// Return (LRESULT):
//
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL acmdFilterDetails
(
PDRIVERINSTANCE pdi,
LPACMFILTERDETAILS padf,
DWORD fdwDetails
)
{
UINT uFilterIndex;
LPWAVEFILTER pwf;
LPVOLUMEWAVEFILTER pwfVolume;
LPECHOWAVEFILTER pwfEcho;
UINT u;
pwf = padf->pwfltr;
//
//
//
//
//
switch (ACM_FILTERDETAILSF_QUERYMASK & fdwDetails)
{
case ACM_FILTERDETAILSF_INDEX:
//
// enumerate by index
//
// for this converter, this is more code than necessary... just
// verify that the filter tag is something we know about
//
switch (padf->dwFilterTag)
{
case WAVE_FILTER_VOLUME:
if (ACM_DRIVER_MAX_VOLUME_FILTERS <= padf->dwFilterIndex)
return (ACMERR_NOTPOSSIBLE);
pwfVolume = (LPVOLUMEWAVEFILTER)padf->pwfltr;
pwf->cbStruct = sizeof(VOLUMEWAVEFILTER);
pwf->dwFilterTag = WAVE_FILTER_VOLUME;
pwf->fdwFilter = 0;
pwfVolume->dwVolume = gdwFilterIndexToVolume[(UINT)padf->dwFilterIndex];
break;
case WAVE_FILTER_ECHO:
if (ACM_DRIVER_MAX_ECHO_FILTERS <= padf->dwFilterIndex)
return (ACMERR_NOTPOSSIBLE);
pwfEcho = (LPECHOWAVEFILTER)padf->pwfltr;
pwf->cbStruct = sizeof(ECHOWAVEFILTER);
pwf->dwFilterTag = WAVE_FILTER_ECHO;
pwf->fdwFilter = 0;
uFilterIndex = (UINT)padf->dwFilterIndex;
u = uFilterIndex / ACM_DRIVER_NUM_DELAY;
pwfEcho->dwVolume = gdwFilterIndexToEchoVol[u];
u = uFilterIndex % ACM_DRIVER_NUM_DELAY;
pwfEcho->dwDelay = gdwFilterIndexToDelay[u];
break;
default:
return (ACMERR_NOTPOSSIBLE);
}
case ACM_FILTERDETAILSF_FILTER:
//
// must want to verify that the filter passed in is supported
// and return a string description...
//
switch (pwf->dwFilterTag)
{
case WAVE_FILTER_VOLUME:
if (!volumeIsValidFilter(pwf))
return (ACMERR_NOTPOSSIBLE);
break;
case WAVE_FILTER_ECHO:
if (!echoIsValidFilter(pwf))
return (ACMERR_NOTPOSSIBLE);
break;
default:
return (ACMERR_NOTPOSSIBLE);
}
break;
default:
//
// don't know how to do the query type passed--return 'not
// supported'.
//
return (MMSYSERR_NOTSUPPORTED);
}
//
// return only the requested info
//
// the ACM will guarantee that the ACMFILTERDETAILS structure
// passed is at least large enough to hold everything in the base
// filter details structure...
//
// get a nice friendly string for the filter we made
//
acmdFilterDetailsToString(pdi, pwf, padf->szFilter);
//
// if they asked for more info than we know how to return, then
// set size of valid structure bytes to correct value.
//
padf->fdwSupport = ACMDRIVERDETAILS_SUPPORTF_FILTER;
padf->cbStruct = min(padf->cbStruct, sizeof(*padf));
//
//
//
return (MMSYSERR_NOERROR);
} // acmdFilterDetails()
//==========================================================================;
//
//
//
//
//==========================================================================;
//--------------------------------------------------------------------------;
//
// LRESULT acmdStreamOpen
//
// Description:
// This function handles the ACMDM_STREAM_OPEN message. This message
// is sent to initiate a new conversion stream. This is usually caused
// by an application calling acmStreamOpen. If this function is
// successful, then one or more ACMDM_STREAM_CONVERT messages will be
// sent to convert individual buffers (user calls acmStreamConvert).
//
// Note that an ACM driver will not receive open requests for ASYNC
// or FILTER operations unless the ACMDRIVERDETAILS_SUPPORTF_ASYNC
// or ACMDRIVERDETAILS_SUPPORTF_FILTER flags are set in the
// ACMDRIVERDETAILS structure. There is no need for the driver to
// check for these requests unless it sets those support bits.
//
// If the ACM_STREAMOPENF_QUERY flag is set in the padsi->fdwOpen
// member, then no resources should be allocated. Just verify that
// the conversion request is possible by this driver and return the
// appropriate error (either ACMERR_NOTPOSSIBLE or MMSYSERR_NOERROR).
// The driver will NOT receive an ACMDM_STREAM_CLOSE for queries.
//
// If the ACM_STREAMOPENF_NONREALTIME bit is NOT set, then conversion
// must be done in 'real-time'. This is a tough one to describe
// exactly. If the driver may have trouble doing the conversion without
// breaking up the audio, then a Configururation dialog might be used
// to allow the user to specify whether the real-time conversion
// request should be succeeded. DO NOT SUCCEED THE CALL UNLESS YOU
// ACTUALLY CAN DO REAL-TIME CONVERSIONS! There may be another driver
// installed that can--so if you succeed the call you are hindering
// the performance of the user's system! Don't be foolish.
//
// Arguments:
// PDRIVERINSTANCE pdi: Pointer to private ACM driver instance structure.
// This structure is [optionally] allocated during the DRV_OPEN message
// which is handled by the acmdDriverOpen function.
//
// LPACMDRVSTREAMINSTANCE padsi: Pointer to instance data for the
// conversion stream. This structure was allocated by the ACM and
// filled with the most common instance data needed for conversions.
// This structure will be passed back to all future stream messages
// if the open succeeds. The information in this structure will never
// change during the lifetime of the stream--so it is not necessary
// to re-verify the information referenced by this structure.
//
// Return (LRESULT):
// The return value is zero (MMSYSERR_NOERROR) if this function
// succeeds with no errors. The return value is a non-zero error code
// if the function fails.
//
// A driver should return ACMERR_NOTPOSSIBLE if the conversion cannot
// be performed due to incompatible source and destination formats.
//
// A driver should return MMSYSERR_NOTSUPPORTED if the conversion
// cannot be performed in real-time and the request does not specify
// the ACM_STREAMOPENF_NONREALTIME flag.
//
//--------------------------------------------------------------------------;
LRESULT FNLOCAL acmdStreamOpen
(
PDRIVERINSTANCE pdi,
LPACMDRVSTREAMINSTANCE padsi
)
{
PSTREAMINSTANCE psi;
LPWAVEFORMATEX pwfxSrc;
LPWAVEFORMATEX pwfxDst;
LPWAVEFILTER pwfltr;
BOOL fRealTime;
//
//
//
pwfxSrc = padsi->pwfxSrc;
pwfxDst = padsi->pwfxDst;
pwfltr = padsi->pwfltr;
fRealTime = (0 == (padsi->fdwOpen & ACM_STREAMOPENF_NONREALTIME));
if( fRealTime )
{
//
// We only do non-realtime conversions.
// Return failure if we are asked for realtime.
//
return (ACMERR_NOTPOSSIBLE);
}
//
// the most important condition to check before doing anything else
// is that this ACM driver can actually perform the conversion we are
// being opened for. this check should fail as quickly as possible
// if the conversion is not possible by this driver.
//
// it is VERY important to fail quickly so the ACM can attempt to
// find a driver that is suitable for the conversion. also note that
// the ACM may call this driver several times with slightl
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -