Phil Burk | e7143e0 | 2019-09-04 15:19:17 -0700 | [diff] [blame] | 1 | # Notes on Implementation |
| 2 | |
| 3 | ## Latency from Resampling |
| 4 | |
| 5 | There are two components of the latency. The resampler itself, and a buffer that |
| 6 | is used to adapt the block sizes. |
| 7 | |
| 8 | 1) The resampler is an FIR running at the target sample rate. So its latency is the number of taps. |
| 9 | From MultiChannelResampler.cpp, numTaps is |
| 10 | |
| 11 | Fastest: 2 |
| 12 | Low: 4 |
| 13 | Medium: 8 |
| 14 | High: 16 |
| 15 | Best: 32 |
| 16 | |
| 17 | For output, the device sampling rate is used, which is typically 48000.For input, the app sampling rate is used. |
| 18 | |
Phil Burk | 3be2553 | 2019-12-20 16:20:57 -0800 | [diff] [blame] | 19 | 2) There is a block size adapter that collects odd sized blocks into larger blocks of the correct size. |
Phil Burk | e7143e0 | 2019-09-04 15:19:17 -0700 | [diff] [blame] | 20 | |
| 21 | The adapter contains one burst of frames, from getFramesPerBurst(). But if the app specifies a |
| 22 | particular size using setFramesPerCallback() then that size will be used. |
| 23 | Here is some pseudo-code to calculate the latency. |
| 24 | |
| 25 | latencyMillis = 0 |
| 26 | targetRate = isOutput ? deviceRate : applicationRate |
| 27 | // Add latency from FIR |
| 28 | latencyMillis += numTaps * 1000.0 / targetRate |
| 29 | // Add latency from block size adaptation |
| 30 | adapterSize = (callbackSize > 0) ? callbackSize : burstSize |
| 31 | if (isOutput && isCallbackUsed) latencyMillis += adapterSize * 1000.0 / deviceRate |
| 32 | else if (isInput && isCallbackUsed) latencyMillis += adapterSize * 1000.0 / applicationRate |
| 33 | else if (isInput && !isCallbackUsed) latencyMillis += adapterSize * 1000.0 / deviceRate |