Integer Math SQRT for Equal Power Scaling in Surround Panner Object

grinch

Well-known member
Hi, I'm writing a surround panner object for use with the Teensy and the CS42448 8ch codec. It accepts an audio input and a -1 to 1 control input, sending the input to one of 8 outputs.

I'm wondering how I can accomplish equal power scaling using audio library integer math. Is there any sort of optimized square root routine I can use for this?

Additionally, in order to pan based on one 16-bit control signal, I'm having to compress the amplitude scaling down to 12-bits. Is there any simple smoothing y'all can recommend that could remove some of the steppiness this introduces to the signal?

Also, this is my first crack at a more complicated audio object using the optimized integer math, if you see anything I could be doing better best practice wise I'd appreciate any tips. Thanks!

Here's the start I have on the panner object code:

Code:
#ifndef panner_h_
#define panner_h_

#include "Arduino.h"
#include "AudioStream.h"

#define PANNER_NUM_CHANNELS 8

class Panner : public AudioStream
{
public:
  Panner( void ) : AudioStream(2, inputQueueArray) {}
	virtual void update(void);
  
private:
	audio_block_t *inputQueueArray[2];
};

#endif

Code:
#include <Arduino.h>
#include "panner.h"
#include "utility/dspinst.h"

void Panner::update(void){
  audio_block_t *in = receiveReadOnly(0);
  audio_block_t *out[8]; // = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  
  if(in){
    audio_block_t *pan = receiveReadOnly(1);
    if(pan){
      for(int och = 0; och < 8; ++och){
        out[och] = allocate();
        if (out[och]) {
          memset(out[och]->data, 0, AUDIO_BLOCK_SAMPLES*2);
        }
      }
      for(int i = 0; i < AUDIO_BLOCK_SAMPLES; ++i){
        int32_t p = pan->data[i];
        if(p < 0){
          p = 32768 + p;
        }
        int a = p >> 12;
        int b = (a + 1) % 8;
        int32_t p2 = (p % 4096) << 4;
        int32_t p1 = (65536 - p2);
        if(out[a]){
          int32_t val1 = signed_multiply_32x16b(p1, in->data[i]);
          out[a]->data[i] = signed_saturate_rshift(val1, 16, 0);
        }
        if(out[b]){
          int32_t val2 = signed_multiply_32x16b(p2, in->data[i]);
          out[b]->data[i] = signed_saturate_rshift(val2, 16, 0);
        }
      }
      for(int och = 0; och < 8; ++och){
        if(out[och]){
          transmit(out[och], och);
          release(out[och]);
        }
      }
      release(pan);
    }
    release(in);
  }
}
 
Back
Top