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

565 lines
14 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
sb16mix.c
Abstract:
Mixer code for the Sound Blaster 16 card.
Environment:
Kernel mode
Revision History:
--*/
#include "sound.h"
#include "sb16mix.h"
/*
** Local functions and data
*/
VOID
SB16WaveinLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SB16WaveoutLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SB16SynthLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SB16SetVolumeControlIds(
PGLOBAL_DEVICE_INFO pGDI
);
BOOLEAN
SB16MixerSet(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
);
BOOLEAN
SB16LineActive(
IN PGLOBAL_DEVICE_INFO pGDI,
IN ULONG LinelId
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,SB16MixerInit)
#pragma alloc_text(INIT,SB16SetVolumeControlIds)
#pragma alloc_text(PAGE,SB16WaveinLineChanged)
#pragma alloc_text(PAGE,SB16LineActive)
#pragma alloc_text(PAGE,SB16MixerOutputFree)
#pragma alloc_text(PAGE,SB16WaveoutLineChanged)
#pragma alloc_text(PAGE,SB16SynthLineChanged)
#pragma alloc_text(PAGE,SB16MixerSet)
#endif
VOID
SB16MixerInit(
PGLOBAL_DEVICE_INFO pGDI
)
/*++
Routine Description:
Initialize our local data for the sound blaster 16
Arguments:
pGDI - Global card device info
Return Value:
None
--*/
{
PLOCAL_MIXER_DATA LocalMixerData;
ULONG i;
LocalMixerData = &pGDI->LocalMixerData;
LocalMixerData->MixerLineInit = SB16LineInit;
LocalMixerData->NumberOfLines = NumberOfLines;
LocalMixerData->MixerControlInit = SB16ControlInit;
LocalMixerData->NumberOfControls = NumberOfControls;
LocalMixerData->MixerTextInit = SB16TextInit;
LocalMixerData->MaxSettableItems = NumberOfControls - 3; // Can't set meters
/*
** NOTE - generic code works out NumberOfTextItems so we don't need to
** set it here (and we shouldn't!).
*/
/*
** Set up our callbacks
*/
LocalMixerData->MixerSet = SB16MixerSet;
LocalMixerData->MixerLineActive = SB16LineActive;
/*
** Note - these generic volume controls control both the recording and
** the playing volumes - whichever they are switched to
*/
SB16SetVolumeControlIds(pGDI);
/*
** Set up line notifications and volume control ids for non-mixer devices
*/
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveInDevice]->DeviceExtension,
SB16WaveinLineChanged);
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
SB16WaveoutLineChanged);
if (pGDI->Synth.DeviceObject) {
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->Synth.DeviceObject->DeviceExtension,
SB16SynthLineChanged);
}
/*
** Set up defaults
*/
for (i = 0; i < NumberOfControls; i++) {
switch (i) {
/*
** For us it's either Mute, a volume, a Mux or a Mixer.
**
** Volumes are set to a fixed value
**
** Nothing is muted
*/
case ControlLineoutVolume:
case ControlWaveInVolume:
case ControlVoiceInVolume:
case ControlLineoutAuxVolume:
case ControlLineoutMidioutVolume:
case ControlLineoutMicVolume:
case ControlLineoutInternalCDVolume:
case ControlLineoutWaveoutVolume:
case ControlWaveInAuxVolume:
case ControlWaveInMidioutVolume:
case ControlWaveInMicVolume:
case ControlWaveInInternalCDVolume:
case ControlVoiceInAuxVolume:
case ControlVoiceInMicVolume:
case ControlLineoutBass:
case ControlLineoutTreble:
/*
** Half volume
*/
LocalMixerData->ControlInfo[i].Data.v[0].u = 32768;
LocalMixerData->ControlInfo[i].Data.v[1].u = 32768;
break;
case ControlLineoutMux:
case ControlWaveInMux:
/*
** Everything is selected initially.
** NOTE - we supply a bogus flag for midi out on line out
** so that SoundMixerLineActive stuff works out correctly.
** for that line.
*/
LocalMixerData->ControlInfo[i].Data.MixMask =
(1 << LocalMixerData->MixerLineInit[DestWaveIn].cConnections) - 1;
break;
case ControlVoiceInMux:
/*
** Only record voice from microphone by default
*/
LocalMixerData->ControlInfo[i].Data.v[0].u = MUXINPUT_MIC;
break;
case ControlLineoutMute:
case ControlLineoutAuxMute:
case ControlLineoutMidioutMute:
case ControlLineoutInternalCDMute:
case ControlLineoutWaveoutMute:
case ControlLineoutGain:
/*
** Already 0
*/
break;
case ControlLineoutMicMute:
case ControlLineoutMicAGC:
case ControlWaveInMicAGC:
case ControlVoiceInMicAGC:
/* AGC on by default and mute the mic so as not to confuse
people */
LocalMixerData->ControlInfo[i].Data.v[0].u = 1;
break;
case ControlWaveInPeak:
case ControlVoiceInPeak:
case ControlLineoutWaveoutPeak:
/*
** Not settable
*/
break;
default:
ASSERT(FALSE); // Added control but forgot to set it!
break;
}
}
}
VOID
SB16WaveinLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
)
{
UCHAR Line;
PLOCAL_MIXER_DATA LocalMixerData;
PGLOBAL_DEVICE_INFO pGDI;
pGDI = pLDI->pGlobalInfo;
LocalMixerData = &((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->LocalMixerData;
/*
** Wave Input is starting or stopping - set the hardware accordingly
*/
if (WAVE_IN_ACTIVE(&pGDI->WaveInfo)) {
SB16SetADCHardware(pGDI);
} else {
SB16ResetADCHardware(pGDI);
}
/*
** The only VU Meter is on wave in so let them know that's changed.
*/
switch (Code) {
case SOUND_LINE_NOTIFY_WAVE:
Line = DestWaveIn;
break;
default: // Get rid of warning
case SOUND_LINE_NOTIFY_VOICE:
Line = DestVoiceIn;
break;
}
SoundMixerChangedItem(
&((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->MixerInfo,
&LocalMixerData->LineNotification[Line]);
}
VOID
SB16WaveoutLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
)
{
PLOCAL_MIXER_DATA LocalMixerData;
LocalMixerData = &((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->LocalMixerData;
/*
** Set the volume
*/
SB16SetVolume((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo,
ControlLineoutWaveoutVolume);
SoundMixerChangedItem(
&((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->MixerInfo,
&LocalMixerData->LineNotification[DestLineoutSourceWaveout]);
}
VOID
SB16SynthLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
)
{
PLOCAL_MIXER_DATA LocalMixerData;
PGLOBAL_DEVICE_INFO pGDI;
pGDI = CONTAINING_RECORD(pLDI->pGlobalInfo, GLOBAL_DEVICE_INFO, Synth);
/*
** Set the volume. We don't know (although we could find out!) which
** output midi is switched to so we set both volumes.
*/
SB16SetVolume(pGDI, ControlLineoutMidioutVolume);
SB16SetVolume(pGDI, ControlWaveInMidioutVolume);
LocalMixerData = &pGDI->LocalMixerData;
SoundMixerChangedItem(
&pGDI->MixerInfo,
&LocalMixerData->LineNotification[DestLineoutSourceMidiout]);
}
VOID
SB16SetVolumeControlIds(
PGLOBAL_DEVICE_INFO pGDI
)
{
SoundSetVolumeControlId(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
ControlLineoutWaveoutVolume);
SoundSetVolumeControlId(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[LineInDevice]->DeviceExtension,
ControlLineoutAuxVolume);
SoundSetVolumeControlId(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[CDInternal]->DeviceExtension,
ControlLineoutInternalCDVolume);
if (pGDI->Synth.DeviceObject) {
SoundSetVolumeControlId(
(PLOCAL_DEVICE_INFO)pGDI->Synth.DeviceObject->DeviceExtension,
ControlLineoutMidioutVolume);
}
}
BOOLEAN
SB16MixerSet(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
)
{
switch (ControlId) {
case ControlLineoutVolume:
case ControlWaveInVolume:
case ControlVoiceInVolume:
case ControlLineoutAuxVolume:
case ControlLineoutMidioutVolume:
case ControlLineoutMicVolume:
case ControlLineoutInternalCDVolume:
case ControlLineoutWaveoutVolume:
case ControlWaveInAuxVolume:
case ControlWaveInMidioutVolume:
case ControlWaveInMicVolume:
case ControlWaveInInternalCDVolume:
case ControlVoiceInAuxVolume:
case ControlVoiceInMicVolume:
return SB16SetVolume(pGDI, ControlId);
case ControlLineoutBass:
case ControlLineoutTreble:
return SB16SetTone(pGDI, ControlId);
case ControlLineoutMux:
case ControlWaveInMux:
case ControlVoiceInMux:
return SB16SetSources(pGDI, ControlId);
case ControlLineoutMute:
case ControlLineoutAuxMute:
case ControlLineoutMidioutMute:
case ControlLineoutMicMute:
case ControlLineoutInternalCDMute:
case ControlLineoutWaveoutMute:
return SB16SetMute(pGDI, ControlId);
case ControlLineoutMicAGC:
case ControlWaveInMicAGC:
case ControlVoiceInMicAGC:
return SB16SetAGC(pGDI, ControlId);
case ControlLineoutGain:
return SB16SetGain(pGDI, ControlId);
case ControlWaveInPeak:
case ControlVoiceInPeak:
case ControlLineoutWaveoutPeak:
/*
** Not settable
*/
return FALSE;
default:
dprintf1(("Invalid ControlId %u", ControlId));
ASSERT(FALSE);
return FALSE;
}
}
BOOLEAN
SB16LineActive(
IN PGLOBAL_DEVICE_INFO pGDI,
IN ULONG LineId
)
{
/*
** The factors that affect this are
** - the mux settings
** - whether there is an output device playing
** - whether we are recording :
**
** If a device is deselected via a mux it's inactive
** A wave output device is only active when it's playing
** (we can't apply this to the whole of wave input because that
** dest contains a mux which is always valid.
**
** If an output source's counterpart is selected for record then
** it is inactive.
*/
switch (LineId) {
/*
** Muxes, line out line out are always available
*/
case DestWaveIn:
/*
** Well, even though the mux is operational we'd better not return
** active if we're not recording or all sorts of peak meters will
** pop up
*/
return WAVE_IN_ACTIVE(&pGDI->WaveInfo);
case DestVoiceIn:
return VOICE_IN_ACTIVE(&pGDI->WaveInfo);
case DestLineout:
return TRUE;
case DestLineoutSourceMidiout:
case DestLineoutSourceInternal:
case DestLineoutSourceAux:
case DestLineoutSourceMic:
return SB16MixerOutputFree(pGDI, LineId);
break;
case DestWaveInSourceMidiout:
case DestWaveInSourceInternal:
case DestWaveInSourceAux:
case DestWaveInSourceMic:
/*
** These guys are only active if wave input is active
*/
if (WAVE_IN_ACTIVE(&pGDI->WaveInfo)) {
if (MixerLineSelected(&pGDI->LocalMixerData, ControlWaveInMux, LineId)) {
return TRUE;
}
}
break;
/*
** Wave out deemed 'active' when open
*/
case DestLineoutSourceWaveout:
if (WAVE_OUT_ACTIVE(&pGDI->WaveInfo)) {
return TRUE;
}
break;
/*
** voice in from aux active when selected and low priority active
*/
case DestVoiceInSourceAux:
case DestVoiceInSourceMic:
if (MixerLineSelected(&pGDI->LocalMixerData, ControlVoiceInMux, LineId) &&
VOICE_IN_ACTIVE(&pGDI->WaveInfo)) {
return TRUE;
}
break;
default:
ASSERT(FALSE); // Invalid
}
return FALSE;
}
BOOLEAN
SB16MixerOutputFree(
IN PGLOBAL_DEVICE_INFO pGDI,
IN ULONG LineId
)
{
/*
** Midi out isn't in the input mixer
*/
if (MixerLineSelected(&pGDI->LocalMixerData, ControlLineoutMux, LineId)) {
if (WAVE_IN_ACTIVE(&pGDI->WaveInfo)) {
ULONG CounterpartId;
switch(LineId) {
case DestLineoutSourceMidiout:
CounterpartId = DestWaveInSourceMidiout;
break;
case DestLineoutSourceInternal:
CounterpartId = DestWaveInSourceInternal;
break;
case DestLineoutSourceAux:
CounterpartId = DestWaveInSourceAux;
break;
case DestLineoutSourceMic:
CounterpartId = DestWaveInSourceMic;
break;
default:
return TRUE;
}
if (!MixerLineSelected(&pGDI->LocalMixerData, ControlWaveInMux, CounterpartId)) {
return TRUE;
}
} else {
if (VOICE_IN_ACTIVE(&pGDI->WaveInfo)) {
if (pGDI->LocalMixerData.
ControlInfo[ControlVoiceInMux].Data.v[0].u ==
MUXINPUT_AUX1) {
if (LineId != DestLineoutSourceAux) {
return TRUE;
}
} else {
if (LineId != DestLineoutSourceMic) {
return TRUE;
}
}
} else {
return TRUE;
}
}
}
return FALSE;
}