ado_pcm_subchn_mixer_create()

Create a PCM subchannel mixer

Synopsis:

#include <audio_driver.h>

ado_pcm_subchn_mixer_t *ado_pcm_subchn_mixer_create (
    ado_pcm_subchn_t *subchn,
    ado_mixer_t *mixer,
    ado_pcm_subchn_mixer_config_t *config );

Arguments:

subchn
The subchannel to associate with.
mixer
The mixer on which to attach the new controls.
config
A pointer to a ado_pcm_subchn_mixer_config_t structure (see below) that describes the type of the controls the hardware has.

Description:

The ado_pcm_subchn_mixer_create() function is a convenience function for creating mixer elements and callbacks for volume control of a PCM subchannel device. If your audio chip supports more than one simultaneous subchannel, and has gain and or mute controls for each subchannel, this convenience function will simplify their control.

ado_pcm_subchn_mixer_config_t structure

typedef struct ado_pcm_subchn_mixer_config
{
HW_CONTEXT_T  *hw_context;

PCM_SUBCHN_CONTEXT_T  *pcm_sc_context;

uint32_t  channel_mask;

uint32_t  volume_jointly:1;

snd_mixer_element_volume1_range_t  volume_range;

uint32_t  mute_jointly:1;

void (*volume_set)  (HW_CONTEXT_T * hw_context,
                    PCM_SUBCHN_CONTEXT_T * pcm_sc_context, int32_t * volumes,
                    int32_t mute, ado_pcm_subchn_mixer_config_t *config);

void (*mute_set)  (HW_CONTEXT_T * hw_context,
                  PCM_SUBCHN_CONTEXT_T * pcm_sc_context,  int32_t * volumes,
                  int32_t mute, ado_pcm_subchn_mixer_config_t *config);
} ado_pcm_subchn_mixer_config_t;
channel_mask
The number and position of voices, and the new mixer controls. Most commonly this will be 11b or 0x3h for the front left and right channels.
volume_range
The gain range for the volume element. The range is assumed to be from least to most gain.
volume_set
An optional callback function used to set the volume gain. When called by io-audio the volumes pointer is an array, number_of_voices deep, with the level of gain to set on the subchannel. The level is guaranteed to be within the range specified. If this argument is NULL, no volume control is created.
mute_set
An optional callback function used to mute the subchannel output. When called, the mute argument uses a bit for each channel to indicate the mute state. If the bit is on, the subchannel is to be muted; if the bit is zero, the subchannel is to be unmuted. If this argument is NULL, no mute control is created.

Returns:

A pointer to the new subchn mixer, or NULL if an error occurred (errno is set).


Note: The ado_pcm_subchn_mixer_t structure is an opaque data type. You'll need a pointer to it when you call ado_pcm_subchn_mixer_destroy() to destroy the subchannel mixer.

Examples:

This example of how to setup a subchannel mixer is taken from the vortex driver. Due to legal restrictions, the full source to the vortex driver isn't availiable in the DDK. The vortex has individual volume and mute controls for each channel of the stereo stream. The volume controls have a range of 0 to 255 settings, corresponding to a decibel range of -102.35 dB to 0 dB.

The vortex hardware functions, vortex_mixer_input_gain() and vortex_mixer_input_mute() set the hardware volume and mute. But in order to work, those functions need to know which hardware mixer and which mixer input the signals are routed through, so this information is kept in the PCM_SUBCHN_CONTEXT_T *vsc variable.

static void
vortex_subchn_volume_set( HW_CONTEXT_T * vortex,
   PCM_SUBCHN_CONTEXT_T * vsc, int32_t * volumes,
   int32_t mute, ado_pcm_subchn_mixer_config_t * config)
{
    if (vortex->card_type == VORTEX_CARD_TYPE_AU8830)
    {
        vortex_mixer_input_gain_8830 (vortex, vsc->mixL,
           vsc->mixinL, volumes[0]);
        vortex_mixer_input_gain_8830 (vortex, vsc->mixR,
           vsc->mixinR, volumes[1]);
    }
    else
    {
        vortex_mixer_input_gain_8820 (vortex, vsc->mixL,
           vsc->mixinL, volumes[0]);
        vortex_mixer_input_gain_8820 (vortex, vsc->mixR,
           vsc->mixinR, volumes[1]);
    }
}

static void
vortex_subchn_mute_set (HW_CONTEXT_T * vortex,
   PCM_SUBCHN_CONTEXT_T * vsc, int32_t * volumes,
   int32_t mute, ado_pcm_subchn_mixer_config_t * config)
{
    if (vortex->card_type == VORTEX_CARD_TYPE_AU8830)
    {
        vortex_mixer_input_mute_8830 (vortex, vsc->mixL,
           vsc->mixinL, mute & (1 << 0));
        vortex_mixer_input_mute_8830 (vortex, vsc->mixR,
           vsc->mixinR, mute & (1 << 1));
    }
    else
    {
        vortex_mixer_input_mute_8820 (vortex, vsc->mixL,
           vsc->mixinL, mute & (1 << 0));
        vortex_mixer_input_mute_8820 (vortex, vsc->mixR,
           vsc->mixinR, mute & (1 << 1));
    }
}


int32_t
vortex_playback_aquire (HW_CONTEXT_T * vortex,
   PCM_SUBCHN_CONTEXT_T ** vsc,
   ado_pcm_config_t * config, ado_pcm_subchn_t * subchn,
   uint32_t * why_failed)
{
    …
    memset (&vsc_mix_cfg, 0, sizeof (vsc_mix_cfg));
    vsc_mix_cfg.hw_context = vortex;
    vsc_mix_cfg.pcm_sc_context = *vsc;
    vsc_mix_cfg.channel_mask = SND_MIXER_CHN_MASK_STEREO;
    vsc_mix_cfg.volume_range.min = 0;
    vsc_mix_cfg.volume_range.max = 0xff;
    vsc_mix_cfg.volume_range.min_dB = -10235;
    vsc_mix_cfg.volume_range.max_dB = 0;
    vsc_mix_cfg.volume_set = vortex_subchn_volume_set;
    vsc_mix_cfg.mute_set = vortex_subchn_mute_set;
    if (((*vsc)->scmix = ado_pcm_subchn_mixer_create (
       subchn, vortex->mixer, &vsc_mix_cfg)) == NULL)
    {
        return (ENOMEM);
    }
    …
}

int32_t
vortex_playback_release (HW_CONTEXT_T * vortex,
    PCM_SUBCHN_CONTEXT_T * vsc,
    ado_pcm_config_t * config)
{
    …
    ado_pcm_subchn_mixer_destroy (vsc->scmix);
    …
}

Classification:

QNX Neutrino

Safety:
Cancellation point No
Interrupt handler No
Signal handler No
Thread No

See also:

ado_pcm_subchn_mixer_destroy()