mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
470 lines
12 KiB
470 lines
12 KiB
//---------------------------------------------------------------------------
|
|
//
|
|
// Module: sbproctl.c
|
|
//
|
|
// Purpose: Sound Blaster Pro Mixer control interface for Sound blaster driver
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright (c) 1994 Microsoft Corporation. All Rights Reserved.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#include "sound.h"
|
|
#include "sbpromix.h"
|
|
|
|
BOOLEAN SBPROSetADCVolume
|
|
(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, SBPROSetMute)
|
|
#pragma alloc_text(PAGE, SBPROSetVolume)
|
|
#pragma alloc_text(PAGE, SBPROSetSources)
|
|
#pragma alloc_text(PAGE, SBPROSetADCHardware)
|
|
#pragma alloc_text(PAGE, SBPROSetADCVolume)
|
|
#pragma alloc_text(PAGE, SBPROResetADCHardware)
|
|
#endif
|
|
|
|
|
|
#if DBG
|
|
static char *ControlNames[NumberOfControls] = {
|
|
"ControlLineoutVolume", // 0
|
|
"ControlLineoutMute", // 1
|
|
|
|
"ControlWaveInMux", // 2
|
|
|
|
"ControlVoiceInMux", // 3
|
|
|
|
"ControlLineoutAuxVolume", // 4
|
|
"ControlLineoutAuxMute", // 5
|
|
|
|
"ControlLineoutMidioutVolume", // 6
|
|
"ControlLineoutMidioutMute", // 7
|
|
|
|
"ControlLineoutInternalCDVolume", // 8
|
|
"ControlLineoutInternalCDMute", // 9
|
|
|
|
"ControlLineoutWaveoutVolume", // 10
|
|
"ControlLineoutWaveoutMute", // 11
|
|
"ControlLineoutWaveoutPeak", // 12
|
|
|
|
"ControlWaveInAuxVolume", // 13
|
|
"ControlWaveInAuxPeak", // 14
|
|
|
|
"ControlWaveInMicPeak", // 15
|
|
|
|
"ControlWaveInInternalCDVolume", // 16
|
|
"ControlWaveInInternalCDPeak", // 17
|
|
|
|
"ControlVoiceInAuxVolume", // 18
|
|
"ControlVoiceInAuxPeak", // 19
|
|
|
|
"ControlVoiceInMicPeak" // 20
|
|
};
|
|
#endif // DBG
|
|
|
|
|
|
//------------------------------------------------------------------------
|
|
// BOOLEAN SBPROSetVolume
|
|
//
|
|
// Description:
|
|
// Sets the audio volume for the specified control.
|
|
//
|
|
// Parameters:
|
|
// PGLOBAL_DEVICE_INFO pGDI
|
|
// Global device data
|
|
//
|
|
// ULONG ControlId
|
|
// Id of the control
|
|
//
|
|
// Return Value:
|
|
// TRUE
|
|
//
|
|
//------------------------------------------------------------------------
|
|
|
|
BOOLEAN SBPROSetVolume
|
|
(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
UCHAR bNumStepsL, bNumStepsR, bDSPReg ;
|
|
PLOCAL_MIXER_CONTROL_INFO ControlInfo;
|
|
|
|
ControlInfo = &pGDI->LocalMixerData.ControlInfo[ControlId];
|
|
|
|
dprintf3(("SBPROSetVolume, Control ID = %s, Left = %u, Right = %u",
|
|
ControlNames[ControlId], ControlInfo->Data.v[0].u, ControlInfo->Data.v[1].u));
|
|
|
|
if (ControlId != ControlLineoutVolume) {
|
|
//
|
|
// If it's not an output line call SBPROSetADCVolume
|
|
//
|
|
|
|
if (SBPROLineInit[SBPROControlInit[ControlId].LineID].Destination
|
|
!= DestLineout) {
|
|
return SBPROSetADCVolume(pGDI, ControlId);
|
|
}
|
|
|
|
|
|
//
|
|
// If wave input is running we don't want to change the volume on lines
|
|
// which are switched to wave input because these lines have the input
|
|
// volume set
|
|
//
|
|
|
|
|
|
if (!SBPROMixerOutputFree(pGDI, SBPROControlInit[ControlId].LineID)) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Convert to steps of 1.5dB attenuation for the DSP
|
|
//
|
|
|
|
bNumStepsL =
|
|
VolLinearToLog( ControlInfo->Data.v[0].u );
|
|
bNumStepsR =
|
|
VolLinearToLog( ControlInfo->Data.v[1].u );
|
|
|
|
// Bounding...
|
|
|
|
if (bNumStepsL > 0x07)
|
|
bNumStepsL = 0x07 ;
|
|
|
|
if (bNumStepsR > 0x07)
|
|
bNumStepsR = 0x07 ;
|
|
|
|
// Convert to levels for the SB mixer
|
|
|
|
bNumStepsL = (0x07 - bNumStepsL) << 5 ;
|
|
bNumStepsR = (0x07 - bNumStepsR) << 1 ;
|
|
|
|
//
|
|
// Check the associated mute... if set, mute the output.
|
|
//
|
|
|
|
ASSERT(SBPROControlInit[ControlId + 1].dwControlType ==
|
|
MIXERCONTROL_CONTROLTYPE_MUTE);
|
|
|
|
if (ControlInfo[1].Data.v[0].u) {
|
|
bNumStepsL = bNumStepsR = 0 ;
|
|
}
|
|
|
|
switch (ControlId)
|
|
{
|
|
case ControlLineoutAuxVolume:
|
|
bDSPReg = DSP_MIX_LINEVOLIDX;
|
|
break ;
|
|
|
|
case ControlLineoutWaveoutVolume:
|
|
|
|
//
|
|
// Only mess with DAC during playback
|
|
//
|
|
|
|
if (!WAVE_OUT_ACTIVE(&pGDI->WaveInfo)) {
|
|
return TRUE;
|
|
}
|
|
|
|
bDSPReg = DSP_MIX_VOICEVOLIDX ;
|
|
break ;
|
|
|
|
case ControlLineoutMidioutVolume:
|
|
bDSPReg = DSP_MIX_FMVOLIDX ;
|
|
break ;
|
|
|
|
case ControlLineoutInternalCDVolume:
|
|
bDSPReg = DSP_MIX_CDVOLIDX;
|
|
break ;
|
|
|
|
case ControlLineoutVolume:
|
|
bDSPReg = DSP_MIX_MSTRVOLIDX;
|
|
break ;
|
|
}
|
|
|
|
dprintf3(( "bNumStepsL = %02x, bNumStepsR = %02x", bNumStepsL, bNumStepsR )) ;
|
|
|
|
dspWriteMixer( pGDI, bDSPReg, (UCHAR)(bNumStepsL | bNumStepsR )) ;
|
|
|
|
return TRUE;
|
|
|
|
} // end of MixSetVolume()
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// MMRESULT SBPROSetMute
|
|
//
|
|
// Description:
|
|
// Sets/unsets the associated control's mute
|
|
//
|
|
// Parameters:
|
|
// PGLOBAL_DEVICE_INFO pGDI
|
|
// Global device data
|
|
//
|
|
// ULONG ControlId
|
|
// Id of the control
|
|
//
|
|
// Return Value:
|
|
// TRUE
|
|
//------------------------------------------------------------------------
|
|
|
|
BOOLEAN SBPROSetMute
|
|
(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
PLOCAL_MIXER_CONTROL_INFO ControlInfo;
|
|
|
|
ControlInfo = &pGDI->LocalMixerData.ControlInfo[ControlId];
|
|
|
|
dprintf3(("MixSetMute, Control ID = %s, Value = %s",
|
|
ControlNames[ControlId], ControlInfo->Data.v[0].u ? "Mute" : "Unmute"));
|
|
|
|
//
|
|
// Force an update of the volume - this will cause the
|
|
// respective control to mute the hardware.
|
|
//
|
|
// NOTE that the mute controls are ALWAYS immediately after
|
|
// their respective volume control
|
|
//
|
|
|
|
ASSERT(SBPROControlInit[ControlId - 1].dwControlType ==
|
|
MIXERCONTROL_CONTROLTYPE_VOLUME);
|
|
return SBPROSetVolume( pGDI, ControlId - 1 ) ;
|
|
|
|
} // end of SBPROSetMute()
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// MMRESULT SBPROSetADCVolume
|
|
//
|
|
// Description:
|
|
// Sets the ADC volume
|
|
//
|
|
// Parameters:
|
|
// PGLOBAL_DEVICE_INFO pGDI
|
|
// Global device data
|
|
//
|
|
// ULONG ControlId
|
|
// Id of the control
|
|
//
|
|
// Return Value:
|
|
// TRUE
|
|
//------------------------------------------------------------------------
|
|
|
|
BOOLEAN SBPROSetADCVolume
|
|
(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
SBPROSetADCHardware(pGDI);
|
|
|
|
return TRUE;
|
|
|
|
} // end of SBPROSetADCVolume()
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// MMRESULT SBPROResetADCHardware
|
|
//
|
|
// Description:
|
|
// Resets the line levels to DEST_LINEOUT settings.
|
|
//
|
|
// Parameters:
|
|
// PGLOBAL_DEVICE_INFO pGDI
|
|
//
|
|
// Return (MMRESULT):
|
|
// nothing
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID SBPROResetADCHardware(PGLOBAL_DEVICE_INFO pGDI)
|
|
{
|
|
dprintf3(( "SBPROResetADCHardware" ));
|
|
|
|
//
|
|
// Just set the volume - the code in SBPROSetVolume will now
|
|
// set the volumes correctly because input is no longer active
|
|
//
|
|
|
|
SBPROSetVolume(pGDI, ControlLineoutAuxVolume);
|
|
SBPROSetVolume(pGDI, ControlLineoutMidioutVolume);
|
|
SBPROSetVolume(pGDI, ControlLineoutInternalCDVolume);
|
|
|
|
} // SBPROResetADCHardware()
|
|
|
|
|
|
VOID Set3BitVolume(PGLOBAL_DEVICE_INFO pGDI, UCHAR Register, USHORT Left, USHORT Right)
|
|
{
|
|
UCHAR bLeft, bRight;
|
|
|
|
bLeft = VolLinearToLog(Left);
|
|
if (bLeft > 0x07) {
|
|
bLeft = 0x07;
|
|
}
|
|
|
|
bRight = VolLinearToLog(Right);
|
|
if (bRight > 0x07) {
|
|
bRight = 0x07;
|
|
}
|
|
|
|
dspWriteMixer(pGDI, Register,
|
|
(UCHAR)(((0x07 - bLeft) << 5) | ((0x07 - bRight) << 1)));
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// MMRESULT SBPROSetADCHardware
|
|
//
|
|
// Description:
|
|
// Sets the ADC hardware per selected wave-in device
|
|
// control settings.
|
|
//
|
|
// Parameters:
|
|
// PGLOBAL_DEVICE_INFO pGDI
|
|
//
|
|
// Return nothing
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID SBPROSetADCHardware(PGLOBAL_DEVICE_INFO pGDI)
|
|
{
|
|
UCHAR bSource;
|
|
UCHAR bNumStepsL, bNumStepsR, bGainL, bGainR, bValue ;
|
|
DWORD dwDest, dwAGCControlID, dwMixerControlID,
|
|
dwGainControlID, dwVolControlID ;
|
|
UINT i ;
|
|
|
|
dprintf3(( "SBPROSetADCHardware" )) ;
|
|
|
|
bSource = 0xFF;
|
|
|
|
if (WAVE_IN_ACTIVE(&pGDI->WaveInfo)) {
|
|
if (MixerLineSelected(&pGDI->LocalMixerData, ControlWaveInMux, DestWaveInSourceAux)) {
|
|
|
|
bSource = 0x06;
|
|
|
|
Set3BitVolume(
|
|
pGDI,
|
|
DSP_MIX_LINEVOLIDX,
|
|
pGDI->LocalMixerData.ControlInfo[ControlWaveInAuxVolume].Data.v[0].u,
|
|
pGDI->LocalMixerData.ControlInfo[ControlWaveInAuxVolume].Data.v[1].u);
|
|
} else
|
|
|
|
if (MixerLineSelected(&pGDI->LocalMixerData, ControlWaveInMux, DestWaveInSourceMic)) {
|
|
|
|
bSource = 0x00;
|
|
|
|
//
|
|
// No volume to set
|
|
//
|
|
} else
|
|
|
|
if (MixerLineSelected(&pGDI->LocalMixerData, ControlWaveInMux, DestWaveInSourceInternal)) {
|
|
|
|
bSource = 0x02;
|
|
|
|
Set3BitVolume(
|
|
pGDI,
|
|
DSP_MIX_CDVOLIDX,
|
|
pGDI->LocalMixerData.ControlInfo[ControlWaveInInternalCDVolume].Data.v[0].u,
|
|
pGDI->LocalMixerData.ControlInfo[ControlWaveInInternalCDVolume].Data.v[1].u);
|
|
}
|
|
} else {
|
|
if (VOICE_IN_ACTIVE(&pGDI->WaveInfo)) {
|
|
|
|
if (pGDI->LocalMixerData.ControlInfo[ControlVoiceInMux].Data.v[0].u ==
|
|
MUXINPUT_AUX1) {
|
|
|
|
bSource = 0x06;
|
|
|
|
Set3BitVolume(
|
|
pGDI,
|
|
DSP_MIX_LINEVOLIDX,
|
|
pGDI->LocalMixerData.ControlInfo[ControlWaveInAuxVolume].Data.v[0].u,
|
|
pGDI->LocalMixerData.ControlInfo[ControlWaveInAuxVolume].Data.v[1].u);
|
|
} else {
|
|
bSource = 0x00;
|
|
}
|
|
} else {
|
|
|
|
//
|
|
// Nothing to set
|
|
//
|
|
return;
|
|
}
|
|
}
|
|
|
|
ASSERT(bSource != 0xFF);
|
|
|
|
//
|
|
// Select input source
|
|
//
|
|
|
|
{
|
|
UCHAR InputSettingRegister;
|
|
|
|
InputSettingRegister = dspReadMixer(pGDI, INPUT_SETTING_REG);
|
|
InputSettingRegister &= ~0x06;
|
|
dspWriteMixer(pGDI, INPUT_SETTING_REG,
|
|
(UCHAR)(InputSettingRegister | bSource));
|
|
}
|
|
|
|
} // SBPROSetADCHardware()
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// MMRESULT SBPROSetMixerSources
|
|
//
|
|
// Description:
|
|
// Sets the mixer sources based on values stored during
|
|
// MxdSetControlDetails(). Does not update ADC hardware
|
|
// unless the associated destination is active.
|
|
//
|
|
// Parameters:
|
|
// PGLOBAL_DEVICE_INFO pGDI
|
|
// Global device data
|
|
//
|
|
// ULONG ControlId
|
|
// Id of the control
|
|
//
|
|
// Return Value:
|
|
// TRUE
|
|
//------------------------------------------------------------------------
|
|
|
|
BOOLEAN SBPROSetSources
|
|
(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
switch (ControlId)
|
|
{
|
|
case ControlWaveInMux:
|
|
case ControlVoiceInMux:
|
|
|
|
// Don't touch if the hardware is not active...
|
|
// (SBPROSetADCHardware checks this)
|
|
|
|
SBPROSetADCHardware(pGDI);
|
|
break ;
|
|
|
|
default:
|
|
// Shouldn't get here...
|
|
|
|
ASSERT(FALSE);
|
|
break;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
} // SBPROSetMixerSources()
|
|
|
|
|