=====Controlling the audio mixer=====
//by Richard Russell, July 2007//\\ \\ **Note: On Windows Vista and Windows 7 each running application has its own independent audio mixer. The code listed here will work correctly, but the mixer controlled is that for the specific application.**\\ \\ The main //BBC BASIC for Windows// help documentation describes [[http://www.bbcbasic.co.uk/bbcwin/manual/bbcwine.html#playsound|how to control the wave output volume]] but this is just one of the volume controls usually provided by the audio mixer (accessed by double-clicking on the loudspeaker icon in the system tray). Typically you can independently control the volume of Wave, Synth and CD outputs and the level of CD, Microphone and Line inputs (and often several others). You can also mute selected outputs and select which input to use for recording.\\ \\ The **FN_mixerset** routine listed at the end of this article allows you to control the audio mixer from your BBC BASIC program. The routine should be called using code similar to the following:
ok% = FN_mixerset(Dest%, Source%, Control%, Setting%)
The routine returns TRUE if the control was set successfully and FALSE if not.\\ \\ The parameters are as follows:
* **"Dest%"** - The destination for the control, which will generally be either the **Speaker Output** (= **4**) or the **Recording Input** (= **7**).
* **"Source%"** - The audio source for the control, for example the **Line Input** (= **&1002**), **Microphone** (= **&1003**), **Synthesizer** (= **&1004**), **CD** (= **&1005**) or **Wave Output** (= **&1008**).
* **"Control%"** - The control type, which will generally be **Volume** (= **&50030001**), **Mute** (= **&20010002**) or **Mux** (= **&70010001**).
* **"Setting%"** - A value in the range **0-65535** for **Volume**, a value in the range **0-1** for **Mute** or the required source selection for **Mux**.
For other possible values consult the Microsoft documentation.\\ \\ So for example to set the **Microphone recording level** to midrange you could use code like this:
ok% = FN_mixerset(7, &1003, &50030001, 32768)
To set the **CD Player output volume** to one-quarter:
ok% = FN_mixerset(4, &1005, &50030001, 16384)
To mute the **Line input**:
ok% = FN_mixerset(4, &1002, &20010002, 1)
To set a **Master Volume** control (which does not have a specific source) set the **"Source%"** parameter to zero. So to set the **Master speaker volume** to full you could do:
ok% = FN_mixerset(4, 0, &50030001, 65535)
Finally here is the code for **FN_mixerset** itself:
DEF FN_mixerset(dest%, source%, type%, setting%)
LOCAL hmx%, res%, ndevs%, dev%, src%, ok%, MixerLine{}
MIXER_OBJECTFMIXER = 0
MIXER_GETLINEINFOF_SOURCE = 1
MIXER_GETLINEINFOF_COMPONENTTYPE = 3
DIM MixerLine{cbStruct%, dwDestination%, dwSource%, dwLineID%, fdwLine%, \
\ dwUser%, dwComponentType%, cChannels%, cConnections%, \
\ cControls%, szShortName&(15), szName&(63), Target{dwType%, \
\ dwDeviceID%, wMid{l&,h&}, wPid{l&,h&}, vDriverVersion%, \
\ szPname&(31)}}
SYS "mixerGetNumDevs" TO ndevs%
IF ndevs%=0 ERROR 100, "No audio mixer devices"
FOR dev% = 0 TO ndevs%-1
SYS "mixerOpen", ^hmx%, dev%, 0, 0, MIXER_OBJECTFMIXER TO res%
IF res% ERROR 100, "mixerOpen failed"
MixerLine.cbStruct% = DIM(MixerLine{})
MixerLine.dwComponentType% = dest%
SYS "mixerGetLineInfo", hmx%, MixerLine{}, \
\ MIXER_GETLINEINFOF_COMPONENTTYPE TO res%
IF res% ERROR 100, "mixerGetLineInfo (destination) failed"
IF source% = 0 THEN
ok% OR= FN_controlset(hmx%, MixerLine.dwLineID%, type%, setting%)
ELSE
FOR src% = 0 TO MixerLine.cConnections%-1
MixerLine.cbStruct% = DIM(MixerLine{})
MixerLine.dwSource% = src%
SYS "mixerGetLineInfo", hmx%, MixerLine{}, \
\ MIXER_GETLINEINFOF_SOURCE TO res%
IF res% ERROR 100, "mixerGetLineInfo (source) failed"
IF MixerLine.dwComponentType% = source% THEN
ok% OR= FN_controlset(hmx%, MixerLine.dwLineID%, type%, setting%)
ENDIF
NEXT src%
ENDIF
SYS "mixerClose", hmx%
NEXT dev%
= ok%
DEF FN_controlset(hmx%, id%, type%, setting%)
LOCAL MixerLineControls{}, MixerControl{}
LOCAL MixerControlDetails{}, MixerControlDetailsData{}
MIXER_GETLINECONTROLSF_ONEBYTYPE = 2
MIXER_SETCONTROLDETAILSF_VALUE = 0
DIM MixerLineControls{cbStruct%, dwLineID%, dwControl%, cControls%, \
\ cbmxctrl%, pamxctrl%}
DIM MixerControl{cbStruct%, dwControlID%, dwControlType%, fdwControl%, \
\ cMultipleItems%, szShortName&(15), szName&(63), \
\ lMinimum%, lMaximum%, dwReserved%(9)}
DIM MixerControlDetails{cbStruct%, dwControlID%, cChannels%, hwndOwner%, \
\ cbDetails%, paDetails%}
DIM MixerControlDetailsData{dwValue%}
MixerLineControls.cbStruct% = DIM(MixerLineControls{})
MixerLineControls.dwLineID% = id%
MixerLineControls.dwControl% = type%
MixerLineControls.cControls% = 1
MixerLineControls.cbmxctrl% = DIM(MixerControl{})
MixerLineControls.pamxctrl% = MixerControl{}
SYS "mixerGetLineControls", hmx%, MixerLineControls{}, \
\ MIXER_GETLINECONTROLSF_ONEBYTYPE TO res%
IF res% THEN = FALSE
MixerControlDetailsData.dwValue% = setting%
MixerControlDetails.cbStruct% = DIM(MixerControlDetails{})
MixerControlDetails.dwControlID% = MixerControl.dwControlID%
MixerControlDetails.cChannels% = 1
MixerControlDetails.cbDetails% = DIM(MixerControlDetailsData{})
MixerControlDetails.paDetails% = MixerControlDetailsData{}
SYS "mixerSetControlDetails", hmx%, MixerControlDetails{}, \
\ MIXER_SETCONTROLDETAILSF_VALUE TO res%
IF res% ERROR 100, "mixerSetControlDetails failed"
= TRUE