I'm working on porting Opus IMDCT/FFT to a fixed point 16-bit DSP with a 48-bit accumulator. I'm trying to do that with 32-bit fixed point numbers to keep the highest possible quality. I'm basing my implementation on Xiph's reference implementation which can be compiled to use fixed points.
Looking at the macros used to implement complex numbers operations, for instance C_ADD
and C_SUB
:
#define C_ADD( res, a,b)\
do {(res).r=ADD32_ovflw((a).r,(b).r); (res).i=ADD32_ovflw((a).i,(b).i); \
}while(0)
#define C_SUB( res, a,b)\
do {(res).r=SUB32_ovflw((a).r,(b).r); (res).i=SUB32_ovflw((a).i,(b).i); \
}while(0)
the underlying macros being used to add fixed point integers are called ADD32_ovflw
and SUB32_ovflw
. In turn, these macros are defined as:
/** Add two 32-bit values, ignore any overflows */
#define ADD32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)+(opus_uint32)(b)))
/** Subtract two 32-bit values, ignore any overflows */
#define SUB32_ovflw(a,b) ((opus_val32)((opus_uint32)(a)-(opus_uint32)(b)))
I'm confused by the meaning of the "ignore any overflows" part. The DSP I'm working on natively support saturating adds and subs; to make an overflowing operation, I need to manually play with the carry flag, which requires many more opcodes.
To the best of my (little) understanding of signal processing, I would say that a well formed FFT part of a IMDCT should never cause any overflow. If an overflow happens, I would say that the fixed point precision is not enough, and scaling should be performed on the input (at the beginning, or after each step).
So probably the real meaning of ADD32_ovflw
is "this will not overflow, do whatever add is more performant on your DSP", rather than "this must absolutely be implemented as an overflowing 32-bit addition". Is this correct?