Understanding the Audio Mixer

o.w.varley

Well-known member
Hey all,

I'm starting to think I don't properly understand how the audio mixer (AudioMixer4) actually works. I've been through the code for it and also looked at the short docs from the Audio System Design Tool. My understanding is that the AudioMixer4 object has 4 channels and each channel can have its own individual gain set to a value between 0 and 32767. Setting a value of 0 will kill the input for the channel, setting a value of 1 is equivalent to unity gain and will leave the input unchanged and any value above 1 will amplify the signal. The default value for gain I can see is set to 1 for each channel when the AudioMixer4 object is created.

Question 1 - From the above understanding, would I be right to say that if I'm using two channels of the AudioMixer4 and their gain is set to 1 then the outputted audio will be a combination of the two inputs without any attenuation or amplification? I.e. both streams will be mixed together and output as a combined output?

Question 2 - There's a note on the AudioMixer4 that says that signal clipping can occur if the gain is set to a value above 1, but also that this can happen if multiple signals add together to greater than 1. When it refers to multiple signals here, I presume its referring to the separate channels of the mixer? If so, does this mean that by default the combination of each channel can cause clipping because the combined gain would be 4? 1 for each channel? Or am I way off the mark here?

Question 3 - If I've got an AudioMixer4 object that has two input channels, one input channel (channel 1) is the output from another mixer and the other channel (channel 2) is from the microphone. With the gain for the microphone channel set to 0, is there any situation in which the input received from channel 1 would boost the gain of channel 2 even with the gain of channel 2 set to zero? I.e. is there any situation whereby the audio being received from the microphone into the mixer could be heard regardless of its gain being 0?

I've used a mixer in my solution and I'm getting behaviour I just don't understand, mostly due to the behaviour explained in Question 3 above. I'm hoping that someone might be able to help shed some light on the errors in my understanding of the mixer.

Any help appreciated!

Owen
 
Question 1 - From the above understanding, would I be right to say that if I'm using two channels of the AudioMixer4 and their gain is set to 1 then the outputted audio will be a combination of the two inputs without any attenuation or amplification? I.e. both streams will be mixed together and output as a combined output?

Question 2 - There's a note on the AudioMixer4 that says that signal clipping can occur if the gain is set to a value above 1, but also that this can happen if multiple signals add together to greater than 1. When it refers to multiple signals here, I presume its referring to the separate channels of the mixer? If so, does this mean that by default the combination of each channel can cause clipping because the combined gain would be 4? 1 for each channel? Or am I way off the mark here?

Question 3 - If I've got an AudioMixer4 object that has two input channels, one input channel (channel 1) is the output from another mixer and the other channel (channel 2) is from the microphone. With the gain for the microphone channel set to 0, is there any situation in which the input received from channel 1 would boost the gain of channel 2 even with the gain of channel 2 set to zero? I.e. is there any situation whereby the audio being received from the microphone into the mixer could be heard regardless of its gain being 0?

Q1 (with Q2): with two channels, each with gain set to 1, the output audio will be a combo of the two inputs without any attenuation or amplification?
A1 (with A2): Yes. Note that, if the two inputs are both full-size signals (each 1.0 in amplitude), assuming all constructive interference between the two (the two signals are some multiple of each other, so they simply add together at their coincident peaks), the output will be twice as big (2.0 in amplitude), & clipping may very well result.

Q3: With the gain for the microphone channel set to 0, is there any situation in which the input received from channel 1 would boost the gain of channel 2 even with the gain of channel 2 set to zero? I.e. is there any situation whereby the audio being received from the microphone into the mixer could be heard regardless of its gain being 0?
A3: The two inputs should be completely independent, so setting any input to "0" should completely disable that input in the mix.

In my "TeensyMIDIPolySynth", where I combined multiple VFOs in a mixer, I tried to keep the overall gain value (the sum of all input gains) to 1.0 or less. Doing so eliminated any clipping in the mixers (which was certainly a problem that I experienced before this implementation was added).

Also, in case you did not use the Audio System Design Tool to generate your audio connectivity, double-check to make sure that you don't accidentally have two signals connected to the same input of a mixer.

Hope that helps !!

Mark J Culross
KD5RXT
 
You are corrent for 1 & 2.
For Q3, gain of zero in a digital system is true zero - only zero samples can result when you multiply by zero digitally.
In analog mixers this is called "offness", and digital mixer offness is perfect at -infinity dB.

However in the Audio library if you run out of AudioMemory, all sorts of strange behaviours can happen, perhaps you
are seeing this - checkout AudioMemoryUsage() and AudioMemoryUsageMax() for tools to help figure out if this is
an issue.
 
Thanks Mark and Mark for helping my understanding. Given that you've indicated that my understanding is correct, I think its probably worth explaining a little more about what's happening in Q3. I'm in the process of putting together a really simple working code example but at the moment you wouldn't be able to compile it without a lot of superfluous code.

