Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 6 of 6

Thread: 16 to 1 Multiplexor with Gain

  1. #1
    Member
    Join Date
    Aug 2016
    Location
    Texas
    Posts
    31

    16 to 1 Multiplexor with Gain

    I'm creating a library object that selects 1 of 16 input blocks, applies gain, and then outputs a single block of audio.
    I've been testing this on the Teensy 4.0. The multiplexing/switch of inputs seems to work fine, but when the gain of the output is set to 0.0 my code seems to crash.
    The gain stage is code taken from the Amplifier library.
    Would appreciate some input on what I might be doing wrong in my code.


    muxAmp.H
    Code:
    #ifndef muxamp_h_
    #define muxamp_h_
    #include "Arduino.h"
    #include "AudioStream.h"
    
    class AudioMuxAmp : public AudioStream
    {
    public:
      AudioMuxAmp(void) : AudioStream(16, inputQueueArray), multiplier(65536){}
      
      virtual void update(void);
      
      void gain(float n) 
      {
        if (n > 32767.0f) n = 32767.0f;
        else if (n < -32767.0f) n = -32767.0f;
        multiplier = n * 65536.0f;
      }
    
      void select(byte input) 
      {
        input_select = input;
      }  
    private:
      int32_t multiplier;
      byte input_select;
      audio_block_t *inputQueueArray[16];
    };
    
    #endif
    muxAmp.cpp
    Code:
    #include <Arduino.h>
    #include "muxamp.h"
    #include "utility/dspinst.h"
    #if defined(__ARM_ARCH_7EM__)
    #define MULTI_UNITYGAIN 65536
    static void applyGain(int16_t *data, int32_t mult)
    {
      uint32_t *p = (uint32_t *)data;
      const uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES);
      do 
      {
        uint32_t tmp32 = *p; // read 2 samples from *data
        int32_t val1 = signed_multiply_32x16b(mult, tmp32);
        int32_t val2 = signed_multiply_32x16t(mult, tmp32);
        val1 = signed_saturate_rshift(val1, 16, 0);
        val2 = signed_saturate_rshift(val2, 16, 0);
        *p++ = pack_16b_16b(val2, val1);
      } 
      while (p < end);
    }
    
    //I added this to write all "0"s to the output block
    static void makeZeros(int16_t *data)
    {
      uint32_t *p = (uint32_t *)data;
      const uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES);
      do 
      {
        *p++ = 0;
      } 
      while (p < end);
    }
    
    #elif defined(KINETISL)
    #define MULTI_UNITYGAIN 256
    static void applyGain(int16_t *data, int32_t mult)
    {
      const int16_t *end = data + AUDIO_BLOCK_SAMPLES;
      do 
      {
        int32_t val = *data * mult;
        *data++ = signed_saturate_rshift(val, 16, 0);
      } 
      while (data < end);
    }
    
    //I added this to write all "0"s to the output block
    static void makeZeros(int16_t *data)
    {
      const int16_t *end = data + AUDIO_BLOCK_SAMPLES;
      do 
      {
        *data++ = 0;
      } 
      while (data < end);
    }
    #endif
    
    
    void AudioMuxAmp::update(void)
    {
      audio_block_t *block;
      int32_t mult = multiplier;
      byte inSource = input_select;
      if (mult == 0) 
      {
        // zero gain, discard any input and transmit nothing
        //block = receiveReadOnly(inSource);//original code
        //if (block) release(block);//original code
    
        //code I changed
        block = receiveWritable(inSource);
        if (block) 
        {
          makeZeros(block->data);
          
          transmit(block);
          release(block);
        }
      } 
      else if (mult == MULTI_UNITYGAIN) 
      {
        // unity gain, pass input to output without any change
        block = receiveReadOnly(inSource);
        if (block) 
        {
          transmit(block);
          release(block);
        }
      } 
      else 
      {
        // apply gain to signal
        block = receiveWritable(inSource);
        if (block) 
        {
          applyGain(block->data, mult);
          transmit(block);
          release(block);
        }
      }
    }

  2. #2
    Senior Member manicksan's Avatar
    Join Date
    Jun 2020
    Location
    Sweden
    Posts
    278
    Why did you change the zero gain code?
    Maybe it's where your problem is?

  3. #3
    Member
    Join Date
    Aug 2016
    Location
    Texas
    Posts
    31
    It was not working before with that in there. I admit I don't fully understand the handling of blocks, and with the original code that says if gain is 0, release block. Seems like the block needs to be transmitted, not simply released to flow on through the objects output and on to other devices. So if I don't understand how a bit of someone else's code works, I try to write something that makes more sense to me.

    I know release just removes ownership of a block so other code can use it. Transmit a block sends out a block. But I don't understand how a receiveReadOnly input block would get transmitted to the objects output to pass along to any following library object's input with a release(block), instead of a transmit(block).

  4. #4
    Senior Member
    Join Date
    Jul 2020
    Posts
    980
    You never release the other blocks, so that upto 15 old blocks may be stuck in the inputQueue, so that when the inSource
    changes an ancient block will be picked up from one of the stuck channel. You should receive from every entry in
    the inputQueue.

    You aren't sanity checking the argument to select(), allowing input_select to be > 15, and you don't initialize input_select
    in the constructor either.

    Can't see why it might be crashing though.

  5. #5
    Member
    Join Date
    Aug 2016
    Location
    Texas
    Posts
    31
    Hi Mark,

    Thanks for the tips, I completely understand your last two points and will update the code to initialize and check for limits.

    Can you explain further on how I would release all 15 blocks of audio_block_t *inputQueueArray[16]; when only 1 is being assigned to "block"?
    Or do I need to create 16 block names in the cpp, one for each input block, then select one for use, then transmit the block used, and release all blocks?

  6. #6
    Member
    Join Date
    Aug 2016
    Location
    Texas
    Posts
    31
    Ok, I think I understand...
    I've attached new files that should work correctly.

    muxAmp.h
    Code:
    #ifndef muxamp_h_
    #define muxamp_h_
    #include "Arduino.h"
    #include "AudioStream.h"
    
    class AudioMuxAmp : public AudioStream
    {
    public:
      AudioMuxAmp(void) : AudioStream(16, inputQueueArray), multiplier(65536), input_select(0){}
      
      virtual void update(void);
      
      void gain(float n) 
      {
        if (n > 32767.0f) n = 32767.0f;
        else if (n < -32767.0f) n = -32767.0f;
        multiplier = n * 65536.0f;
      }
    
      void select(byte input) 
      {
        input_select = input;
        if(input_select > 15)
          {
            input_select = 15;
          }
      }  
    private:
      int32_t multiplier;
      byte input_select;
      audio_block_t *inputQueueArray[16];
    };
    
    #endif
    muxAmp.cpp
    Code:
    #include <Arduino.h>
    #include "muxamp.h"
    #include "utility/dspinst.h"
    
    #if defined(__ARM_ARCH_7EM__)
    #define MULTI_UNITYGAIN 65536
    static void applyGain(int16_t *data, int32_t mult)
    {
      uint32_t *p = (uint32_t *)data;
      const uint32_t *end = (uint32_t *)(data + AUDIO_BLOCK_SAMPLES);
      do 
      {
        uint32_t tmp32 = *p; // read 2 samples from *data
        int32_t val1 = signed_multiply_32x16b(mult, tmp32);
        int32_t val2 = signed_multiply_32x16t(mult, tmp32);
        val1 = signed_saturate_rshift(val1, 16, 0);
        val2 = signed_saturate_rshift(val2, 16, 0);
        *p++ = pack_16b_16b(val2, val1);
      } 
      while (p < end);
    }
    
    #elif defined(KINETISL)
    #define MULTI_UNITYGAIN 256
    static void applyGain(int16_t *data, int32_t mult)
    {
      const int16_t *end = data + AUDIO_BLOCK_SAMPLES;
      do 
      {
        int32_t val = *data * mult;
        *data++ = signed_saturate_rshift(val, 16, 0);
      } 
      while (data < end);
    }
    #endif
    
    
    void AudioMuxAmp::update(void)
    {
      audio_block_t *in;
      int32_t mult = multiplier;
      byte inSource = input_select;
      byte channel;
        
      for (channel=0; channel < 16; channel++) 
        {
          if (channel == inSource)
            {
              if (mult == 0) 
                {
                  // zero gain, discard any input and transmit nothing
                  in = receiveReadOnly(channel);
                } 
                else if (mult == MULTI_UNITYGAIN) 
                {
                  // unity gain, pass input to output without any change
                  in = receiveReadOnly(channel);
                  if (in) 
                  {
                    transmit(in);
                  }
                } 
                else 
                {
                  // apply gain to signal
                  in = receiveWritable(channel);
                  if (in) 
                  {
                    applyGain(in->data, mult);
                    transmit(in);
                  }
                }
            }
          else
            {
              in = receiveReadOnly(channel);  
            }
          release(in);  
        }
    }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •