Tone generator algorithms performance

This article presents the performance analysis of various back-end algorithms of the tone generator that are implemented in PJMEDIA. Both the performance in both speed and accuracy terms will be analyzed.

The Algorithms

The tone generator (tonegen.c) supports several algorithms, and since version 1.0-rc3, the use of these algorithms can be controlled by by using the PJMEDIA_TONEGEN_ALG macro setting:

  • PJMEDIA_TONEGEN_SINE: the good-old generation using math’s sine(), floating point. This has very good precision but it’s the slowest and requires floating point support and linking with the math library.

  • PJMEDIA_TONEGEN_FLOATING_POINT: (default when floating point is enabled):: Floating point approximation of sine(). This has relatively good precision and much faster than plain (sine()*, but it requires floating-point support and linking with the math library.

  • PJMEDIA_TONEGEN_FIXED_POINT_CORDIC: (new in 1.0-rc3, and the default when floating point is disabled):: Fixed point using sine signal generated by a 28-bit CORDIC algorithm. This algorithm can be tuned to provide balance between precision and performance by tuning the PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP setting, and it is suitable for platforms that lack floating-point support.

  • PJMEDIA_TONEGEN_FAST_FIXED_POINT: Fast fixed point using some approximation to generate sine waves. The tone generated by this algorithm is not very precise, however the algorithm is very fast.

Accuracy

For the accuracy test, we setup the tone generator to generate digit A from DTMF, with frequencies of 697 and 1209. We then saved the tone to a WAV file and analyzed the frequency using CoolEdit (now becomes Adobe Audition).

This is simple to do with pjsua:

$ pjsua -play-tone 697,1209,200,2000 -rec-file tone.wav

then issue these commands:

cc 1 2
sleep 5000
cd 1 2
q

And here is the graphics from the frequency analysis.

tonegen_analysis.png

Performance

Below is the time measurements of the algorithms. The test measures the generation of 1 second worth of dual-tone at 8KHz sampling rate. For single-tone, just divide the results by two, and for 16KHz dual-tone, just multiply the results by two.

The MIPS value uses the same convention as in Media Performance (MIPS test).

Linux, ARM9 (ARM926EJ-S), gcc

PJSIP was compiled with -O3 -msoft-float -DNDEBUG -DPJ_HAS_FLOATING_POINT=0 flags.

time (usec)

CPU (%)

MIPS

PJMEDIA_TONEGEN_SINE

506,535

50.653

100.29

PJMEDIA_TONEGEN_FLOATING_POINT

18,037

1.804

3.57

PJ MEDIA_TONEGEN_FIXED_POINT_CORDIC with 16 iterations

17,694

1.769

3.50

PJ MEDIA_TONEGEN_FIXED_POINT_CORDIC with 12 iterations

13,561

1.356

2.69

PJ MEDIA_TONEGEN_FIXED_POINT_CORDIC with 10 iterations

11,662

1.166

2.31

PJ MEDIA_TONEGEN_FIXED_POINT_CORDIC with 8 iterations

9,872

0.987

1.95

PJ MEDIA_TONEGEN_FIXED_POINT_CORDIC with 7 iterations

8,943

0.894

1.77

PJMEDIA_TONEGEN_FAST_FIXED_POINT

1,449

0.145

0.29

Windows, P4 2.66 GHz, Visual Studio 6

time (usec)

CPU (%)

MIPS

PJMEDIA_TONEGEN_SINE

1,348

0.135

10.92

PJMEDIA_TONEGEN_FLOATING_POINT

605

0.060

4.90

P JMEDIA_TONEGEN_FIXED_POINT_CORDIC with 16 iterations

1,372

0.137

11.12

P JMEDIA_TONEGEN_FIXED_POINT_CORDIC with 12 iterations

1,140

0.114

9.24

P JMEDIA_TONEGEN_FIXED_POINT_CORDIC with 10 iterations

998

0.100

8.09

P JMEDIA_TONEGEN_FIXED_POINT_CORDIC with 8 iterations

826

0.083

6.69

P JMEDIA_TONEGEN_FIXED_POINT_CORDIC with 7 iterations

743

0.074

6.02

PJMEDIA_TONEGEN_FAST_FIXED_POINT

117

0.012

0.95

Conclusion

Based on the results above, and as of version 1.0-rc3, we set the tone generator settings in config_site.h as follows:

  • on PC and platforms where floating point is available:

    #define PJMEDIA_TONEGEN_ALG                     PJMEDIA_TONEGEN_FLOATING_POINT
    
  • on platforms where floating point is NOT available:

    #define PJMEDIA_TONEGEN_ALG                     PJMEDIA_TONEGEN_FIXED_POINT_CORDIC
    #define PJMEDIA_TONEGEN_FIXED_POINT_CORDIC_LOOP 10
    

These settings of course can be overridden in your config_site.h as usual.