I've got the following Audio objects in my setup; AudioInputI2S (mic), AudioVoiceIn (custom), AudioMixer4 and AudioOutputI2S (headset). I've got patch cords that link the AudioVoiceIn object and mic to the AudioMixer4 using channel 0 (AudioVoiceIn) and 1 (Mic). I've triple checked I've not got them both into the same channel, thanks for the steer. The gain for channel 0 is always set to 1.0, the gain for channel 1 is adjusted by the user using a potentiometer but will be a value between 0 and 1.0, i.e. attenuation only, no amplification.

The AudioVoiceIn object in basic terms is a 10 channel mixer that receives audio data packets over UDP, smashes them together into a single output and then passes this off to the AudioMixer4 which mixes in the microphone and sends the output to a set of headphones. Each of the 10 channels in the AudioVoiceIn object can have its own gain individually adjusted to a value between 0.0 and 1.0. As I mentioned above, the gain for the input channel on the AudioMixer4 that takes the output from the AudioVoiceIn object has a gain that's always set to 1.0.

The problem I'm getting is that I've I adjust the gain of my mic via the potentiometer to be zero (which sets the gain to 0 for the channel on the AudioMixer4 object), and there's no input coming in via the AudioVoiceIn object then, as expected, I can't hear the microphone. However, if any input is being received via the AudioVoiceIn object then the microphone is being re-enabled (despite the gain not changing from 0) and I can, incorrectly, hear my voice again.

If the microphone has a gain that's greater than 0 (so I can hear myself in the headset), and audio is being received by the AudioVoiceIn object then the resulting sound is louder than normal. I.e. if there's nothing coming from AudioVoiceIn I can hear myself at a given level, however, when the AudioVoiceIn object is receiving audio then I can hear myself at a higher than normal level. When the AudioVoiceIn object stops receiving input there's a ~1 second delay before the level drops back down to a normal level.

All of my testing points towards there being something in the AudioVoiceIn that is (somehow) affecting the gain for all channels of the AudioMixer4 object, but I just can't see how and given the previous responses I think this is very unlikely. I'm allocating an AudioMemory block of 64 and I've never seen the usage go above 4 even with all 10 channels on the AudioVoiceIn receiving data. The other thing I'm considering is whether I'm some how inadvertently accessing the memory which holds the mic data and somehow mixing that back in to the AudioVoiceIn. I'll share a snippet from AudioVoiceIn with the update function below:

Code:
void AudioVoiceIn::update(void)
    {
        bool hasData = false;

        // Only update if we're playing 
        if (!_enabled)
            return;

        // Check we have data
        for (int i = 0; i < NUM_BUFFERS; i++)
        {
            if (_buffers[i].HasData())
                hasData = true;
            else
            {
                // If a buffer has no data in it but is reserved then we release the reservation
                if (_buffers[i].IsReserved())
                    _buffers[i].ClearReservation();
            }
        }

        if (!hasData)
            return;

        audio_block_t* out = allocate();

        if (out == nullptr)
        {
            TEENSY_DEBUG.println("NULL pointer returned from allocate in AudioVoiceIn::update");
            return;
        }

        // Loop through all of our buffers, if any have data in them then add these to the audio block we've
        // defined as the out variable. This will mix all of the blocks into a single block for transmission.
        for (int i = 0; i < NUM_BUFFERS; i++)
        {
            if (_buffers[i].HasData())
            {
                int16_t* block = _buffers[i].Pop();

                if (block == nullptr)
                {
                    TEENSY_DEBUG.println("NULL pointer received by AudioVoiceIn");
                    release(out);
                    return;
                }
                else
                {
                    ApplyGainThenAdd(out->data, block, _buffers[i].GetVolume());
                }
            }
        }

        transmit(out);
        release(out);
    }

Fully appreciate that the above can't be run independently, I'm working on something that will run and will share it when I am able. The ApplyGainThenAdd function is the exact same as the AudioMixer4 method.

Any help appreciated,

Owen
 
I would look for where you may be writing to a readonly audio buffer, for example maybe your allocate() function.
 
Interesting! I've just read the docs on allocate and it does say:
The data[] array of a newly allocated block is likely to contain old data. If you require the block to be zero (silent), you must write all 128 samples.

I'm not quite sure how I missed that but I'll try setting them to zero and see what that does.
 
You're using ApplyGainThenAdd into a freshly allocated block - you mustn't assume the contents, the memory system only allocates
the memory, it doesn't zero it. If you look at AudioMixer4 update() you'll see it uses the overwriting version "ApplyGain()" for the
first block, then uses "ApplyGainThenAdd()" for any subsequent blocks - you just need to follow the same pattern.

So you were simply adding on top of old junk from previous uses of the block.
 
Spot on both rcarr and MarkT, scrubbing the memory in the allocated block has resolved the issue.

Thank you both for your inputs, much appreciated!
 
I just have one question. I use a mixer like this on primesound on live shows and I want to listen only my instrument and voice (input 1 and 2 for example) on my In-Ears (Im the only one using it). How do I select only does lines?
 
Back
Top