574 lines
13 KiB
C
574 lines
13 KiB
C
//---------------------------------------------------------------------------
|
|
//
|
|
// CONTROLS.C
|
|
//
|
|
// Copyright (c) 1993 Microsoft Corporation. All rights reserved.
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Module: controls.c
|
|
//
|
|
// Purpose: Mixer control interface for MVAUDIO.SYS
|
|
//
|
|
|
|
#include "sound.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE, MixSetMute)
|
|
#pragma alloc_text(PAGE, MixSetTrebleBass)
|
|
#pragma alloc_text(PAGE, MixSetSingleMux)
|
|
#pragma alloc_text(PAGE, MixSetMultiMux)
|
|
#pragma alloc_text(PAGE, MixSetVolume)
|
|
#endif
|
|
|
|
//
|
|
// Utility routines
|
|
//
|
|
|
|
/*
|
|
** Translate our control ids into real hardware ids
|
|
*/
|
|
|
|
VOID
|
|
GetInputAndOutputId(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId,
|
|
PUCHAR Input,
|
|
PUCHAR Output,
|
|
PBOOLEAN IsInput
|
|
)
|
|
{
|
|
switch (ControlId) {
|
|
case ControlLineoutMute:
|
|
case ControlLineoutMux:
|
|
case ControlLineoutBass:
|
|
case ControlLineoutTreble:
|
|
#ifdef LOUDNESS
|
|
case ControlLineoutLoudness:
|
|
case ControlLineoutStereoEnhance:
|
|
#endif // LOUDNESS
|
|
case ControlWaveInMux:
|
|
case ControlWaveInPeak:
|
|
case ControlVoiceInMux:
|
|
ASSERTMSG("Mixer invalid control id for volume setting", FALSE);
|
|
break;
|
|
|
|
case ControlLineoutVolume:
|
|
*Input = 0;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = FALSE;
|
|
break;
|
|
|
|
case ControlWaveInVolume:
|
|
*Input = 0;
|
|
*Output = OUT_PCM;
|
|
*IsInput = FALSE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutAux1Volume:
|
|
*Input = IN_EXTERNAL;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutMidioutVolume:
|
|
*Input = IN_SYNTHESIZER;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutMicVolume:
|
|
*Input = IN_MICROPHONE;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutInternalCDVolume:
|
|
*Input = IN_INTERNAL;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutPCSpeakerVolume:
|
|
if (IS_MIXER_508B(pGDI)) {
|
|
*Input = IN_SNDBLASTER;
|
|
} else {
|
|
*Input = IN_PC_SPEAKER;
|
|
}
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutAux2Volume:
|
|
ASSERT(IS_MIXER_508B(pGDI));
|
|
*Input = IN_PC_SPEAKER;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
|
|
case ControlLineoutWaveoutVolume:
|
|
*Input = IN_PCM;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlLineoutMixerVolume:
|
|
*Input = IN_MIXER;
|
|
*Output = OUT_AMPLIFIER;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlWaveInAux1Volume:
|
|
*Input = IN_EXTERNAL;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlWaveInMidioutVolume:
|
|
*Input = IN_SYNTHESIZER;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlWaveInMicVolume:
|
|
*Input = IN_MICROPHONE;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlWaveInInternalCDVolume:
|
|
*Input = IN_INTERNAL;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlWaveInAux2Volume:
|
|
ASSERT(IS_MIXER_508B(pGDI));
|
|
*Input = IN_PC_SPEAKER;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlWaveInPCSpeakerVolume:
|
|
if (IS_MIXER_508B(pGDI)) {
|
|
*Input = IN_SNDBLASTER;
|
|
} else {
|
|
*Input = IN_PC_SPEAKER;
|
|
}
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlVoiceInAux1Volume:
|
|
*Input = IN_EXTERNAL;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
|
|
case ControlVoiceInMicVolume:
|
|
*Input = IN_MICROPHONE;
|
|
*Output = OUT_PCM;
|
|
*IsInput = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Set mute
|
|
*/
|
|
|
|
VOID
|
|
SetMute(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
BOOLEAN Mute
|
|
)
|
|
{
|
|
/*
|
|
** Update the mute status and if it's changed set the master volume
|
|
** directly (so the change doesn't NOOP
|
|
*/
|
|
|
|
if (pGDI->MixerState.Mute != Mute) {
|
|
pGDI->MixerState.Mute = Mute;
|
|
SetOutput(pGDI,
|
|
OUT_AMPLIFIER,
|
|
pGDI->MixerState.OutputSettings[OUT_AMPLIFIER].Left,
|
|
_LEFT);
|
|
SetOutput(pGDI,
|
|
OUT_AMPLIFIER,
|
|
pGDI->MixerState.OutputSettings[OUT_AMPLIFIER].Right,
|
|
_RIGHT);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
ChangeInput(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
UCHAR Input,
|
|
UCHAR Output,
|
|
USHORT Channel,
|
|
USHORT Old,
|
|
USHORT New
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Change an input gradually from its current value to its target value
|
|
|
|
NOTE - this routine ASSUMES that each input has 32 steps
|
|
|
|
--*/
|
|
{
|
|
USHORT Current, Final;
|
|
|
|
Current = Old >> 11;
|
|
Final = New >> 11;
|
|
|
|
/*
|
|
** At least once to get the output amp right
|
|
*/
|
|
|
|
while (TRUE) {
|
|
SetInput(pGDI,
|
|
Input,
|
|
(USHORT)(Current << 11),
|
|
Channel,
|
|
MIXCROSSCAPS_NORMAL_STEREO,
|
|
Output);
|
|
|
|
if (Current == Final) {
|
|
break;
|
|
}
|
|
Current = Current > Final ? Current - 1 : Current + 1;
|
|
}
|
|
}
|
|
VOID
|
|
ChangeOutput(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
UCHAR Output,
|
|
USHORT Channel,
|
|
USHORT Old,
|
|
USHORT New
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Change an output gradually from its current value to its target value
|
|
|
|
NOTE - this routine ASSUMES that each output has 64 steps
|
|
|
|
--*/
|
|
{
|
|
USHORT Current, Final;
|
|
|
|
Current = Old >> 10;
|
|
Final = New >> 10;
|
|
|
|
/*
|
|
** At least once to get the output amp right
|
|
*/
|
|
|
|
while (TRUE) {
|
|
SetOutput(pGDI,
|
|
Output,
|
|
(USHORT)(Current << 10),
|
|
Channel);
|
|
|
|
if (Current == Final) {
|
|
break;
|
|
}
|
|
Current = Current > Final ? Current - 1 : Current + 1;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UpdateInput(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
UCHAR Input,
|
|
UCHAR Output,
|
|
USHORT Left,
|
|
USHORT Right
|
|
)
|
|
{
|
|
ASSERT(Input < NUM_INPUTS && Output < NUM_OUTPUTS);
|
|
|
|
/*
|
|
** Check to see if any change is required
|
|
*/
|
|
|
|
if (pGDI->MixerState.InputSettings[Input].Output != Output ||
|
|
pGDI->MixerState.InputSettings[Input].Left != Left ||
|
|
pGDI->MixerState.InputSettings[Input].Right != Right) {
|
|
|
|
ChangeInput(pGDI,
|
|
Input,
|
|
Output,
|
|
_LEFT,
|
|
pGDI->MixerState.InputSettings[Input].Left,
|
|
Left);
|
|
|
|
ChangeInput(pGDI,
|
|
Input,
|
|
Output,
|
|
_RIGHT,
|
|
pGDI->MixerState.InputSettings[Input].Right,
|
|
Right);
|
|
|
|
pGDI->MixerState.InputSettings[Input].Output = Output;
|
|
pGDI->MixerState.InputSettings[Input].Left = Left;
|
|
pGDI->MixerState.InputSettings[Input].Right = Right;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
UpdateOutputLevel(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
UCHAR Output,
|
|
USHORT Left,
|
|
USHORT Right
|
|
)
|
|
{
|
|
ASSERT(Output < NUM_OUTPUTS);
|
|
|
|
/*
|
|
** Check to see if any change is required
|
|
*/
|
|
|
|
if (pGDI->MixerState.OutputSettings[Output].Left != Left ||
|
|
pGDI->MixerState.OutputSettings[Output].Right != Right) {
|
|
|
|
ChangeOutput(pGDI,
|
|
Output,
|
|
_LEFT,
|
|
pGDI->MixerState.OutputSettings[Output].Left,
|
|
Left);
|
|
|
|
ChangeOutput(pGDI,
|
|
Output,
|
|
_RIGHT,
|
|
pGDI->MixerState.OutputSettings[Output].Right,
|
|
Right);
|
|
|
|
pGDI->MixerState.OutputSettings[Output].Left = Left;
|
|
pGDI->MixerState.OutputSettings[Output].Right = Right;
|
|
}
|
|
}
|
|
|
|
BOOLEAN
|
|
MixSetVolume(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
PLOCAL_MIXER_CONTROL_INFO ControlInfo;
|
|
PLOCAL_MIXER_DATA LocalMixerData;
|
|
ULONG LineFlags;
|
|
NTSTATUS Status;
|
|
UCHAR Input;
|
|
UCHAR Output;
|
|
BOOLEAN IsInput;
|
|
|
|
LocalMixerData = &pGDI->LocalMixerData;
|
|
|
|
ControlInfo = &LocalMixerData->ControlInfo[ControlId];
|
|
|
|
/*
|
|
** We need to work out :
|
|
**
|
|
** 1. Is the line active - if not do nothing
|
|
**
|
|
** NOTE: To not set it if it isn't active means we must
|
|
** make sure we set the volume if the line becomes active.
|
|
** This applies specifically to wave out and midi out which
|
|
** are only active when the respective devices are playing.
|
|
** Set mixer.c!SoundSynthLineChanged and
|
|
** mixer.c!SoundWaveoutLineChanged.
|
|
**
|
|
** 2. Otherwise, deduce the hardware line id and change the
|
|
** 3. Setting
|
|
*/
|
|
|
|
Status = HwGetLineFlags(&pGDI->MixerInfo,
|
|
MixerControlInit[ControlId].LineID,
|
|
sizeof(ULONG),
|
|
&LineFlags);
|
|
|
|
ASSERTMSG("HwGetLineFlags returned bad for internal call!",
|
|
NT_SUCCESS(Status));
|
|
|
|
if (!(LineFlags & MIXERLINE_LINEF_ACTIVE)) {
|
|
return TRUE;
|
|
}
|
|
|
|
/*
|
|
** Deduce the hardware info
|
|
*/
|
|
|
|
GetInputAndOutputId(pGDI, ControlId, &Input, &Output, &IsInput);
|
|
|
|
/*
|
|
** Set the relevant control
|
|
*/
|
|
|
|
if (IsInput) {
|
|
UpdateInput(pGDI,
|
|
Input,
|
|
Output,
|
|
ControlInfo->Data.v[0].u,
|
|
ControlInfo->Data.v[1].u);
|
|
|
|
} else {
|
|
/*
|
|
** We're updating an 'output' line - ie OUT_PCM or OUT_AMPLIFIER
|
|
*/
|
|
|
|
UpdateOutputLevel(pGDI,
|
|
Output,
|
|
ControlInfo->Data.v[0].u,
|
|
ControlInfo->Data.v[1].u);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
MixSetSingleMux(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
/*
|
|
** We don't need to do anything if the stuff isn't 'active'
|
|
** If it is 'active' we just need to pull the lines to their
|
|
** correct destinations.
|
|
*/
|
|
|
|
ASSERT(ControlId == ControlVoiceInMux);
|
|
MixSetVolume(pGDI, ControlVoiceInAux1Volume);
|
|
MixSetVolume(pGDI, ControlVoiceInMicVolume);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN
|
|
MixSetMultiMux(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
int i;
|
|
ASSERT(ControlId == ControlWaveInMux ||
|
|
ControlId == ControlLineoutMux);
|
|
|
|
/*
|
|
** Set everything that can be set
|
|
*/
|
|
|
|
for (i = 0;
|
|
i < MAX_INPUTS - 2;
|
|
i++) {
|
|
|
|
MixSetVolume(pGDI, ControlLineoutAux1Volume + i);
|
|
MixSetVolume(pGDI, ControlWaveInAux1Volume + i);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
VOID
|
|
UpdateEQ(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
USHORT Type,
|
|
USHORT Level
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
|
|
Set the Treble and Bass levels - these are assumed to always be switched
|
|
to the OUT_AMPLIFIER
|
|
|
|
--*/
|
|
{
|
|
PUSHORT DestLevel;
|
|
USHORT Current, Target;
|
|
|
|
DestLevel = Type == _TREBLE ? &pGDI->MixerState.Treble :
|
|
&pGDI->MixerState.Bass;
|
|
|
|
for (Current = *DestLevel >> 11,
|
|
Target = Level >> 11;
|
|
Current != Target;
|
|
Current = Current > Target ? Current - 1 : Current + 1
|
|
) {
|
|
|
|
SetEQ(pGDI,
|
|
OUT_AMPLIFIER,
|
|
Type,
|
|
Current);
|
|
}
|
|
|
|
*DestLevel = Level;
|
|
}
|
|
|
|
BOOLEAN
|
|
MixSetTrebleBass(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
UpdateEQ(pGDI,
|
|
(USHORT)(ControlId == ControlLineoutTreble ?
|
|
_TREBLE : _BASS),
|
|
pGDI->LocalMixerData.ControlInfo[ControlId].Data.v[0].u);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef LOUDNESS
|
|
BOOLEAN
|
|
MixSetLineControl(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
ASSERT(ControlId == ControlLineoutLoudness ||
|
|
ControlId == ControlLineoutStereoEnhance);
|
|
|
|
SetEqMode(
|
|
pGDI,
|
|
pGDI->LocalMixerData.ControlInfo[ControlLineoutLoudness].Data.v[0].u,
|
|
pGDI->LocalMixerData.ControlInfo[ControlLineoutStereoEnhance].Data.v[0].u);
|
|
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN
|
|
MixSetMute(
|
|
PGLOBAL_DEVICE_INFO pGDI,
|
|
ULONG ControlId
|
|
)
|
|
{
|
|
ASSERT(ControlId == ControlLineoutMute);
|
|
SetMute(pGDI,
|
|
(BOOLEAN)
|
|
(pGDI->LocalMixerData.ControlInfo[ControlLineoutMute].Data.v[0].u != 0));
|
|
return TRUE;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// End of File: controls.c
|
|
//---------------------------------------------------------------------------
|
|
|