trummerschlunk / master_me

automatic mastering plugin for live streaming, podcasts and internet radio.
GNU General Public License v3.0
542 stars 22 forks source link

Optiimzation - avoid log() calls in inner loop #9

Open x42 opened 2 years ago

x42 commented 2 years ago

https://github.com/trummerschlunk/soundsgood/blob/e8eb9ba756971c22c5da8ca5a1f887f9f342faac/soundsgood.dsp#L348

The value is for display only. With a custom GUI it's preferable to have the GUI call it. Currently FAUST compiles this into the inner loop and calls log10() for each sample!

Since it's for display only, accuracy is not required you might want to investigate a fast_log implementation https://www.flipcode.com/archives/Fast_log_Function.shtml

falkTX commented 2 years ago

It is best to have the values on the dsp side be linear and let the GUI deal with the calculations for log scale.

sletz commented 2 years ago

Does this helps ?

falkTX commented 2 years ago

I dont think so. we want to avoid some calculations altogether, the issue is not optimization but one of simply not doing them. The GUI is the one that needs to display values on screen, the values it receives do not need to be in log scale, it is quite fine to do the conversion on the GUI side.

sletz commented 2 years ago

Then this C++ conversion code might help.

jkbd commented 2 years ago

I don't know how to make use of the LogValueConverter. But I just remembered that FAUST can use external C functions via Foreign Expressions. That way, some of the normal log10 calls could be replaced with the approximation @x42 suggested above.

jkbd commented 2 years ago

This Taylor-approximation looked interesting to me. But further investigation showed, that this cannot solve our problem.

This Python code

import numpy as np
import matplotlib.pyplot as plt

eps = np.finfo(float).eps
x = np.linspace(eps, 2.0, num=10**4)

plt.plot(x, 20*np.log(x)/np.log(10), label="factor2decibel")

def ln_approx_5(x):
    """
    The Taylor approximation is calculated with SageMath (https://www.sagemath.org/):
sage: ln(x).taylor(x, 0.0707945784384138, 5).horner(x)
```
where `0.0707945784384138` is the x value at -23dB.
"""
return ((((112468.2650380697*x - 49763.396319187115)*x + 9394.609770881507)*x - 997.6311574844394)*x + 70.6268772311377)*x - 4.931306190276485

plt.plot(x, 20*ln_approx_5(x)/np.log(10), label="degree 5")

def ln_approx_11(x): return ((((((((((406075992864.511x - 347850542618.52094)x + 136810736245.84268)x - 32688422094.510403)x + 5289515570.280675)x - 611632740.7376956)x + 51960338.44758817)x - 3284384.1570663475)x + 155011.06121954476)x - 5486.971366164414)x + 155.3791299085029)*x - 5.667850201820498

plt.plot(x, 20*ln_approx_11(x)/np.log(10), label="degree 11")

def ln_approx_42(x): return ((((((((((((((((((((((((((((((((((((((((x(-(4.75062455944967e+46)x + 1.4469896798574425e+47) - 2.1524999999999812e+47)x + 2.0839019499307262e+47)x - 1.476260185786845e+47)x + 8.157524221420126e+46)x - 3.6602274100007795e+46)x + 1.3707144342764619e+46)x - 4.370329389860752e+45)x + 1.2042469514201538e+45)x - 2.9013054712441056e+44)x + 6.167924296304309e+43)x - 1.1656278666150943e+43)x + 1.9699766602062316e+42)x - 2.992064900743801e+41)x + 4.100454989478739e+40)x - 5.087052816328745e+39)x + 5.72827702369729e+38)x - 5.867056670588852e+37)x + 5.474712652474278e+36)x - 4.659768327420024e+35)x + 3.620521220644458e+34)x - 2.568958037099986e+33)x + 1.6646984097251124e+32)x - 9.848248980054393e+30)x + 5.3151447931161086e+29)x - 2.614084440040622e+28)x + 1.1697809757872537e+27)x - 4.753363261576625e+25)x + 1.7495071687140665e+24)x - 5.814333388836693e+22)x + 1.738233210776675e+21)x - 4.653111241729626e+19)x + 1.1091415784016607e+18)x - 2.3383154588928156e+16)x + 432431169745875.56)x - 6944793221868.8955)x + 95673154083.40453)x - 1114003390.0013206)x + 10785012.016971951)x - 85896.0426594101)x + 593.2657687415557)x - 6.974715663591488

plt.plot(x, 20*ln_approx_42(x)/np.log(10), label="degree 42", alpha=0.5)

plt.ylim(-96, 6)

plt.xscale('log')

plt.xlabel('Factor') plt.ylabel('Decibel') plt.legend() plt.show()


produces the image
![grafik](https://user-images.githubusercontent.com/20183922/187543692-a075c5db-a5be-4e0e-a32a-19231ff2e76a.png)
where you can see, the approximation is only close to `factor2decibel` within a narrow interval and with higher degrees numerical problems seem to arise.
sletz commented 2 years ago

Use case of converters here https://github.com/grame-cncm/faust/blob/master-dev/architecture/faust/gui/APIUI.h

x42 commented 2 years ago

Reading the produced C++ code of the final product now, the log here is really just the tip of the iceberg and would just be a micro optimization.