I'd preface this by saying that I'm fairly new to the axoloti firmware, so if others have better information/insights please correct me.
I'm wondering how both the k-rate and s-rate Hz numbers relate to both the
number of lines in a code block and the processor's clock speed.
They don't...
So far, I've picked up that k-rate code is 3 kHz s-rate is 48 kHz
Right. The codec/sai is setup to playback 48000 samples per second.
Each sample is a 32 bit fixed point (q5.27) quantity.
There are 2 channels of audio.
Some signals in a synth are relatively slow moving, E.g envelopes.
We can save memory and cpu by generating them at a slower rate.
In axoloti the factor is x16, so the k-rate signals have 3000 values/second.
and the CPU's clock speed is 168 MHz.
Right. The CPU is actually rated for 180 MHz, but ST in their wisdom made it impossible to run the USB with this CPU speed.
For the k-/s-rate numbers, does this mean that the Axoloti board will execute
the entire code.krate block for an object 3,000 times a second, and the entire
code.srate block 48,000 times a second?
Yes. If you write an some object code in the GUI and look at what gets generated you will see the following:
void dsp(blah...) {
your_krate_code();
for(i = 0 i < BUFSIZE; i ++) {
your_srate_code();
}
}
ie - your krate code gets called once and the srate code gets called in a 16x loop.
Some of the objects don't bother with the srate code. They just do everything (including the srate work) in the krate code specification.
16 x 1/48000 = 1/3 ms of signal. So: an object generating an srate signal must be called 3000 times/second.
As for the CPU's clock speed, since it's much higher than the k-/s-rate speeds
I'm assuming that there is some multithreading going on
Yes, in so far as the firmware uses chibios and chibios supports multiple concurrent tasks/threads.
such that the processor is executing multiple k-/s-rate things at the same
time. Is this right?
No. One thread is responsible for generating the audio buffers and that is "ThreadDSP".
Basically it works as follows:
The codec/SAI needs to be fed at a rate of 48000 samples/second (x 2 channels) to generate clean audio.
The SAI is fed by DMA from memory. The DMA is arranged in double buffering mode. ie: when the SAI is reading from one buffer the CPU can be busy filling in the other buffer. When the SAI is done with one buffer the DMA will be switched to the other buffer, so the CPU has to be done with filling it in before this happens.
Every time the DMA switches buffers an interrupt gets generated. This interrupt wakes up ThreadDSP and tells it to get busy computing the sound and filling in the output buffer the SAI is not currently reading from.
To do this the code calls the patch you have created. See: PatchProcess in xpatch.cpp
That code hooks up all the objects you have created and ultimately computes the 16 samples (x2 channels) needed for the audio output.
When you return from your patch the ThreadDSP code will time how long it took and see how much you beat the deadline by. This gives you the CPU load number.
So- the bigger the patch, the more complex the objects, the greater the number of voices, the longer it will take the CPU to compute the sound. Every 1/3 ms the ThreadDSP code will wake up and will go full speed trying to get the buffer filled before the SAI needs it.
Hope this helps.