NT4/private/ntos/dd/sound/soundsys/controls.c
2020-09-30 17:12:29 +02:00

595 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//---------------------------------------------------------------------------
//
// CONTROLS.C
//
// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
//
// Module: controls.c
//
// Purpose: Mixer control interface for SNDSYS.DRV
//
//@@BEGIN_MSINTERNAL
// Development Team:
// Bernie McIlroy (BernieM)
// Bryan A. Woodruff (BryanW)
//
// History: Date Author Comment
// 4/??/93 BernieM Wrote it.
// 5/ 4/93 BryanW Added master volume support.
// 5/ 8/93 BryanW Added this comment block.
// 5/21/93 BryanW Fixed levels/muting when < min.
// 9/24/93 RobinSp Adapted for Windows NT
//@@END_MSINTERNAL
//
//---------------------------------------------------------------------------
//
// Copyright (c) 1993 Microsoft Corporation. All Rights Reserved.
//
//---------------------------------------------------------------------------
#include "sound.h"
#define SILENCE (192)
BOOLEAN MixUpdateGlobalLevels
(
PGLOBAL_DEVICE_INFO pGDI
);
UCHAR
VolLinearToLog(
IN USHORT volume
)
/*++
Routine Description :
Converts a linear scale to a logarithm :
0xffffffff -> 0
0x00010000 -> 191
Arguments :
volume - 0 to 0xffff
Return Value :
value in decibels attenuation, each unit is 1.5 dB
--*/
{
ULONG gain, shift;
ULONG temp;
static CONST UCHAR lut[16] = {0,0,0,1,1,1,2,2,2,2,3,3,3,3,3,3};
UCHAR out;
if (volume == 0) {
return SILENCE;
}
if (volume == 0xFFFF) {
return 0;
}
/* get an estimate to within 6 dB of gain */
for (temp = volume, gain = 0, shift = 0;
temp != 0;
gain += 4, temp >>= 1, shift++);
/* look at highest 3 bits in number into look-up-table to
find how many more dB */
if (shift > 5)
temp = volume >> (shift - 5);
else if (shift < 5)
temp = volume << (5 - shift);
else
temp = volume;
temp &= 0x000f;
gain += lut[temp];
out = (UCHAR) ((16 * 4) + 3 - gain);
return (out < 128) ? out : (UCHAR)127;
}
//------------------------------------------------------------------------
// BOOLEAN MixSetVolume
//
// Description:
// Sets the volume for a control.
//
// Parameters:
// LPMIXERCONTROLDETAILS pmcd
// pointer to mixer control detailss structure
//
// UINT uCardNum
// card number
//
//
// Return Value:
// Nothing.
//
//@@BEGIN_MSINTERNAL
// History: Date Author Comment
// 5/ 5/93 BryanW Added this comment block.
//@@END_MSINTERNAL
//
//------------------------------------------------------------------------
BOOLEAN MixSetVolume
(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
)
{
BYTE bNumStepsL, bNumStepsR ;
ULONG MuteControlId;
dprintf2(( "MixSetVolume" )) ;
ASSERTMSG("Volume control has signed data!",
!pGDI->LocalMixerData.ControlInfo[ControlId].Signed);
/*
** Convert to steps of 1.5dB attenuation for the CODEC
*/
bNumStepsL = VolLinearToLog( pGDI->LocalMixerData.ControlInfo[ControlId].Data.v[0].u ) ;
bNumStepsR = VolLinearToLog( pGDI->LocalMixerData.ControlInfo[ControlId].Data.v[1].u ) ;
/*
** Add master attenuation
*/
bNumStepsL +=
VolLinearToLog(pGDI->LocalMixerData.ControlInfo[
ControlLineoutVolume].Data.v[0].u);
bNumStepsR +=
VolLinearToLog(pGDI->LocalMixerData.ControlInfo[
ControlLineoutVolume].Data.v[1].u);
/*
** If either this line's mute or the lineout (master)
** mute is on, mute it.
*/
switch (ControlId) {
case ControlLineoutWaveoutVolume:
MuteControlId = ControlLineoutWaveoutMute;
break;
case ControlLineoutAux1Volume:
MuteControlId = ControlLineoutAux1Mute;
break;
default:
ASSERT(FALSE);
}
if (pGDI->LocalMixerData.ControlInfo[
ControlLineoutMute].Data.v[0].u != 0 ||
pGDI->LocalMixerData.ControlInfo[
MuteControlId].Data.v[0].u != 0)
{
bNumStepsL = 0x80 ;
bNumStepsR = 0x80 ;
}
dprintf2(("bNumStepsL = %d, bNumStepsR = %d",
(int)bNumStepsL, (int)bNumStepsR )) ;
/*
** Note that we perform this compare after setting the mute
** bit and will reset the mute - the number of cycles wasted
** vs. the compare of special casing the 0x80 is a wash.
*/
HwEnter(&pGDI->Hw);
switch (ControlId)
{
case ControlLineoutAux1Volume:
// AUX1 added gain in the K grade parts...
if (pGDI->Hw.CODECClass != CODEC_J_CLASS)
{
// Mute when out of range...
if (bNumStepsL > 0x1F)
bNumStepsL = 0x80 ;
if (bNumStepsR > 0x1F)
bNumStepsR = 0x80 ;
}
else
{
// Mute when out of range...
if (bNumStepsL > 0x0F)
bNumStepsL = 0x80 ;
if (bNumStepsR > 0x0F)
bNumStepsR = 0x80 ;
}
CODECRegisterWrite( &pGDI->Hw, REGISTER_LEFTAUX1, bNumStepsL ) ;
CODECRegisterWrite( &pGDI->Hw, REGISTER_RIGHTAUX1, bNumStepsR ) ;
break ;
case ControlLineoutWaveoutVolume:
// Mute when out of range...
if (pGDI->Hw.CODECClass != CODEC_J_CLASS)
{
if (bNumStepsL > 0x3F)
bNumStepsL = 0x80 ;
if (bNumStepsR > 0x3F)
bNumStepsR = 0x80 ;
}
else
{
// Don't mute DAC, just fully attenuate on 'J' to avoid
// garbage with muting other sources (bug in chip).
if (bNumStepsL > 0x3F)
bNumStepsL = 0x3F ;
if (bNumStepsR > 0x3F)
bNumStepsR = 0x3F ;
}
/*
** Only write to hardware when active
*/
if (pGDI->DeviceInUse == WaveOutDevice)
{
CODECRegisterWrite( &pGDI->Hw, REGISTER_LEFTOUTPUT, bNumStepsL ) ;
CODECRegisterWrite( &pGDI->Hw, REGISTER_RIGHTOUTPUT, bNumStepsR ) ;
}
break ;
default:
ASSERT(FALSE);
break;
}
HwLeave(&pGDI->Hw);
return TRUE;
} // end of MixSetVolume()
//--------------------------------------------------------------------------
//
// BOOLEAN MixSetADCHardware
//
// Description:
// Sets the ADC hardware...
//
// Parameters:
// LPMIXERCONTROLDETAILS pmcd
// pointer to control details
//
// UINT uCardNum
// card number
//
// Return (BOOLEAN):
// TRUE if no problem
//
//@@BEGIN_MSINTERNAL
// History: Date Author Comment
// 8/18/93 BryanW
//@@END_MSINTERNAL
//
//--------------------------------------------------------------------------
BOOLEAN MixSetADCHardware
(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
)
{
BYTE bSource;
BYTE bMicGainL = 0, bMicGainR = 0 ;
BYTE bNumStepsL, bNumStepsR;
BYTE bADCToCODECLeft, bADCToCODECRight;
ULONG MuxControlId;
ULONG ADCControlId;
PWAVE_INFO WaveInfo;
WaveInfo = &pGDI->WaveInfo;
dprintf2(( "MixSetADCHardware" )) ;
/*
** Determine if we should be changing the hardware
*/
if (pGDI->DeviceInUse != WaveInDevice) {
return TRUE;
}
/*
** Is this a control of the currently selected source?
** If so, just return...
*/
if (WaveInfo->LowPriorityHandle != NULL &&
!WaveInfo->LowPrioritySaved) {
MuxControlId = ControlVoiceInMux;
ADCControlId =
pGDI->LocalMixerData.ControlInfo[ControlVoiceInMux].Data.v[0].u ==
MUXINPUT_AUX1 ?
ControlVoiceInAux1Volume :
ControlVoiceInMicVolume;
} else {
MuxControlId = ControlWaveInMux;
ADCControlId =
pGDI->LocalMixerData.ControlInfo[ControlWaveInMux].Data.v[0].u ==
MUXINPUT_AUX1 ?
ControlWaveInAux1Volume :
ControlWaveInMicVolume;
}
/*
** Don't set it if nothing is changing. If ADC is starting we're lazy
** and just pass in -1.
*/
if (ControlId != (ULONG)-1L &&
ControlId != MuxControlId &&
ControlId != ADCControlId)
{
dprintf2(( "MixSetADCVolume: User is adjusting an inactive input level..." )) ;
return TRUE;
}
/*
** If we got here, we know that the user is altering a control that
** is for the currently active device
*/
bNumStepsL =
VolLinearToLog(pGDI->LocalMixerData.ControlInfo[ADCControlId].Data.v[0].u);
bNumStepsR =
VolLinearToLog(pGDI->LocalMixerData.ControlInfo[ADCControlId].Data.v[1].u);
if (pGDI->LocalMixerData.ControlInfo[MuxControlId].Data.v[0].u == MUXINPUT_MIC)
{
#ifndef STEREOMIC
/*
** Mic is mono, so use Left setting for Right also...
*/
bNumStepsR = bNumStepsL ;
#endif
// Don't use gain on Compaq BA hardware...
// doesn't seem to like it and peaks quite easily.
if (pGDI->Hw.CompaqBA)
{
// Bounding...
if (bNumStepsL > 0x0F)
bNumStepsL = 0x0F ;
if (bNumStepsR > 0x0F)
bNumStepsR = 0x0F ;
// 16 steps for 22.5 dB of gain...
bNumStepsL = 0x0F - bNumStepsL ;
bNumStepsR = 0x0F - bNumStepsR ;
}
else
{
// Bounding...
if (bNumStepsL > 28)
bNumStepsL = 28 ;
if (bNumStepsR > 28)
bNumStepsR = 28 ;
// 28 steps for 42.5 dB of gain...
bNumStepsL = 28 - bNumStepsL ;
bNumStepsR = 28 - bNumStepsR ;
// set 20 dB gain accordingly
if (bNumStepsL > 13)
{
bMicGainL = 0x20 ;
bNumStepsL -= 13 ;
}
if (bNumStepsR > 13)
{
bMicGainR = 0x20 ;
bNumStepsR -= 13 ;
}
}
//
// Now set bSource to Mic for hardware
//
bSource = 0x80;
}
else
{
/*
** Bounding...
*/
if (bNumStepsL > 0x0F)
bNumStepsL = 0x0F ;
if (bNumStepsR > 0x0F)
bNumStepsR = 0x0F ;
bNumStepsL = 0x0F - bNumStepsL ;
bNumStepsR = 0x0F - bNumStepsR ;
//
// Now set bSource to Line-In (for hardware)
//
bSource = 0x40;
}
bADCToCODECLeft = bSource | bMicGainL | bNumStepsL;
bADCToCODECRight = bSource | bMicGainR | bNumStepsR;
ASSERT( (bADCToCODECLeft & 0xC0) != 0xC0 );
ASSERT( (bADCToCODECRight & 0xC0) != 0xC0 );
// #pragma message( "NEED: Auto-calibrate when changing input levels on 'J'" )
HwEnter(&pGDI->Hw);
CODECRegisterWrite( &pGDI->Hw, REGISTER_LEFTINPUT, bADCToCODECLeft );
CODECRegisterWrite( &pGDI->Hw, REGISTER_RIGHTINPUT, bADCToCODECRight );
HwLeave(&pGDI->Hw);
return TRUE;
} // MixSetADCHardware()
//--------------------------------------------------------------------------
//
// BOOLEAN MixSetMasterVolume
//
// Description:
// Sets the master volume
//
// Parameters:
// LPMIXERCONTROLDETAILS pmcd
// pointer to control details
//
// UINT uCardNum
// card number
//
// Return (BOOLEAN):
// TRUE if no problem
//
//@@BEGIN_MSINTERNAL
// History: Date Author Comment
// 5/20/93 BryanW Added this comment block
//@@END_MSINTERNAL
//
//--------------------------------------------------------------------------
BOOLEAN FAR PASCAL MixSetMasterVolume
(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
)
{
dprintf2(("MixSetMasterVolume")) ;
return MixUpdateGlobalLevels(pGDI);
} // MixSetMasterVolume()
//--------------------------------------------------------------------------
//
// BOOLEAN MixSetMute
//
// Description:
// Turns the mute on and off
//
// Parameters:
// LPMIXERCONTROLDETAILS pmcd
// pointer to control details
//
// UINT uCardNum
// card number
//
// Return (BOOLEAN):
// TRUE if no problem
//
//@@BEGIN_MSINTERNAL
// History: Date Author Comment
// 5/20/93 BryanW Added this comment block
//@@END_MSINTERNAL
//
//--------------------------------------------------------------------------
BOOLEAN FAR PASCAL MixSetMute
(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
)
{
//
// The value in the dwValue field has already been updated.
// Nothing to do now, but update all the actual levels.
//
MixUpdateGlobalLevels( pGDI ) ;
return TRUE ;
} // MixSetMute()
//--------------------------------------------------------------------------
//
// BOOLEAN MixUpdateGlobalLevels
//
// Description:
// Updates all controls. This is called when some of the modelling
// causes the hardware to be updated (eg we changed the mux or the
// master)
//
// Parameters:
// UINT uCardNum
//
// Return (BOOLEAN):
// TRUE if no problem
//
//@@BEGIN_MSINTERNAL
// History: Date Author Comment
// 5/20/93 BryanW Added this comment block.
//@@END_MSINTERNAL
//
//--------------------------------------------------------------------------
BOOLEAN MixUpdateGlobalLevels
(
PGLOBAL_DEVICE_INFO pGDI
)
{
/*
** Adjust AUX1 volume.
*/
MixSetVolume( pGDI, (ULONG)ControlLineoutAux1Volume ) ;
/*
** Adjust DAC volume.
*/
MixSetVolume( pGDI, (ULONG)ControlLineoutWaveoutVolume ) ;
return TRUE;
} // MixUpdateGlobalLevels()
//---------------------------------------------------------------------------
// End of File: controls.c
//---------------------------------------------------------------------------