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

502 lines
12 KiB
C

/*++
Copyright (c) 1993 Microsoft Corporation
Module Name:
sbpromix.c
Abstract:
Mixer code for the Sound Blaster Pro card.
Environment:
Kernel mode
Revision History:
--*/
#include "sound.h"
#include "sbpromix.h"
/*
** Local functions and data
*/
VOID
SBPROWaveinLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SBPROWaveoutLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SBPROSynthLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
);
VOID
SBPROSetVolumeControlIds(
PGLOBAL_DEVICE_INFO pGDI
);
BOOLEAN
SBPROMixerSet(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
);
BOOLEAN
SBPROLineActive(
IN PGLOBAL_DEVICE_INFO pGDI,
IN ULONG LinelId
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT,SBPROMixerInit)
#pragma alloc_text(INIT,SBPROSetVolumeControlIds)
#pragma alloc_text(PAGE,SBPROWaveinLineChanged)
#pragma alloc_text(PAGE,SBPROLineActive)
#pragma alloc_text(PAGE,SBPROMixerOutputFree)
#pragma alloc_text(PAGE,SBPROWaveoutLineChanged)
#pragma alloc_text(PAGE,SBPROSynthLineChanged)
#pragma alloc_text(PAGE,SBPROMixerSet)
#endif
VOID
SBPROMixerInit(
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 = SBPROLineInit;
LocalMixerData->NumberOfLines = NumberOfLines;
LocalMixerData->MixerControlInit = SBPROControlInit;
LocalMixerData->NumberOfControls = NumberOfControls;
LocalMixerData->MixerTextInit = SBPROTextInit;
LocalMixerData->MaxSettableItems = NumberOfControls - 6; // 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 = SBPROMixerSet;
LocalMixerData->MixerLineActive = SBPROLineActive;
/*
** Note - these generic volume controls control both the recording and
** the playing volumes - whichever they are switched to
*/
SBPROSetVolumeControlIds(pGDI);
/*
** Set up line notifications and volume control ids for non-mixer devices
*/
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveInDevice]->DeviceExtension,
SBPROWaveinLineChanged);
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->DeviceObject[WaveOutDevice]->DeviceExtension,
SBPROWaveoutLineChanged);
if (pGDI->Synth.DeviceObject) {
SoundSetLineNotify(
(PLOCAL_DEVICE_INFO)pGDI->Synth.DeviceObject->DeviceExtension,
SBPROSynthLineChanged);
}
/*
** 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 ControlLineoutAuxVolume:
case ControlLineoutMidioutVolume:
case ControlLineoutWaveoutVolume:
case ControlLineoutInternalCDVolume:
case ControlWaveInAuxVolume:
case ControlWaveInInternalCDVolume:
case ControlVoiceInAuxVolume:
/*
** Half volume
*/
LocalMixerData->ControlInfo[i].Data.v[0].u = 32768;
LocalMixerData->ControlInfo[i].Data.v[1].u = 32768;
break;
case ControlWaveInMux:
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:
/*
** Already 0
*/
break;
case ControlLineoutWaveoutPeak:
case ControlWaveInAuxPeak:
case ControlWaveInMicPeak:
case ControlWaveInInternalCDPeak:
case ControlVoiceInAuxPeak:
case ControlVoiceInMicPeak:
/*
** Not settable
*/
break;
default:
ASSERT(FALSE); // Added control but forgot to set it!
break;
}
}
}
VOID
SBPROWaveinLineChanged(
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)) {
SBPROSetADCHardware(pGDI);
} else {
SBPROResetADCHardware(pGDI);
}
/*
** The only VU Meter is on currently selected wave input
*/
switch (Code) {
case SOUND_LINE_NOTIFY_WAVE:
Line = DestWaveInSourceAux +
LocalMixerData->ControlInfo[ControlWaveInMux].Data.v[0].u;
break;
case SOUND_LINE_NOTIFY_VOICE:
Line = DestVoiceInSourceAux +
LocalMixerData->ControlInfo[ControlVoiceInMux].Data.v[0].u;
break;
}
SoundMixerChangedItem(
&((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->MixerInfo,
&LocalMixerData->LineNotification[Line]);
}
VOID
SBPROWaveoutLineChanged(
PLOCAL_DEVICE_INFO pLDI,
UCHAR Code
)
{
PLOCAL_MIXER_DATA LocalMixerData;
LocalMixerData = &((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->LocalMixerData;
/*
** Set the volume
*/
SBPROSetVolume((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo,
ControlLineoutWaveoutVolume);
SoundMixerChangedItem(
&((PGLOBAL_DEVICE_INFO)pLDI->pGlobalInfo)->MixerInfo,
&LocalMixerData->LineNotification[DestLineoutSourceWaveout]);
}
VOID
SBPROSynthLineChanged(
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.
*/
SBPROSetVolume(pGDI, ControlLineoutMidioutVolume);
LocalMixerData = &pGDI->LocalMixerData;
SoundMixerChangedItem(
&pGDI->MixerInfo,
&LocalMixerData->LineNotification[DestLineoutSourceMidiout]);
}
VOID
SBPROSetVolumeControlIds(
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
SBPROMixerSet(
PGLOBAL_DEVICE_INFO pGDI,
ULONG ControlId
)
{
switch (ControlId) {
case ControlLineoutVolume: // 0
case ControlLineoutAuxVolume: // 4
case ControlLineoutMidioutVolume: // 6
case ControlLineoutInternalCDVolume: // 8
case ControlLineoutWaveoutVolume: // 10
case ControlWaveInAuxVolume: // 13
case ControlWaveInInternalCDVolume: // 16
case ControlVoiceInAuxVolume: // 18
return SBPROSetVolume(pGDI, ControlId);
case ControlLineoutMidioutMute: // 7
case ControlLineoutAuxMute: // 5
case ControlLineoutMute: // 1
case ControlLineoutInternalCDMute: // 9
case ControlLineoutWaveoutMute: // 11
return SBPROSetMute(pGDI, ControlId);
case ControlWaveInMux: // 2
case ControlVoiceInMux: // 3
return SBPROSetSources(pGDI, ControlId);
case ControlLineoutWaveoutPeak: // 12
case ControlWaveInAuxPeak: // 14
case ControlWaveInMicPeak: // 15
case ControlWaveInInternalCDPeak: // 17
case ControlVoiceInAuxPeak: // 19
case ControlVoiceInMicPeak: // 20
/*
** Not settable
*/
return FALSE;
default:
dprintf1(("Invalid ControlId %u", ControlId));
ASSERT(FALSE);
return FALSE;
}
}
BOOLEAN
SBPROLineActive(
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:
return TRUE;
case DestLineoutSourceInternal:
case DestLineoutSourceAux:
return SBPROMixerOutputFree(pGDI, LineId);
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
SBPROMixerOutputFree(
IN PGLOBAL_DEVICE_INFO pGDI,
IN ULONG LineId
)
{
if (WAVE_IN_ACTIVE(&pGDI->WaveInfo)) {
ULONG CounterpartId;
switch(LineId) {
case DestLineoutSourceInternal:
CounterpartId = DestWaveInSourceInternal;
break;
case DestLineoutSourceAux:
CounterpartId = DestWaveInSourceAux;
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 {
return TRUE;
}
}
return FALSE;
}