Audio in NDI®#
Dynamic Range#
When sending or receiving audio in NDI®, it’s important to understand the dynamic range that the library works with.
Audio samples are passed as 32-bit floating point values, but they are not necessarily normalized to +/- 1.0. Instead, a sine wave at 2.0 peak-to-peak is considered to be at +4 dBu.
The following table explains the relationship between the different scales:
dBu |
dBVU |
dBFS (SMPTE) |
dBFS (EBU) |
NDI Amplitude |
|---|---|---|---|---|
+24 dB |
+20 dB |
0 dB |
10.0 |
|
+18 dB |
+14 dB |
-6 dB |
0 dB |
\(10 ^{14/20} \approx 5.01\) |
+4 dB |
0 dB |
-20 dB |
-14 dB |
1.0 |
-16 dB |
-20 dB |
-40 dB |
-34 dB |
0.1 |
See also
NDI Audio Frames for more information on audio frames in NDI®.
Why It Matters#
That same waveform (amplitude of +/- 1.0) will be -20 dBFS (SMPTE) and -14 dBFS (EBU).
We can then see that, in the SMPTE scale:
giving the amplitude \(A_{fs}\) as:
If you simply pass a wavefile in 32-bit float format into NDI®, it will be 20 dB lower than expected. Conversely, if you are receiving audio from NDI®, the audio will be 20 dB higher than expected (ouch)!
How to Handle It#
Starting with cyndilib v0.0.8, scaling audio samples to/from NDI® can be done automatically by the
AudioFrame, but its reference level
must be set appropriately.
By default, it is set to dBVU so no scaling is done to
maintain backwards-compatibility [1].
To send or receive normalized audio, set the reference level to dBFS_smpte.
>>> from cyndilib import AudioReference, AudioSendFrame, AudioFrameSync
>>> send_frame = AudioSendFrame()
>>> send_frame.reference_level = AudioReference.dBFS_smpte
>>> # Now send_frame can be filled with normalized audio samples
>>> # and they will be scaled up by 20 dB (10x amplitude) when sent.
>>> recv_frame = AudioFrameSync()
>>> recv_frame.reference_level = AudioReference.dBFS_smpte
>>> # Now recv_frame will provide normalized audio samples
>>> # by scaling down the received samples by 20 dB (0.1x amplitude).