📄 wmaudiosignals.c
字号:
* See WMStatus.h for all other values and meanings.
*---------------------------------------------------------------------------*/
WMSTATUS WMAudioSetSignalVolume( WM_DEVICE_HANDLE hDevice,
WM_AUDIO_SIGNAL signal,
unsigned short volume,
WM_AUDIO_CHANNELS channels
)
{
WMSTATUS status;
int baseVol;
/*
* Convert to dBFS, measured in 1/16dB.
*/
baseVol = WMAudioVolToDbAdv( hDevice, volume );
/*
* Call through to our helper function.
*/
status = WMAudioSetSignalVolumeAdv( hDevice,
signal,
baseVol,
channels
);
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAudioSetSignalVolumes
*
* Set the perceived volumes for the given stereo signal.
* Experiments have shown that a 10dB increase in sound level corresponds
* approximately to a perceived doubling of loudness. We take 0x10000 as
* 0dBFS, and scale from there (so 0xFFFF is loudest, 0x8000 is -10dBFS,
* 0x4000 is -20dBFS, etc).
*
* Note: Linearly reducing the perceived volume does _not_ result in a linear
* attenuation of the output signal.
*
* Parameters:
* hDevice The handle to the device (from WMOpenDevice).
* signal The signal to set.
* leftVol The level to apply to the left channel, where 0xFFFF
* is 0dBFS.
* rightVol The level to apply to the right channel, where 0xFFFF
* is 0dBFS.
*
* Returns: WMSTATUS
* WMS_SUCCESS - success
* WMS_UNSUPPORTED - signal is not supported, or doesn't
* support volume control
* WMS_NO_SUPPORTED_DEVICE - device support not present
* See WMStatus.h for all other values and meanings.
*---------------------------------------------------------------------------*/
WMSTATUS WMAudioSetSignalVolumes( WM_DEVICE_HANDLE hDevice,
WM_AUDIO_SIGNAL signal,
unsigned short leftVol,
unsigned short rightVol
)
{
WMSTATUS status;
int baseVolLeft, baseVolRight;
/*
* Convert to dBFS, measured in 1/16dB.
*/
baseVolLeft = WMAudioVolToDbAdv( hDevice, leftVol );
baseVolRight = WMAudioVolToDbAdv( hDevice, rightVol );
/*
* Call through to our helper function.
*/
status = WMAudioSetSignalVolumesAdv( hDevice,
signal,
baseVolLeft,
baseVolRight
);
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAudioSetSignalVolumeDb
*
* Set the signal level relative to full-scale.
*
* Note: the underlying device may not use dB steps. In this case, the applied
* level will be rounded to the nearest available step. For example, if the device
* has a 1.5dB step size (typical of AC'97 devices), a level of 4 or 5 would both
* result in a 4.5dBFS signal.
*
* Parameters:
* hDevice The handle to the device (from WMOpenDevice).
* signal The signal to set.
* dbVol The relative amplification or attenuation to apply,
* in decibels.
* channels One or more of the WM_CHANNEL_XXX constants.
*
*
* Returns: WMSTATUS
* WMS_SUCCESS - success
* WMS_UNSUPPORTED - signal is not supported, or doesn't
* support volume control
* WMS_NO_SUPPORTED_DEVICE - device support not present
* See WMStatus.h for all other values and meanings.
*---------------------------------------------------------------------------*/
WMSTATUS WMAudioSetSignalVolumeDb( WM_DEVICE_HANDLE hDevice,
WM_AUDIO_SIGNAL signal,
int dbVol,
WM_AUDIO_CHANNELS channels
)
{
WMSTATUS status;
/*
* Call through to our helper function.
*/
status = WMAudioSetSignalVolumeAdv( hDevice,
signal,
WM_SIGNAL_LEVEL( dbVol ),
channels
);
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAudioSetSignalVolumesDb
*
* Set the signal level relative to full-scale.
*
* Note: the underlying device may not use dB steps. In this case, the applied
* level will be rounded to the nearest available step. For example, if the device
* has a 1.5dB step size (typical of AC'97 devices), a level of 4 or 5 would both
* result in a 4.5dBFS signal.
*
* Parameters:
* hDevice The handle to the device (from WMOpenDevice).
* signal The signal to set.
* leftVol The relative amplification or attenuation to apply
* to the left channel, in decibels.
* rightVol The relative amplification or attenuation to apply
* to the right channel, in decibels.
*
*
* Returns: WMSTATUS
* WMS_SUCCESS - success
* WMS_UNSUPPORTED - signal is not supported, or doesn't
* support volume control
* WMS_NO_SUPPORTED_DEVICE - device support not present
* See WMStatus.h for all other values and meanings.
*---------------------------------------------------------------------------*/
WMSTATUS WMAudioSetSignalVolumesDb( WM_DEVICE_HANDLE hDevice,
WM_AUDIO_SIGNAL signal,
int leftVol,
int rightVol
)
{
WMSTATUS status;
/*
* Call through to our helper function.
*/
status = WMAudioSetSignalVolumesAdv( hDevice,
signal,
WM_SIGNAL_LEVEL( leftVol ),
WM_SIGNAL_LEVEL( rightVol )
);
return status;
}
/*-----------------------------------------------------------------------------
* Function: WMAudioSetSignalVolumeAdv
*
* Set the signal level relative to full-scale, specifying the level in 1/16dB
* steps relative to full scale. The WM_SIGNAL_LEVEL macro can convert from
* a dB value to the corresponding 1/16dB value. E.g. WM_SIGNAL_LEVEL( 1.5 )
* gives 0x18, which corresponds to 1.5dBFS.
*
* Note: the underlying device will probably not be able to set this level
* precisely. The applied level will be rounded to the nearest available
* step. For example, if the device has a 1.5dB step size (typical of AC'97
* devices), a level of WM_SIGNAL_LEVEL(4) (0x40), WM_SIGNAL_LEVEL(4.125) (0x42),
* WM_SIGNAL_LEVEL(4.5) (0x48) or WM_SIGNAL_LEVEL( 5 ) (0x50) would all
* result in a 4.5dBFS signal.
*
* Parameters:
* hDevice The handle to the device (from WMOpenDevice).
* signal The signal to set.
* baseVol The relative amplification or attenuation to apply,
* in 1/16 dB steps.
* channels One or more of the WM_CHANNEL_XXX constants.
*
* Returns: WMSTATUS
* WMS_SUCCESS - success
* WMS_UNSUPPORTED - signal is not supported, or doesn't
* support volume control
* WMS_NO_SUPPORTED_DEVICE - device support not present
* See WMStatus.h for all other values and meanings.
*---------------------------------------------------------------------------*/
WMSTATUS WMAudioSetSignalVolumeAdv( WM_DEVICE_HANDLE hDevice,
WM_AUDIO_SIGNAL signal,
int baseVol,
WM_AUDIO_CHANNELS channels
)
{
WMSTATUS status = WMS_UNSUPPORTED;
const WM_SIGNAL_DETAILS *pSignalDetails = NULL;
const WM_CHIPDEF *pChipDef;
unsigned int nSignal;
WM_REGTYPE reg = WM_REG_INVALID;
WM_REGVAL regval = 0;
WM_REGVAL mask = 0;
WM_REGVAL update = 0;
/*
* Make sure that the signal is valid.
*/
if ( !WM_SIGNAL_IS_VALID( signal ) )
{
status = WMS_UNSUPPORTED;
goto error;
}
/*
* Look up our chipdef.
*/
pChipDef = WMGetChipDef( hDevice );
if ( !pChipDef )
{
status = WMS_NO_SUPPORTED_DEVICE;
goto error;
}
/*
* Run through the signals, looking for ones which match. We have
* several scenarios here:
*
* - single field (one entry)
* - multiple fields in the same register (e.g. AC'97)
* - multiple fields in multiple registers (e.g. WM8753)
*/
for ( nSignal = 0; nSignal < pChipDef->signalCount; nSignal++ )
{
pSignalDetails = &pChipDef->pSignalDetails[ nSignal ];
if ( pSignalDetails->signal == signal &&
WM_REG_INVALID != pSignalDetails->reg
)
{
/* The signal matches. Does the channel? */
if ( ( WM_CHANNEL_ALL == channels ) ||
( 0 == ( pSignalDetails->flags & WM_CHANNEL_ALL ) ) ||
( 0 != ( channels & pSignalDetails->flags ) )
)
{
int regVol;
int halfStep;
/*
* It matches.
* Check whether we need to setup for a new register.
*/
if ( pSignalDetails->reg != reg )
{
if ( WM_REG_INVALID != reg )
{
/*
* If we're adding to a previous signal, but it's a different
* register, write the previous one.
*/
status = WMSetField( hDevice, reg, regval, mask );
if ( WM_ERROR( status ) )
{
goto error;
}
}
/* Now initialise our working variables */
reg = pSignalDetails->reg;
regval = 0;
mask = 0;
if ( pSignalDetails->flags & WM_SIG_HAS_UPDATE )
update = pSignalDetails->special;
}
/*
* Work out what is the largest value less than half a step
* (i.e. the largest value we can add to an exact signal so
* we can guarantee it will not change on rounding.
*/
halfStep = pSignalDetails->step/2;
if ( halfStep < 0 )
halfStep = -halfStep;
halfStep = halfStep - 1;
if ( baseVol < 0 )
halfStep = -halfStep;
/*
* Now work out the register value.
* Note we add half a step to get the rounding right.
*/
regVol = baseVol + halfStep;
regVol = regVol / pSignalDetails->step;
regVol += pSignalDetails->zerodB;
/* Trim it to the valid range */
if ( regVol > pSignalDetails->maxval )
regVol = pSignalDetails->maxval;
if ( regVol < pSignalDetails->minval )
regVol = pSignalDetails->minval;
/* Now shift it to the right place in the register */
regVol = regVol << pSignalDetails->shift;
regval |= (WM_REGVAL) regVol;
/* And store the mask */
mask |= pSignalDetails->mask;
#if WM_AUDIO_USE_ZERO_CROSS
/* Set zero-cross if it's there */
if ( WM_SIG_NO_ZERO_CROSS != pSignalDetails->zeroCross )
{
regval |= pSignalDetails->zeroCross;
mask |= pSignalDetails->zeroCross;
}
#endif
/* Check whether we've got a "both" bit we can use */
if ( WM_CHANNEL_STEREO == ( channels & WM_CHANNEL_STEREO ) &&
( pSignalDetails->flags & WM_SIG_HAS_BOTH )
)
{
regval |= pSignalDetails->special;
mask |= pSignalDetails->special;
break;
}
}
}
}
/* Did we find it? */
if ( WM_REG_INVALID == reg )
{
status = WMS_UNSUPPORTED;
goto error;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -